codiedev 0.10.0-beta.1 → 0.10.0-beta.11

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 (155) hide show
  1. package/README.md +11 -5
  2. package/assets/opencode-plugin.mjs +6 -0
  3. package/assets/session-key.mjs +48 -0
  4. package/assets/tui-brand-plugin.tsx +73 -0
  5. package/dist/backup/cache.js +1 -5
  6. package/dist/backup/match.js +0 -6
  7. package/dist/backup/run.js +3 -35
  8. package/dist/captureExclusions.js +0 -12
  9. package/dist/captureLog.js +0 -28
  10. package/dist/captureReadiness.js +0 -58
  11. package/dist/captureSignals.js +184 -0
  12. package/dist/cli.js +135 -72
  13. package/dist/cliSession.js +456 -0
  14. package/dist/codexHookTrust.js +125 -6
  15. package/dist/codexLimitScan.js +359 -0
  16. package/dist/codie.js +77 -130
  17. package/dist/codieBrandInstall.js +80 -0
  18. package/dist/codieLauncher.js +76 -79
  19. package/dist/codieRuntime.js +19 -23
  20. package/dist/codieRuntimeInstall.js +108 -23
  21. package/dist/codieUsage.js +181 -0
  22. package/dist/commands/agentTemplates.generated.js +136 -0
  23. package/dist/commands/agents.js +1101 -0
  24. package/dist/commands/agentsSdk.generated.js +7 -0
  25. package/dist/commands/ask.js +0 -3
  26. package/dist/commands/capture.js +0 -2
  27. package/dist/commands/createTicket.js +0 -10
  28. package/dist/commands/doctor.js +53 -120
  29. package/dist/commands/evals.js +187 -0
  30. package/dist/commands/inbox.js +0 -2
  31. package/dist/commands/library.js +0 -3
  32. package/dist/commands/pack.js +573 -0
  33. package/dist/commands/ping.js +0 -2
  34. package/dist/commands/pull.js +6 -10
  35. package/dist/commands/push.js +2 -12
  36. package/dist/commands/search.js +0 -4
  37. package/dist/commands/send.js +0 -5
  38. package/dist/commands/share.js +0 -4
  39. package/dist/commands/shared.js +0 -35
  40. package/dist/commands/traces.js +344 -0
  41. package/dist/commands/tracesLabel.js +348 -0
  42. package/dist/configDir.js +18 -11
  43. package/dist/connect.js +55 -118
  44. package/dist/connectFlow.js +35 -9
  45. package/dist/copilotHooks.js +391 -0
  46. package/dist/copilotInstallation.js +64 -0
  47. package/dist/cursorHooks.js +38 -30
  48. package/dist/cursorLifecycle.js +109 -0
  49. package/dist/detection.js +0 -30
  50. package/dist/harnessDirs.js +77 -0
  51. package/dist/hook.js +256 -445
  52. package/dist/inboxFormat.js +0 -24
  53. package/dist/launchContext.js +150 -0
  54. package/dist/launcher.js +168 -0
  55. package/dist/limitEvent.js +44 -13
  56. package/dist/limitEventReporter.js +1 -1
  57. package/dist/managedPi.js +256 -0
  58. package/dist/mcp.js +5 -384
  59. package/dist/nativeSteering.js +24 -0
  60. package/dist/packs/codie.js +182 -0
  61. package/dist/packs/harnesses.js +411 -0
  62. package/dist/packs/hookGate.js +256 -0
  63. package/dist/packs/install.js +286 -0
  64. package/dist/packs/manifest.js +126 -0
  65. package/dist/packs/paths.js +81 -0
  66. package/dist/packs/shim.js +214 -0
  67. package/dist/packs/store.js +155 -0
  68. package/dist/packs/sync.js +170 -0
  69. package/dist/piHooks.js +216 -0
  70. package/dist/piRuntime.js +120 -0
  71. package/dist/repoResolver.js +0 -19
  72. package/dist/secret.js +0 -3
  73. package/dist/selfUpdate.js +376 -0
  74. package/dist/skillMarker.js +23 -0
  75. package/dist/subagents.js +135 -0
  76. package/dist/teamSkillContext.js +10 -0
  77. package/dist/transcriptModels.js +205 -0
  78. package/dist/upgradeNudge.js +0 -30
  79. package/dist/utils.js +502 -828
  80. package/dist/version.js +0 -10
  81. package/dist/versionCheck.js +0 -33
  82. package/package.json +8 -9
  83. package/dist/backup/cache.d.ts +0 -14
  84. package/dist/backup/match.d.ts +0 -2
  85. package/dist/backup/run.d.ts +0 -25
  86. package/dist/captureExclusions.d.ts +0 -30
  87. package/dist/captureLog.d.ts +0 -20
  88. package/dist/captureReadiness.d.ts +0 -65
  89. package/dist/cli.d.ts +0 -16
  90. package/dist/codexHookTrust.d.ts +0 -34
  91. package/dist/codie.d.ts +0 -2
  92. package/dist/codieLauncher.d.ts +0 -53
  93. package/dist/codieRuntime.d.ts +0 -29
  94. package/dist/codieRuntimeInstall.d.ts +0 -28
  95. package/dist/codieStartup.d.ts +0 -26
  96. package/dist/codieStartup.js +0 -30
  97. package/dist/commands/ask.d.ts +0 -1
  98. package/dist/commands/capture.d.ts +0 -14
  99. package/dist/commands/createTicket.d.ts +0 -27
  100. package/dist/commands/delete.d.ts +0 -1
  101. package/dist/commands/doctor.d.ts +0 -1
  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/ping.d.ts +0 -1
  106. package/dist/commands/promote.d.ts +0 -1
  107. package/dist/commands/promote.js +0 -53
  108. package/dist/commands/pull.d.ts +0 -2
  109. package/dist/commands/push.d.ts +0 -33
  110. package/dist/commands/react.d.ts +0 -2
  111. package/dist/commands/react.js +0 -40
  112. package/dist/commands/reverseTicket.d.ts +0 -2
  113. package/dist/commands/reverseTicket.js +0 -477
  114. package/dist/commands/search.d.ts +0 -2
  115. package/dist/commands/security.d.ts +0 -1
  116. package/dist/commands/security.js +0 -156
  117. package/dist/commands/send.d.ts +0 -2
  118. package/dist/commands/share.d.ts +0 -2
  119. package/dist/commands/shared.d.ts +0 -64
  120. package/dist/configDir.d.ts +0 -1
  121. package/dist/connect.d.ts +0 -1
  122. package/dist/connectFlow.d.ts +0 -13
  123. package/dist/cursorHooks.d.ts +0 -23
  124. package/dist/detection.d.ts +0 -30
  125. package/dist/hook.d.ts +0 -6
  126. package/dist/inboxFormat.d.ts +0 -38
  127. package/dist/limitEvent.d.ts +0 -16
  128. package/dist/limitEventReporter.d.ts +0 -21
  129. package/dist/mcp.d.ts +0 -12
  130. package/dist/prUrl.d.ts +0 -9
  131. package/dist/prUrl.js +0 -33
  132. package/dist/repoResolver.d.ts +0 -17
  133. package/dist/secret.d.ts +0 -1
  134. package/dist/security.d.ts +0 -102
  135. package/dist/security.js +0 -437
  136. package/dist/securityDeepScan.d.ts +0 -41
  137. package/dist/securityDeepScan.js +0 -248
  138. package/dist/securityDoctor.d.ts +0 -32
  139. package/dist/securityDoctor.js +0 -63
  140. package/dist/securityFeature.d.ts +0 -5
  141. package/dist/securityFeature.js +0 -7
  142. package/dist/securityInstall.d.ts +0 -63
  143. package/dist/securityInstall.js +0 -239
  144. package/dist/securityInventory.d.ts +0 -54
  145. package/dist/securityInventory.js +0 -556
  146. package/dist/securityPilot.d.ts +0 -19
  147. package/dist/securityPilot.js +0 -61
  148. package/dist/securityPolicy.d.ts +0 -33
  149. package/dist/securityPolicy.js +0 -188
  150. package/dist/securitySession.d.ts +0 -6
  151. package/dist/securitySession.js +0 -72
  152. package/dist/upgradeNudge.d.ts +0 -25
  153. package/dist/utils.d.ts +0 -342
  154. package/dist/version.d.ts +0 -1
  155. package/dist/versionCheck.d.ts +0 -68
