codiedev 0.9.88 → 0.9.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.d.ts CHANGED
@@ -111,6 +111,10 @@ export declare function openCodeInstalled(): boolean;
111
111
  * keeps `codiedev connect` as the only setup step even when Codie/OpenCode is
112
112
  * installed later. OpenCode loads this file from its documented plugin dir. */
113
113
  export declare function installOpenCodeCapturePlugin(): void;
114
+ /** Rewrite an OpenCode plugin installed by an older CLI: one that still wires
115
+ * the retired Agent Security tool hooks, or predates the prompt guard (it
116
+ * would let a stopped prompt through). Only touches an existing Codiedev plugin. */
117
+ export declare function ensureOpenCodePluginCurrent(): void;
114
118
  export declare function piInstalled(): boolean;
115
119
  /** Subcommands the pi extension calls, in the order inspectPiExtension checks. */
116
120
  export declare const PI_EXTENSION_SUBCOMMANDS: readonly ["session-start-pi", "backup-pi", "capture-pi-final", "discover-pi", "security-pre-pi", "security-post-pi", "security-failure-pi"];
@@ -143,7 +147,7 @@ export declare function ensureAllCodiedevHooksInstalled(): void;
143
147
  export declare function hasDirectHookPath(configText: string): boolean;
144
148
  export declare function migrateHooksToLauncher(): string[];
145
149
  export declare function ensureSessionStartHookInstalled(): void;
