codiedev 0.9.90 → 0.9.91

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/hook.js CHANGED
@@ -685,6 +685,11 @@ async function main() {
685
685
  // starts it (hourly throttle inside).
686
686
  (0, localScrub_1.maybeSpawnLocalScrub)({ connected: Boolean((0, utils_1.readConfig)()), cwd: hookInput.cwd });
687
687
  }
688
+ // Scripted sessions (`claude -p`, the Agent SDK, `codex exec`, `codie run`,
689
+ // `pi -p`) get no suggestion: they run a fixed job and ignore it, and a
690
+ // pipeline fires this hook hundreds of times a day.
691
+ if (promptHarness && (0, launchContext_1.isScriptedPrompt)(promptHarness, hookInput))
692
+ return;
688
693
  if (process.argv[2] !== "discover-copilot")
689
694
  await runDiscover(hookInput.prompt);
690
695
  return;
@@ -43,4 +43,31 @@ export declare function hookLaunch(hookCommand: string | undefined, input: {
43
43
  copilotClientName?: string;
44
44
  detectCopilot?: () => string | undefined;
45
45
  }): string | undefined;
46
+ /** Codex writes `session_meta` as the first line of its rollout file; its
47
+ * `source` is "cli", "vscode", "exec" (`codex exec`), "mcp", or an object
48
+ * for a sub-agent. A first line longer than `head` reads as unknown. */
49
+ export declare function codexLaunchFromRolloutHead(head: string): string | undefined;
50
+ export type PromptHookHarness = "claude-code" | "codex" | "codie-harness" | "copilot" | "pi";
51
+ /**
52
+ * True when a prompt hook is running inside a session a script started
53
+ * (`claude -p`, the Agent SDK, `codex exec`, `codie run`, `pi -p`…). Such a
54
+ * session already knows what it is doing, so team-skill suggestions are
55
+ * skipped for it: the lookup would send every scripted prompt to the backend
56
+ * for advice nothing reads.
57
+ *
58
+ * Where the answer comes from, per harness:
59
+ * - Codie and pi pass `launch` in the hook input (their plugin knows its argv).
60
+ * - Claude Code names its entrypoint in the hook's environment: "cli" for a
61
+ * person, "sdk-*" for a script.
62
+ * - Codex records it on the first line of the rollout file the hook is given.
63
+ * Unknown or absent values are treated as a person, so nobody loses
64
+ * suggestions by mistake.
65
+ */
66
+ export declare function isScriptedPrompt(harness: PromptHookHarness, input: {
67
+ launch?: unknown;
68
+ transcript_path?: unknown;
69
+ }, deps?: {
70
+ env?: Record<string, string | undefined>;
71
+ readHead?: (file: string) => string;
72
+ }): boolean;
46
73
  export {};
@@ -7,7 +7,10 @@ exports.windowsAncestors = windowsAncestors;
7
7
  exports.detectCursorLaunch = detectCursorLaunch;
8
8
  exports.detectCopilotLaunch = detectCopilotLaunch;
9
9
  exports.hookLaunch = hookLaunch;
10
+ exports.codexLaunchFromRolloutHead = codexLaunchFromRolloutHead;
11
+ exports.isScriptedPrompt = isScriptedPrompt;
10
12
  const node_child_process_1 = require("node:child_process");
