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
@@ -1,8 +1,4 @@
1
1
  "use strict";
2
- // `codiedev send <filename> <recipient> [message]` — share an artifact AND
3
- // send a short message that lands in the teammate's inbox. The active-
4
- // handoff version of `codiedev share`. Use this when the user is actively
5
- // looping someone in.
6
2
  Object.defineProperty(exports, "__esModule", { value: true });
7
3
  exports.runSend = runSend;
8
4
  const shared_1 = require("./shared");
@@ -13,7 +9,6 @@ function parseArgs(args) {
13
9
  console.error('Usage: codiedev send <filename> <recipient> ["<message>"]');
14
10
  process.exit(1);
15
11
  }
16
- // Recombine remaining tokens — supports both quoted and unquoted messages.
17
12
  const message = rest.length > 0 ? (0, shared_1.stripQuotes)(rest.join(" ")) : undefined;
18
13
  return { filename, to, message };
19
14
  }
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- // `codiedev share <filename> <recipient> [--role read|edit]` — silently
3
- // grant a teammate access to an artifact (no notification). Use
4
- // `codiedev send` instead when the user wants to actively loop someone in.
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.runShare = runShare;
7
4
  const shared_1 = require("./shared");
@@ -71,7 +68,6 @@ async function runShare(args, configOverride) {
71
68
  latencyMs: Date.now() - start,
72
69
  error: err.message,
73
70
  });
74
- // Ambiguous recipients return 409 with candidates in the body.
75
71
  const body = err.body;