146
- export declare const CODIEDEV_INSTRUCTIONS_BODY = "## Codiedev \u2014 team artifact layer\n\nThis machine is connected to Codiedev. Teammates share specs, reviews,\ndecisions, and messages via a CLI on every dev's machine.\n\n**When the user asks to share, push, ping, check messages, or capture a\nthought, use the `codiedev` CLI via Bash:**\n\n| Intent | Command |\n|---|---|\n| \"push this spec\" / \"save this as a skill\" | `codiedev push <file.md>` |\n| \"pull X\" / \"grab the latest spec-X\" / \"what did a teammate push?\" | `codiedev pull <key>` |\n| \"delete X\" / \"remove that test push\" / \"rm spec-old\" | `codiedev delete <key>` (always confirm with the user first) |\n| \"ping a teammate about this\" / \"ask someone for their take\" / \"send them this file\" | `codiedev ping <name> \"<msg>\" [--with <key>] [--file <path>]` |\n| \"any messages?\" / \"check my inbox\" / \"what did a teammate say?\" | `codiedev inbox` |\n| \"read that reply\" / \"mark that ping read\" | `codiedev read <ping-id>` |\n| \"reply to that\" / \"tell them X\" (answering a message from `codiedev inbox`) | `codiedev reply <ping-id> \"<msg>\" [--file <path>]` (not a new ping: this threads it and marks theirs answered) |\n| \"note that X is a follow-up\" / \"remember X\" | `codiedev note \"<text>\"` |\n| \"share with a teammate\" / \"give someone access\" (no notification) | `codiedev share <key> <name> [--role read\\|edit]` |\n| \"send this to a teammate\" / \"ask someone to look at this\" | `codiedev send <key> <name> [\"<msg>\"]` |\n| \"find something about X\" / \"has anyone solved Y?\" | `codiedev search \"<query>\" [--limit N]` |\n| \"show my library\" / \"what artifacts exist?\" | `codiedev library [--scope mine\\|shared\\|all] [--kind doc\\|skill]` |\n| \"run my agent's test cases\" / \"check the dataset on model Y\" / \"run v2 of the dataset\" | `codiedev traces cases <agent> [--dataset <name> [--version <n>]] [--model <id>]` (writes cases + RUN_CASES.md + results.json; follow it, then `codiedev traces report <results.json>`) |\n| \"how are my agents doing?\" / \"what's failing this week?\" / \"show the booking agent's failed runs\" / \"why did run X fail?\" | `codiedev traces overview`; `codiedev traces runs <agent> [--failed] [--flag <issue>] [--days n]`; `codiedev traces run <run> --agent <name>` (add `--json` to read the data yourself) |\n| \"add a helpfulness 1\u20135 score\" / \"make a review queue for tone\" | `codiedev traces score-kinds add <name> --type number --min 1 --max 5`; `codiedev traces queue create <name> --scores <a,b>` |\n| \"score that run 4 for helpfulness\" / \"how is my agent scoring?\" | `codiedev traces score <run> <score> <value> [--agent <name>] [--comment <why>]`; `codiedev traces scores <agent>` |\n| \"put this week's failed runs in the review queue\" | `codiedev traces queue list`; `codiedev traces queue add <queue> --agent <name> [--failed] [--days n]` |\n| \"have a judge score 10% of my agent's runs\" / \"turn off automatic scoring\" | `codiedev traces judge <agent> --on --scores <a,b> --sample 10 [--budget 25]`; `--off`; no flags shows it |\n| \"import these test cases from a CSV\" / \"add an example to the dataset\" / \"save the dataset as a version\" | `codiedev traces import <agent> <file> --dataset <name>`; `codiedev traces add-example <agent> --dataset <name> --input \"\u2026\" [--expected \"\u2026\"]`; `codiedev traces save-version <dataset>`; `codiedev traces versions <dataset>` |\n| \"make a starter pack\" / \"add this to our pack\" / \"package these skills for my team\" | write a `<slug>.pack.md` (start from `codiedev pack export <slug> --manifest --out .` for an existing pack), then `codiedev pack apply <file> [--publish]` \u2014 see **Starter packs** below |\n| \"publish the pack\" / \"ship the pack to my team\" | `codiedev pack publish <slug> [--channel stable\\|beta\\|alpha]` |\n| \"what was the last eval on X?\" / \"file these eval results\" | `codiedev evals last <subject>` before starting a related eval; `codiedev evals report <run.json>` after each variant runs (scores only \u2014 `codiedev evals help` for the shape) |\n\n**Starter packs** (team managers and admins): a pack.md is frontmatter\n(`name:`, `slug:`, optional `description:`) then sections. Ask the user\nwhat to include, write the file, run `codiedev pack apply <file> --dry-run`\nto show them, then apply for real:\n\n```\n---\nname: \"Healthcare scan\"\nslug: \"healthcare-scan\"\n---\n\n# Healthcare scan\n\n## Skills\n\n- ./skills/healthcare-scan\n- lint.md @teammate@example.com\n\n## Files\n\n- runner <- ~/.claude/runner\n```\n\nUnder **Skills**, a local path (`./\u2026`, `~/\u2026` or `/\u2026`) to a skill folder\nor SKILL.md is pushed to the library and added, with the rest of its folder\nshipped as the skill's files; `<key> @<author email>` adds a teammate's\nlibrary skill. **Files** maps local folders to paths in the pack\n(`.` is the pack root). In skills, point at shipped files relative to the\nskill's folder or with `${CLAUDE_PLUGIN_ROOT}/\u2026`. Applying changes the\ndraft; `--publish` (or `codiedev pack publish`) sends it to the team.\n\n**Just push the file \u2014 we'll figure out where it goes.** Every artifact\nis classified into one of two kinds at upload time:\n\n- **skill** \u2014 the file has SKILL.md frontmatter (`name:` + `description:`\n inside a `---` block). Shows on the Skills page in the portal and is\n invokable as a slash command (`/<name>`).\n- **doc** \u2014 everything else. Lives in the library: list it with\n `codiedev library`, fetch it with `codiedev pull <key>`.\n\nDetection is content-based, not filename-based. The filename prefix\n(`spec-` / `decision-` / `proposal-` / `bugfix-` / `review-` /\n`note-`) is preserved as a *tag* you can filter by, but it never gates\nvisibility. A SKILL-frontmatter file named `note-foo.md` still becomes\na skill.\n\nThe `codiedev push` response always says where the artifact landed \u2014\nread it back to the user so they can confirm.\n\n**Resolving \"the spec we just worked on\":**\n- If a file was recently edited in this session matching the conventions\n above, push that file.\n- If content was drafted inline in the conversation, write it to a file\n first (e.g., `/tmp/spec-xxx.md`) then push.\n\n**Teammate names:** first name usually works (`codiedev ping <name> ...`).\nIf ambiguous, the CLI returns candidates \u2014 retry with the full email.\n\n**Search before pushing.** For any \"save this as \u2026\" request, run\n`codiedev search \"<query>\"` first. If prior art exists, pull it and\niterate rather than duplicating.\n\n**Sharing vs sending:** `codiedev share` is silent (access only, no\nnotification). `codiedev send` both grants access AND pings the\nrecipient. Use send when the user is actively looping someone in.\n\n**Errors:**\n- \"not connected\" \u2192 user needs to run `npx codiedev connect` with their\n API token from https://codiedev.com/portal/integrations/claude-code\n- \"ambiguous recipient\" \u2192 surface candidates to the user\n";
150
+ export declare const CODIEDEV_INSTRUCTIONS_BODY = "## Codiedev \u2014 team artifact layer\n\nThis machine is connected to Codiedev. Teammates share specs, reviews,\ndecisions, and messages via a CLI on every dev's machine.\n\n**When the user asks to share, push, ping, check messages, or capture a\nthought, use the `codiedev` CLI via Bash:**\n\n| Intent | Command |\n|---|---|\n| \"push this spec\" / \"save this as a skill\" | `codiedev push <file.md>` |\n| \"pull X\" / \"grab the latest spec-X\" / \"what did a teammate push?\" | `codiedev pull <key>` |\n| \"delete X\" / \"remove that test push\" / \"rm spec-old\" | `codiedev delete <key>` (always confirm with the user first) |\n| \"ping a teammate about this\" / \"send them this spec\" / \"send them this file\" | `codiedev ping <name> \"<msg>\" [--with <key>] [--file <path>]` (`--with` also gives them access) |\n| \"any messages?\" / \"check my inbox\" / \"what did a teammate say?\" | `codiedev inbox` |\n| \"read that reply\" / \"mark that ping read\" | `codiedev read <ping-id>` |\n| \"reply to that\" / \"tell them X\" (answering a message from `codiedev inbox`) | `codiedev reply <ping-id> \"<msg>\" [--file <path>]` (not a new ping: this threads it and marks theirs answered) |\n| \"note that X is a follow-up\" / \"remember X\" | `codiedev note \"<text>\"` |\n| \"share with a teammate\" / \"give someone access\" (no notification) | `codiedev ping <name> --with <key> [--edit]` (no message = silent share) |\n| \"find something about X\" / \"has anyone solved Y?\" | `codiedev search \"<query>\" [--limit N]` |\n| \"show my library\" / \"what artifacts exist?\" | `codiedev library [--scope mine\\|shared\\|all] [--kind doc\\|skill]` |\n| \"run my agent's test cases\" / \"check the dataset on model Y\" / \"run v2 of the dataset\" | `codiedev traces cases <agent> [--dataset <name> [--version <n>]] [--model <id>]` (writes cases + RUN_CASES.md + results.json; follow it, then `codiedev traces report <results.json>`) |\n| \"how are my agents doing?\" / \"what's failing this week?\" / \"show the booking agent's failed runs\" / \"why did run X fail?\" | `codiedev traces overview`; `codiedev traces runs <agent> [--failed] [--flag <issue>] [--days n]`; `codiedev traces run <run> --agent <name>` (add `--json` to read the data yourself) |\n| \"add a helpfulness 1\u20135 score\" / \"make a review queue for tone\" | `codiedev traces score-kinds add <name> --type number --min 1 --max 5`; `codiedev traces queue create <name> --scores <a,b>` |\n| \"score that run 4 for helpfulness\" / \"how is my agent scoring?\" | `codiedev traces score <run> <score> <value> [--agent <name>] [--comment <why>]`; `codiedev traces scores <agent>` |\n| \"put this week's failed runs in the review queue\" | `codiedev traces queue list`; `codiedev traces queue add <queue> --agent <name> [--failed] [--days n]` |\n| \"have a judge score 10% of my agent's runs\" / \"turn off automatic scoring\" | `codiedev traces judge <agent> --on --scores <a,b> --sample 10 [--budget 25]`; `--off`; no flags shows it |\n| \"import these test cases from a CSV\" / \"add an example to the dataset\" / \"save the dataset as a version\" | `codiedev traces import <agent> <file> --dataset <name>`; `codiedev traces add-example <agent> --dataset <name> --input \"\u2026\" [--expected \"\u2026\"]`; `codiedev traces save-version <dataset>`; `codiedev traces versions <dataset>` |\n| \"make a starter pack\" / \"add this to our pack\" / \"package these skills for my team\" | write a `<slug>.pack.md` (start from `codiedev pack export <slug> --manifest --out .` for an existing pack), then `codiedev pack apply <file> [--publish]` \u2014 see **Starter packs** below |\n| \"publish the pack\" / \"ship the pack to my team\" | `codiedev pack publish <slug> [--channel stable\\|beta\\|alpha]` |\n| \"what was the last eval on X?\" / \"file these eval results\" | `codiedev evals last <subject>` before starting a related eval; `codiedev evals report <run.json>` after each variant runs (scores only \u2014 `codiedev evals help` for the shape) |\n\n**Starter packs** (team managers and admins): a pack.md is frontmatter\n(`name:`, `slug:`, optional `description:`) then sections. Ask the user\nwhat to include, write the file, run `codiedev pack apply <file> --dry-run`\nto show them, then apply for real:\n\n```\n---\nname: \"Healthcare scan\"\nslug: \"healthcare-scan\"\n---\n\n# Healthcare scan\n\n## Skills\n\n- ./skills/healthcare-scan\n- lint.md @teammate@example.com\n\n## Files\n\n- runner <- ~/.claude/runner\n```\n\nUnder **Skills**, a local path (`./\u2026`, `~/\u2026` or `/\u2026`) to a skill folder\nor SKILL.md is pushed to the library and added, with the rest of its folder\nshipped as the skill's files; `<key> @<author email>` adds a teammate's\nlibrary skill. **Files** maps local folders to paths in the pack\n(`.` is the pack root). In skills, point at shipped files relative to the\nskill's folder or with `${CLAUDE_PLUGIN_ROOT}/\u2026`. Applying changes the\ndraft; `--publish` (or `codiedev pack publish`) sends it to the team.\n\n**Just push the file \u2014 we'll figure out where it goes.** Every artifact\nis classified into one of two kinds at upload time:\n\n- **skill** \u2014 the file has SKILL.md frontmatter (`name:` + `description:`\n inside a `---` block). Shows on the Skills page in the portal and is\n invokable as a slash command (`/<name>`).\n- **doc** \u2014 everything else. Lives in the library: list it with\n `codiedev library`, fetch it with `codiedev pull <key>`.\n\nDetection is content-based, not filename-based. The filename prefix\n(`spec-` / `decision-` / `proposal-` / `bugfix-` / `review-` /\n`note-`) is preserved as a *tag* you can filter by, but it never gates\nvisibility. A SKILL-frontmatter file named `note-foo.md` still becomes\na skill.\n\nThe `codiedev push` response always says where the artifact landed \u2014\nread it back to the user so they can confirm.\n\n**Resolving \"the spec we just worked on\":**\n- If a file was recently edited in this session matching the conventions\n above, push that file.\n- If content was drafted inline in the conversation, write it to a file\n first (e.g., `/tmp/spec-xxx.md`) then push.\n\n**Teammate names:** first name usually works (`codiedev ping <name> ...`).\nIf ambiguous, the CLI returns candidates \u2014 retry with the full email.\n\n**Search before pushing.** For any \"save this as \u2026\" request, run\n`codiedev search \"<query>\"` first. If prior art exists, pull it and\niterate rather than duplicating.\n\n**One command for messaging and sharing:** `codiedev ping`. A message\nlands in their inbox and emails them; `--with <key>` also gives them read\naccess (`--edit` for edit). With `--with` and no message it's a silent\nshare. (`codiedev send` / `share` still work as aliases.)\n\n**Errors:**\n- \"not connected\" \u2192 user needs to run `npx codiedev connect` with their\n API token from https://codiedev.com/portal/integrations/claude-code\n- \"ambiguous recipient\" \u2192 surface candidates to the user\n";
147
151
  /** The full Codiedev instructions (team-skill context + command table), for
148
152
  * harnesses Codiedev launches itself (Codie, Codie's pi) rather than a
149
153
  * user-owned instructions file. */