13
+ const node_fs_1 = require("node:fs");
11
14
  /**
12
15
  * How a harness that records nothing about its own launch was started.
13
16
  * Claude Code (`entrypoint`) and Codex (`session_meta.source`) stamp this in
@@ -198,3 +201,79 @@ function hookLaunch(hookCommand, input, deps = {}) {
198
201
  }
199
202
  return undefined;
200
203
  }
204
+ /** Launch values a script drives. Mirrors isScriptedEntrypoint in
205
+ * convex/lib/sessionAutomation.ts, plus pi's print/json/rpc modes, which
206
+ * docs/dev-users/install.md also counts as scripted. */
207
+ const SCRIPTED_LAUNCHES = new Set([
208
+ "codex:exec", "codex:mcp",
209
+ "codie:run", "codie:serve", "codie:acp",
210
+ "cursor:print", "copilot:print",
211
+ "pi:print", "pi:json", "pi:rpc",
212
+ ]);
213
+ const isScriptedLaunch = (launch) => launch.startsWith("sdk") || SCRIPTED_LAUNCHES.has(launch);
214
+ /** Codex writes `session_meta` as the first line of its rollout file; its
215
+ * `source` is "cli", "vscode", "exec" (`codex exec`), "mcp", or an object
216
+ * for a sub-agent. A first line longer than `head` reads as unknown. */
217
+ function codexLaunchFromRolloutHead(head) {
218
+ const end = head.indexOf("\n");
219
+ if (end < 0)
220
+ return undefined;
221
+ try {
222
+ const first = JSON.parse(head.slice(0, end));
223
+ if (first?.type !== "session_meta")
224
+ return undefined;
225
+ const src = first.payload?.source;
226
+ if (typeof src === "string")
227
+ return VALUE.test(`codex:${src}`) ? `codex:${src}` : undefined;
228
+ if (src && typeof src === "object")
229
+ return `codex:${Object.keys(src)[0] ?? "other"}`;
230
+ }
231
+ catch {
232
+ // not JSON: unknown
233
+ }
234
+ return undefined;
235
+ }
236
+ /** The first `bytes` of a file, or "" when it can't be read. */
237
+ function readHead(file, bytes = 256 * 1024) {
238
+ let fd;
239
+ try {
240
+ fd = (0, node_fs_1.openSync)(file, "r");
241
+ const buf = Buffer.alloc(bytes);
242
+ return buf.toString("utf8", 0, (0, node_fs_1.readSync)(fd, buf, 0, bytes, 0));
243
+ }
244
+ catch {
245
+ return "";
246
+ }
247
+ finally {
248
+ if (fd !== undefined)
249
+ (0, node_fs_1.closeSync)(fd);
250
+ }
251
+ }
252
+ /**
253
+ * True when a prompt hook is running inside a session a script started
254
+ * (`claude -p`, the Agent SDK, `codex exec`, `codie run`, `pi -p`…). Such a
255
+ * session already knows what it is doing, so team-skill suggestions are
256
+ * skipped for it: the lookup would send every scripted prompt to the backend
257
+ * for advice nothing reads.
258
+ *
259
+ * Where the answer comes from, per harness:
260
+ * - Codie and pi pass `launch` in the hook input (their plugin knows its argv).
261
+ * - Claude Code names its entrypoint in the hook's environment: "cli" for a
262
+ * person, "sdk-*" for a script.
263
+ * - Codex records it on the first line of the rollout file the hook is given.
264
+ * Unknown or absent values are treated as a person, so nobody loses
265
+ * suggestions by mistake.
266
+ */
267
+ function isScriptedPrompt(harness, input, deps = {}) {
268
+ if (typeof input.launch === "string" && VALUE.test(input.launch))
269
+ return isScriptedLaunch(input.launch);
270
+ if (harness === "claude-code") {
271
+ const entrypoint = (deps.env ?? process.env).CLAUDE_CODE_ENTRYPOINT;
272
+ return typeof entrypoint === "string" && entrypoint.startsWith("sdk");
273
+ }
274
+ if (harness === "codex" && typeof input.transcript_path === "string" && input.transcript_path) {
275
+ const launch = codexLaunchFromRolloutHead((deps.readHead ?? readHead)(input.transcript_path));
276
+ return launch !== undefined && isScriptedLaunch(launch);
277
+ }
278
+ return false;
279
+ }
package/dist/utils.js CHANGED
@@ -1165,7 +1165,7 @@ function installOpenCodeCapturePlugin() {
1165
1165
  ` const id = input?.sessionID ?? input?.sessionId ?? "unknown";\n` +
1166
1166
  ` const cwd = worktree || directory || process.cwd();\n` +
1167
1167
  ` const prompt = Array.isArray(output?.parts) ? output.parts.filter((part) => part?.type === "text").map((part) => part.text || "").join("\\n") : "";\n` +
1168
- ` const decision = invokeSync(PROMPT, { session_id: id, cwd, prompt });\n` +
1168
+ ` const decision = invokeSync(PROMPT, { session_id: id, cwd, prompt, launch: LAUNCH });\n` +
1169
1169
  ` if (decision?.decision === "block") {\n` +
1170
1170
  ` // A key in the prompt (Team Security setting): stop it before the model.\n` +
1171
1171
  ` const reason = String(decision.reason || "Codiedev stopped this prompt.");\n` +
@@ -1348,7 +1348,7 @@ function piExtensionSource(agentSecurityEnabled) {
1348
1348
  ` pi.on("input", async (event, ctx) => {\n` +
1349
1349
  ` if (event?.source === "extension") return { action: "continue" };\n` +
1350
1350
  ` const s = current(ctx);\n` +
1351
- ` const decision = invokeSync(PROMPT, { session_id: s.id, cwd: s.cwd, prompt: event?.text ?? "" });\n` +
1351
+ ` const decision = invokeSync(PROMPT, { session_id: s.id, cwd: s.cwd, prompt: event?.text ?? "", launch: LAUNCH });\n` +
1352
1352
  ` if (decision?.decision === "block") {\n` +
1353
1353
  ` // A key in the prompt (Team Security setting): pi never sends it.\n` +
1354
1354
  ` const reason = String(decision.reason || "Codiedev stopped this prompt.");\n` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.90",
3
+ "version": "0.9.91",
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",