codiedev 0.10.0-beta.10 → 0.10.0-beta.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,5 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  const connect_1 = require("./connect");
5
38
  const cliSession_1 = require("./cliSession");
@@ -110,6 +143,7 @@ Privacy:
110
143
  codiedev ignore <path> Never capture this folder or its children
111
144
  codiedev unignore <path> Stop ignoring a folder
112
145
  codiedev ignored [path] List ignored folders, or check one path
146
+ codiedev scrub [--dry-run] Remove keys from past agent sessions on this machine
113
147
 
114
148
  Capture:
115
149
  codiedev note "<text>" Capture a passing thought
@@ -545,6 +579,11 @@ async function main() {
545
579
  case "read":
546
580
  await (0, inbox_1.runRead)(rest);
547
581
  return;
582
+ case "scrub": {
583
+ const { runScrubCommand } = await Promise.resolve().then(() => __importStar(require("./commands/scrub")));
584
+ process.exitCode = await runScrubCommand(rest);
585
+ return;
586
+ }
548
587
  case "note":
549
588
  await (0, note_1.runNote)(rest);
550
589
  return;
@@ -154,7 +154,7 @@ result to \`/agent/.codiedev/output.json\`.
154
154
  Preinstalled: Python 3.12 with openai, mcp, httpx, pydantic; Node 22 with
155
155
  openai, @modelcontextprotocol/sdk, tsx; git, curl.
156
156
  - **Exit code:** 0 = succeeded. An exception or non-zero exit = failed, with
157
- the last log line as the error. Everything printed goes to the run's log.
157
+ the exception (or the last log line) as the error. Everything printed goes to the run's log.
158
158
 
159
159
  ## The sandbox
160
160
 
@@ -168,12 +168,16 @@ variables:
168
168
  | \`CODIEDEV_GATEWAY_URL\`, \`CODIEDEV_API_KEY\` | The same two, under Codiedev names |
169
169
  | \`CODIEDEV_AGENT\`, \`CODIEDEV_RUN_ID\` | This agent's name and this run's id |
170
170
  | \`CODIEDEV_ATTEMPT\`, \`CODIEDEV_MAX_ATTEMPTS\` | Which try this is, out of how many |
171
+ | \`CODIEDEV_MODEL\` | The agent's default model: the first one its key allows (unset when it allows every model) |
171
172
  | your secrets | Each by its own name, e.g. \`GITHUB_TOKEN\` |
172
173
 
173
174
  **Models:** use a model id from your company's **Models** page, like
174
175
  \`openai/gpt-5.1-codex-mini\`. A model your company hasn't approved fails with
175
176
  \`model_not_allowed\`. Calls are traced under the agent's name and count
176
177
  toward its \`budgetUsd\` (a monthly budget for the agent, not per run).
178
+ A call counts toward a run's cost when it sends the header
179
+ \`X-Codiedev-Run-Id: $CODIEDEV_RUN_ID\`. \`agents.openai()\` does; for any other
180
+ client or tool, add the header yourself (see opencode below).
177
181
 
178
182
  **Dependencies** from \`package.json\` install into \`/agent/node_modules\`, so
179
183
  their binaries are in \`/agent/node_modules/.bin\`. Python packages are importable
@@ -193,7 +197,9 @@ config = {
193
197
  "autoupdate": False, "share": "disabled", "permission": "allow",
194
198
  "provider": {"codiedev": {
195
199
  "npm": "@ai-sdk/openai-compatible",
196
- "options": {"baseURL": os.environ["OPENAI_BASE_URL"], "apiKey": "{env:OPENAI_API_KEY}"},
200
+ "options": {"baseURL": os.environ["OPENAI_BASE_URL"], "apiKey": "{env:OPENAI_API_KEY}",
201
+ # Counts its model calls toward this run's cost.
202
+ "headers": {"X-Codiedev-Run-Id": os.environ["CODIEDEV_RUN_ID"]}},
197
203
  "models": {MODEL: {}},
198
204
  }},
199
205
  }
@@ -455,13 +461,21 @@ function writeGuides(dir) {
455
461
  if (!fs.existsSync(path.join(dir, "CLAUDE.md")))
456
462
  fs.writeFileSync(path.join(dir, "CLAUDE.md"), "@AGENTS.md\n");
457
463
  }
464
+ function fillTemplate(text, file, name, model) {
465
+ let out = text.replace(/%NAME%/g, name);
466
+ if (!model) {
467
+ const fallback = file.endsWith(".py") ? 'os.environ.get("CODIEDEV_MODEL", "codiedev/fast")' : '(process.env.CODIEDEV_MODEL ?? "codiedev/fast")';
468
+ out = out.replace(/"%MODEL%"/g, fallback);
469
+ }
470
+ return out.replace(/%MODEL%/g, model ?? "codiedev/fast");
471
+ }
458
472
  async function initFromTemplate(name, dir, id, args) {
459
- const model = flag(args, "--model") ?? "codiedev/fast";
473
+ const model = flag(args, "--model");
460
474
  const starter = agentTemplates_generated_1.TEMPLATES.find((t) => t.id === id);
461
475
  if (starter) {
462
476
  for (const [rel, text] of Object.entries(starter.files)) {
463
477
  fs.mkdirSync(path.dirname(path.join(dir, rel)), { recursive: true });
464
- fs.writeFileSync(path.join(dir, rel), text.replace(/%NAME%/g, name).replace(/%MODEL%/g, model));
478
+ fs.writeFileSync(path.join(dir, rel), fillTemplate(text, rel, name, model));
465
479
  }
466
480
  writeGuides(dir);
467
481
  console.log(`Created ${path.relative(process.cwd(), dir) || "."}/ from the ${starter.title} template.`);
@@ -502,16 +516,15 @@ async function cmdInit(args) {
502
516
  if (existing)
503
517
  fail(`${dir} already has an ${existing}`);
504
518
  fs.mkdirSync(dir, { recursive: true });
505
- const model = flag(args, "--model") ?? "codiedev/fast";
506
- const fill = (t) => t.replace(/%NAME%/g, name).replace(/%MODEL%/g, model);
519
+ const model = flag(args, "--model");
507
520
  let entrypoint = "agent.py";
508
521
  if (lang.startsWith("py")) {
509
- fs.writeFileSync(path.join(dir, "agent.py"), fill(STARTER_AGENT));
522
+ fs.writeFileSync(path.join(dir, "agent.py"), fillTemplate(STARTER_AGENT, "agent.py", name, model));
510
523
  fs.writeFileSync(path.join(dir, "requirements.txt"), "# Extra packages for this agent, one per line. openai, mcp, httpx and pydantic are preinstalled.\n");
511
524
  }
512
525
  else {
513
526
  entrypoint = lang.startsWith("t") ? "agent.ts" : "agent.mjs";
514
- fs.writeFileSync(path.join(dir, entrypoint), fill(STARTER_TS));
527
+ fs.writeFileSync(path.join(dir, entrypoint), fillTemplate(STARTER_TS, entrypoint, name, model));
515
528
  fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ name, private: true, type: "module", dependencies: {} }, null, 2) + "\n");
516
529
  }
517
530
  fs.writeFileSync(path.join(dir, "agent.json"), JSON.stringify({ name, entrypoint, timeoutSec: 600 }, null, 2) + "\n");
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SCRUB_HELP = void 0;
4
+ exports.parseScrubArgs = parseScrubArgs;
5
+ exports.formatScrubSummary = formatScrubSummary;
6
+ exports.runScrubCommand = runScrubCommand;
7
+ const localScrub_1 = require("../localScrub");
8
+ exports.SCRUB_HELP = `codiedev scrub — remove keys from past agent sessions on this machine
9
+
10
+ Usage:
11
+ codiedev scrub [--dry-run] [--path <file>]... [--session <id>]... [--min-age <minutes>]
12
+
13
+ Cleans the session files Claude Code, Codex, Cursor, Copilot, OpenCode/Codie
14
+ and pi keep locally, using the same rules as the Codiedev server. Each key is
15
+ replaced with [REDACTED:<kind>]. Sessions changed in the last hour are skipped
16
+ so open sessions are never touched. When signed in, what was found (session,
17
+ key type and last 4, removed or not) shows on your Security page; the keys
18
+ themselves never leave this machine.
19
+
20
+ --dry-run Count what would be cleaned; change nothing
21
+ --path <file> Only this file (repeatable)
22
+ --session <id> With --path <opencode.db>: only this OpenCode/Codie session
23
+ --min-age <min> Skip files changed in the last <min> minutes (default 60)
24
+ `;
25
+ function parseScrubArgs(args) {
26
+ let dryRun = false;
27
+ let help = false;
28
+ const only = [];
29
+ const sessions = [];
30
+ let minAgeMs = localScrub_1.MIN_AGE_MS;
31
+ for (let i = 0; i < args.length; i++) {
32
+ const a = args[i];
33
+ if (a === "--dry-run")
34
+ dryRun = true;
35
+ else if (a === "--help" || a === "-h")
36
+ help = true;
37
+ else if (a === "--path" && args[i + 1])
38
+ only.push(args[++i]);
39
+ else if (a === "--session" && args[i + 1])
40
+ sessions.push(args[++i]);
41
+ else if (a === "--min-age" && args[i + 1]) {
42
+ const m = Number(args[++i]);
43
+ if (Number.isFinite(m) && m >= 0)
44
+ minAgeMs = m * 60_000;
45
+ }
46
+ }
47
+ return { dryRun, help, minAgeMs, ...(only.length ? { only } : {}), ...(sessions.length ? { onlySessions: sessions } : {}) };
48
+ }
49
+ function formatScrubSummary(s) {
50
+ const lines = [];
51
+ const verb = s.dryRun ? "Would remove" : "Removed";
52
+ lines.push(s.redactions === 0
53
+ ? `No keys found in ${s.scanned} session file${s.scanned === 1 ? "" : "s"} checked.`
54
+ : `${verb} ${s.redactions} key${s.redactions === 1 ? "" : "s"}${s.dryRun ? "" : ` from ${s.cleaned} file${s.cleaned === 1 ? "" : "s"}`} (${s.scanned} checked).`);
55
+ for (const [h, t] of Object.entries(s.byHarness))
56
+ lines.push(` ${h}: ${t.redactions} in ${t.files} file${t.files === 1 ? "" : "s"}`);
57
+ if (s.skippedRecent)
58
+ lines.push(`Skipped ${s.skippedRecent} changed in the last hour (may be open).`);
59
+ if (s.skippedLarge)
60
+ lines.push(`Skipped ${s.skippedLarge} over 100 MB.`);
61
+ if (s.changedWhileCleaning)
62
+ lines.push(`Left ${s.changedWhileCleaning} alone: changed while cleaning.`);
63
+ if (s.errors)
64
+ lines.push(`${s.errors} couldn't be read or written.`);
65
+ if (s.unfinished)
66
+ lines.push("Stopped at the time limit; the next run continues.");
67
+ if (s.leftInCursor.keys > 0) {
68
+ const { keys, chats } = s.leftInCursor;
69
+ lines.push(`${keys} key${keys === 1 ? " is" : "s are"} still in ${chats} Cursor chat${chats === 1 ? "" : "s"}. ` +
70
+ "Cursor's own chat store can't be cleaned without breaking the chat; delete those chats in Cursor to remove them.");
71
+ }
72
+ return lines.join("\n");
73
+ }
74
+ async function runScrubCommand(args) {
75
+ const opts = parseScrubArgs(args);
76
+ if (opts.help) {
77
+ console.log(exports.SCRUB_HELP);
78
+ return 0;
79
+ }
80
+ const summary = await (0, localScrub_1.runAndReport)({
81
+ dryRun: opts.dryRun,
82
+ only: opts.only,
83
+ onlySessions: opts.onlySessions,
84
+ minAgeMs: opts.minAgeMs,
85
+ budgetMs: 10 * 60_000,
86
+ });
87
+ console.log(formatScrubSummary(summary));
88
+ if (summary.reported)
89
+ console.log("Sent to your Security page in Codiedev (key type and last 4 only, never the key).");
90
+ return summary.errors > 0 ? 1 : 0;
91
+ }
package/dist/hook.js CHANGED
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.buildDiscoveryContext = buildDiscoveryContext;
38
+ const localScrub_1 = require("./localScrub");
38
39
  const captureSignals_1 = require("./captureSignals");
39
40
  const transcriptModels_1 = require("./transcriptModels");
40
41
  const fs = __importStar(require("fs"));
@@ -442,6 +443,15 @@ async function main() {
442
443
  }
443
444
  process.exit(0);
444
445
  }
446
+ if (process.argv[2] === "local-scrub") {
447
+ try {
448
+ const { runAndReport } = await Promise.resolve().then(() => __importStar(require("./localScrub")));
449
+ await runAndReport();
450
+ }
451
+ catch {
452
+ }
453
+ process.exit(0);
454
+ }
445
455
  if (process.argv[2] === "self-update") {
446
456
  await (0, selfUpdate_1.runSelfUpdate)(process.argv[1]);
447
457
  process.exit(0);
@@ -489,6 +499,8 @@ async function main() {
489
499
  await runCodexLimitSweep(hookInput.session_id);
490
500
  if (source === "codex")
491
501
  (0, sync_1.maybeSpawnPackSync)({ connected: Boolean((0, utils_1.readConfig)()), cli: path.join(__dirname, "cli.js") });
502
+ if (source === "codex")
503
+ (0, localScrub_1.maybeSpawnLocalScrub)({ connected: Boolean((0, utils_1.readConfig)()) });
492
504
  if (source !== "copilot")
493
505
  await runDiscover(hookInput.prompt);
494
506
  return;
@@ -530,6 +542,7 @@ async function main() {
530
542
  process.argv[2] === "session-start-opencode" ||
531
543
  process.argv[2] === "session-start-pi") {
532
544
  (0, sync_1.maybeSpawnPackSync)({ connected: Boolean((0, utils_1.readConfig)()), cli: path.join(__dirname, "cli.js") });
545
+ (0, localScrub_1.maybeSpawnLocalScrub)({ connected: Boolean((0, utils_1.readConfig)()) });
533
546
  const packNag = process.argv[2] === "session-start-opencode" || process.argv[2] === "session-start-pi" ? null : (0, sync_1.packNagLine)();
534
547
  if (packNag && process.argv[2] === "session-start")
535
548
  process.stdout.write(`${packNag}\n`);