package/dist/utils.js CHANGED
@@ -64,6 +64,7 @@ exports.cursorInstalled = cursorInstalled;
64
64
  exports.copilotInstalled = copilotInstalled;
65
65
  exports.openCodeInstalled = openCodeInstalled;
66
66
  exports.installOpenCodeCapturePlugin = installOpenCodeCapturePlugin;
67
+ exports.ensureOpenCodePluginCurrent = ensureOpenCodePluginCurrent;
67
68
  exports.piInstalled = piInstalled;
68
69
  exports.piExtensionSource = piExtensionSource;
69
70
  exports.installPiExtension = installPiExtension;
@@ -1165,6 +1166,22 @@ function installOpenCodeCapturePlugin() {
1165
1166
  ` const cwd = worktree || directory || process.cwd();\n` +
1166
1167
  ` const prompt = Array.isArray(output?.parts) ? output.parts.filter((part) => part?.type === "text").map((part) => part.text || "").join("\\n") : "";\n` +
1167
1168
  ` const decision = invokeSync(PROMPT, { session_id: id, cwd, prompt });\n` +
1169
+ ` if (decision?.decision === "block") {\n` +
1170
+ ` // A key in the prompt (Team Security setting): stop it before the model.\n` +
1171
+ ` const reason = String(decision.reason || "Codiedev stopped this prompt.");\n` +
1172
+ ` const toast = { title: "Prompt not sent", message: reason, variant: "error", duration: 12000 };\n` +
1173
+ ` // Older SDKs take { body }, newer ones the fields themselves. The TUI\n` +
1174
+ ` // follows a stopped prompt with its own generic \"Failed to send\n` +
1175
+ ` // prompt\" toast; show ours now and again just after, so ours stays up.\n` +
1176
+ ` const show = () => { try { Promise.resolve(client.tui.showToast({ body: toast, ...toast })).catch(() => {}); } catch {} };\n` +
1177
+ ` show();\n` +
1178
+ ` setTimeout(show, 600);\n` +
1179
+ ` if (process.env.CODIEDEV_PROMPT_BLOCK_OUTPUT === "marker") {\n` +
1180
+ ` process.stderr.write("__CODIEDEV_PROMPT_BLOCKED__" + JSON.stringify({ reason }) + "\\n");\n` +
1181
+ ` process.exit(3);\n` +
1182
+ ` }\n` +
1183
+ ` throw new Error(reason);\n` +
1184
+ ` }\n` +
1168
1185
  ` const context = decision?.hookSpecificOutput?.additionalContext;\n` +
1169
1186
  ` if (context && Array.isArray(output?.parts)) {\n` +
1170
1187
  ` // Preserve the native part IDs required by current engine schemas.\n` +
@@ -1215,6 +1232,20 @@ function installOpenCodeCapturePlugin() {
1215
1232
  fs.writeFileSync(OPENCODE_PLUGIN_PATH, source, { encoding: "utf8", mode: 0o600 });
1216
1233
  fs.chmodSync(OPENCODE_PLUGIN_PATH, 0o600);
1217
1234
  }
1235
+ /** Rewrite an OpenCode plugin installed by an older CLI: one that still wires
1236
+ * the retired Agent Security tool hooks, or predates the prompt guard (it
1237
+ * would let a stopped prompt through). Only touches an existing Codiedev plugin. */
1238
+ function ensureOpenCodePluginCurrent() {
1239
+ try {
1240
+ if (!fs.existsSync(OPENCODE_PLUGIN_PATH))
1241
+ return;
1242
+ const current = fs.readFileSync(OPENCODE_PLUGIN_PATH, "utf8");
1243
+ if (!current.includes("SECURITY_PRE") && current.includes("CODIEDEV_PROMPT_BLOCK_OUTPUT"))
1244
+ return;
1245
+ installOpenCodeCapturePlugin();
1246
+ }
1247
+ catch { /* best-effort */ }
1248
+ }
1218
1249
  function piInstalled() {
1219
1250
  if (fs.existsSync((0, harnessDirs_1.piAgentDir)()))
1220
1251
  return true;
@@ -1318,8 +1349,14 @@ function piExtensionSource(agentSecurityEnabled) {
1318
1349
  ` if (event?.source === "extension") return { action: "continue" };\n` +
1319
1350
  ` const s = current(ctx);\n` +
1320
1351
  ` const decision = invokeSync(PROMPT, { session_id: s.id, cwd: s.cwd, prompt: event?.text ?? "" });\n` +
1321
- ` const reason = blockReason(decision);\n` +
1322
- ` if (reason) { warn(ctx, reason); return { action: "handled" }; }\n` +
1352
+ ` if (decision?.decision === "block") {\n` +
1353
+ ` // A key in the prompt (Team Security setting): pi never sends it.\n` +
1354
+ ` const reason = String(decision.reason || "Codiedev stopped this prompt.");\n` +
1355
+ ` if (ctx?.hasUI) { try { ctx.ui.notify(reason, "error"); } catch { process.stderr.write("\\n" + reason + "\\n"); } }\n` +
1356
+ ` else process.stderr.write("\\n" + reason + "\\n");\n` +
1357
+ ` pendingContext = null;\n` +
1358
+ ` return { action: "handled" };\n` +
1359
+ ` }\n` +
1323
1360
  ` pendingContext = decision?.hookSpecificOutput?.additionalContext || null;\n` +
1324
1361
  ` return { action: "continue" };\n` +
1325
1362
  ` });\n\n` +
@@ -1674,13 +1711,12 @@ thought, use the \`codiedev\` CLI via Bash:**
1674
1711
  | "push this spec" / "save this as a skill" | \`codiedev push <file.md>\` |
1675
1712
  | "pull X" / "grab the latest spec-X" / "what did a teammate push?" | \`codiedev pull <key>\` |
1676
1713
  | "delete X" / "remove that test push" / "rm spec-old" | \`codiedev delete <key>\` (always confirm with the user first) |
1677
- | "ping a teammate about this" / "ask someone for their take" / "send them this file" | \`codiedev ping <name> "<msg>" [--with <key>] [--file <path>]\` |
1714
+ | "ping a teammate about this" / "send them this spec" / "send them this file" | \`codiedev ping <name> "<msg>" [--with <key>] [--file <path>]\` (\`--with\` also gives them access) |
1678
1715
  | "any messages?" / "check my inbox" / "what did a teammate say?" | \`codiedev inbox\` |
1679
1716
  | "read that reply" / "mark that ping read" | \`codiedev read <ping-id>\` |
1680
1717
  | "reply to that" / "tell them X" (answering a message from \`codiedev inbox\`) | \`codiedev reply <ping-id> "<msg>" [--file <path>]\` (not a new ping: this threads it and marks theirs answered) |
1681
1718
  | "note that X is a follow-up" / "remember X" | \`codiedev note "<text>"\` |
1682
- | "share with a teammate" / "give someone access" (no notification) | \`codiedev share <key> <name> [--role read\\|edit]\` |
1683
- | "send this to a teammate" / "ask someone to look at this" | \`codiedev send <key> <name> ["<msg>"]\` |
1719
+ | "share with a teammate" / "give someone access" (no notification) | \`codiedev ping <name> --with <key> [--edit]\` (no message = silent share) |
1684
1720
  | "find something about X" / "has anyone solved Y?" | \`codiedev search "<query>" [--limit N]\` |
1685
1721
  | "show my library" / "what artifacts exist?" | \`codiedev library [--scope mine\\|shared\\|all] [--kind doc\\|skill]\` |
1686
1722
  | "run my agent's test cases" / "check the dataset on model Y" / "run v2 of the dataset" | \`codiedev traces cases <agent> [--dataset <name> [--version <n>]] [--model <id>]\` (writes cases + RUN_CASES.md + results.json; follow it, then \`codiedev traces report <results.json>\`) |
@@ -1756,9 +1792,10 @@ If ambiguous, the CLI returns candidates — retry with the full email.
1756
1792
  \`codiedev search "<query>"\` first. If prior art exists, pull it and
1757
1793
  iterate rather than duplicating.
1758
1794
 
1759
- **Sharing vs sending:** \`codiedev share\` is silent (access only, no
1760
- notification). \`codiedev send\` both grants access AND pings the
1761
- recipient. Use send when the user is actively looping someone in.
1795
+ **One command for messaging and sharing:** \`codiedev ping\`. A message
1796
+ lands in their inbox and emails them; \`--with <key>\` also gives them read
1797
+ access (\`--edit\` for edit). With \`--with\` and no message it's a silent
1798
+ share. (\`codiedev send\` / \`share\` still work as aliases.)
1762
1799
 
1763
1800
  **Errors:**
1764
1801
  - "not connected" → user needs to run \`npx codiedev connect\` with their
@@ -2259,10 +2296,10 @@ function installCursorHook() {
2259
2296
  replaceManaged("stop", ["backup-cursor"]);
2260
2297
  for (const event of ["postToolUse", "postToolUseFailure", "subagentStart", "subagentStop"])
2261
2298
  replaceManaged(event, ["observe-cursor"]);
2262
- // Cursor cannot inject dynamic context from beforeSubmitPrompt today.
2263
- // Remove older Codiedev discovery entries so prompts are not uploaded for
2264
- // a response the host will discard; preserve any third-party hooks.
2265
- replaceManaged("beforeSubmitPrompt", []);
2299
+ // Stops a prompt with a key in it when the company turned that on (a quick
2300
+ // local no-op otherwise). It also replaces older Codiedev discovery entries,
2301
+ // so prompts are not uploaded for a response the host will discard.
2302
+ replaceManaged("beforeSubmitPrompt", ["prompt-guard-cursor"]);
2266
2303
  fs.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(hooksFile, null, 2), "utf8");
2267
2304
  }
2268
2305
  // GitHub Copilot reads every `$COPILOT_HOME/hooks/*.json`, so Codiedev owns
@@ -2358,6 +2395,7 @@ function ensureCursorCodiedevHooksInstalled() {
2358
2395
  ["postToolUseFailure", "observe-cursor"],
2359
2396
  ["subagentStart", "observe-cursor"],
2360
2397
  ["subagentStop", "observe-cursor"],
2398
+ ["beforeSubmitPrompt", "prompt-guard-cursor"],
2361
2399
  ];
2362
2400
  const has = (eventName, subcommand) => {
2363
2401
  const entries = hooks[eventName];
@@ -2369,7 +2407,8 @@ function ensureCursorCodiedevHooksInstalled() {
2369
2407
  });
2370
2408
  };
2371
2409
  const promptEntries = hooks.beforeSubmitPrompt;
2372
- const hasStalePromptHook = Array.isArray(promptEntries) && promptEntries.some((entry) => (0, detection_1.isCodiedevHookCommand)(entry.command));
2410
+ const hasStalePromptHook = Array.isArray(promptEntries) && promptEntries.some((entry) => (0, detection_1.isCodiedevHookCommand)(entry.command)
2411
+ && !String(entry.command ?? "").trim().endsWith("prompt-guard-cursor"));
2373
2412
  if (!required.every(([eventName, subcommand]) => has(eventName, subcommand)) ||
2374
2413
  hasStalePromptHook) {
2375
2414
  installCursorHook();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.88",
3
+ "version": "0.9.90",
4
4
  "description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",