76
72
  if (body && Array.isArray(body.candidates) && body.candidates.length > 0) {
77
73
  console.error(`Recipient "${parsed.to}" is ambiguous. Candidates:`);
@@ -45,13 +45,6 @@ const https = __importStar(require("https"));
45
45
  const http = __importStar(require("http"));
46
46
  const utils_1 = require("../utils");
47
47
  const version_1 = require("../version");
48
- /**
49
- * Layer per-command env overrides on top of the on-disk config. Useful for
50
- * ad-hoc testing — point a prod-connected CLI at a dev Convex deployment
51
- * without re-running `codiedev connect`. Both CODIEDEV_URL and CODIEDEV_TOKEN
52
- * must be set together (half-overrides would mismatch URL and auth realm).
53
- * Other fields (companyId, repos[]) come from the file unchanged.
54
- */
55
48
  function applyConfigEnvOverrides(config) {
56
49
  const url = process.env.CODIEDEV_URL;
57
50
  const token = process.env.CODIEDEV_TOKEN;
@@ -60,10 +53,6 @@ function applyConfigEnvOverrides(config) {
60
53
  }
61
54
  return config;
62
55
  }
63
- /**
64
- * Require a connected Codiedev config. Exits the process with a helpful
65
- * message if the user hasn't run `codiedev connect` yet.
66
- */
67
56
  function requireConfig() {
68
57
  const config = (0, utils_1.readConfig)();
69
58
  if (!config) {
@@ -72,10 +61,6 @@ function requireConfig() {
72
61
  }
73
62
  return applyConfigEnvOverrides(config);
74
63
  }
75
- /**
76
- * Perform an authenticated HTTP request against the Codiedev backend.
77
- * Returns the parsed JSON response body. Throws on non-2xx.
78
- */
79
64
  function apiRequest(method, path, options) {
80
65
  return new Promise((resolve, reject) => {
81
66
  const base = options.config.backendUrl;
@@ -135,12 +120,6 @@ function apiRequest(method, path, options) {
135
120
  req.end();
136
121
  });
137
122
  }
138
- /**
139
- * Fire-and-forget per-invocation telemetry from CLI subcommands. Mirrors
140
- * the MCP server's emitTelemetry but stamps `source: "cli"` so adoption
141
- * dashboards can distinguish between the two surfaces. Never blocks the
142
- * user's command, never throws — telemetry must not change behavior.
143
- */
144
123
  function recordAgentEvent(config, event) {
145
124
  apiRequest("POST", "/api/telemetry/mcp-event", {
146
125
  config,
@@ -153,7 +132,6 @@ function recordAgentEvent(config, event) {
153
132
  source: "cli",
154
133
  },
155
134
  }).catch(() => {
156
- // Swallow — telemetry must never affect user-facing flow.
157
135
  });
158
136
  }
159
137
  function recordInstallEvent(config, event) {
@@ -169,14 +147,8 @@ function recordInstallEvent(config, event) {
169
147
  cliVersion: version_1.CLI_VERSION,
170
148
  },
171
149
  }).catch(() => {
172
- // Swallow — telemetry must never affect connect flow.
173
150
  });
174
151
  }
175
- /**
176
- * Wraps a CLI subcommand body so success and failure both record telemetry
177
- * and the original error propagates after the event is queued. Use this in
178
- * each `runXxx` command instead of inline timing + try/catch boilerplate.
179
- */
180
152
  async function withTelemetry(config, tool, fn) {
181
153
  const start = Date.now();
182
154
  try {
@@ -194,9 +166,6 @@ async function withTelemetry(config, tool, fn) {
194
166
  throw err;
195
167
  }
196
168
  }
197
- /**
198
- * Relative-time formatter for inbox / listing output.
199
- */
200
169
  function timeAgo(ts) {
201
170
  const diff = Date.now() - ts;
202
171
  const mins = Math.floor(diff / 60000);
@@ -210,10 +179,6 @@ function timeAgo(ts) {
210
179
  const days = Math.floor(hours / 24);
211
180
  return `${days}d ago`;
212
181
  }
213
- /**
214
- * Strip surrounding quotes from a CLI argument if the user wrapped it.
215
- * `codiedev ping <name> "hey"` on some shells passes the quotes through.
216
- */
217
182
  function stripQuotes(s) {
218
183
  if ((s.startsWith('"') && s.endsWith('"')) ||
219
184
  (s.startsWith("'") && s.endsWith("'"))) {
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- // `codiedev traces agents`
3
- // `codiedev traces cases <agent> [--dataset name] [--model id] [--out dir] [--json]`
4
- // `codiedev traces report <results.json> [--harness name]`
5
- // (scores, review queues, automatic scoring and datasets: ./tracesLabel.ts)
6
- //
7
- // Test cases are runs an engineer saved from Codiedev → Traces. They run in
8
- // the engineer's coding agent, not in the portal: `cases` writes them into the
9
- // repo with a brief the agent follows to replay each one against the agent's
10
- // own code, optionally on another model (a regression check before a model
11
- // swap), and a results.json for `report` to send back so Traces shows pass
12
- // rates by model.
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);
@@ -114,7 +103,6 @@ const recordedModel = (res) => res.cases.flatMap((c) => c.steps.map((s) => s.mod
114
103
  function slugify(name) {
115
104
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
116
105
  }
117
- /** The brief a coding agent follows to run the cases and report back. */
118
106
  function casesBrief(res, casesFile, opts = {}) {
119
107
  const fix = res.cases.filter((c) => c.kind === "fix");
120
108
  const keep = res.cases.filter((c) => c.kind === "keep");
@@ -148,7 +136,6 @@ function casesBrief(res, casesFile, opts = {}) {
148
136
  }
149
137
  return lines.filter((line, i, all) => !(line === "" && all[i - 1] === "")).join("\n") + "\n";
150
138
  }
151
- /** The results.json a run starts from: every case, passes to be filled in. */
152
139
  function resultsTemplate(res, model) {
153
140
  return {
154
141
  agent: res.agent.name,
@@ -1,11 +1,4 @@
1
1
  "use strict";
2
- // `codiedev traces overview | runs | run | score | scores | score-kinds |
3
- // queue | judge | import | add-example | versions | save-version`: what the
4
- // Traces portal shows and does (agents, runs, failures, scores, review
5
- // queues, automatic scoring, datasets), so a coding agent can do it from
6
- // plain words ("put this week's failed runs in the Week 44 queue"). Each
7
- // calls a /api/cli/traces/* route that runs the portal's own code, with the
8
- // same permissions.
9
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
3
  if (k2 === undefined) k2 = k;
11
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -83,7 +76,6 @@ function parseArgs(args) {
83
76
  }
84
77
  return out;
85
78
  }
86
- /** "4" → 4, "true" → true, anything else as text (a category). */
87
79
  function scoreValue(raw) {
88
80
  const t = raw.trim();
89
81
  if (/^(true|false)$/i.test(t))
package/dist/configDir.js CHANGED
@@ -36,33 +36,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.realHome = realHome;
37
37
  exports.pickHome = pickHome;
38
38
  exports.codiedevStateDir = codiedevStateDir;
39
- // Single source of truth for where the CLI's config/state lives on disk.
40
- //
41
- // Defaults to ~/.codiedev. The desktop app sets CODIEDEV_CONFIG_DIR to
42
- // ~/.codiedev-desktop so a desktop session never touches the user's real
43
- // prod config — env-based (not a flag) so detached capture-finish/upload
44
- // children inherit the override automatically.
45
- //
46
- // Deliberately dependency-free (only node:path/os) so it can be imported
47
- // by both utils.ts and modules utils.ts itself imports (e.g. captureLog.ts)
48
- // without creating a circular import.
49
39
  const path = __importStar(require("path"));
50
40
  const os = __importStar(require("os"));
51
- /**
52
- * The user's home, always absolute. $HOME can arrive relative or unexpanded ("~", ".", "") from a
53
- * sandboxed shell or a wrapper; trusting it once wrote hook commands like ".codiedev/bin/…" into
54
- * ~/.claude/settings.json, which only resolve when Claude Code starts in the home folder, so
55
- * capture silently failed in every project. Fall back to the account's home from the OS.
56
- */
57
41
  function realHome() {
58
42
  let fromOs;
59
43
  try {
60
44
  fromOs = os.userInfo().homedir;
61
45
  }
62
- catch { /* no passwd entry */ }
46
+ catch { }
63
47
  return pickHome(os.homedir(), fromOs);
64
48
  }
65
- /** $HOME when it's a real absolute path, else the OS account's home, else resolved against cwd. */
66
49
  function pickHome(fromEnv, fromOs) {
67
50
  if (fromEnv && path.isAbsolute(fromEnv) && !fromEnv.split(path.sep).includes("~"))
68
51
  return fromEnv;
package/dist/connect.js CHANGED
@@ -47,21 +47,7 @@ const version_1 = require("./version");
47
47
  const upgradeNudge_1 = require("./upgradeNudge");
48
48
  const shared_1 = require("./commands/shared");
49
49
  const harnessDirs_1 = require("./harnessDirs");
50
- // cli.codiedev.com is a Convex custom domain on the prod deployment; the
51
- // underlying judicious-falcon-861.convex.site URL keeps serving, so configs
52
- // written by older CLI versions stay valid without a re-connect.
53
50
  const BACKEND_URL = process.env.CODIEDEV_URL || "https://cli.codiedev.com";
54
- /**
55
- * Reads a line from stdin without echoing the typed/pasted characters —
56
- * for tokens, passwords, anything that shouldn't end up in terminal
57
- * scrollback or screenshots. Echoes `*` per character so the user gets
58
- * visual feedback that input is being received.
59
- *
60
- * Falls back to the regular `prompt()` if stdin isn't a TTY (e.g., piped
61
- * input in CI). Without a TTY there's no echo to suppress anyway, and
62
- * raw mode would error.
63
- */
64
- /** One visible line from the terminal (for yes/no questions). */
65
51
  function prompt(question) {
66
52
  return new Promise((resolve) => {
67
53
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -76,7 +62,6 @@ function promptHidden(question) {
76
62
  const stdin = process.stdin;
77
63
  const stdout = process.stdout;
78
64
  if (!stdin.isTTY) {
79
- // CI / piped input — no terminal to mute. Fall back to readline.
80
65
  const rl = readline.createInterface({ input: stdin, output: stdout });
81
66
  rl.question(question, (answer) => {
82
67
  rl.close();
@@ -93,23 +78,18 @@ function promptHidden(question) {
93
78
  };
94
79
  const onData = (chunk) => {
95
80
  const key = chunk.toString("utf8");
96
- // Iterate so a single `chunk` containing a multi-char paste still
97
- // masks each character individually.
98
81
  for (const ch of key) {
99
- // Ctrl+C — abort like a normal terminal interrupt.
100
82
  if (ch === "") {
101
83
  cleanup();
102
84
  stdout.write("\n");
103
85
  process.exit(130);
104
86
  }
105
- // Enter — finalize.
106
87
  if (ch === "\r" || ch === "\n") {
107
88
  cleanup();
108
89
  stdout.write("\n");
109
90
  resolve(buf.trim());
110
91
  return;
111
92
  }
112
- // Backspace / DEL — erase one masked char.
113
93
  if (ch === "" || ch === "\b") {
114
94
  if (buf.length > 0) {
115
95
  buf = buf.slice(0, -1);
@@ -117,7 +97,6 @@ function promptHidden(question) {
117
97
  }
118
98
  continue;
119
99
  }
120
- // Ignore other control bytes (escape sequences from arrow keys, etc.)
121
100
  if (ch.charCodeAt(0) < 0x20)
122
101
  continue;
123
102
  buf += ch;
@@ -173,24 +152,13 @@ function postJson(url, body, extraHeaders = {}) {
173
152
  });
174
153
  }
175
154
  async function runConnect(args = []) {
176
- // `--force` (or `-f`) re-prompts for a token even if `~/.codiedev/config.json`
177
- // already has one. Default behavior reuses the saved token so users can
178
- // re-run `connect` (e.g., after installing Claude Code) without having to
179
- // mint a fresh token from the portal — which is what bit Sonifi's first
180
- // engineer when he interpreted "no visible token" as "the old one is gone".
181
155
  const force = args.includes("--force") || args.includes("-f");
182
- // `--token`: paste an API token instead of signing in (CI). Otherwise sign
183
- // in with the browser: a loopback redirect on a desktop, a device code
184
- // (approve on any device) over SSH or with no display, detected
185
- // automatically. `--no-browser` / `--browser` force one or the other.
186
156
  const pasteToken = args.includes("--token");
187
157
  const useDevice = args.includes("--no-browser") || (!args.includes("--browser") && (0, cliSession_1.isHeadless)());
188
158
  console.log("\nWelcome to Codiedev CLI\n");
189
159
  await (0, upgradeNudge_1.maybePrintUpgradeNudge)();
190
160
  console.log("This will connect your coding agent to your Codiedev workspace and install");
191
161
  console.log("the session capture hook for org-wide session sharing.\n");
192
- // A saved browser sign-in is reused only if it still works: refresh it
193
- // first (a revoked one comes back signed out, with an empty token).
194
162
  await (0, cliSession_1.ensureFreshToken)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
195
163
  const saved = (0, utils_1.readConfig)();
196
164
  const decision = (0, connectFlow_1.resolveConnectToken)({ savedConfig: saved, force: force || pasteToken });
@@ -204,8 +172,6 @@ async function runConnect(args = []) {
204
172
  : `Reusing API token from ~/.codiedev/config.json (run with --force to sign in again).\n`);
205
173
  }
206
174
  else if (!pasteToken) {
207
- // Replacing a browser sign-in: end the old one so the portal doesn't
208
- // keep listing it.
209
175
  if (saved?.auth)
210
176
  await (0, cliSession_1.logout)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
211
177
  const result = await (0, connectFlow_1.signInWithTokenFallback)({
@@ -222,8 +188,6 @@ async function runConnect(args = []) {
222
188
  auth = result.auth;
223
189
  }
224
190
  else {
225
- // Hidden prompt — masks the token with `*` as it's typed/pasted so it
226
- // doesn't end up in terminal scrollback or screenshots.
227
191
  token = await promptHidden("Enter your Codiedev API token: ");
228
192
  if (!token) {
229
193
  console.error("Error: API token is required.");
@@ -241,7 +205,6 @@ async function runConnect(args = []) {
241
205
  console.error(`\nError: Failed to validate token — ${err.message}`);
242
206
  process.exit(1);
243
207
  }
244
- // Extract fields from response
245
208
  const companyId = responseData.companyId;
246
209
  const companyName = responseData.companyName;
247
210
  const repos = responseData.repos ?? [];
@@ -268,15 +231,7 @@ async function runConnect(args = []) {
268
231
  console.error(`\nError: Failed to save config — ${err.message}`);
269
232
  process.exit(1);
270
233
  }
271
- // Once we have a valid token + config, every subsequent step posts a
272
- // per-step row to /api/telemetry/install-event so the admin page can show
273
- // a timeline when a customer says "it connected but it doesn't work."
274
- // Fire-and-forget — never blocks the connect flow.
275
234
  (0, shared_1.recordInstallEvent)(config, { step: "started", ok: true });
276
- // One-way device status sync. Local config remains authoritative: a network
277
- // failure here never removes or weakens an ignored path. This also registers
278
- // a freshly connected device with an empty list so the portal can distinguish
279
- // "connected, no exclusions" from "old CLI has never reported status".
280
235
  try {
281
236
  await postJson(`${BACKEND_URL}/api/cli/capture-exclusions`, {
282
237
  deviceId: config.deviceId,
@@ -287,17 +242,6 @@ async function runConnect(args = []) {
287
242
  catch (err) {
288
243
  console.warn(`Warning: Local capture settings are active, but portal status did not sync — ${err.message}`);
289
244
  }
290
- // Migration: strip MCP server entries written by pre-CLI-only versions
291
- // of `codiedev connect`. These pointed at `npx codiedev-mcp`, a binary
292
- // that was removed in 0.3.4 and that 0.7.11+ no longer ships. Without
293
- // cleanup, customers upgrading from any prior version see persistent
294
- // "MCP server failed to start" errors in their agent UIs even though
295
- // the CLI works fine. Each helper is idempotent and a no-op when the
296
- // relevant config file doesn't exist.
297
- //
298
- // Each call is wrapped because the user's upgrade path matters more
299
- // than the cleanup. A locked / wrong-owner config file (rare but real)
300
- // shouldn't block the install loop or strand them on an old version.
301
245
  for (const [label, fn] of [
302
246
  ["Claude Code", utils_1.cleanupClaudeCodeMcp],
303
247
  ["Codex", utils_1.cleanupCodexMcp],
@@ -325,13 +269,7 @@ async function runConnect(args = []) {
325
269
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "copilot", ok: hasCopilot });
326
270
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "pi", ok: hasPi });
327
271
  const installed = [];
328
- // Machine-readable target keys reported back to the backend via
329
- // /api/cli/markInstalled so the portal's "Connected" state reflects
330
- // what's actually wired up on this machine, not just "token validated."
331
272
  const installedTargets = [];
332
- // Wrap each per-target write so we emit one install_target row each. The
333
- // existing user-visible behavior (console.warn on failure, continue) is
334
- // unchanged — telemetry just observes the outcome.
335
273
  const runInstall = (target, fn, label, targetKey) => {
336
274
  try {
337
275
  fn();
@@ -362,26 +300,15 @@ async function runConnect(args = []) {
362
300
  runInstall("cursor-hook", utils_1.installCursorHook, "Cursor sessionStart + stop backup + sessionEnd capture hooks (~/.cursor/hooks.json)", "cursor-hook");
363
301
  runInstall("cursor-instructions", utils_1.installCursorInstructions, "Cursor agent instructions (~/.cursor/rules/codiedev.mdc)", "cursor-instructions");
364
302
  }
365
- // One user-level hook file covers both VS Code Copilot Chat and the Copilot
366
- // CLI (they share the runtime and its hooks).
367
303
  if (hasCopilot) {
368
- runInstall("copilot-hook", () => (0, utils_1.installCopilotHook)(), `GitHub Copilot (VS Code + CLI) sessionStart + agentStop backup + sessionEnd capture hooks (${(0, utils_1.copilotHooksPath)()})`, "copilot-hook");
304
+ runInstall("copilot-hook", utils_1.installCopilotHook, `GitHub Copilot (VS Code + CLI) sessionStart + agentStop backup + sessionEnd capture hooks (${(0, utils_1.copilotHooksPath)()})`, "copilot-hook");
369
305
  runInstall("copilot-instructions", utils_1.installCopilotInstructions, "GitHub Copilot CLI team artifact instructions", "copilot-instructions");
370
306
  }
371
- // Staged like OpenCode's adapter: dormant until pi starts, so installing pi
372
- // later needs no second `connect`.
373
- runInstall("pi-extension", () => (0, utils_1.installPiExtension)(), `pi session start + prompt guard + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
307
+ runInstall("pi-extension", utils_1.installPiExtension, `pi session start + skill discovery + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
374
308
  if (hasPi) {
375
309
  runInstall("pi-instructions", utils_1.installPiInstructions, `pi agent instructions (${(0, harnessDirs_1.displayPath)((0, utils_1.piInstructionsPath)())})`, "pi-instructions");
376
310
  }
377
- // Always stage the adapter. It is dormant until OpenCode starts, which lets
378
- // a user connect Claude Code today and install the Codie harness tomorrow
379
- // without needing a second setup ritual.
380
311
  runInstall("opencode-capture-adapter", utils_1.installOpenCodeCapturePlugin, `OpenCode session capture adapter (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.openCodeConfigDir)(), "plugins", "codiedev.js"))})`, "opencode-capture");
381
- // Tell the backend which targets we wired up so the portal's onboarding
382
- // card flips to "Connected" only when something actually installed —
383
- // not on bare token validation. Best-effort: a network failure here
384
- // doesn't undo the local install, and `codiedev doctor` still works.
385
312
  if (installedTargets.length > 0) {
386
313
  try {
387
314
  await postJson(`${BACKEND_URL}/api/cli/markInstalled`, {
@@ -416,5 +343,6 @@ async function runConnect(args = []) {
416
343
  }
417
344
  console.log();
418
345
  console.log("Run `codiedev doctor` to verify everything's wired up.");
346
+ console.log("If `codiedev` is not on PATH, run `npx codiedev@latest doctor` instead.");
419
347
  console.log();
420
348
  }
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- // Pure helper for `npx codiedev connect` — decides where the API token
3
- // comes from. Splitting this out lets us TDD the policy (re-use vs. re-prompt)
4
- // without touching readline or fs at all.
5
- //
6
- // Motivation: Jackson hit a confusing flow where he had a working token in
7
- // `~/.codiedev/config.json`, re-ran `connect` (to pick up Claude Code that
8
- // he'd just installed), and was forced to paste a token again. Since the
9
- // portal only displays the plaintext on creation, his only option was to
10
- // generate a new one — leaving him thinking the old one had been lost.
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.resolveConnectToken = resolveConnectToken;
13
4
  exports.signInWithTokenFallback = signInWithTokenFallback;
@@ -20,12 +11,6 @@ function resolveConnectToken(input) {
20
11
  return { source: "prompt-required" };
21
12
  return { source: "reused", token: input.savedConfig.token };
22
13
  }
23
- /**
24
- * Browser sign-in, with the API-token paste as the way out: if the browser
25
- * flow fails (blocked page, expired code, proxy) an interactive user is asked
26
- * whether to paste a token instead, rather than being sent to rerun connect.
27
- * Returns null when there's nothing to continue with (caller exits 1).
28
- */
29
14
  async function signInWithTokenFallback(deps) {
30
15
  deps.log("Prefer an API token? Press Ctrl+C and run `codiedev connect --token`.\n");
31
16
  try {
@@ -41,23 +41,12 @@ exports.parseCopilotWorkspace = parseCopilotWorkspace;
41
41
  exports.readCopilotWorkspace = readCopilotWorkspace;
42
42
  exports.copilotLaunch = copilotLaunch;
43
43
  exports.normalizeCopilotHookInput = normalizeCopilotHookInput;
44
- exports.copilotPreToolBlockResponse = copilotPreToolBlockResponse;
45
44
  exports.isCopilotTranscriptEmpty = isCopilotTranscriptEmpty;
46
45
  exports.hasCopilotShutdown = hasCopilotShutdown;
47
46
  exports.normalizeCopilotTranscript = normalizeCopilotTranscript;
48
47
  const fs = __importStar(require("node:fs"));
49
48
  const os = __importStar(require("node:os"));
50
49
  const path = __importStar(require("node:path"));
51
- /**
52
- * GitHub Copilot: VS Code Copilot Chat's agent and the Copilot CLI run on the
53
- * same runtime and write the same session record,
54
- * `$COPILOT_HOME/session-state/<sessionId>/events.jsonl` (plus
55
- * `workspace.yaml`), and both read user hooks from `$COPILOT_HOME/hooks/*.json`.
56
- * Everything Copilot-specific is translated here, at the process boundary, so
57
- * the shared capture pipeline only ever sees the Claude-shaped transcript it
58
- * already parses.
59
- */
60
- /** `$COPILOT_HOME`, else `~/.copilot` (the runtime honours the same variable). */
61
50
  function copilotHome(env = process.env, home = os.homedir()) {
62
51
  const override = env.COPILOT_HOME?.trim();
63
52
  return override ? path.resolve(override) : path.join(home, ".copilot");
@@ -66,12 +55,10 @@ const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
66
55
  function copilotSessionDir(sessionId, home = copilotHome()) {
67
56
  return SESSION_ID.test(sessionId) ? path.join(home, "session-state", sessionId) : undefined;
68
57
  }
69
- /** sessionEnd carries no transcript path; the session id names the file. */
70
58
  function copilotTranscriptPath(sessionId, home = copilotHome()) {
71
59
  const dir = sessionId ? copilotSessionDir(sessionId, home) : undefined;
72
60
  return dir ? path.join(dir, "events.jsonl") : undefined;
73
61
  }
74
- /** workspace.yaml is flat `key: value` lines; no YAML dependency needed. */
75
62
  function parseCopilotWorkspace(yaml) {
76
63
  const fields = new Map();
77
64
  for (const line of yaml.split(/\r?\n/)) {
@@ -93,7 +80,6 @@ function parseCopilotWorkspace(yaml) {
93
80
  ...(pick("client_name") ? { clientName: pick("client_name") } : {}),
94
81
  };
95
82
  }
96
- /** The workspace.yaml beside a transcript (or for a session id); {} if absent. */
97
83
  function readCopilotWorkspace(transcriptPathOrDir) {
98
84
  if (!transcriptPathOrDir)
99
85
  return {};
@@ -107,25 +93,12 @@ function readCopilotWorkspace(transcriptPathOrDir) {
107
93
  }
108
94
  exports.COPILOT_VSCODE_CLIENT = "vscode-agent-host";
109
95
  const isVSCodeClient = (name) => name === exports.COPILOT_VSCODE_CLIENT || name === "vscode";
110
- /**
111
- * How the session was launched. VS Code names itself in workspace.yaml; the
112
- * CLI doesn't record whether it ran headless, so that comes from the process
113
- * that launched the hook (`detected`, see launchContext). Unknown stays
114
- * unknown rather than guessing "human".
115
- */
116
96
  function copilotLaunch(clientName, detected) {
117
97
  if (isVSCodeClient(clientName))
118
98
  return "copilot:vscode";
119
99
  return detected;
120
100
  }
121
101
  const firstString = (...values) => values.find((value) => typeof value === "string" && value.trim().length > 0);
122
- /**
123
- * Copilot's hook payloads are camelCase (`sessionId`, `transcriptPath`,
124
- * `toolName`/`toolArgs`/`toolResult`); preToolUse in the CLI batches calls as
125
- * `toolCalls: [{id, name, args}]`. Translate to the shared snake_case shape.
126
- * The FIRST tool call fills tool_name/tool_input; `copilotToolCalls` keeps all
127
- * of them so security can check each.
128
- */
129
102
  function normalizeCopilotHookInput(input, home = copilotHome()) {
130
103
  const sessionId = firstString(input.session_id, input.sessionId);
131
104
  const transcriptPath = firstString(input.transcript_path, input.transcriptPath)
@@ -166,21 +139,12 @@ function copilotToolCalls(input) {
166
139
  const name = firstString(input.toolName, input.tool_name);
167
140
  return name ? [{ name, input: parse(input.toolArgs ?? input.tool_input) }] : [];
168
141
  }
169
- /** Copilot's preToolUse deny output. */
170
- function copilotPreToolBlockResponse(reason) {
171
- return { permissionDecision: "deny", permissionDecisionReason: reason };
172
- }
173
- /** Only a byte-empty record is safe to discard (same rule as Cursor). */
174
142
  function isCopilotTranscriptEmpty(content) {
175
143
  return content.trim().length === 0;
176
144
  }
177
- /** session.shutdown carries the per-model token totals; written after sessionEnd. */
178
145
  function hasCopilotShutdown(content) {
179
146
  return content.includes('"session.shutdown"');
180
147
  }
181
- // Copilot tool names → the Claude names the shared parsers key on (Bash
182
- // commands for git output and worktree dirs; Edit/Write for the dirs a session
183
- // wrote to). Anything else keeps Copilot's own name.
184
148
  function claudeTool(name, args) {
185
149
  const a = (args && typeof args === "object" ? args : {});
186
150
  const lower = name.toLowerCase();
@@ -195,15 +159,11 @@ function claudeTool(name, args) {
195
159
  return { name: "Write", input: { ...a, file_path: file } };
196
160
  if (lower === "view" && file)
197
161
  return { name: "Read", input: { ...a, file_path: file } };
198
- // The skill tool's runs are counted from skill.invoked (which also covers
199
- // skills the user invoked directly); drop its argument so it isn't counted twice.
200
162
  if (lower === "skill")
201
163
  return { name: "skill", input: {} };
202
164
  return { name, input: args ?? {} };
203
165
  }
204
166
  const num = (value) => (typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0);
205
- /** Image-only prompts have empty content. Keep attachment descriptions without
206
- * reading local files, uploading image bytes, or inventing OCR prompt text. */
207
167
  function copilotUserContent(data) {
208
168
  const content = [];
209
169
  if (typeof data.content === "string" && data.content)
@@ -249,27 +209,11 @@ function sumAgentMetrics(agents) {
249
209
  }
250
210
  return Object.fromEntries(Object.entries(totals).map(([model, usage]) => [model, { usage }]));
251
211
  }
252
- /**
253
- * events.jsonl → Claude-shaped JSONL:
254
- * session.start → system record (cwd, branch, entrypoint for VS Code)
255
- * user.message → user text
256
- * assistant.message → assistant text + tool_use blocks (model on every call)
257
- * tool.execution_complete→ user tool_result (git output feeds branch/sha joins)
258
- * skill.invoked → copilot.skill_invoked (one skill run)
259
- * session.shutdown → copilot.usage per model (tokens, sub-agents
260
- * included; requests counted from the assistant
261
- * calls, so 0 here) + copilot.usage_summary
262
- * session.usage_checkpoint → copilot.usage_summary (premium requests and
263
- * nano-AIU so far; superseded by shutdown)
264
- * subagent.started → counted as a fleet sub-agent
265
- * Hooks, permissions, system prompts and checkpoints are dropped.
266
- */
267
212
  function normalizeCopilotTranscript(raw, opts = {}) {
268
213
  const out = [];
269
214
  const subagentCalls = new Set();
270
215
  let shutdownAgents = 0;
271
216
  let assistantModel = false;
272
- // Copilot's subscription usage: the latest checkpoint, superseded by shutdown.
273
217
  let premium;
274
218
  let checkpointModels = [];
275
219
  let final = false;
@@ -351,9 +295,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
351
295
  id: firstString(data.apiCallId, data.messageId, uuid),
352
296
  role: "assistant",
353
297
  content,
354
- // One model call. Copilot reports tokens only at shutdown. A record
355
- // with no model is the runtime's own step (e.g. read_agent after a
356
- // fleet sub-agent finishes), not a model call, so it isn't counted.
357
298
  ...(typeof data.model === "string" && data.model
358
299
  ? {
359
300
  model: data.model,
@@ -368,8 +309,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
368
309
  if (data.error?.code === "user_denied") {
369
310
  out.push(JSON.stringify({ type: "agent.rejection", ...base, id: data.toolCallId ?? uuid }));
370
311
  }
371
- // A space after the array bracket keeps the shared git-output scan
372
- // (`[branch sha]` commit lines) from anchoring on JSON's own "[".
373
312
  out.push(JSON.stringify({
374
313
  type: "user",
375
314
  ...base,
@@ -394,8 +333,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
394
333
  premium = premiumOf(data, timestamp);
395
334
  const agents = Object.entries(data.agentMetrics ?? {});
396
335
  shutdownAgents = agents.filter(([agent]) => agent !== "main").length;
397
- // modelMetrics is the whole session, sub-agents included; older
398
- // records without it are summed from the per-agent metrics.
399
336
  const metrics = data.modelMetrics ?? sumAgentMetrics(agents.map(([, agent]) => agent?.modelMetrics));
400
337
  for (const [model, metric] of Object.entries(metrics)) {
401
338
  const usage = metric?.usage ?? {};
@@ -410,8 +347,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
410
347
  id: `copilot-usage:${model}`,
411
348
  model,
412
349
  usage: {
413
- // Copilot's inputTokens include the cached prompt; the shared
414
- // shape counts fresh input separately from cache reads.
415
350
  input_tokens: Math.max(0, num(usage.inputTokens) - cacheRead),
416
351
  output_tokens: num(usage.outputTokens),
417
352
  cache_read_input_tokens: cacheRead,
@@ -426,8 +361,6 @@ function normalizeCopilotTranscript(raw, opts = {}) {
426
361
  break;
427
362
  }
428
363
  }
429
- // No model on any assistant call (seen in open VS Code chats): name the
430
- // models from the last checkpoint. No tokens are invented; requests stay 0.
431
364
  if (!assistantModel) {
432
365
  for (const model of checkpointModels) {
433
366
  out.push(JSON.stringify({
@@ -49,7 +49,6 @@ function inspectCopilotHooks(file = path.join((0, copilotHooks_1.copilotHome)(),
49
49
  const missing = expected.filter(([event, subcommand]) => {
50
50
  const entries = parsed.hooks?.[event];
51
51
  return !Array.isArray(entries) || !entries.some((entry) => {
52
- // Both platforms must have the managed command, not just the current one.
53
52
  const commands = [entry.bash ?? entry.command, entry.powershell ?? entry.command];
54
53
  return commands.every((command) => typeof command === "string"
55
54
  && (0, detection_1.isCodiedevHookCommand)(command) && command.trim().endsWith(subcommand));