package/dist/connect.js CHANGED
@@ -39,36 +39,29 @@ const https = __importStar(require("https"));
39
39
  const http = __importStar(require("http"));
40
40
  const crypto = __importStar(require("crypto"));
41
41
  const os = __importStar(require("os"));
42
- const fs = __importStar(require("fs"));
43
42
  const path = __importStar(require("path"));
44
43
  const utils_1 = require("./utils");
44
+ const cliSession_1 = require("./cliSession");
45
45
  const connectFlow_1 = require("./connectFlow");
46
46
  const version_1 = require("./version");
47
47
  const upgradeNudge_1 = require("./upgradeNudge");
48
48
  const shared_1 = require("./commands/shared");
49
- const securityInstall_1 = require("./securityInstall");
50
- const securityPolicy_1 = require("./securityPolicy");
51
- const securityFeature_1 = require("./securityFeature");
52
- // cli.codiedev.com is a Convex custom domain on the prod deployment; the
53
- // underlying judicious-falcon-861.convex.site URL keeps serving, so configs
54
- // written by older CLI versions stay valid without a re-connect.
49
+ const harnessDirs_1 = require("./harnessDirs");
55
50
  const BACKEND_URL = process.env.CODIEDEV_URL || "https://cli.codiedev.com";
56
- /**
57
- * Reads a line from stdin without echoing the typed/pasted characters —
58
- * for tokens, passwords, anything that shouldn't end up in terminal
59
- * scrollback or screenshots. Echoes `*` per character so the user gets
60
- * visual feedback that input is being received.
61
- *
62
- * Falls back to the regular `prompt()` if stdin isn't a TTY (e.g., piped
63
- * input in CI). Without a TTY there's no echo to suppress anyway, and
64
- * raw mode would error.
65
- */
51
+ function prompt(question) {
52
+ return new Promise((resolve) => {
53
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
54
+ rl.question(question, (answer) => {
55
+ rl.close();
56
+ resolve(answer);
57
+ });
58
+ });
59
+ }
66
60
  function promptHidden(question) {
67
61
  return new Promise((resolve) => {
68
62
  const stdin = process.stdin;
69
63
  const stdout = process.stdout;
70
64
  if (!stdin.isTTY) {
71
- // CI / piped input — no terminal to mute. Fall back to readline.
72
65
  const rl = readline.createInterface({ input: stdin, output: stdout });
73
66
  rl.question(question, (answer) => {
74
67
  rl.close();
@@ -85,23 +78,18 @@ function promptHidden(question) {
85
78
  };
86
79
  const onData = (chunk) => {
87
80
  const key = chunk.toString("utf8");
88
- // Iterate so a single `chunk` containing a multi-char paste still
89
- // masks each character individually.
90
81
  for (const ch of key) {
91
- // Ctrl+C — abort like a normal terminal interrupt.
92
82
  if (ch === "") {
93
83
  cleanup();
94
84
  stdout.write("\n");
95
85
  process.exit(130);
96
86
  }
97
- // Enter — finalize.
98
87
  if (ch === "\r" || ch === "\n") {
99
88
  cleanup();
100
89
  stdout.write("\n");
101
90
  resolve(buf.trim());
102
91
  return;
103
92
  }
104
- // Backspace / DEL — erase one masked char.
105
93
  if (ch === "" || ch === "\b") {
106
94
  if (buf.length > 0) {
107
95
  buf = buf.slice(0, -1);
@@ -109,7 +97,6 @@ function promptHidden(question) {
109
97
  }
110
98
  continue;
111
99
  }
112
- // Ignore other control bytes (escape sequences from arrow keys, etc.)
113
100
  if (ch.charCodeAt(0) < 0x20)
114
101
  continue;
115
102
  buf += ch;
@@ -165,26 +152,42 @@ function postJson(url, body, extraHeaders = {}) {
165
152
  });
166
153
  }
167
154
  async function runConnect(args = []) {
168
- // `--force` (or `-f`) re-prompts for a token even if `~/.codiedev/config.json`
169
- // already has one. Default behavior reuses the saved token so users can
170
- // re-run `connect` (e.g., after installing Claude Code) without having to
171
- // mint a fresh token from the portal — which is what bit Sonifi's first
172
- // engineer when he interpreted "no visible token" as "the old one is gone".
173
155
  const force = args.includes("--force") || args.includes("-f");
156
+ const pasteToken = args.includes("--token");
157
+ const useDevice = args.includes("--no-browser") || (!args.includes("--browser") && (0, cliSession_1.isHeadless)());
174
158
  console.log("\nWelcome to Codiedev CLI\n");
175
159
  await (0, upgradeNudge_1.maybePrintUpgradeNudge)();
176
160
  console.log("This will connect your coding agent to your Codiedev workspace and install");
177
161
  console.log("the session capture hook for org-wide session sharing.\n");
162
+ await (0, cliSession_1.ensureFreshToken)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
178
163
  const saved = (0, utils_1.readConfig)();
179
- const decision = (0, connectFlow_1.resolveConnectToken)({ savedConfig: saved, force });
164
+ const decision = (0, connectFlow_1.resolveConnectToken)({ savedConfig: saved, force: force || pasteToken });
180
165
  let token;
166
+ let auth;
181
167
  if (decision.source === "reused") {
182
168
  token = decision.token;
183
- console.log(`Reusing API token from ~/.codiedev/config.json (run with --force to use a new one).\n`);
169
+ auth = saved?.auth;
170
+ console.log(auth
171
+ ? `Reusing your browser sign-in from ~/.codiedev/config.json (run with --force to sign in again).\n`
172
+ : `Reusing API token from ~/.codiedev/config.json (run with --force to sign in again).\n`);
173
+ }
174
+ else if (!pasteToken) {
175
+ if (saved?.auth)
176
+ await (0, cliSession_1.logout)({ configPath: utils_1.CONFIG_PATH }).catch(() => undefined);
177
+ const result = await (0, connectFlow_1.signInWithTokenFallback)({
178
+ signIn: () => useDevice ? (0, cliSession_1.deviceLogin)({ backendUrl: BACKEND_URL }) : (0, cliSession_1.browserLogin)({ backendUrl: BACKEND_URL }),
179
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
180
+ askYesNo: async (q) => /^y(es)?$/i.test((await prompt(q)).trim()),
181
+ askToken: promptHidden,
182
+ log: (line) => console.log(line),
183
+ error: (line) => console.error(line),
184
+ });
185
+ if (!result)
186
+ process.exit(1);
187
+ token = result.token;
188
+ auth = result.auth;
184
189
  }
185
190
  else {
186
- // Hidden prompt — masks the token with `*` as it's typed/pasted so it
187
- // doesn't end up in terminal scrollback or screenshots.
188
191
  token = await promptHidden("Enter your Codiedev API token: ");
189
192
  if (!token) {
190
193
  console.error("Error: API token is required.");
@@ -202,10 +205,8 @@ async function runConnect(args = []) {
202
205
  console.error(`\nError: Failed to validate token — ${err.message}`);
203
206
  process.exit(1);
204
207
  }
205
- // Extract fields from response
206
208
  const companyId = responseData.companyId;
207
209
  const companyName = responseData.companyName;
208
- const agentSecurityEnabled = responseData.agentSecurityEnabled === true;
209
210
  const repos = responseData.repos ?? [];
210
211
  if (!companyId || !companyName) {
211
212
  console.error("\nError: Invalid response from server. Token may be invalid.");
@@ -218,10 +219,10 @@ async function runConnect(args = []) {
218
219
  repos,
219
220
  lastSynced: new Date().toISOString(),
220
221
  backendUrl: BACKEND_URL,
221
- agentSecurityEnabled,
222
222
  deviceId: saved?.deviceId || crypto.randomUUID(),
223
223
  deviceName: saved?.deviceName || os.hostname(),
224
224
  captureIgnoredPaths: saved?.captureIgnoredPaths ?? [],
225
+ ...(auth ? { auth } : {}),
225
226
  };
226
227
  try {
227
228
  (0, utils_1.writeConfig)(config);
@@ -230,15 +231,7 @@ async function runConnect(args = []) {
230
231
  console.error(`\nError: Failed to save config — ${err.message}`);
231
232
  process.exit(1);
232
233
  }
233
- // Once we have a valid token + config, every subsequent step posts a
234
- // per-step row to /api/telemetry/install-event so the admin page can show
235
- // a timeline when a customer says "it connected but it doesn't work."
236
- // Fire-and-forget — never blocks the connect flow.
237
234
  (0, shared_1.recordInstallEvent)(config, { step: "started", ok: true });
238
- // One-way device status sync. Local config remains authoritative: a network
239
- // failure here never removes or weakens an ignored path. This also registers
240
- // a freshly connected device with an empty list so the portal can distinguish
241
- // "connected, no exclusions" from "old CLI has never reported status".
242
235
  try {
243
236
  await postJson(`${BACKEND_URL}/api/cli/capture-exclusions`, {
244
237
  deviceId: config.deviceId,
@@ -249,17 +242,6 @@ async function runConnect(args = []) {
249
242
  catch (err) {
250
243
  console.warn(`Warning: Local capture settings are active, but portal status did not sync — ${err.message}`);
251
244
  }
252
- // Migration: strip MCP server entries written by pre-CLI-only versions
253
- // of `codiedev connect`. These pointed at `npx codiedev-mcp`, a binary
254
- // that was removed in 0.3.4 and that 0.7.11+ no longer ships. Without
255
- // cleanup, customers upgrading from any prior version see persistent
256
- // "MCP server failed to start" errors in their agent UIs even though
257
- // the CLI works fine. Each helper is idempotent and a no-op when the
258
- // relevant config file doesn't exist.
259
- //
260
- // Each call is wrapped because the user's upgrade path matters more
261
- // than the cleanup. A locked / wrong-owner config file (rare but real)
262
- // shouldn't block the install loop or strand them on an old version.
263
245
  for (const [label, fn] of [
264
246
  ["Claude Code", utils_1.cleanupClaudeCodeMcp],
265
247
  ["Codex", utils_1.cleanupCodexMcp],
@@ -278,29 +260,16 @@ async function runConnect(args = []) {
278
260
  const hasCodex = (0, utils_1.codexInstalled)();
279
261
  const hasCursor = (0, utils_1.cursorInstalled)();
280
262
  const hasOpenCode = (0, utils_1.openCodeInstalled)();
263
+ const hasCopilot = (0, utils_1.copilotInstalled)();
264
+ const hasPi = (0, utils_1.piInstalled)();
281
265
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "claude-code", ok: hasClaude });
282
266
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "codex", ok: hasCodex });
283
267
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "cursor", ok: hasCursor });
284
268
  (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "opencode", ok: hasOpenCode });
269
+ (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "copilot", ok: hasCopilot });
270
+ (0, shared_1.recordInstallEvent)(config, { step: "detect", target: "pi", ok: hasPi });
285
271
  const installed = [];
286
- // Machine-readable target keys reported back to the backend via
287
- // /api/cli/markInstalled so the portal's "Connected" state reflects
288
- // what's actually wired up on this machine, not just "token validated."
289
272
  const installedTargets = [];
290
- const home = os.homedir();
291
- const securityConfigPaths = [
292
- path.join(home, ".claude", "settings.json"),
293
- path.join(home, ".codex", "hooks.json"),
294
- path.join(home, ".cursor", "hooks.json"),
295
- path.join(home, ".config", "opencode", "plugins", "codiedev.js"),
296
- path.join(home, ".codex", "config.toml"),
297
- ];
298
- // Snapshot before any hook update. Rollback is intentionally not automatic:
299
- // an administrator can inspect these 0600 copies before restoring them.
300
- const securitySnapshot = (0, securityInstall_1.createSecurityInstallSnapshot)(securityConfigPaths);
301
- // Wrap each per-target write so we emit one install_target row each. The
302
- // existing user-visible behavior (console.warn on failure, continue) is
303
- // unchanged — telemetry just observes the outcome.
304
273
  const runInstall = (target, fn, label, targetKey) => {
305
274
  try {
306
275
  fn();
@@ -320,56 +289,26 @@ async function runConnect(args = []) {
320
289
  }
321
290
  };
322
291
  if (hasClaude) {
323
- runInstall("claude-code-hook", () => (0, utils_1.installHook)(agentSecurityEnabled), "Claude Code SessionEnd (capture) + UserPromptSubmit (skill discovery) + Stop (auto-backup) hooks (~/.claude/settings.json)", "claudeCode-hook");
324
- runInstall("claude-code-instructions", utils_1.installClaudeCodeInstructions, "Claude Code agent instructions (~/.claude/CLAUDE.md)", "claudeCode-instructions");
292
+ runInstall("claude-code-hook", utils_1.installHook, `Claude Code SessionEnd (capture) + UserPromptSubmit (skill discovery) + Stop (auto-backup) hooks (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.claudeConfigDir)(), "settings.json"))})`, "claudeCode-hook");
293
+ runInstall("claude-code-instructions", utils_1.installClaudeCodeInstructions, `Claude Code agent instructions (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.claudeConfigDir)(), "CLAUDE.md"))})`, "claudeCode-instructions");
325
294
  }
326
295
  if (hasCodex) {
327
- runInstall("codex-hook", () => (0, utils_1.installCodexHook)(agentSecurityEnabled), "Codex Stop (capture + auto-backup) hooks (~/.codex/hooks.json)", "codex-hook");
328
- runInstall("codex-instructions", utils_1.installCodexInstructions, "Codex agent instructions (~/.codex/AGENTS.md)", "codex-instructions");
296
+ runInstall("codex-hook", utils_1.installCodexHook, `Codex Stop (capture + auto-backup) hooks (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.codexHome)(), "hooks.json"))})`, "codex-hook");
297
+ runInstall("codex-instructions", utils_1.installCodexInstructions, `Codex agent instructions (${(0, harnessDirs_1.displayPath)(path.join((0, harnessDirs_1.codexHome)(), "AGENTS.md"))})`, "codex-instructions");
329
298
  }
330
299
  if (hasCursor) {
331
- runInstall("cursor-hook", () => (0, utils_1.installCursorHook)(agentSecurityEnabled), "Cursor sessionStart + prompt security + stop backup + sessionEnd capture hooks (~/.cursor/hooks.json)", "cursor-hook");
300
+ runInstall("cursor-hook", utils_1.installCursorHook, "Cursor sessionStart + stop backup + sessionEnd capture hooks (~/.cursor/hooks.json)", "cursor-hook");
332
301
  runInstall("cursor-instructions", utils_1.installCursorInstructions, "Cursor agent instructions (~/.cursor/rules/codiedev.mdc)", "cursor-instructions");
333
302
  }
334
- // Always stage the adapter. It is dormant until OpenCode starts, which lets
335
- // a user connect Claude Code today and install the Codie harness tomorrow
336
- // without needing a second setup ritual.
337
- runInstall("opencode-capture-adapter", () => (0, utils_1.installOpenCodeCapturePlugin)(agentSecurityEnabled), "OpenCode session capture adapter (~/.config/opencode/plugins/codiedev.js)", "opencode-capture");
338
- // Record the exact installed hook bytes and the pre-update rollback files.
339
- // This supplies health/integrity checks without requiring a package publish
340
- // or trusting whichever `node` happens to be first on PATH later.
341
- try {
342
- const hookScriptPath = path.join(__dirname, "hook.js");
343
- if (agentSecurityEnabled && fs.existsSync(hookScriptPath)) {
344
- const targets = [];
345
- if (installedTargets.includes("claudeCode-hook"))
346
- targets.push({ surface: "claude-code", configPath: securityConfigPaths[0] });
347
- if (installedTargets.includes("codex-hook"))
348
- targets.push({ surface: "codex", configPath: securityConfigPaths[1] });
349
- if (installedTargets.includes("cursor-hook"))
350
- targets.push({ surface: "cursor", configPath: securityConfigPaths[2] });
351
- if (installedTargets.includes("opencode-capture"))
352
- targets.push({ surface: "codie-harness", configPath: securityConfigPaths[3] });
353
- (0, securityInstall_1.writeSecurityInstallManifest)({ hookScriptPath, snapshot: securitySnapshot, targets });
354
- }
355
- }
356
- catch (err) {
357
- console.warn(`Warning: Security hooks installed, but integrity manifest could not be written — ${err.message}`);
303
+ if (hasCopilot) {
304
+ runInstall("copilot-hook", utils_1.installCopilotHook, `GitHub Copilot (VS Code + CLI) sessionStart + agentStop backup + sessionEnd capture hooks (${(0, utils_1.copilotHooksPath)()})`, "copilot-hook");
305
+ runInstall("copilot-instructions", utils_1.installCopilotInstructions, "GitHub Copilot CLI team artifact instructions", "copilot-instructions");
358
306
  }
359
- // Prime the local cache after installation. Hooks read this file only, so
360
- // an endpoint decision never depends on live network latency.
361
- if (agentSecurityEnabled) {
362
- try {
363
- await (0, securityPolicy_1.syncEndpointSecurityPolicy)(config);
364
- }
365
- catch (err) {
366
- console.warn(`Warning: Agent-security policy will use safe defaults until sync succeeds — ${err.message}`);
367
- }
307
+ runInstall("pi-extension", utils_1.installPiExtension, `pi session start + skill discovery + capture extension (${(0, harnessDirs_1.displayPath)((0, utils_1.piExtensionPath)())})`, "pi-extension");
308
+ if (hasPi) {
309
+ runInstall("pi-instructions", utils_1.installPiInstructions, `pi agent instructions (${(0, harnessDirs_1.displayPath)((0, utils_1.piInstructionsPath)())})`, "pi-instructions");
368
310
  }
369
- // Tell the backend which targets we wired up so the portal's onboarding
370
- // card flips to "Connected" only when something actually installed —
371
- // not on bare token validation. Best-effort: a network failure here
372
- // doesn't undo the local install, and `codiedev doctor` still works.
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");
373
312
  if (installedTargets.length > 0) {
374
313
  try {
375
314
  await postJson(`${BACKEND_URL}/api/cli/markInstalled`, {
@@ -388,7 +327,7 @@ async function runConnect(args = []) {
388
327
  });
389
328
  }
390
329
  }
391
- if (!hasClaude && !hasCodex && !hasCursor && !hasOpenCode) {
330
+ if (!hasClaude && !hasCodex && !hasCursor && !hasOpenCode && !hasCopilot && !hasPi) {
392
331
  console.warn("\nNo existing AI client detected; the Codie/OpenCode adapter is ready for a later install.");
393
332
  console.warn("If you just installed Claude Code, launch it once (so ~/.claude is created),");
394
333
  console.warn("then re-run `npx codiedev connect` to wire up the capture hook.");
@@ -404,8 +343,6 @@ async function runConnect(args = []) {
404
343
  }
405
344
  console.log();
406
345
  console.log("Run `codiedev doctor` to verify everything's wired up.");
407
- if ((0, securityFeature_1.isAgentSecurityEnabled)(config)) {
408
- console.log("Run `codiedev security pilot` to validate blocking safely.");
409
- }
346
+ console.log("If `codiedev` is not on PATH, run `npx codiedev@latest doctor` instead.");
410
347
  console.log();
411
348
  }
@@ -1,15 +1,7 @@
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;
4
+ exports.signInWithTokenFallback = signInWithTokenFallback;
13
5
  function resolveConnectToken(input) {
14
6
  if (input.force)
15
7
  return { source: "prompt-required" };
@@ -19,3 +11,37 @@ function resolveConnectToken(input) {
19
11
  return { source: "prompt-required" };
20
12
  return { source: "reused", token: input.savedConfig.token };
21
13
  }
14
+ async function signInWithTokenFallback(deps) {
15
+ deps.log("Prefer an API token? Press Ctrl+C and run `codiedev connect --token`.\n");
16
+ try {
17
+ const s = await deps.signIn();
18
+ deps.log("Signed in. No API key is stored on this machine.\n");
19
+ return {
20
+ token: s.accessToken,
21
+ auth: {
22
+ kind: "browser",
23
+ clientId: s.clientId,
24
+ refreshToken: s.refreshToken,
25
+ accessTokenExpiresAt: s.expiresAt,
26
+ },
27
+ };
28
+ }
29
+ catch (err) {
30
+ deps.error(`\nBrowser sign-in didn't finish: ${err.message}`);
31
+ if (!deps.interactive) {
32
+ deps.error("To paste an API token instead, run `codiedev connect --token`.");
33
+ return null;
34
+ }
35
+ if (!(await deps.askYesNo("Paste an API token instead? [y/N] "))) {
36
+ deps.error("Run `codiedev connect` to try again, or `codiedev connect --token` to paste a token.");
37
+ return null;
38
+ }
39
+ deps.log("Create one at https://codiedev.com/portal/integrations/claude-code\n");
40
+ const token = (await deps.askToken("Enter your Codiedev API token: ")).trim();
41
+ if (!token) {
42
+ deps.error("Error: API token is required.");
43
+ return null;
44
+ }
45
+ return { token };
46
+ }
47
+ }