mirror of
https://github.com/theniceboy/.config.git
synced 2025-12-26 06:24:57 +08:00
opencode config
This commit is contained in:
parent
7530931e2b
commit
b208e0612f
4 changed files with 201 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -89,3 +89,5 @@ tmux/cache
|
|||
agent-tracker/.DS_Store
|
||||
agent-tracker/run
|
||||
!starship-tmux.toml
|
||||
|
||||
!/opencode/
|
||||
|
|
|
|||
40
opencode/AGENTS.md
Normal file
40
opencode/AGENTS.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
## Hard Rule: No Change‑Note Comments In Code
|
||||
|
||||
- Agents MUST NOT add comments that describe the change they just made (e.g., “removed”, “legacy”, “cleanup”, “hotfix”, “flag removed”, “temporary workaround”).
|
||||
- Only add comments for genuinely non‑obvious, persistent logic or external invariants. Keep such comments short (max 2 lines).
|
||||
|
||||
Forbidden examples:
|
||||
- // shouldShowDoneButton removed; UI reacts to selection
|
||||
- // legacy code kept for now
|
||||
- // temporary cleanup / hotfix
|
||||
|
||||
Allowed examples (non‑obvious logic):
|
||||
- // Bound must be >= 30px to render handles reliably
|
||||
- // Server returns seconds (not ms); convert before diffing
|
||||
|
||||
Rationale placement:
|
||||
- Put change reasoning in your plan/final message or PR description — not in code.
|
||||
|
||||
CRITICAL WORKFLOW REQUIREMENT
|
||||
- When the user asks for something but there's ambiguity, you must always ask for clarification before proceeding. Provide users some options.
|
||||
- When giving user responses, give short and concise answers. Avoid unnecessary verbosity.
|
||||
- Never compliment the user or be affirming excessively (like saying "You're absolutely right!" etc). Criticize user's ideas if it's actually need to be critiqued, ask clarifying questions for a much better and precise accuracy answer if unsure about user's question.
|
||||
- Avoid getting stuck. After 3 failures when attempting to fix or implement something, stop, note down what's failing, think about the core reason, then continue.
|
||||
- When migrating or refactoring code, do not leave legacy code. Remove all deprecated or unused code.
|
||||
|
||||
Other recommendations:
|
||||
- When giving the user bullet lists, use different bullet characters for different levels
|
||||
- Use numbered lists for options/confirmations.
|
||||
- Prompt users to reply compactly (e.g., "1Y 2N 3Y").
|
||||
- Default to numbers for multi-step plans and checklists.
|
||||
|
||||
---------
|
||||
|
||||
## Code Change Guidelines
|
||||
|
||||
- No useless comments or code. Only comment truly complex logic.
|
||||
- No need to write a comment like "removed foo" after removing code
|
||||
- Keep diffs minimal and scoped; do not add files/utilities unless required.
|
||||
- Prefer existing mechanisms
|
||||
- Remove dead code, unused imports, debug prints, and extra empty lines.
|
||||
- Do not leave temporary scaffolding; revert anything not needed.
|
||||
32
opencode/opencode.json
Normal file
32
opencode/opencode.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"small_model": "zai-coding-plan/glm-4.6",
|
||||
"lsp": {
|
||||
"dart": {
|
||||
"command": [
|
||||
"dart",
|
||||
"language-server"
|
||||
],
|
||||
"extensions": [
|
||||
".dart"
|
||||
]
|
||||
}
|
||||
},
|
||||
"permission": {
|
||||
"edit": "allow",
|
||||
"bash": "allow",
|
||||
"webfetch": "allow",
|
||||
"doom_loop": "allow",
|
||||
"external_directory": "allow"
|
||||
},
|
||||
"mcp": {
|
||||
"web": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"mctrl-mcp",
|
||||
"web"
|
||||
],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
127
opencode/plugin/tracker-notify.js
Normal file
127
opencode/plugin/tracker-notify.js
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
const NOTIFY_BIN = "/usr/bin/python3";
|
||||
const NOTIFY_SCRIPT = "/Users/david/.config/codex/notify.py";
|
||||
const MAX_SUMMARY_CHARS = 600;
|
||||
const TRACKER_BIN = "/Users/david/.config/agent-tracker/bin/tracker-client";
|
||||
const finishedSessions = new Set(); // track by sessionID
|
||||
|
||||
export const TrackerNotifyPlugin = async ({ client, directory, $ }) => {
|
||||
const trackerReady = async () => {
|
||||
const check = await $`test -x ${TRACKER_BIN}`.nothrow();
|
||||
return check?.exitCode === 0;
|
||||
};
|
||||
|
||||
const summarizeText = (parts = []) => {
|
||||
const text = parts
|
||||
.filter((p) => p?.type === "text" && !p.ignored)
|
||||
.map((p) => p.text || "")
|
||||
.join("\n")
|
||||
.trim();
|
||||
return text.slice(0, MAX_SUMMARY_CHARS);
|
||||
};
|
||||
|
||||
const collectUserInputs = (messages) => {
|
||||
return messages
|
||||
.filter((m) => m?.info?.role === "user")
|
||||
.slice(-3)
|
||||
.map((m) => summarizeText(m.parts))
|
||||
.filter((text) => text);
|
||||
};
|
||||
|
||||
const startTask = async (summary) => {
|
||||
if (!summary) return;
|
||||
if (!(await trackerReady())) return;
|
||||
await $`${TRACKER_BIN} command -summary ${summary} start_task`.nothrow();
|
||||
};
|
||||
|
||||
const finishTask = async (summary) => {
|
||||
if (!(await trackerReady())) return;
|
||||
await $`${TRACKER_BIN} command -summary ${summary || "done"} finish_task`.nothrow();
|
||||
};
|
||||
|
||||
const notify = async (sessionID) => {
|
||||
try {
|
||||
const messages =
|
||||
(await client.session.messages({
|
||||
path: { id: sessionID },
|
||||
query: { directory },
|
||||
})) || [];
|
||||
|
||||
const assistant = [...messages]
|
||||
.reverse()
|
||||
.find((m) => m?.info?.role === "assistant");
|
||||
if (!assistant) return;
|
||||
|
||||
const assistantText = summarizeText(assistant.parts);
|
||||
if (!assistantText) return;
|
||||
|
||||
const payload = {
|
||||
type: "agent-turn-complete",
|
||||
"last-assistant-message": assistantText,
|
||||
input_messages: collectUserInputs(messages),
|
||||
};
|
||||
|
||||
const serialized = JSON.stringify(payload);
|
||||
try {
|
||||
await $`${NOTIFY_BIN} ${NOTIFY_SCRIPT} ${serialized}`;
|
||||
} catch {
|
||||
// ignore notification failures but still finish
|
||||
}
|
||||
} catch {
|
||||
// Ignore notification failures
|
||||
}
|
||||
};
|
||||
|
||||
const finishOnce = async (sessionID, summary) => {
|
||||
if (!sessionID || finishedSessions.has(sessionID)) return;
|
||||
finishedSessions.add(sessionID);
|
||||
await finishTask(summary?.slice(0, 200) || "");
|
||||
};
|
||||
|
||||
return {
|
||||
event: async ({ event }) => {
|
||||
// On idle: ensure finish, even if message hook missed
|
||||
if (event?.type === "session.idle" && event?.properties?.sessionID) {
|
||||
const sessionID = event.properties.sessionID;
|
||||
let text = "";
|
||||
try {
|
||||
const messages =
|
||||
(await client.session.messages({
|
||||
path: { id: sessionID },
|
||||
query: { directory },
|
||||
})) || [];
|
||||
const assistant = [...messages]
|
||||
.reverse()
|
||||
.find((m) => m?.info?.role === "assistant");
|
||||
if (assistant) text = summarizeText(assistant.parts);
|
||||
} catch {
|
||||
// ignore fetch errors
|
||||
}
|
||||
await finishOnce(sessionID, text || "done");
|
||||
await notify(sessionID);
|
||||
}
|
||||
},
|
||||
"chat.message": async (_input, output) => {
|
||||
if (output?.message?.role !== "user") return;
|
||||
const summary = summarizeText(output.parts).slice(0, 200);
|
||||
await startTask(summary);
|
||||
},
|
||||
"message.updated": async ({ event }) => {
|
||||
if (event?.properties?.info?.role !== "assistant") return;
|
||||
const sessionID = event?.properties?.info?.sessionID;
|
||||
if (!sessionID) return;
|
||||
|
||||
const parts = event?.properties?.parts || [];
|
||||
const text = summarizeText(parts) || "done";
|
||||
|
||||
// Prefer explicit finish flag; otherwise if we see any assistant message update after start, finish once.
|
||||
const isFinished =
|
||||
event?.properties?.info?.finish ||
|
||||
event?.properties?.info?.summary ||
|
||||
false;
|
||||
|
||||
if (isFinished || !finishedSessions.has(sessionID)) {
|
||||
await finishOnce(sessionID, text);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue