codiedev 0.9.80 → 0.10.0-beta.10

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.
Files changed (154) hide show
  1. package/README.md +12 -5
  2. package/dist/backup/cache.js +1 -5
  3. package/dist/backup/match.js +0 -6
  4. package/dist/backup/run.js +3 -35
  5. package/dist/captureExclusions.js +0 -12
  6. package/dist/captureLog.js +0 -28
  7. package/dist/captureReadiness.js +0 -58
  8. package/dist/captureSignals.js +0 -11
  9. package/dist/cli.js +11 -33
  10. package/dist/cliSession.js +3 -60
  11. package/dist/codexHookTrust.js +0 -28
  12. package/dist/codexLimitScan.js +0 -107
  13. package/dist/codie.js +64 -57
  14. package/dist/codieBrandInstall.js +0 -18
  15. package/dist/codieLauncher.js +1 -72
  16. package/dist/codieRuntime.js +27 -32
  17. package/dist/codieRuntimeInstall.js +11 -43
  18. package/dist/codieUsage.js +0 -49
  19. package/dist/commands/agentTemplates.generated.js +136 -0
  20. package/dist/commands/agents.js +1088 -0
  21. package/dist/commands/agentsSdk.generated.js +7 -0
  22. package/dist/commands/ask.js +0 -3
  23. package/dist/commands/capture.js +0 -2
  24. package/dist/commands/createTicket.js +0 -10
  25. package/dist/commands/doctor.js +2 -72
  26. package/dist/commands/evals.js +3 -9
  27. package/dist/commands/inbox.js +0 -2
  28. package/dist/commands/library.js +0 -3
  29. package/dist/commands/pack.js +0 -29
  30. package/dist/commands/ping.js +0 -2
  31. package/dist/commands/pull.js +0 -9
  32. package/dist/commands/push.js +0 -12
  33. package/dist/commands/search.js +0 -4
  34. package/dist/commands/send.js +0 -5
  35. package/dist/commands/share.js +0 -4
  36. package/dist/commands/shared.js +0 -35
  37. package/dist/commands/traces.js +0 -13
  38. package/dist/commands/tracesLabel.js +0 -8
  39. package/dist/configDir.js +1 -18
  40. package/dist/connect.js +3 -75
  41. package/dist/connectFlow.js +0 -15
  42. package/dist/copilotHooks.js +0 -67
  43. package/dist/copilotInstallation.js +0 -1
  44. package/dist/cursorHooks.js +1 -11
  45. package/dist/cursorLifecycle.js +1 -7
  46. package/dist/detection.js +0 -30
  47. package/dist/harnessDirs.js +0 -19
  48. package/dist/hook.js +43 -293
  49. package/dist/inboxFormat.js +0 -24
  50. package/dist/launchContext.js +0 -50
  51. package/dist/launcher.js +0 -33
  52. package/dist/limitEvent.js +2 -34
  53. package/dist/managedPi.js +2 -50
  54. package/dist/mcp.js +0 -48
  55. package/dist/nativeSteering.js +1 -4
  56. package/dist/packs/codie.js +0 -15
  57. package/dist/packs/harnesses.js +1 -38
  58. package/dist/packs/hookGate.js +0 -33
  59. package/dist/packs/install.js +0 -20
  60. package/dist/packs/manifest.js +1 -15
  61. package/dist/packs/paths.js +0 -8
  62. package/dist/packs/shim.js +0 -8
  63. package/dist/packs/store.js +0 -12
  64. package/dist/packs/sync.js +0 -20
  65. package/dist/piHooks.js +4 -45
  66. package/dist/piRuntime.js +0 -18
  67. package/dist/repoResolver.js +0 -19
  68. package/dist/secret.js +0 -3
  69. package/dist/selfUpdate.js +2 -77
  70. package/dist/skillMarker.js +0 -14
  71. package/dist/subagents.js +0 -18
  72. package/dist/teamSkillContext.js +0 -1
  73. package/dist/transcriptModels.js +0 -8
  74. package/dist/upgradeNudge.js +1 -30
  75. package/dist/utils.js +165 -768
  76. package/dist/version.js +0 -10
  77. package/dist/versionCheck.js +0 -33
  78. package/package.json +13 -8
  79. package/dist/backup/cache.d.ts +0 -14
  80. package/dist/backup/match.d.ts +0 -2
  81. package/dist/backup/run.d.ts +0 -25
  82. package/dist/captureExclusions.d.ts +0 -30
  83. package/dist/captureLog.d.ts +0 -20
  84. package/dist/captureReadiness.d.ts +0 -65
  85. package/dist/captureSignals.d.ts +0 -47
  86. package/dist/cli.d.ts +0 -15
  87. package/dist/cliSession.d.ts +0 -108
  88. package/dist/codexHookTrust.d.ts +0 -49
  89. package/dist/codexLimitScan.d.ts +0 -64
  90. package/dist/codie.d.ts +0 -2
  91. package/dist/codieBrandInstall.d.ts +0 -11
  92. package/dist/codieLauncher.d.ts +0 -87
  93. package/dist/codieRuntime.d.ts +0 -35
  94. package/dist/codieRuntimeInstall.d.ts +0 -56
  95. package/dist/codieUsage.d.ts +0 -64
  96. package/dist/commands/ask.d.ts +0 -1
  97. package/dist/commands/capture.d.ts +0 -14
  98. package/dist/commands/createTicket.d.ts +0 -27
  99. package/dist/commands/delete.d.ts +0 -1
  100. package/dist/commands/doctor.d.ts +0 -9
  101. package/dist/commands/evals.d.ts +0 -3
  102. package/dist/commands/inbox.d.ts +0 -3
  103. package/dist/commands/library.d.ts +0 -2
  104. package/dist/commands/note.d.ts +0 -1
  105. package/dist/commands/pack.d.ts +0 -54
  106. package/dist/commands/ping.d.ts +0 -1
  107. package/dist/commands/pull.d.ts +0 -2
  108. package/dist/commands/push.d.ts +0 -33
  109. package/dist/commands/search.d.ts +0 -2
  110. package/dist/commands/send.d.ts +0 -2
  111. package/dist/commands/share.d.ts +0 -2
  112. package/dist/commands/shared.d.ts +0 -64
  113. package/dist/commands/traces.d.ts +0 -72
  114. package/dist/commands/tracesLabel.d.ts +0 -24
  115. package/dist/configDir.d.ts +0 -10
  116. package/dist/connect.d.ts +0 -1
  117. package/dist/connectFlow.d.ts +0 -34
  118. package/dist/copilotHooks.d.ts +0 -85
  119. package/dist/copilotInstallation.d.ts +0 -10
  120. package/dist/cursorHooks.d.ts +0 -13
  121. package/dist/cursorLifecycle.d.ts +0 -2
  122. package/dist/detection.d.ts +0 -30
  123. package/dist/harnessDirs.d.ts +0 -15
  124. package/dist/hook.d.ts +0 -6
  125. package/dist/inboxFormat.d.ts +0 -38
  126. package/dist/launchContext.d.ts +0 -46
  127. package/dist/launcher.d.ts +0 -25
  128. package/dist/limitEvent.d.ts +0 -15
  129. package/dist/limitEventReporter.d.ts +0 -21
  130. package/dist/managedPi.d.ts +0 -48
  131. package/dist/mcp.d.ts +0 -12
  132. package/dist/nativeSteering.d.ts +0 -5
  133. package/dist/packs/codie.d.ts +0 -45
  134. package/dist/packs/harnesses.d.ts +0 -74
  135. package/dist/packs/hookGate.d.ts +0 -53
  136. package/dist/packs/install.d.ts +0 -46
  137. package/dist/packs/manifest.d.ts +0 -52
  138. package/dist/packs/paths.d.ts +0 -17
  139. package/dist/packs/shim.d.ts +0 -26
  140. package/dist/packs/store.d.ts +0 -42
  141. package/dist/packs/sync.d.ts +0 -40
  142. package/dist/piHooks.d.ts +0 -22
  143. package/dist/piRuntime.d.ts +0 -26
  144. package/dist/repoResolver.d.ts +0 -17
  145. package/dist/secret.d.ts +0 -1
  146. package/dist/selfUpdate.d.ts +0 -64
  147. package/dist/skillMarker.d.ts +0 -6
  148. package/dist/subagents.d.ts +0 -36
  149. package/dist/teamSkillContext.d.ts +0 -9
  150. package/dist/transcriptModels.d.ts +0 -20
  151. package/dist/upgradeNudge.d.ts +0 -24
  152. package/dist/utils.d.ts +0 -396
  153. package/dist/version.d.ts +0 -1
  154. package/dist/versionCheck.d.ts +0 -68
@@ -2,32 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatInbox = formatInbox;
4
4
  const shared_1 = require("./commands/shared");
5
- /**
6
- * Render the inbox for BOTH surfaces — `codiedev inbox` and the MCP
7
- * `codiedev_inbox` tool an agent calls for "any messages?". Shared so the
8
- * agent path can never drift back to pings-only while the human path shows
9
- * mentions.
10
- */
11
5
  function formatInbox(opts) {
12
6
  const mentions = opts.mentions ?? [];
13
- // The backend applies `limit` to each source independently, so asking for N
14
- // can return up to 2N — and with no `--limit` it defaults to 50 per source,
15
- // i.e. 100 rows, twice the pre-change maximum. Cap the COMBINED list by
16
- // recency, always (matching the backend's own default), so the header is
17
- // truthful and `--limit` actually holds.
18
- //
19
- // Selected by identity rather than by a `createdAt >= cutoff` filter: rows
20
- // tied on the cutoff millisecond are reachable (Convex freezes Date.now()
21
- // per transaction, and seeded activity carries synthetic stamps) and a
22
- // threshold filter lets every tied row through, overshooting the limit.
23
7
  const DEFAULT_LIMIT = 50;
24
8
  const cap = opts.limit ?? DEFAULT_LIMIT;
25
- // Pings claim the budget first, then mentions fill whatever is left — both
26
- // newest-first. Before this change pings owned the whole budget, so this is
27
- // purely additive and can never hide a ping that used to be visible. A flat
28
- // recency cap would instead let a busy feed evict every direct ping, and
29
- // pings are the actionable half: they carry the id you reply to, and losing
30
- // them all takes the mark-read footer with them.
31
9
  const byRecency = (xs) => [...xs].sort((a, b) => b.createdAt - a.createdAt);
32
10
  const keptPings = byRecency(opts.pings).slice(0, cap);
33
11
  const keptMentions = byRecency(mentions).slice(0, Math.max(0, cap - keptPings.length));
@@ -50,8 +28,6 @@ function formatInbox(opts) {
50
28
  lines.push(` id: ${p.pingId}`);
51
29
  lines.push("");
52
30
  }
53
- // Mentions carry no CLI-side body to reply to — the thread lives in the feed
54
- // — so each row ends in the deep link rather than an id.
55
31
  for (const m of keptMentions) {
56
32
  const dot = m.readAt ? "·" : "●";
57
33
  const from = m.from?.name ?? "someone";
@@ -8,38 +8,22 @@ exports.detectCursorLaunch = detectCursorLaunch;
8
8
  exports.detectCopilotLaunch = detectCopilotLaunch;
9
9
  exports.hookLaunch = hookLaunch;
10
10
  const node_child_process_1 = require("node:child_process");
11
- /**
12
- * How a harness that records nothing about its own launch was started.
13
- * Claude Code (`entrypoint`) and Codex (`session_meta.source`) stamp this in
14
- * the transcript; Cursor, Codie and the Copilot CLI do not, so the hook reads
15
- * it from the process that launched it. Raw, namespaced values; what counts as
16
- * "automated" is decided in reporting, not here.
17
- */
18
11
  const VALUE = /^[a-z0-9][a-z0-9_.:-]{0,39}$/;
19
- /** Codie (OpenCode) subcommands, read in-process by the capture plugin. */
20
12
  const CODIE_SUBCOMMANDS = ["run", "serve", "acp", "web", "attach"];
21
13
  function codieLaunchFromArgv(argv) {
22
14
  const sub = argv.find((a) => CODIE_SUBCOMMANDS.includes(a));
23
15
  return sub ? `codie:${sub}` : "codie:tui";
24
16
  }
25
- /**
26
- * Split a command line into tokens, honouring double quotes (Windows quotes
27
- * paths with spaces: "C:\\Program Files\\…\\node.exe" "…\\index.js" -p hi).
28
- */
29
17
  function tokenize(command) {
30
18
  const tokens = [];
31
19
  for (const m of command.matchAll(/"([^"]*)"|(\S+)/g))
32
20
  tokens.push(m[1] ?? m[2]);
33
21
  return tokens;
34
22
  }
35
- /** A path segment named cursor-agent / agent (Unix or Windows separators). */
36
23
  const CURSOR_AGENT_PATH = /(^|[/\\])cursor-agent([/\\]|\.(exe|cmd|ps1)$|$)/i;
37
24
  const AGENT_BIN = /(^|[/\\])(cursor-)?agent(\.(exe|cmd|ps1))?$/i;
38
- /** One launching process's command line → a Cursor launch value. */
39
25
  function cursorLaunchFromCommand(command) {
40
26
  const tokens = tokenize(command);
41
- // The CLI runs as `<launcher> [node] …/cursor-agent/versions/<v>/index.js [flags] [prompt]`
42
- // on macOS/Linux (~/.local/share/cursor-agent) and Windows (%LOCALAPPDATA%\cursor-agent).
43
27
  const isAgent = tokens.some((t) => CURSOR_AGENT_PATH.test(t) || /[/\\]\.local[/\\]share[/\\]cursor/i.test(t))
44
28
  && tokens.some((t) => AGENT_BIN.test(t) || /index\.js$/i.test(t));
45
29
  if (isAgent) {
@@ -51,14 +35,7 @@ function cursorLaunchFromCommand(command) {
51
35
  return "cursor:ide";
52
36
  return undefined;
53
37
  }
54
- /** Cursor flags that take a value; the token after them is not the prompt. */
55
38
  const CURSOR_VALUE_FLAGS = new Set(["--model", "-m", "--output-format", "--api-key", "--resume", "--workspace", "--mode", "-H", "--header"]);
56
- /**
57
- * The flags before the prompt. The prompt is on the command line too, so a
58
- * prompt mentioning "-p" must not read as headless: stop at the first token
59
- * that is neither a flag nor a flag's value. Starts after the launcher script
60
- * (`…/index.js`) when present, else after the agent binary.
61
- */
62
39
  function cursorFlags(tokens) {
63
40
  let start = tokens.findIndex((t) => /index\.js$/i.test(t));
64
41
  if (start < 0)
@@ -74,20 +51,10 @@ function cursorFlags(tokens) {
74
51
  }
75
52
  return flags;
76
53
  }
77
- /** The Copilot CLI binary or its npm launcher (`copilot`, `copilot.exe`, `copilot.cmd`). */
78
54
  const COPILOT_BIN = /(^|[/\\])copilot(\.(exe|cmd|ps1|js))?$/i;
79
55
  const NODE_BIN = /(^|[/\\])node(\.exe)?$/i;
80
- /**
81
- * One launching process's command line → a Copilot CLI launch value. The CLI
82
- * runs as `…/@github/copilot-<platform>/copilot [flags]` under
83
- * `node …/bin/copilot [flags]`; `-p`/`--prompt` is headless (scripted). VS
84
- * Code's agent (`copilot-runtime --headless`) is named by workspace.yaml
85
- * instead, so it never matches here.
86
- */
87
56
  function copilotLaunchFromCommand(command) {
88
57
  const tokens = tokenize(command);
89
- // Only the program itself (or the script `node` runs): a shell command line
90
- // that merely mentions "copilot" as a word is not the Copilot CLI.
91
58
  const bin = COPILOT_BIN.test(tokens[0] ?? "")
92
59
  ? 0
93
60
  : NODE_BIN.test(tokens[0] ?? "") && COPILOT_BIN.test(tokens[1] ?? "")
@@ -99,7 +66,6 @@ function copilotLaunchFromCommand(command) {
99
66
  const t = tokens[i];
100
67
  if (t === "-p" || t === "--prompt" || t.startsWith("--prompt="))
101
68
  return "copilot:print";
102
- // The prompt itself can mention "-p": stop at the first non-flag token.
103
69
  if (!t.startsWith("-"))
104
70
  break;
105
71
  if (COPILOT_VALUE_FLAGS.has(t))
@@ -107,7 +73,6 @@ function copilotLaunchFromCommand(command) {
107
73
  }
108
74
  return "copilot:cli";
109
75
  }
110
- /** Copilot CLI flags that take a value; the token after them is not a flag. */
111
76
  const COPILOT_VALUE_FLAGS = new Set([
112
77
  "--model", "--add-dir", "--allow-tool", "--deny-tool", "--resume", "--log-dir",
113
78
  "--log-level", "--agent", "--config-dir", "--allow-url", "--deny-url",
@@ -119,11 +84,6 @@ const psPosix = (pid) => {
119
84
  const match = line.match(/^(\d+)\s+(.*)$/s);
120
85
  return match ? { ppid: Number(match[1]), command: match[2] } : null;
121
86
  };
122
- /**
123
- * Windows: one PowerShell call returns the whole ancestor chain (spawning
124
- * PowerShell per level would cost ~0.5s each). CommandLine needs CIM, which
125
- * every supported Windows has; any failure means "unknown", never a guess.
126
- */
127
87
  function windowsAncestors(startPid, depth) {
128
88
  const script = `$p=${Math.trunc(startPid)};$o=@();for($i=0;$i -lt ${Math.trunc(depth)} -and $p -gt 0;$i++){` +
129
89
  `$x=Get-CimInstance Win32_Process -Filter "ProcessId=$p" -ErrorAction SilentlyContinue;if(!$x){break};` +
@@ -131,8 +91,6 @@ function windowsAncestors(startPid, depth) {
131
91
  `ConvertTo-Json -InputObject @($o) -Compress`;
132
92
  const result = (0, node_child_process_1.spawnSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
133
93
  encoding: "utf8",
134
- // A cold PowerShell start can take several seconds on a busy machine; the
135
- // capture hook has 30s, and an unanswered walk just means "unknown".
136
94
  timeout: 10000,
137
95
  windowsHide: true,
138
96
  });
@@ -146,7 +104,6 @@ function windowsAncestors(startPid, depth) {
146
104
  return null;
147
105
  }
148
106
  }
149
- /** First launch value `fromCommand` finds among up to `depth` ancestors. */
150
107
  function detectLaunch(fromCommand, startPid, deps) {
151
108
  const depth = deps.depth ?? 5;
152
109
  if ((deps.platform ?? process.platform) === "win32" && !deps.ps) {
@@ -173,25 +130,18 @@ function detectLaunch(fromCommand, startPid, deps) {
173
130
  }
174
131
  return undefined;
175
132
  }
176
- /**
177
- * Walk up to `depth` ancestors (a shell or `npx` usually sits between Cursor
178
- * and the hook) and return the first Cursor launch found.
179
- */
180
133
  function detectCursorLaunch(startPid = process.ppid, deps = {}) {
181
134
  return detectLaunch(cursorLaunchFromCommand, startPid, deps);
182
135
  }
183
- /** The Copilot CLI that launched this hook (`copilot:print` / `copilot:cli`). */
184
136
  function detectCopilotLaunch(startPid = process.ppid, deps = {}) {
185
137
  return detectLaunch(copilotLaunchFromCommand, startPid, deps);
186
138
  }
187
- /** The launch value a hook invocation should carry into its capture job. */
188
139
  function hookLaunch(hookCommand, input, deps = {}) {
189
140
  if (typeof input.launch === "string" && VALUE.test(input.launch))
190
141
  return input.launch;
191
142
  if (hookCommand?.endsWith("-cursor"))
192
143
  return detectCursorLaunch();
193
144
  if (hookCommand?.endsWith("-copilot")) {
194
- // VS Code names itself in workspace.yaml; only the CLI needs the walk.
195
145
  if (deps.copilotClientName === "vscode-agent-host")
196
146
  return "copilot:vscode";
197
147
  return (deps.detectCopilot ?? detectCopilotLaunch)();
package/dist/launcher.js CHANGED
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- // Stable hook launcher.
3
- //
4
- // Harness configs used to bake the absolute path of whichever install ran
5
- // `connect` (…/node_modules/codiedev/dist/hook.js). That path is only stable
6
- // for npm/bun globals: pnpm puts every global install in a fresh hashed dir,
7
- // and repo checkouts, Homebrew cellar moves, etc. can strand it too. Instead,
8
- // every hook config points at one file we own —
9
- // <codiedevStateDir()>/bin/codiedev-hook-launcher.cjs — which forwards to the
10
- // install recorded in <codiedevStateDir()>/install.json. Moving to a new
11
- // install (self-update, re-connect) rewrites one JSON file, never the
12
- // harness configs, so Codex hook trust and IT-managed dotfiles stay put.
13
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
3
  if (k2 === undefined) k2 = k;
15
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -56,7 +45,6 @@ const fs = __importStar(require("fs"));
56
45
  const path = __importStar(require("path"));
57
46
  const configDir_1 = require("./configDir");
58
47
  exports.LAUNCHER_FILE = "codiedev-hook-launcher.cjs";
59
- // Bump when LAUNCHER_SOURCE changes so existing launchers get rewritten.
60
48
  const LAUNCHER_REVISION = 1;
61
49
  function launcherPath() {
62
50
  return path.join((0, configDir_1.codiedevStateDir)(), "bin", exports.LAUNCHER_FILE);
@@ -64,15 +52,9 @@ function launcherPath() {
64
52
  function installRecordPath() {
65
53
  return path.join((0, configDir_1.codiedevStateDir)(), "install.json");
66
54
  }
67
- /** True iff `cmd` invokes the stable launcher (from any state dir). */
68
55
  function usesLauncher(cmd) {
69
56
  return typeof cmd === "string" && cmd.includes(exports.LAUNCHER_FILE);
70
57
  }
71
- // Plain CommonJS with no dependencies: it runs under whatever node the harness
72
- // config names, before any of our modules load. `fallback` is the install the
73
- // launcher was written for, used if install.json is missing or points at a
74
- // directory that no longer exists. If neither exists it exits 0 so a stranded
75
- // hook can never fail the developer's session.
76
58
  function launcherSource(fallback) {
77
59
  return `// codiedev-hook-launcher revision ${LAUNCHER_REVISION}. Managed by codiedev; safe to delete (re-run \`codiedev connect\`).
78
60
  "use strict";
@@ -115,10 +97,6 @@ function packageVersionFor(hookScript) {
115
97
  return undefined;
116
98
  }
117
99
  }
118
- /**
119
- * The hook script worth recording: absolute and present, and a global install over an npx cache
120
- * copy (npm prunes ~/.npm/_npx, and hooks pointed there go quietly dead). Null = don't record.
121
- */
122
100
  function stableHookScript(hookScript, globalCandidates = globalHookScripts()) {
123
101
  if (!hookScript || !path.isAbsolute(hookScript) || hookScript.includes(`${path.sep}~${path.sep}`))
124
102
  return null;
@@ -131,7 +109,6 @@ function stableHookScript(hookScript, globalCandidates = globalHookScripts()) {
131
109
  }
132
110
  return hookScript;
133
111
  }
134
- /** Where a global `npm i -g codiedev` puts hook.js, next to the node running this. */
135
112
  function globalHookScripts() {
136
113
  const prefix = path.dirname(path.dirname(process.execPath));
137
114
  return [
@@ -139,7 +116,6 @@ function globalHookScripts() {
139
116
  path.join(prefix, "node_modules", "codiedev", "dist", "hook.js"),
140
117
  ];
141
118
  }
142
- /** Point the launcher at `hookScript`. Atomic, so a hook mid-launch never reads half a file. */
143
119
  function recordCurrentInstall(requested) {
144
120
  const hookScript = stableHookScript(requested);
145
121
  if (!hookScript)
@@ -158,12 +134,6 @@ function recordCurrentInstall(requested) {
158
134
  }
159
135
  }
160
136
  let ensuredFor;
161
- /**
162
- * Make sure the launcher exists and forwards to `hookScript`, returning the
163
- * launcher path to bake into hook configs — or null if the state dir is not
164
- * writable, in which case callers keep baking the direct path. Memoized:
165
- * one connect writes ~20 hook entries.
166
- */
167
137
  function ensureLauncher(requested) {
168
138
  const hookScript = stableHookScript(requested);
169
139
  if (!hookScript)
@@ -172,7 +142,6 @@ function ensureLauncher(requested) {
172
142
  return launcherPath();
173
143
  try {
174
144
  const target = launcherPath();
175
- // A relative launcher path in a hook config only works from one folder; never bake one.
176
145
  if (!path.isAbsolute(target))
177
146
  return null;
178
147
  const source = launcherSource(hookScript);
@@ -181,7 +150,6 @@ function ensureLauncher(requested) {
181
150
  current = fs.readFileSync(target, "utf8");
182
151
  }
183
152
  catch {
184
- // first install
185
153
  }
186
154
  if (current !== source)
187
155
  writeAtomic(target, source);
@@ -195,7 +163,6 @@ function ensureLauncher(requested) {
195
163
  return null;
196
164
  }
197
165
  }
198
- // Test-only: the memo lives for the process lifetime.
199
166
  function resetLauncherCacheForTests() {
200
167
  ensuredFor = undefined;
201
168
  }
@@ -14,7 +14,6 @@ function classifyLimitKind(text) {
14
14
  return "org_spend";
15
15
  return "other";
16
16
  }
17
- // "… · resets 9:50pm (UTC)" → "9:50pm (UTC)". Null when absent.
18
17
  function parseResetText(text) {
19
18
  const m = text.match(/resets\s+(.+?)\s*$/i);
20
19
  return m ? m[1].trim() : null;
@@ -27,8 +26,6 @@ function messageText(entry) {
27
26
  return c.map((x) => (x && typeof x === "object" ? x.text ?? "" : "")).join(" ");
28
27
  return "";
29
28
  }
30
- // Scans transcript JSONL for the LAST top-level `error: "rate_limit"` entry.
31
- // (Validated shape: error/isApiErrorMessage are top-level, not under message.)
32
29
  function parseLimitEventFromTranscript(transcript) {
33
30
  let found = null;
34
31
  for (const line of transcript.split("\n")) {
@@ -53,29 +50,6 @@ function parseLimitEventFromTranscript(transcript) {
53
50
  }
54
51
  return found;
55
52
  }
56
- /**
57
- * Codex's `rate_limit_reached_type` is exactly five values (read off the 0.154
58
- * binary): `rate_limit_reached`, `workspace_{owner,member}_credits_depleted`
59
- * and `workspace_{owner,member}_usage_limit_reached`.
60
- *
61
- * The split that matters to a reader of the dashboard is "someone must act on
62
- * money" vs "this dev is throttled and it will reset" — so map on what the
63
- * snapshot actually asserts, not on the word "credits":
64
- *
65
- * - A member out of their OWN allowance is a rate limit. Real snapshots carry
66
- * `spend_control_reached: null` and `individual_limit: null` — nobody
67
- * configured a budget, the window is simply used up. Calling that personal
68
- * spend tells a manager the dev overspent, which is not what happened.
69
- *
70
- * Deliberately NOT gated on `individual_limit`: it has only ever been
71
- * observed null, so its populated shape and meaning are unknown, and a
72
- * wrong guess reinstates the mislabel this exists to remove. The reason
73
- * string is the causal signal; `individual_limit` is at best correlative.
74
- * - A member whose ADMIN capped them (`usage_limit_reached`) is personal spend:
75
- * there really is a cap, and someone can raise it.
76
- * - Anything owner-scoped is org spend — the org's allowance or credits are
77
- * gone and somebody has to act.
78
- */
79
53
  function codexLimitKind(reason, spendControlReached) {
80
54
  if (spendControlReached || reason.startsWith("workspace_owner_"))
81
55
  return "org_spend";
@@ -96,7 +70,6 @@ function codexResetText(rateLimits) {
96
70
  .sort((a, b) => a - b)[0];
97
71
  return resetAt ? new Date(resetAt * 1000).toISOString() : null;
98
72
  }
99
- /** Parse the structured rate-limit snapshot written to Codex rollout JSONL. */
100
73
  function parseCodexLimitEventFromTranscript(transcript) {
101
74
  let found = null;
102
75
  for (const line of transcript.split("\n")) {
@@ -131,7 +104,6 @@ function parseCodexLimitEventFromTranscript(transcript) {
131
104
  }
132
105
  return found;
133
106
  }
134
- /** Only explicit provider errors qualify; never scan user/assistant prose. */
135
107
  function parseNativeLimitError(input, now = Date.now()) {
136
108
  const context = input.errorContext ?? input.error_context;
137
109
  if (context !== undefined && context !== "model_call")
@@ -162,19 +134,15 @@ function parseNativeLimitEventFromTranscript(transcript) {
162
134
  continue;
163
135
  }
164
136
  if (!entry.timestamp)
165
- continue; // no stable timestamp means snapshots cannot deduplicate
137
+ continue;
166
138
  if (entry.type === "agent.error" || entry.type === "session.error") {
167
139
  found = parseNativeLimitError({ ...(entry.data ?? entry), timestamp: entry.timestamp }) ?? found;
168
140
  }
169
141
  }
170
- catch { /* tolerant of incomplete transcript tails */ }
142
+ catch { }
171
143
  }
172
144
  return found;
173
145
  }
174
- // Tail of the raw transcript to ship with the limit event so the server can
175
- // summarize "what they were working on" immediately — without waiting for the
176
- // SessionEnd capture (which can lag hours, or drop entirely on Windows).
177
- // Resumes at a line boundary so every JSONL line in the tail still parses.
178
146
  const DEFAULT_TAIL_CHARS = 65536;
179
147
  function tailForLimitEvent(transcript, maxChars = DEFAULT_TAIL_CHARS) {
180
148
  if (transcript.length <= maxChars)
package/dist/managedPi.js CHANGED
@@ -40,28 +40,6 @@ exports.prepareManagedPiDir = prepareManagedPiDir;
40
40
  exports.managedPiEnv = managedPiEnv;
41
41
  exports.managedPiArgs = managedPiArgs;
42
42
  exports.runManagedPi = runManagedPi;
43
- // `codie --pi [args]`: pi as a Codiedev harness, on the company's approved
44
- // gateway models (the same catalog and key the OpenCode engine uses).
45
- //
46
- // The managed launch closes every path to a model that skips the gateway
47
- // instead of trusting the user's ~/.pi:
48
- // - pi runs from a Codiedev-owned agent dir (PI_CODING_AGENT_DIR), rewritten
49
- // on every launch: only the `codiedev` provider, no packages, no
50
- // extensions and no auth.json (so no stored provider credentials).
51
- // - provider API keys pi would read from the environment are removed.
52
- // - extension discovery is off (`--no-extensions`, which also skips
53
- // project-local .pi/extensions); the only extensions are the guard below
54
- // and the Codiedev capture extension.
55
- // - flags that bring their own credentials or code (--api-key, --provider,
56
- // -e) and the package subcommands are refused.
57
- // - the guard points every other provider at a dead loopback address and
58
- // keeps the session on an approved model, which covers an in-session
59
- // /login too. Throwing from pi's before_provider_request does NOT stop a
60
- // request (pi logs it and sends anyway), hence the base-URL override.
61
- //
62
- // Sessions, skills, prompts, themes and context files keep working; they
63
- // don't reach a model on their own. Ported from #1783, minus the harness-pack
64
- // proxy: pi talks to the gateway directly, like `codie`.
65
43
  const child_process_1 = require("child_process");
66
44
  const fs = __importStar(require("fs"));
67
45
  const path = __importStar(require("path"));
@@ -69,7 +47,6 @@ const codieLauncher_1 = require("./codieLauncher");
69
47
  const piRuntime_1 = require("./piRuntime");
70
48
  const utils_1 = require("./utils");
71
49
  exports.PI_PROVIDER_ID = "codiedev";
72
- /** Env vars pi reads provider credentials from (`pi --help`, pi 0.73). */
73
50
  exports.PI_PROVIDER_ENV = [
74
51
  "ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "AZURE_OPENAI_API_KEY",
75
52
  "AZURE_OPENAI_BASE_URL", "AZURE_OPENAI_RESOURCE_NAME", "DEEPSEEK_API_KEY", "GEMINI_API_KEY",
@@ -81,18 +58,10 @@ exports.PI_PROVIDER_ENV = [
81
58
  "AWS_BEARER_TOKEN_BEDROCK", "GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_CLOUD_API_KEY",
82
59
  "COPILOT_GITHUB_TOKEN",
83
60
  ];
84
- /** pi subcommands that install or change extension sources. */
85
61
  const BLOCKED_SUBCOMMANDS = new Set(["install", "remove", "uninstall", "config"]);
86
62
  exports.GUARD_FILE = "codie-guard.ts";
87
63
  exports.CAPTURE_FILE = "codiedev-capture.ts";
88
- /** Where the guard points every other provider: a loopback port nothing
89
- * listens on, so a request (and whatever key it carries) never leaves the
90
- * machine. */
91
64
  exports.BLOCKED_BASE_URL = "http://127.0.0.1:9/blocked-by-codiedev";
92
- /** The pi extension that keeps a managed session on Codiedev models and tags
93
- * each gateway request with the session, repo and skills, so gateway billing
94
- * joins the captured pi session (same headers as the OpenCode metadata
95
- * plugin, assets/git-refs.mjs). */
96
65
  exports.GUARD_SOURCE = `// Written by Codiedev on every \`codie --pi\` launch. Edits are overwritten.
97
66
  import { execFile, execFileSync } from "node:child_process";
98
67
  import { readFileSync } from "node:fs";
@@ -180,8 +149,6 @@ export default function (pi) {
180
149
  function managedPiAgentDir(stateDir) {
181
150
  return path.join(stateDir, "managed", "pi", "agent");
182
151
  }
183
- /** pi's models.json entry for the gateway. The key is read from
184
- * CODIEDEV_GATEWAY_KEY at request time (pi resolves an env var name). */
185
152
  function piProviderConfig(gatewayUrl, catalog) {
186
153
  return {
187
154
  baseUrl: gatewayUrl.replace(/\/+$/, ""),
@@ -192,9 +159,6 @@ function piProviderConfig(gatewayUrl, catalog) {
192
159
  id: (0, codieLauncher_1.bareModel)(model.id),
193
160
  name: model.name || (0, codieLauncher_1.bareModel)(model.id),
194
161
  ...(model.limit ? { contextWindow: model.limit.context, maxTokens: model.limit.output } : {}),
195
- // pi shows a session's spend from this. The gateway publishes prompt and
196
- // completion prices only, so cache is unpriced; gateway settlement is
197
- // the true figure.
198
162
  ...(model.cost ? { cost: { input: model.cost.input, output: model.cost.output, cacheRead: 0, cacheWrite: 0 } } : {}),
199
163
  })),
200
164
  };
@@ -204,8 +168,6 @@ function writeJsonAtomic(file, value) {
204
168
  fs.writeFileSync(tmp, JSON.stringify(value, null, 2) + "\n", { mode: 0o600 });
205
169
  fs.renameSync(tmp, file);
206
170
  }
207
- /** Rewrite everything Codiedev owns in the managed agent dir. Sessions (and
208
- * anything else pi keeps there) are left alone. Returns the extensions to load. */
209
171
  function prepareManagedPiDir(opts) {
210
172
  const { agentDir, gatewayUrl, catalog } = opts;
211
173
  if (!catalog.length)
@@ -226,22 +188,18 @@ function prepareManagedPiDir(opts) {
226
188
  skills: opts.skillPaths ?? [],
227
189
  enableInstallTelemetry: false,
228
190
  });
229
- // Stored provider credentials (a /login from an earlier session) and any
230
- // extensions dropped into the dir go away on every launch.
231
191
  fs.rmSync(path.join(agentDir, "auth.json"), { force: true });
232
192
  fs.rmSync(path.join(agentDir, "extensions"), { recursive: true, force: true });
233
193
  const guard = path.join(agentDir, exports.GUARD_FILE);
234
194
  fs.writeFileSync(guard, exports.GUARD_SOURCE, { mode: 0o600 });
235
195
  const capture = path.join(agentDir, exports.CAPTURE_FILE);
236
- fs.writeFileSync(capture, (0, utils_1.piExtensionSource)(opts.agentSecurityEnabled), { mode: 0o600 });
196
+ fs.writeFileSync(capture, (0, utils_1.piExtensionSource)(), { mode: 0o600 });
237
197
  return [guard, capture];
238
198
  }
239
- /** The child env: no provider credentials, pi pointed at the managed dir. */
240
199
  function managedPiEnv(env, agentDir, key, platform = process.platform) {
241
200
  const blocked = new Set([...exports.PI_PROVIDER_ENV, "PI_CODING_AGENT_DIR"]);
242
201
  const out = {};
243
202
  for (const [k, v] of Object.entries(env)) {
244
- // Windows env names are case-insensitive.
245
203
  if (blocked.has(platform === "win32" ? k.toUpperCase() : k))
246
204
  continue;
247
205
  out[k] = v;
@@ -254,8 +212,6 @@ function managedPiEnv(env, agentDir, key, platform = process.platform) {
254
212
  class ManagedPiArgError extends Error {
255
213
  }
256
214
  exports.ManagedPiArgError = ManagedPiArgError;
257
- /** Refuse what would bring other credentials or code into the session, then
258
- * pin extension loading to the managed extensions. */
259
215
  function managedPiArgs(args, extensions) {
260
216
  if (args.length && BLOCKED_SUBCOMMANDS.has(args[0])) {
261
217
  throw new ManagedPiArgError(`\`pi ${args[0]}\` changes extension sources, which codie --pi manages. Ask your Codiedev admin to approve a package instead.`);
@@ -282,12 +238,9 @@ function runManagedPi(opts) {
282
238
  const agentDir = managedPiAgentDir(opts.stateDir);
283
239
  const extensions = prepareManagedPiDir({
284
240
  agentDir, gatewayUrl: opts.gatewayUrl, catalog: opts.catalog, model: env.CODIEDEV_MODEL,
285
- skillPaths: opts.skillPaths, agentSecurityEnabled: opts.agentSecurityEnabled,
241
+ skillPaths: opts.skillPaths,
286
242
  });
287
243
  const args = managedPiArgs(opts.args, extensions);
288
- // CODIEDEV_PI_BIN runs a specific pi binary (tests, canaries pinned to a
289
- // version). Otherwise pi is Codiedev's own pinned install, fetched on first
290
- // use like the Codie engine and run on this Node.
291
244
  const bin = env.CODIEDEV_PI_BIN?.trim();
292
245
  const [command, commandArgs] = bin
293
246
  ? [bin, args]
@@ -295,7 +248,6 @@ function runManagedPi(opts) {
295
248
  const result = (0, child_process_1.spawnSync)(command, commandArgs, {
296
249
  stdio: "inherit",
297
250
  env: managedPiEnv(env, agentDir, opts.key),
298
- // A pi binary given as an npm launcher is a .cmd shim on Windows.
299
251
  shell: Boolean(bin) && process.platform === "win32",
300
252
  });
301
253
  if (result.error)
package/dist/mcp.js CHANGED
@@ -1,15 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- /**
4
- * Codiedev MCP server.
5
- *
6
- * Exposes the Codiedev artifact-collaboration surface as Model Context
7
- * Protocol tools so Claude Code / Codex / any MCP-capable agent can invoke
8
- * them natively from natural language (e.g. "push the spec we just worked on").
9
- *
10
- * Reads the same ~/.codiedev/config.json the CLI uses. Install + wire up by
11
- * running `npx codiedev connect`.
12
- */
13
3
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
4
  if (k2 === undefined) k2 = k;
15
5
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -55,8 +45,6 @@ const cliSession_1 = require("./cliSession");
55
45
  const shared_1 = require("./commands/shared");
56
46
  const inboxFormat_1 = require("./inboxFormat");
57
47
  const PKG_NAME = "codiedev";
58
- // Read version from the bundled package.json so the startup log + tool reports
59
- // always reflect the actually-installed version, rather than a stale constant.
60
48
  const PKG_VERSION = (() => {
61
49
  try {
62
50
  const pkgPath = path.resolve(__dirname, "..", "package.json");
@@ -66,10 +54,6 @@ const PKG_VERSION = (() => {
66
54
  return "unknown";
67
55
  }
68
56
  })();
69
- // ─────────────────────────────────────────────────────────────────────────────
70
- // Tool definitions — descriptions tuned so Claude/Codex resolve natural-language
71
- // requests into the right tool without manual steering.
72
- // ─────────────────────────────────────────────────────────────────────────────
73
57
  const TOOLS = [
74
58
  {
75
59
  name: "codiedev_push",
@@ -372,17 +356,10 @@ const TOOLS = [
372
356
  },
373
357
  },
374
358
  ];
375
- // ─────────────────────────────────────────────────────────────────────────────
376
- // Server
377
- // ─────────────────────────────────────────────────────────────────────────────
378
359
  const server = new index_js_1.Server({ name: PKG_NAME, version: PKG_VERSION }, { capabilities: { tools: {} } });
379
360
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
380
361
  tools: TOOLS,
381
362
  }));
382
- /**
383
- * Fire-and-forget telemetry — POST one event per tool invocation. Never blocks,
384
- * never throws into the user-facing path. Drop silently on any failure.
385
- */
386
363
  function emitTelemetry(config, event) {
387
364
  if (!config)
388
365
  return;
@@ -396,11 +373,9 @@ function emitTelemetry(config, event) {
396
373
  mcpVersion: PKG_VERSION,
397
374
  },
398
375
  }).catch(() => {
399
- // Swallow — telemetry should never affect the user's session.
400
376
  });
401
377
  }
402
378
  server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
403
- // Long-lived process: the access token may expire while it runs.
404
379
  await (0, cliSession_1.ensureFreshToken)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
405
380
  const config = (0, utils_1.readConfig)();
406
381
  if (!config) {
@@ -517,10 +492,6 @@ async function handlePull(args, config) {
517
492
  throw new Error("key required");
518
493
  const res = await (0, shared_1.apiRequest)("GET", "/api/cli/pull", { config, query: { key, version } });
519
494
  const a = res.artifact;
520
- // Lead with the new-vocab kind. Legacy doc-shape (spec/decision/...) is
521
- // surfaced as a tag list after, so callers still see it but it's no
522
- // longer the primary label. Falls back to "doc" if the row pre-dates the
523
- // kind field.
524
495
  const kindLabel = a.kind ?? "doc";
525
496
  const tagList = (a.tags ?? []).filter((t) => t).join(", ");
526
497
  const tagSuffix = tagList ? ` · tags: ${tagList}` : "";
@@ -528,8 +499,6 @@ async function handlePull(args, config) {
528
499
  `**${kindLabel}** · v${a.version ?? 1} · ${a.lifecycle ?? "draft"}${tagSuffix} · ` +
529
500
  `updated ${(0, shared_1.timeAgo)(a.updatedAt ?? a.createdAt)}\n\n---\n\n`;
530
501
  return {
531
- // A skill's text carries its identity marker, so a copy the agent writes
532
- // to disk still attributes its runs exactly (skillMarker.ts).
533
502
  content: [{ type: "text", text: header + (a.kind === "skill" || (!a.kind && (0, skillMarker_1.looksLikeSkill)(a.markdown)) ? (0, skillMarker_1.stampSkillMarker)(a.markdown, a._id) : a.markdown) }],
534
503
  };
535
504
  }
@@ -606,9 +575,6 @@ async function handleInbox(args, config) {
606
575
  config,
607
576
  query: { unreadOnly: unreadOnly ? "1" : undefined, limit },
608
577
  });
609
- // Shared with `codiedev inbox` so this agent-facing path can never drift
610
- // back to pings-only. CLAUDE.md routes "any messages?" here, so a
611
- // mentions-blind version reproduces the bug for agents.
612
578
  const text = (0, inboxFormat_1.formatInbox)({
613
579
  pings: res.pings,
614
580
  mentions: res.mentions,
@@ -660,8 +626,6 @@ async function handleShareWith(args, config) {
660
626
  ],
661
627
  };
662
628
  }
663
- // noop / duplicate path — surface where the existing grant came from so
664
- // the user knows whether to expect it next time.
665
629
  const e = res.existing;
666
630
  let why = "";
667
631
  if (e) {
@@ -794,9 +758,6 @@ async function handleGetLibrary(args, config) {
794
758
  const v = a.version ? ` v${a.version}` : "";
795
759
  const life = a.lifecycle ? ` · ${a.lifecycle}` : "";
796
760
  const when = a.updatedAt ? ` · ${(0, shared_1.timeAgo)(a.updatedAt)}` : "";
797
- // Lead with the canonical kind (doc | skill). Tags carry the legacy
798
- // doc-shape (spec/decision/...) plus any author-added labels — surface
799
- // them after the kind so the row is self-describing.
800
761
  const k = a.kind ?? (a.type === "note" ? "doc" : "doc");
801
762
  const tagList = (a.tags ?? []).length > 0 ? ` [${a.tags.join(", ")}]` : "";
802
763
  lines.push(`[${k}]${tagList} ${loc}${a.key ?? a.title}${v}${life}${when}`);
@@ -823,9 +784,6 @@ function formatAmbiguousRecipient(err, to) {
823
784
  }
824
785
  throw err;
825
786
  }
826
- // ─────────────────────────────────────────────────────────────────────────────
827
- // Helpers
828
- // ─────────────────────────────────────────────────────────────────────────────
829
787
  function asString(v) {
830
788
  return typeof v === "string" ? v : "";
831
789
  }
@@ -843,20 +801,14 @@ function asStringArrayOrUndefined(v) {
843
801
  return undefined;
844
802
  return v.filter((x) => typeof x === "string");
845
803
  }
846
- // ─────────────────────────────────────────────────────────────────────────────
847
- // Main
848
- // ─────────────────────────────────────────────────────────────────────────────
849
804
  async function main() {
850
805
  const transport = new stdio_js_1.StdioServerTransport();
851
806
  await server.connect(transport);
852
- // stdio transport handles I/O until process exits.
853
- // Log to stderr only — stdout is reserved for MCP protocol.
854
807
  process.stderr.write(`[codiedev-mcp] ready (v${PKG_VERSION}, config ${(0, utils_1.readConfig)() ? "present" : "missing"})\n`);
855
808
  }
856
809
  main().catch((err) => {
857
810
  process.stderr.write(`[codiedev-mcp] fatal: ${err.message}\n`);
858
811
  process.exit(1);
859
812
  });
860
- // Avoid "Cannot find name 'path', 'fs'" since we imported them but may not use.
861
813
  void path;
862
814
  void fs;