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
@@ -0,0 +1,1101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AGENT_GUIDE = exports.AGENTS_HELP = void 0;
37
+ exports.parseEvery = parseEvery;
38
+ exports.parseDuration = parseDuration;
39
+ exports.runAgents = runAgents;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const child_process_1 = require("child_process");
43
+ const shared_1 = require("./shared");
44
+ const sdk = __importStar(require("./agentsSdk.generated"));
45
+ const agentTemplates_generated_1 = require("./agentTemplates.generated");
46
+ exports.AGENTS_HELP = `
47
+ codiedev agents — deploy agents and run them in fresh sandboxes
48
+
49
+ codiedev agents init <name> [dir] [--lang python|ts|js] [--template <id>]
50
+ Scaffold an agent folder (entrypoint, agent.json, AGENTS.md),
51
+ blank or from a starter / your team's template
52
+ codiedev agents templates [--json] Starter templates and the ones your team and company shared
53
+ codiedev agents publish <agent> [--company] [--summary "…"] [--title "…"] [--as <slug>]
54
+ Share an agent as a template (your team, or --company)
55
+ codiedev agents install <template> <name>
56
+ Deploy a copy of a shared template as your own agent
57
+ codiedev agents unpublish <template> Take a template you shared off the marketplace
58
+ codiedev agents connect <name> [--description "…"] [--budget <usd>]
59
+ An agent you already run on your own servers: get its key.
60
+ Its model calls (via the gateway) show in Traces with spend,
61
+ budget and a kill switch; the key also reaches approvals and state
62
+ codiedev agents deploy [dir] Package the folder and deploy it (new version each time)
63
+ codiedev agents run <name> [--input '<json>' | --input-file f] [--no-wait] [--json] [--quiet]
64
+ [--idempotency-key k] [--delay 30m] [--retries n]
65
+ Start a run; streams its log, then prints the output
66
+ codiedev agents run --local [dir] [--input …] [--env-file .env] [--remote-state]
67
+ Run the agent on this machine with the same SDK, no deploy
68
+ codiedev agents runs [name] [--failed] [--limit n] [--json]
69
+ Recent runs, newest first
70
+ codiedev agents show <run-id> [--json] One run: input, output, error, log, cost, child runs
71
+ codiedev agents logs <run-id> [-f] A run's log; -f follows it until the run ends
72
+ codiedev agents cancel <run-id> Stop a run and its sandbox
73
+ codiedev agents list [--json] Your company's agents, schedules and last runs
74
+ codiedev agents secrets <name> [set KEY=value | unset KEY] [--mine]
75
+ Environment variables the agent gets on every run
76
+ codiedev agents webhook <name> [--off] A URL that starts a run with the request body as input
77
+ codiedev agents stop <name> | --all [--reason "…"] Kill switch: cancel its runs, cut model access, block every start
78
+ codiedev agents resume <name> | --all Let it run again (owner or admin; --all is admins)
79
+ codiedev agents pull <name> [dir] [--version n]
80
+ Download a deployed agent's folder to change and redeploy
81
+ codiedev agents versions <name> Its last 10 deploys
82
+ codiedev agents rollback <name> [--to n]
83
+ Ship an earlier version again (the previous one by default)
84
+ codiedev agents state <name> [list [prefix] | get <key> | set <key> '<json>' | delete <key>]
85
+ The agent's stored state (owner and admins)
86
+ codiedev agents approvals [--all] [--json]
87
+ Decisions agents are waiting on
88
+ codiedev agents decide <approval-id> <option> [--comment "…"]
89
+ Decide one; the agent's run starts with the decision
90
+ codiedev agents delete <name> Remove an agent (its run history stays)
91
+
92
+ agent.json: { "name": "ticket-triage", "entrypoint": "agent.py", "timeoutSec": 600,
93
+ "every": "15m", "retries": 2, "cpu": 1, "memoryMb": 2048, "budgetUsd": 25 }
94
+ .codiedevignore lists extra files to leave out of the bundle (.env*, .git,
95
+ node_modules and virtualenvs are always left out).
96
+ entrypoint: a .py, .js, .mjs, .ts or .sh file. "every" (5m–7d) runs it on a
97
+ schedule; set null for none. retries (0–5) tries a failed run again on the
98
+ same run id, after 15s, 30s, 60s… cpu 0.25–8 cores, memoryMb 512–32768.
99
+ Leave a setting out to keep what it is now (it can be changed on the agent's
100
+ Setup tab in the portal); a new agent gets the defaults.
101
+ `.trim();
102
+ exports.AGENT_GUIDE = `# Building a Codiedev agent
103
+
104
+ This folder is one agent. Each time it's started, Codiedev runs it once in a
105
+ fresh sandbox, then destroys the sandbox. Model access, tracing and secrets
106
+ are already wired in. You write the entrypoint (\`agent.py\`, \`agent.ts\`,
107
+ \`agent.mjs\` or a \`.sh\` script, named in agent.json).
108
+
109
+ ## The primitive
110
+
111
+ Python:
112
+
113
+ \`\`\`python
114
+ import codiedev_agents as agents
115
+
116
+ task = agents.input() # this run's input (any JSON), or None
117
+ llm = agents.openai() # OpenAI SDK client on the Codiedev gateway, traced
118
+ reply = llm.chat.completions.create(model=MODEL, messages=[...])
119
+ agents.output({"answer": "..."}) # this run's result (any JSON)
120
+ \`\`\`
121
+
122
+ TypeScript / JavaScript (\`codiedev-agents\` and \`openai\` are preinstalled):
123
+
124
+ \`\`\`ts
125
+ import * as agents from "codiedev-agents";
126
+
127
+ const task = agents.input();
128
+ const llm = await agents.openai();
129
+ const reply = await llm.chat.completions.create({ model: MODEL, messages: [...] });
130
+ agents.output({ answer: reply.choices[0].message.content });
131
+ \`\`\`
132
+
133
+ From a shell script: the input is \`/agent/.codiedev/input.json\`; write the
134
+ result to \`/agent/.codiedev/output.json\`.
135
+
136
+ - **Chain agents:** \`agents.run("other-agent", {...})\` starts another deployed
137
+ agent as a child run, waits, and returns it; its result is \`["output"]\`
138
+ (\`.output\` in JS). Use \`agents.start(...)\` + \`agents.get(id)\` to fan out in
139
+ parallel. Children show under their parent in Codiedev.
140
+ - **Tools / MCP:** call APIs directly (\`httpx\`, \`fetch\`), or start any MCP
141
+ server over stdio: Python \`mcp\` and Node \`@modelcontextprotocol/sdk\` are
142
+ installed, and \`npx -y <server>\` works. For a remote MCP server, put its
143
+ URL and token in secrets.
144
+ - **Personal secrets:** \`"personalSecrets": ["SALESFORCE_TOKEN"]\` in agent.json
145
+ means each person sets their own (\`secrets <name> set KEY=… --mine\`), and a
146
+ run someone starts uses theirs, never yours. Schedules and webhooks use the
147
+ shared value. Teammates "Use" your agent instead of copying it, so they get
148
+ your updates.
149
+ - **Secrets:** \`codiedev agents secrets <name> set ZENDESK_TOKEN=…\`; read them
150
+ from the environment (\`os.environ["ZENDESK_TOKEN"]\`, \`process.env.ZENDESK_TOKEN\`).
151
+ Never put tokens in code.
152
+ - **Dependencies:** \`requirements.txt\` and/or \`package.json\` (+ lock file). They
153
+ install once into a cached image when they change, not on every run.
154
+ Preinstalled: Python 3.12 with openai, mcp, httpx, pydantic; Node 22 with
155
+ openai, @modelcontextprotocol/sdk, tsx; git, curl.
156
+ - **Exit code:** 0 = succeeded. An exception or non-zero exit = failed, with
157
+ the exception (or the last log line) as the error. Everything printed goes to the run's log.
158
+
159
+ ## The sandbox
160
+
161
+ Linux x64 (Debian, glibc) with internet access. Your code is in \`/agent\` (the
162
+ working directory); \`/tmp\` is writable. Every run gets these environment
163
+ variables:
164
+
165
+ | Variable | What it is |
166
+ |---|---|
167
+ | \`OPENAI_BASE_URL\`, \`OPENAI_API_KEY\` | The Codiedev model gateway and this agent's key. Any OpenAI-compatible tool picks them up as is. |
168
+ | \`CODIEDEV_GATEWAY_URL\`, \`CODIEDEV_API_KEY\` | The same two, under Codiedev names |
169
+ | \`CODIEDEV_AGENT\`, \`CODIEDEV_RUN_ID\` | This agent's name and this run's id |
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) |
172
+ | your secrets | Each by its own name, e.g. \`GITHUB_TOKEN\` |
173
+
174
+ **Models:** use a model id from your company's **Models** page, like
175
+ \`openai/gpt-5.1-codex-mini\`. A model your company hasn't approved fails with
176
+ \`model_not_allowed\`. Calls are traced under the agent's name and count
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).
181
+
182
+ **Dependencies** from \`package.json\` install into \`/agent/node_modules\`, so
183
+ their binaries are in \`/agent/node_modules/.bin\`. Python packages are importable
184
+ as usual. A Python agent can have a \`package.json\` too (both install).
185
+
186
+ ## Outside tools (opencode, aider, Codex CLI…)
187
+
188
+ Any tool that speaks the OpenAI API works: point it at \`OPENAI_BASE_URL\` with
189
+ \`OPENAI_API_KEY\`. For example, opencode as a coding agent inside a run
190
+ (\`"opencode-ai"\` in package.json, \`"timeoutSec": 3600\` and \`"cpu": 2,
191
+ "memoryMb": 4096\` in agent.json):
192
+
193
+ \`\`\`python
194
+ import json, os, subprocess
195
+ config = {
196
+ "$schema": "https://opencode.ai/config.json",
197
+ "autoupdate": False, "share": "disabled", "permission": "allow",
198
+ "provider": {"codiedev": {
199
+ "npm": "@ai-sdk/openai-compatible",
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"]}},
203
+ "models": {MODEL: {}},
204
+ }},
205
+ }
206
+ json.dump(config, open(f"{repo_dir}/opencode.json", "w"))
207
+ subprocess.run(["/agent/node_modules/.bin/opencode", "run", "--model", f"codiedev/{MODEL}", prompt],
208
+ cwd=repo_dir, check=True, timeout=45 * 60)
209
+ \`\`\`
210
+
211
+ Keep the tool's own time limit under the run's, so the agent can still write
212
+ its output. Git is installed; clone with a token from secrets
213
+ (\`https://x-access-token:$GITHUB_TOKEN@github.com/owner/repo.git\`).
214
+
215
+ ## Building blocks
216
+
217
+ All in the SDK (Python names shown; JS uses camelCase and returns promises).
218
+
219
+ - **State that outlives runs:** \`agents.state.get(key, default)\`,
220
+ \`.set(key, value, ttl=None)\`, \`.delete(key)\`, \`.list(prefix)\`. Values are any
221
+ JSON up to 64 KB, 1,000 keys per agent, shared by all its runs. For a
222
+ counter or a cursor that parallel runs touch, use
223
+ \`agents.state.update(key, lambda old: ...)\`, or \`get_versioned\` +
224
+ \`set(..., if_version=n)\`, which raises \`StateConflict\` instead of overwriting.
225
+ - **Retries:** \`"retries": 2\` in agent.json (or \`--retries\` / \`retries=\` per run)
226
+ tries a failed run again on the same run id after 15s, 30s, 60s… Callers
227
+ waiting on it keep waiting. \`agents.attempt()\` says which try this is.
228
+ - **Steps (durable across retries):** wrap side effects in
229
+ \`agents.step("post-reply", lambda: post_reply())\`. A finished step returns
230
+ its saved result on a retry instead of running again, so a retry never
231
+ posts twice. A multi-step job is a list of steps.
232
+ - **Answering a webhook:** a caller that POSTs to \`<webhook url>?wait=30\`
233
+ gets the run's result as the HTTP response (Slack slash commands, form
234
+ handlers). \`agents.respond(body, status=200, headers=None)\` sets exactly
235
+ what it gets; otherwise it's the output. Runs take seconds to start, so
236
+ for senders with a 3s limit, acknowledge and post back instead.
237
+ - **Later:** \`agents.start("name", input, delay=3600)\` starts a run in an hour
238
+ (up to 7 days). An agent can schedule its own next check this way.
239
+ - **Human approval:** \`agents.request_approval("Refund $120 to Acme?",
240
+ details=..., context={...})\` puts a decision in Codiedev (Agents →
241
+ Approvals, or \`codiedev agents decide\`) and returns a \`url\` to post anywhere.
242
+ End the run there; when someone decides, a new run of this agent starts
243
+ with input \`{"approval": {"decision", "comment", "decidedBy"}, "context": ...}\`.
244
+ Check \`agents.input().get("approval")\` at the top to tell the two apart.
245
+ Unanswered by \`expires_in\` (default 7 days): decision \`"expired"\`.
246
+ \`options=[...]\` for other choices; \`approvers=[emails]\` to limit who decides.
247
+
248
+ ## Ship, watch, iterate
249
+
250
+ \`\`\`bash
251
+ codiedev agents run --local --input '{"ticket": 42}' # run it here first, no deploy
252
+ codiedev agents deploy # from this folder
253
+ codiedev agents run <name> --input '{"ticket": 42}' # streams the log, prints output
254
+ codiedev agents runs <name> --failed # what broke
255
+ codiedev agents show <run-id> --json # input, output, log, cost, children
256
+ codiedev agents logs <run-id> -f # follow a run that's still going
257
+ \`\`\`
258
+
259
+ To fix a failing agent: \`codiedev agents runs <name> --failed\`, read the run
260
+ with \`show --json\`, change the code, try it with \`run --local\` and the same
261
+ input, \`deploy\`, then rerun it with \`codiedev agents run <name> --input-file <file>\`.
262
+ A deploy that made things worse: \`codiedev agents rollback <name>\` (the last
263
+ 10 versions are kept; \`codiedev agents versions <name>\` lists them).
264
+
265
+ \`run --local\` runs the entrypoint on your machine with the same SDK: secrets
266
+ from \`.env\` (never bundled), state in \`.codiedev/local/state.json\`
267
+ (\`--remote-state\` uses the deployed agent's), model calls on your own CLI
268
+ token. Python agents need \`openai\` installed locally; TS runs through \`npx tsx\`. \`show\` also prints the run's
269
+ Traces id, so \`codiedev traces\` (test cases, evals) works on it.
270
+
271
+ ## Starting runs
272
+
273
+ - **Schedule:** set \`"every": "15m"\` in agent.json and redeploy. A scheduled run
274
+ is skipped while the previous one is still going.
275
+ - **Webhook:** \`codiedev agents webhook <name>\` returns a URL. A POST to it
276
+ starts a run with the body as input (JSON parsed, anything else as a
277
+ string). \`agents.request()\` gives the exact request (method, query,
278
+ headers, raw body) so the agent can verify the sender's signature (Slack
279
+ \`X-Slack-Signature\`, GitHub \`X-Hub-Signature-256\`); keep the signing
280
+ secret in secrets. Slack's URL check is answered for you.
281
+ - **From other code:** POST \`/api/agents/v1/run\` with \`{"agent", "input"}\` and
282
+ your CLI token, or \`codiedev_agents.run()\` with \`CODIEDEV_TOKEN\` and
283
+ \`CODIEDEV_AGENTS_URL\` set.
284
+ - **No duplicates:** send \`Idempotency-Key\` (header, or \`idempotencyKey\` in the
285
+ body, or \`--idempotency-key\`). A repeat within a day returns the first run.
286
+
287
+ ## Sharing it
288
+
289
+ \`codiedev agents publish <name> --summary "…"\` shares it as a template with
290
+ your team (\`--company\` for everyone), like a skill. Teammates find it under
291
+ Agents → Marketplace or \`codiedev agents templates\`; they can run yours as
292
+ is, or install their own copy (\`codiedev agents install <template> <name>\`)
293
+ with their own secrets. Publish again to update it. Write a README.md in the
294
+ folder: it's what people read before installing.
295
+
296
+ ## Who can do what
297
+
298
+ Anyone in the company can run, pull and watch any agent. Redeploying,
299
+ deleting, rolling back, secrets, webhooks and reading its state from outside
300
+ a run are for the agent's owner (who first deployed it) and company admins,
301
+ since whoever can redeploy an agent can read its secrets. Anyone can decide
302
+ an approval unless it names approvers.
303
+
304
+ ## Cost and limits
305
+
306
+ Each run shows its sandbox time and cost (passed through at the provider's
307
+ rate, about $0.19 an hour at 1 core / 2 GB) and its model spend. The agent's
308
+ gateway key has a monthly budget (\`budgetUsd\` in agent.json, $25 by default).
309
+
310
+ Input 64 KB, output 256 KB, bundle 10 MB, runs up to 1 hour, chains up to 5
311
+ deep, 25 runs at once per company, retries up to 5, delays up to 7 days,
312
+ state 1,000 keys × 64 KB per agent.
313
+ `;
314
+ const STARTER_AGENT = `"""%NAME% — a Codiedev agent. See AGENTS.md for the primitive."""
315
+
316
+ import json
317
+ import os
318
+
319
+ import codiedev_agents as agents
320
+
321
+ MODEL = os.environ.get("MODEL", "%MODEL%")
322
+
323
+
324
+ def main() -> None:
325
+ task = agents.input() or {"question": "Say hello and tell me what you can do."}
326
+ llm = agents.openai()
327
+ reply = llm.chat.completions.create(
328
+ model=MODEL,
329
+ messages=[
330
+ {"role": "system", "content": "You are a concise, helpful assistant."},
331
+ {"role": "user", "content": json.dumps(task)},
332
+ ],
333
+ )
334
+ answer = reply.choices[0].message.content
335
+ print(answer)
336
+ agents.output({"answer": answer})
337
+
338
+
339
+ if __name__ == "__main__":
340
+ main()
341
+ `;
342
+ const STARTER_TS = `// %NAME% — a Codiedev agent. See AGENTS.md for the primitive.
343
+ import * as agents from "codiedev-agents";
344
+
345
+ const MODEL = process.env.MODEL ?? "%MODEL%";
346
+
347
+ const task = agents.input({ question: "Say hello and tell me what you can do." });
348
+ const llm = await agents.openai();
349
+ const reply = await llm.chat.completions.create({
350
+ model: MODEL,
351
+ messages: [
352
+ { role: "system", content: "You are a concise, helpful assistant." },
353
+ { role: "user", content: JSON.stringify(task) },
354
+ ],
355
+ });
356
+ const answer = reply.choices[0].message.content;
357
+ console.log(answer);
358
+ agents.output({ answer });
359
+ `;
360
+ const ENTRYPOINTS = ["agent.py", "agent.ts", "agent.mjs", "agent.js", "agent.sh"];
361
+ const BOOLEAN_FLAGS = ["--mine", "--json", "--no-wait", "--failed", "--off", "--quiet", "--follow", "--force", "--local", "--remote-state", "--all"];
362
+ function flag(args, name) {
363
+ const i = args.indexOf(name);
364
+ return i >= 0 ? args[i + 1] : undefined;
365
+ }
366
+ function positional(args) {
367
+ const out = [];
368
+ for (let i = 0; i < args.length; i++) {
369
+ if (args[i] === "-f")
370
+ continue;
371
+ if (args[i].startsWith("--")) {
372
+ if (!BOOLEAN_FLAGS.includes(args[i]))
373
+ i++;
374
+ continue;
375
+ }
376
+ out.push(args[i]);
377
+ }
378
+ return out;
379
+ }
380
+ function parseEvery(value) {
381
+ if (value === undefined)
382
+ return undefined;
383
+ if (value === null || value === "" || value === "off")
384
+ return null;
385
+ const m = /^(\d+)\s*(m|min|h|d)$/.exec(String(value).trim());
386
+ if (!m)
387
+ throw new Error(`"every" looks like 15m, 2h or 1d (got ${value})`);
388
+ const n = Number(m[1]);
389
+ return m[2] === "d" ? n * 1440 : m[2] === "h" ? n * 60 : n;
390
+ }
391
+ function fail(message) {
392
+ console.error(message);
393
+ process.exit(1);
394
+ }
395
+ function readAgentJson(dir) {
396
+ const file = path.join(dir, "agent.json");
397
+ if (!fs.existsSync(file))
398
+ return {};
399
+ try {
400
+ return JSON.parse(fs.readFileSync(file, "utf8"));
401
+ }
402
+ catch (err) {
403
+ return fail(`agent.json isn't valid JSON: ${err.message}`);
404
+ }
405
+ }
406
+ const EXCLUDES = [".git", "node_modules", ".venv", "venv", "__pycache__", ".codiedev", ".env", ".env.*", "*.pyc", ".DS_Store"];
407
+ function ignorePatterns(dir) {
408
+ const file = path.join(dir, ".codiedevignore");
409
+ if (!fs.existsSync(file))
410
+ return [];
411
+ return fs.readFileSync(file, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
412
+ }
413
+ function bundle(dir) {
414
+ const mac = process.platform === "darwin" ? ["--no-mac-metadata", "--no-xattrs"] : [];
415
+ const excludes = [...EXCLUDES, ...ignorePatterns(dir)];
416
+ const args = ["-czf", "-", ...mac, ...excludes.map((e) => `--exclude=${e}`), "-C", dir, "."];
417
+ return (0, child_process_1.execFileSync)("tar", args, { maxBuffer: 64 * 1024 * 1024, env: { ...process.env, COPYFILE_DISABLE: "1" } });
418
+ }
419
+ function ago(at) {
420
+ if (!at)
421
+ return "—";
422
+ const s = Math.round((Date.now() - at) / 1000);
423
+ if (s < 60)
424
+ return `${s}s ago`;
425
+ if (s < 3600)
426
+ return `${Math.round(s / 60)}m ago`;
427
+ if (s < 86400)
428
+ return `${Math.round(s / 3600)}h ago`;
429
+ return `${Math.round(s / 86400)}d ago`;
430
+ }
431
+ const secs = (ms) => (ms == null ? "—" : `${(ms / 1000).toFixed(1)}s`);
432
+ const DONE = ["succeeded", "failed", "cancelled"];
433
+ const usd = (n) => (n == null ? "—" : n < 0.01 ? `$${n.toFixed(4)}` : `$${n.toFixed(2)}`);
434
+ function makeLogPrinter(write) {
435
+ let printed = 0;
436
+ return (run) => {
437
+ const tail = run.logTail ?? "";
438
+ const total = run.logChars ?? tail.length;
439
+ if (total <= printed)
440
+ return;
441
+ const fresh = total - printed;
442
+ if (fresh > tail.length)
443
+ write(`… ${fresh - tail.length} characters not shown …\n`);
444
+ write(tail.slice(Math.max(0, tail.length - fresh)));
445
+ printed = total;
446
+ };
447
+ }
448
+ function pretty(text) {
449
+ if (text == null)
450
+ return "(none)";
451
+ try {
452
+ return JSON.stringify(JSON.parse(text), null, 2);
453
+ }
454
+ catch {
455
+ return text;
456
+ }
457
+ }
458
+ function writeGuides(dir) {
459
+ if (!fs.existsSync(path.join(dir, "AGENTS.md")))
460
+ fs.writeFileSync(path.join(dir, "AGENTS.md"), exports.AGENT_GUIDE);
461
+ if (!fs.existsSync(path.join(dir, "CLAUDE.md")))
462
+ fs.writeFileSync(path.join(dir, "CLAUDE.md"), "@AGENTS.md\n");
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
+ }
472
+ async function initFromTemplate(name, dir, id, args) {
473
+ const model = flag(args, "--model");
474
+ const starter = agentTemplates_generated_1.TEMPLATES.find((t) => t.id === id);
475
+ if (starter) {
476
+ for (const [rel, text] of Object.entries(starter.files)) {
477
+ fs.mkdirSync(path.dirname(path.join(dir, rel)), { recursive: true });
478
+ fs.writeFileSync(path.join(dir, rel), fillTemplate(text, rel, name, model));
479
+ }
480
+ writeGuides(dir);
481
+ console.log(`Created ${path.relative(process.cwd(), dir) || "."}/ from the ${starter.title} template.`);
482
+ console.log(`Read its README.md, then try it: cd ${path.relative(process.cwd(), dir) || "."} && codiedev agents run --local`);
483
+ return;
484
+ }
485
+ const config = (0, shared_1.requireConfig)();
486
+ const res = await fetch(new URL(`/api/agents/v1/templates/bundle?slug=${encodeURIComponent(id)}`, config.backendUrl), { headers: { Authorization: `Bearer ${config.token}` } });
487
+ if (!res.ok) {
488
+ const body = (await res.json().catch(() => ({})));
489
+ fail(`${body.error ?? `HTTP ${res.status}`}. Starter templates: ${agentTemplates_generated_1.TEMPLATES.map((t) => t.id).join(", ")} (codiedev agents templates)`);
490
+ }
491
+ const meta = JSON.parse(res.headers.get("x-codiedev-template") ?? "{}");
492
+ (0, child_process_1.execFileSync)("tar", ["-xzf", "-", "-C", dir], { input: Buffer.from(await res.arrayBuffer()) });
493
+ const agentJson = readAgentJson(dir);
494
+ fs.writeFileSync(path.join(dir, "agent.json"), JSON.stringify({ ...agentJson, name }, null, 2) + "\n");
495
+ writeGuides(dir);
496
+ console.log(`Created ${path.relative(process.cwd(), dir) || "."}/ from the ${id} template.`);
497
+ if (meta.secretNames?.length)
498
+ console.log(`It uses secrets: ${meta.secretNames.join(", ")}. Set them after deploying: codiedev agents secrets ${name} set NAME=value`);
499
+ }
500
+ async function cmdInit(args) {
501
+ const [name, dirArg] = positional(args);
502
+ if (!name || !/^[a-z][a-z0-9-]{1,47}$/.test(name))
503
+ fail("Usage: codiedev agents init <name> [dir] [--template <id>] (lowercase letters, digits, dashes)");
504
+ const dir = path.resolve(dirArg ?? name);
505
+ const template = flag(args, "--template");
506
+ if (template) {
507
+ if (fs.existsSync(dir) && fs.readdirSync(dir).length)
508
+ fail(`${dir} isn't empty. Pick another folder.`);
509
+ fs.mkdirSync(dir, { recursive: true });
510
+ return initFromTemplate(name, dir, template, args);
511
+ }
512
+ const lang = flag(args, "--lang") ?? "python";
513
+ if (!["python", "py", "ts", "typescript", "js", "javascript"].includes(lang))
514
+ fail("--lang is python, ts or js");
515
+ const existing = ENTRYPOINTS.find((f) => fs.existsSync(path.join(dir, f)));
516
+ if (existing)
517
+ fail(`${dir} already has an ${existing}`);
518
+ fs.mkdirSync(dir, { recursive: true });
519
+ const model = flag(args, "--model");
520
+ let entrypoint = "agent.py";
521
+ if (lang.startsWith("py")) {
522
+ fs.writeFileSync(path.join(dir, "agent.py"), fillTemplate(STARTER_AGENT, "agent.py", name, model));
523
+ fs.writeFileSync(path.join(dir, "requirements.txt"), "# Extra packages for this agent, one per line. openai, mcp, httpx and pydantic are preinstalled.\n");
524
+ }
525
+ else {
526
+ entrypoint = lang.startsWith("t") ? "agent.ts" : "agent.mjs";
527
+ fs.writeFileSync(path.join(dir, entrypoint), fillTemplate(STARTER_TS, entrypoint, name, model));
528
+ fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ name, private: true, type: "module", dependencies: {} }, null, 2) + "\n");
529
+ }
530
+ fs.writeFileSync(path.join(dir, "agent.json"), JSON.stringify({ name, entrypoint, timeoutSec: 600 }, null, 2) + "\n");
531
+ writeGuides(dir);
532
+ console.log(`Created ${path.relative(process.cwd(), dir) || "."}/ with ${entrypoint}, agent.json and AGENTS.md.`);
533
+ console.log(`Want a head start? codiedev agents templates`);
534
+ console.log(`Next: edit ${entrypoint} (or ask your coding agent to, it reads AGENTS.md), then \`codiedev agents deploy ${dirArg ?? name}\`.`);
535
+ }
536
+ async function cmdDeploy(args, config) {
537
+ const dir = path.resolve(positional(args)[0] ?? ".");
538
+ const meta = readAgentJson(dir);
539
+ const name = flag(args, "--name") ?? meta.name;
540
+ if (!name)
541
+ fail("Name the agent in agent.json (\"name\") or with --name");
542
+ const entrypoint = meta.entrypoint ?? ENTRYPOINTS.find((f) => fs.existsSync(path.join(dir, f))) ?? "agent.py";
543
+ if (!fs.existsSync(path.join(dir, entrypoint)))
544
+ fail(`${entrypoint} not found in ${dir}. Set "entrypoint" in agent.json.`);
545
+ let everyMinutes;
546
+ try {
547
+ everyMinutes = parseEvery(flag(args, "--every") ?? (meta.every === undefined ? null : meta.every));
548
+ }
549
+ catch (err) {
550
+ fail(err.message);
551
+ }
552
+ const tgz = bundle(dir);
553
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/deploy", {
554
+ config,
555
+ body: {
556
+ name,
557
+ bundle: tgz.toString("base64"),
558
+ entrypoint,
559
+ timeoutSec: Number(flag(args, "--timeout") ?? meta.timeoutSec ?? 600),
560
+ everyMinutes: everyMinutes ?? null,
561
+ ...(meta.cpu !== undefined ? { cpu: meta.cpu } : {}),
562
+ ...(meta.memoryMb !== undefined ? { memoryMb: meta.memoryMb } : {}),
563
+ ...(meta.budgetUsd !== undefined ? { monthlyBudgetUsd: meta.budgetUsd } : {}),
564
+ ...(meta.retries !== undefined ? { retries: meta.retries } : {}),
565
+ ...(meta.personalSecrets !== undefined ? { personalSecrets: meta.personalSecrets } : {}),
566
+ },
567
+ });
568
+ console.log(`${res.created ? "Deployed" : "Updated"} ${res.agent} → version ${res.version} (${(tgz.length / 1024).toFixed(1)} KB)${everyMinutes ? `, runs every ${everyMinutes}m` : ""}${meta.retries ? `, ${meta.retries} retries` : ""}`);
569
+ if (!res.created)
570
+ console.log(`Undo: codiedev agents rollback ${res.agent}`);
571
+ const deps = ["requirements.txt", "package.json"].filter((f) => fs.existsSync(path.join(dir, f)));
572
+ if (deps.length)
573
+ console.log(`Dependencies (${deps.join(", ")}) install on the first run after they change, then come from cache.`);
574
+ console.log(`Run it: codiedev agents run ${res.agent}`);
575
+ }
576
+ async function waitFor(config, id, timeoutMs, onUpdate) {
577
+ const deadline = Date.now() + timeoutMs;
578
+ for (;;) {
579
+ const run = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/run?id=${encodeURIComponent(id)}`, { config });
580
+ onUpdate?.(run);
581
+ if (DONE.includes(run.status))
582
+ return run;
583
+ if (Date.now() > deadline)
584
+ fail(`Still ${run.status} after ${timeoutMs / 1000}s. Check later: codiedev agents show ${id}`);
585
+ await new Promise((r) => setTimeout(r, 2000));
586
+ }
587
+ }
588
+ function readInput(args) {
589
+ const raw = flag(args, "--input") ?? (flag(args, "--input-file") ? fs.readFileSync(flag(args, "--input-file"), "utf8") : undefined);
590
+ if (raw === undefined)
591
+ return undefined;
592
+ try {
593
+ return JSON.parse(raw);
594
+ }
595
+ catch {
596
+ return raw;
597
+ }
598
+ }
599
+ function parseDuration(value) {
600
+ const m = /^(\d+)\s*(s|m|min|h|d)?$/.exec(value.trim());
601
+ if (!m)
602
+ throw new Error(`durations look like 90s, 30m, 2h or 1d (got ${value})`);
603
+ const n = Number(m[1]);
604
+ return m[2] === "d" ? n * 86400 : m[2] === "h" ? n * 3600 : m[2] === "m" || m[2] === "min" ? n * 60 : n;
605
+ }
606
+ async function cmdRun(args, config) {
607
+ const [name] = positional(args);
608
+ if (!name)
609
+ fail("Usage: codiedev agents run <name> [--input '<json>'] [--no-wait] (or --local [dir])");
610
+ const input = readInput(args);
611
+ const idempotencyKey = flag(args, "--idempotency-key");
612
+ let delaySec;
613
+ try {
614
+ delaySec = flag(args, "--delay") ? parseDuration(flag(args, "--delay")) : undefined;
615
+ }
616
+ catch (err) {
617
+ fail(err.message);
618
+ }
619
+ const retries = flag(args, "--retries") !== undefined ? Number(flag(args, "--retries")) : undefined;
620
+ const started = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/run", {
621
+ config,
622
+ body: { agent: name, input, source: "cli", ...(idempotencyKey ? { idempotencyKey } : {}), ...(delaySec ? { delaySec } : {}), ...(retries !== undefined ? { retries } : {}) },
623
+ });
624
+ if (delaySec) {
625
+ console.log(args.includes("--json") ? JSON.stringify(started) : `Scheduled ${name} run ${started.runId} to start in ${flag(args, "--delay")}. Watch it: codiedev agents logs ${started.runId} -f`);
626
+ return;
627
+ }
628
+ if (args.includes("--no-wait")) {
629
+ console.log(args.includes("--json") ? JSON.stringify(started) : `${started.status === "existing" ? "Already started" : "Started"} ${name} run ${started.runId}`);
630
+ return;
631
+ }
632
+ const quiet = args.includes("--quiet") || args.includes("--json");
633
+ process.stderr.write(`Run ${started.runId}${started.status === "existing" ? " (already started with this idempotency key)" : ""}\n`);
634
+ const printLog = makeLogPrinter((t) => process.stderr.write(t));
635
+ let lastStatus = "";
636
+ const run = await waitFor(config, started.runId, Number(flag(args, "--timeout") ?? 3900) * 1000, (r) => {
637
+ const label = r.attempt && r.attempt > 1 ? `${r.status} · attempt ${r.attempt}/${r.maxAttempts}` : r.status;
638
+ if (label !== lastStatus && !DONE.includes(r.status))
639
+ process.stderr.write(`[${label}]\n`);
640
+ lastStatus = label;
641
+ if (!quiet)
642
+ printLog(r);
643
+ });
644
+ const cost = `${secs(run.computeMs ?? run.durationMs)} · compute ${usd(run.computeUsd)} · models ${usd(run.modelUsd)}`;
645
+ if (args.includes("--json")) {
646
+ console.log(JSON.stringify(run, null, 2));
647
+ }
648
+ else if (run.status === "succeeded") {
649
+ process.stderr.write(`[succeeded · ${cost}]\n`);
650
+ console.log(pretty(run.output));
651
+ }
652
+ else {
653
+ process.stderr.write(`[${run.status} · ${cost}]\n`);
654
+ console.error(`${run.status}: ${run.error ?? "no error message"}`);
655
+ if (quiet && run.logTail)
656
+ console.error(`\nLog (tail):\n${run.logTail.split("\n").slice(-25).join("\n")}`);
657
+ console.error(`\nInspect: codiedev agents show ${run.id}`);
658
+ }
659
+ if (run.status !== "succeeded")
660
+ process.exit(1);
661
+ }
662
+ async function cmdRuns(args, config) {
663
+ const [name] = positional(args);
664
+ const q = new URLSearchParams();
665
+ if (name)
666
+ q.set("agent", name);
667
+ if (args.includes("--failed"))
668
+ q.set("status", "failed");
669
+ q.set("limit", flag(args, "--limit") ?? "20");
670
+ const { runs } = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/runs?${q}`, { config });
671
+ if (args.includes("--json"))
672
+ return void console.log(JSON.stringify(runs, null, 2));
673
+ if (!runs.length)
674
+ return void console.log("No runs.");
675
+ for (const r of runs) {
676
+ const chain = r.parentRunId ? ` ↳ child of ${r.parentRunId}` : "";
677
+ console.log(`${r.id} ${r.agent.padEnd(20)} ${r.status.padEnd(10)} ${r.trigger.padEnd(9)} ${secs(r.durationMs).padStart(7)} ${usd(r.computeUsd).padStart(8)} ${ago(r.createdAt)}${chain}`);
678
+ if (r.error)
679
+ console.log(` ${r.error}`);
680
+ }
681
+ }
682
+ async function cmdShow(args, config) {
683
+ const [id] = positional(args);
684
+ if (!id)
685
+ fail("Usage: codiedev agents show <run-id>");
686
+ const r = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/run?id=${encodeURIComponent(id)}`, { config });
687
+ if (args.includes("--json"))
688
+ return void console.log(JSON.stringify(r, null, 2));
689
+ const attempts = r.maxAttempts && r.maxAttempts > 1 ? ` · attempt ${r.attempt}/${r.maxAttempts}` : "";
690
+ const scheduled = r.scheduledFor ? ` · starts ${new Date(r.scheduledFor).toLocaleString()}` : "";
691
+ console.log(`${r.agent} v${r.version} · ${r.status}${attempts}${scheduled} · ${r.trigger} · ${secs(r.durationMs)} · ${ago(r.createdAt)}`);
692
+ console.log(`Cost: compute ${usd(r.computeUsd)}${r.computeMs != null ? ` (${secs(r.computeMs)} sandbox)` : ""} · models ${usd(r.modelUsd)} over ${r.modelCalls ?? 0} calls`);
693
+ if (r.traceRunId)
694
+ console.log(`Trace: ${portalUrl()}/portal/traces?view=runs&run=${encodeURIComponent(r.traceRunId)}`);
695
+ if (r.parentRunId)
696
+ console.log(`Parent: ${r.parentRunId}`);
697
+ if (r.error)
698
+ console.log(`Error: ${r.error}`);
699
+ console.log(`\nInput:\n${pretty(r.input)}\n\nOutput:\n${pretty(r.output)}`);
700
+ if (r.children?.length) {
701
+ console.log("\nChild runs:");
702
+ for (const c of r.children)
703
+ console.log(` ${c.id} ${c.agent} ${c.status} ${secs(c.durationMs)}`);
704
+ }
705
+ if (r.logTail)
706
+ console.log(`\nLog${(r.logChars ?? 0) > r.logTail.length ? " (last 16 KB)" : ""}:\n${r.logTail}`);
707
+ }
708
+ function portalUrl() {
709
+ return (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
710
+ }
711
+ async function cmdLogs(args, config) {
712
+ const [id] = positional(args);
713
+ if (!id)
714
+ fail("Usage: codiedev agents logs <run-id> [-f]");
715
+ const follow = args.includes("-f") || args.includes("--follow");
716
+ const print = makeLogPrinter((t) => process.stdout.write(t));
717
+ const run = follow
718
+ ? await waitFor(config, id, 3900 * 1000, print)
719
+ : await (0, shared_1.apiRequest)("GET", `/api/agents/v1/run?id=${encodeURIComponent(id)}`, { config });
720
+ if (!follow)
721
+ print(run);
722
+ if (follow || !DONE.includes(run.status))
723
+ process.stderr.write(`[${run.status}]\n`);
724
+ }
725
+ async function cmdList(args, config) {
726
+ const { agents } = await (0, shared_1.apiRequest)("GET", "/api/agents/v1/agents", { config });
727
+ if (args.includes("--json"))
728
+ return void console.log(JSON.stringify(agents, null, 2));
729
+ if (!agents.length)
730
+ return void console.log("No agents yet. Start one: codiedev agents init <name>");
731
+ for (const a of agents) {
732
+ const how = [a.everyMinutes ? `every ${a.everyMinutes}m` : null, a.hasWebhook ? "webhook" : null].filter(Boolean).join(", ") || "on demand";
733
+ const last = a.lastRun ? `${a.lastRun.status} ${ago(a.lastRun.createdAt)}` : "never run";
734
+ console.log(`${a.name.padEnd(24)} v${String(a.version).padEnd(4)} ${how.padEnd(20)} last: ${last.padEnd(20)} 24h: ${a.runs24h} runs, ${a.failed24h} failed, ${usd(a.computeUsd24h ?? 0)} compute (${a.owner})`);
735
+ }
736
+ }
737
+ async function cmdSecrets(args, config) {
738
+ const [name, action, pair] = positional(args);
739
+ const mine = args.includes("--mine");
740
+ const usage = "Usage: codiedev agents secrets <name> [set KEY=value | unset KEY] [--mine]";
741
+ if (!name)
742
+ fail(usage);
743
+ if (!action) {
744
+ const { secrets } = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/secrets?agent=${encodeURIComponent(name)}`, { config });
745
+ if (!secrets.length)
746
+ return void console.log(`${name} has no secrets. Add one: codiedev agents secrets ${name} set KEY=value`);
747
+ for (const s of secrets) {
748
+ const shared = s.updatedAt ? `shared, updated ${ago(s.updatedAt)}` : "no shared value";
749
+ console.log(s.personal ? `${s.name} (personal: ${s.yours ? `yours set ${ago(s.yours)}` : `yours not set; codiedev agents secrets ${name} set ${s.name}=… --mine`}; ${shared})` : `${s.name} (${shared})`);
750
+ }
751
+ return;
752
+ }
753
+ if (action === "set") {
754
+ const eq = pair?.indexOf("=") ?? -1;
755
+ if (!pair || eq < 1)
756
+ fail(usage);
757
+ await (0, shared_1.apiRequest)("POST", "/api/agents/v1/secrets", { config, body: { agent: name, name: pair.slice(0, eq), value: pair.slice(eq + 1), mine } });
758
+ return void console.log(mine ? `Set your own ${pair.slice(0, eq)} on ${name}. Runs you start use it.` : `Set ${pair.slice(0, eq)} on ${name}. It's in the environment from the next run.`);
759
+ }
760
+ if (action === "unset") {
761
+ if (!pair)
762
+ fail(usage);
763
+ await (0, shared_1.apiRequest)("POST", "/api/agents/v1/secrets", { config, body: { agent: name, name: pair, value: null, mine } });
764
+ return void console.log(mine ? `Removed your own ${pair} from ${name}.` : `Removed ${pair} from ${name}.`);
765
+ }
766
+ fail(usage);
767
+ }
768
+ async function cmdControl(args, config, stop) {
769
+ const [name] = positional(args);
770
+ const all = args.includes("--all");
771
+ if (!name && !all)
772
+ fail(`Usage: codiedev agents ${stop ? "stop" : "resume"} <name> | --all${stop ? " [--reason \"…\"]" : ""}`);
773
+ const res = await (0, shared_1.apiRequest)("POST", `/api/agents/v1/${stop ? "stop" : "resume"}`, { config, body: { agent: name, all, reason: flag(args, "--reason") } });
774
+ const what = all ? "Every agent" : name;
775
+ if (stop)
776
+ console.log(res.already ? `${what} was already stopped.` : `${what} stopped. Cancelled ${res.cancelledRuns ?? 0} run(s) and revoked model access. Nothing starts it until someone resumes it.`);
777
+ else
778
+ console.log(res.companyStopped ? `${what} resumed, but every agent is still stopped company-wide; an admin runs codiedev agents resume --all.` : `${what} resumed with a fresh model key.`);
779
+ }
780
+ async function cmdWebhook(args, config) {
781
+ const [name] = positional(args);
782
+ if (!name)
783
+ fail("Usage: codiedev agents webhook <name> [--off]");
784
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/webhook", { config, body: { agent: name, off: args.includes("--off") } });
785
+ if (!res.url)
786
+ return void console.log(`Removed ${name}'s webhook.`);
787
+ console.log(res.url);
788
+ if (process.stderr.isTTY)
789
+ process.stderr.write("POST JSON to this URL to start a run; the body is the input. It's shown once, and running this again replaces it.\n");
790
+ }
791
+ async function cmdPull(args, config) {
792
+ const [name, dirArg] = positional(args);
793
+ if (!name)
794
+ fail("Usage: codiedev agents pull <name> [dir]");
795
+ const dir = path.resolve(dirArg ?? name);
796
+ if (fs.existsSync(dir) && fs.readdirSync(dir).length && !args.includes("--force"))
797
+ fail(`${dir} isn't empty. Pick another folder or pass --force to unpack over it.`);
798
+ const version = flag(args, "--version");
799
+ const res = await fetch(new URL(`/api/agents/v1/bundle?agent=${encodeURIComponent(name)}${version ? `&version=${encodeURIComponent(version)}` : ""}`, config.backendUrl), {
800
+ headers: { Authorization: `Bearer ${config.token}` },
801
+ });
802
+ if (!res.ok) {
803
+ const body = (await res.json().catch(() => ({})));
804
+ fail(`codiedev agents pull: ${body.error ?? `HTTP ${res.status}`}`);
805
+ }
806
+ fs.mkdirSync(dir, { recursive: true });
807
+ (0, child_process_1.execFileSync)("tar", ["-xzf", "-", "-C", dir], { input: Buffer.from(await res.arrayBuffer()) });
808
+ console.log(`Pulled ${name} v${res.headers.get("x-codiedev-agent-version") ?? "?"} into ${path.relative(process.cwd(), dir) || "."}/. Secrets stay in Codiedev; deploy from here to ship a new version.`);
809
+ }
810
+ async function cmdVersions(args, config) {
811
+ const [name] = positional(args);
812
+ if (!name)
813
+ fail("Usage: codiedev agents versions <name>");
814
+ const { versions } = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/versions?agent=${encodeURIComponent(name)}`, { config });
815
+ if (args.includes("--json"))
816
+ return void console.log(JSON.stringify(versions, null, 2));
817
+ for (const r of versions) {
818
+ const note = [r.current ? "current" : null, r.rollbackOf ? `rollback to v${r.rollbackOf}` : null, r.everyMinutes ? `every ${r.everyMinutes}m` : null, r.retries ? `${r.retries} retries` : null].filter(Boolean).join(", ");
819
+ console.log(`v${String(r.version).padEnd(4)} ${ago(r.createdAt).padEnd(9)} ${r.deployedBy.padEnd(22)} ${(r.bundleBytes / 1024).toFixed(1).padStart(7)} KB ${note}`);
820
+ }
821
+ if (versions.length > 1)
822
+ console.log(`\nRoll back: codiedev agents rollback ${name} [--to <n>]`);
823
+ }
824
+ async function cmdRollback(args, config) {
825
+ const [name] = positional(args);
826
+ if (!name)
827
+ fail("Usage: codiedev agents rollback <name> [--to <version>]");
828
+ const to = flag(args, "--to");
829
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/rollback", { config, body: { agent: name, ...(to ? { to: Number(to.replace(/^v/, "")) } : {}) } });
830
+ console.log(`Rolled ${name} back to v${res.from}'s code and settings, as v${res.version}. New runs use it now.`);
831
+ }
832
+ async function cmdState(args, config) {
833
+ const [name, action = "list", key, value] = positional(args);
834
+ if (!name)
835
+ fail("Usage: codiedev agents state <name> [list [prefix] | get <key> | set <key> '<json>' | delete <key>]");
836
+ const agent = encodeURIComponent(name);
837
+ if (action === "list") {
838
+ const keys = [];
839
+ let after = null;
840
+ do {
841
+ const q = new URLSearchParams({ agent: name, prefix: key ?? "", values: args.includes("--json") ? "1" : "0", limit: "200", ...(after ? { after } : {}) });
842
+ const page = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/state?${q}`, { config });
843
+ keys.push(...page.keys);
844
+ after = page.next;
845
+ } while (after);
846
+ if (args.includes("--json"))
847
+ return void console.log(JSON.stringify(keys.map((k) => ({ ...k, value: k.value ? JSON.parse(k.value) : undefined })), null, 2));
848
+ if (!keys.length)
849
+ return void console.log(`${name} has no state${key ? ` under ${key}` : ""}.`);
850
+ for (const k of keys)
851
+ console.log(`${k.key.padEnd(40)} v${String(k.version).padEnd(5)} ${String(k.bytes).padStart(7)} B ${ago(k.updatedAt)}${k.expiresAt ? ` expires ${new Date(k.expiresAt).toLocaleString()}` : ""}`);
852
+ return;
853
+ }
854
+ if (!key)
855
+ fail(`Usage: codiedev agents state ${name} ${action} <key>`);
856
+ if (action === "get") {
857
+ const row = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/state?agent=${agent}&key=${encodeURIComponent(key)}`, { config });
858
+ return void console.log(pretty(row.value));
859
+ }
860
+ if (action === "set" || action === "delete") {
861
+ let parsed = null;
862
+ if (action === "set") {
863
+ if (value === undefined)
864
+ fail(`Usage: codiedev agents state ${name} set <key> '<json>'`);
865
+ try {
866
+ parsed = JSON.parse(value);
867
+ }
868
+ catch {
869
+ parsed = value;
870
+ }
871
+ }
872
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/state", { config, body: { agent: name, key, value: parsed } });
873
+ return void console.log(action === "set" ? `Set ${key} (v${res.version}).` : `Deleted ${key}.`);
874
+ }
875
+ fail("Usage: codiedev agents state <name> [list [prefix] | get <key> | set <key> '<json>' | delete <key>]");
876
+ }
877
+ async function cmdApprovals(args, config) {
878
+ const status = args.includes("--all") ? "decided" : "pending";
879
+ const { approvals } = await (0, shared_1.apiRequest)("GET", `/api/agents/v1/approvals?status=${status}`, { config });
880
+ if (args.includes("--json"))
881
+ return void console.log(JSON.stringify(approvals, null, 2));
882
+ if (!approvals.length)
883
+ return void console.log(status === "pending" ? "No approvals waiting." : "No decided approvals.");
884
+ for (const a of approvals) {
885
+ console.log(`${a.id} ${a.agent.padEnd(20)} ${a.title}`);
886
+ if (a.status === "pending")
887
+ console.log(` ${a.options.join(" | ")} · asked ${ago(a.createdAt)} · expires ${new Date(a.expiresAt).toLocaleString()}`);
888
+ else
889
+ console.log(` ${a.decision} by ${a.decidedBy ?? "—"}${a.resumeRunId ? ` → run ${a.resumeRunId}` : ""}`);
890
+ if (a.details)
891
+ console.log(a.details.split("\n").slice(0, 6).map((l) => ` ${l}`).join("\n"));
892
+ }
893
+ if (status === "pending")
894
+ console.log(`\nDecide: codiedev agents decide <id> <option> [--comment "…"]`);
895
+ }
896
+ async function cmdDecide(args, config) {
897
+ const [id, decision] = positional(args);
898
+ if (!id || !decision)
899
+ fail('Usage: codiedev agents decide <approval-id> <option> [--comment "…"]');
900
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/approvals/decide", { config, body: { id, decision, comment: flag(args, "--comment") } });
901
+ console.log(`Decided: ${res.decision}.${res.runId ? ` Started run ${res.runId} (codiedev agents logs ${res.runId} -f).` : ""}`);
902
+ }
903
+ function readEnvFile(file) {
904
+ const out = {};
905
+ for (const line of fs.readFileSync(file, "utf8").split("\n")) {
906
+ const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/.exec(line);
907
+ if (!m)
908
+ continue;
909
+ out[m[1]] = m[2].replace(/^(["'])(.*)\1$/, "$2");
910
+ }
911
+ return out;
912
+ }
913
+ async function cmdRunLocal(args) {
914
+ const dir = path.resolve(positional(args)[0] ?? ".");
915
+ const meta = readAgentJson(dir);
916
+ const name = meta.name ?? path.basename(dir);
917
+ const entrypoint = meta.entrypoint ?? ENTRYPOINTS.find((f) => fs.existsSync(path.join(dir, f)));
918
+ if (!entrypoint || !fs.existsSync(path.join(dir, entrypoint)))
919
+ fail(`No entrypoint in ${dir}. Set "entrypoint" in agent.json, or run from the agent's folder.`);
920
+ let config = null;
921
+ try {
922
+ config = (0, shared_1.requireConfig)();
923
+ }
924
+ catch {
925
+ }
926
+ const work = path.join(dir, ".codiedev", "local");
927
+ fs.mkdirSync(path.join(work, "py"), { recursive: true });
928
+ fs.writeFileSync(path.join(work, "py", "codiedev_agents.py"), sdk.python);
929
+ const jsSdk = path.join(dir, "node_modules", "codiedev-agents");
930
+ if (/\.(m?[jt]s|cjs|mts)$/.test(entrypoint)) {
931
+ fs.mkdirSync(jsSdk, { recursive: true });
932
+ fs.writeFileSync(path.join(jsSdk, "index.mjs"), sdk.jsIndex);
933
+ fs.writeFileSync(path.join(jsSdk, "index.d.ts"), sdk.jsTypes);
934
+ fs.writeFileSync(path.join(jsSdk, "package.json"), sdk.jsPackage);
935
+ }
936
+ const files = { input: path.join(work, "input.json"), output: path.join(work, "output.json"), request: path.join(work, "request.json"), response: path.join(work, "response.json") };
937
+ fs.writeFileSync(files.input, JSON.stringify(readInput(args) ?? null));
938
+ for (const f of [files.output, files.response])
939
+ fs.rmSync(f, { force: true });
940
+ const requestFile = flag(args, "--request-file");
941
+ if (requestFile)
942
+ fs.copyFileSync(path.resolve(requestFile), files.request);
943
+ else
944
+ fs.rmSync(files.request, { force: true });
945
+ const envFile = flag(args, "--env-file") ?? (fs.existsSync(path.join(dir, ".env")) ? path.join(dir, ".env") : undefined);
946
+ const secrets = envFile ? readEnvFile(envFile) : {};
947
+ const remoteState = args.includes("--remote-state");
948
+ if (remoteState && !config)
949
+ fail("--remote-state needs `codiedev connect` first.");
950
+ if (remoteState && !meta.name)
951
+ fail('--remote-state needs "name" in agent.json, so it uses the right agent\'s state.');
952
+ const runId = `local-${Date.now()}`;
953
+ const env = {
954
+ ...process.env,
955
+ ...secrets,
956
+ CODIEDEV_LOCAL: "1",
957
+ CODIEDEV_AGENT: name,
958
+ CODIEDEV_RUN_ID: runId,
959
+ CODIEDEV_ATTEMPT: "1",
960
+ CODIEDEV_MAX_ATTEMPTS: "1",
961
+ CODIEDEV_INPUT_PATH: files.input,
962
+ CODIEDEV_OUTPUT_PATH: files.output,
963
+ CODIEDEV_REQUEST_PATH: files.request,
964
+ CODIEDEV_RESPONSE_PATH: files.response,
965
+ ...(remoteState ? {} : { CODIEDEV_STATE_PATH: path.join(work, "state.json") }),
966
+ PYTHONPATH: [path.join(work, "py"), process.env.PYTHONPATH].filter(Boolean).join(path.delimiter),
967
+ ...(config ? { CODIEDEV_AGENTS_URL: config.backendUrl, CODIEDEV_TOKEN: config.token } : {}),
968
+ };
969
+ const ext = path.extname(entrypoint);
970
+ const [cmd, ...cmdArgs] = ext === ".py" ? [process.env.PYTHON ?? "python3", "-u", entrypoint]
971
+ : ext === ".sh" ? ["bash", entrypoint]
972
+ : ext === ".ts" || ext === ".mts" ? ["npx", "--yes", "tsx", entrypoint]
973
+ : [process.execPath, entrypoint];
974
+ process.stderr.write(`[local run of ${name} · ${entrypoint}${envFile ? ` · secrets from ${path.relative(process.cwd(), envFile) || envFile}` : ""} · state ${remoteState ? "from Codiedev" : "in .codiedev/local/state.json"}]\n`);
975
+ const started = Date.now();
976
+ const res = (0, child_process_1.spawnSync)(cmd, cmdArgs, { cwd: dir, env, stdio: ["inherit", process.stderr, process.stderr] });
977
+ const took = `${((Date.now() - started) / 1000).toFixed(1)}s`;
978
+ if (res.error)
979
+ fail(`Couldn't start ${cmd}: ${res.error.message}`);
980
+ const output = fs.existsSync(files.output) ? fs.readFileSync(files.output, "utf8") : null;
981
+ const response = fs.existsSync(files.response) ? fs.readFileSync(files.response, "utf8") : null;
982
+ if (res.status === 0) {
983
+ process.stderr.write(`[succeeded · ${took} · local]\n`);
984
+ if (response)
985
+ process.stderr.write(`Webhook response: ${response}\n`);
986
+ console.log(pretty(output));
987
+ }
988
+ else {
989
+ process.stderr.write(`[failed · exit ${res.status ?? res.signal} · ${took} · local]\n`);
990
+ process.exit(1);
991
+ }
992
+ }
993
+ async function cmdTemplates(args) {
994
+ let shared = [];
995
+ try {
996
+ shared = (await (0, shared_1.apiRequest)("GET", "/api/agents/v1/templates", { config: (0, shared_1.requireConfig)() })).templates;
997
+ }
998
+ catch {
999
+ }
1000
+ if (args.includes("--json"))
1001
+ return void console.log(JSON.stringify({ starters: agentTemplates_generated_1.TEMPLATES.map(({ files: _f, ...t }) => t), shared }, null, 2));
1002
+ console.log("Starter templates\n");
1003
+ for (const t of agentTemplates_generated_1.TEMPLATES)
1004
+ console.log(` ${t.id.padEnd(18)} ${t.title} · ${t.trigger}\n ${"".padEnd(18)} ${t.summary}\n`);
1005
+ if (shared.length) {
1006
+ console.log("Shared in your company\n");
1007
+ for (const t of shared)
1008
+ console.log(` ${t.slug.padEnd(18)} ${t.title} · by ${t.publishedBy} · ${t.visibility === "team" ? `team${t.team ? ` ${t.team}` : ""}` : "company"} · ${t.installs} installs\n ${"".padEnd(18)} ${t.summary}\n`);
1009
+ }
1010
+ console.log("Start one: codiedev agents init <name> --template <id>");
1011
+ if (shared.length)
1012
+ console.log("Or deploy a shared one as is: codiedev agents install <template> <name>");
1013
+ }
1014
+ async function cmdPublish(args, config) {
1015
+ const [agent] = positional(args);
1016
+ if (!agent)
1017
+ fail('Usage: codiedev agents publish <agent> --summary "what it does" [--company] [--title "…"] [--as <slug>]');
1018
+ const summary = flag(args, "--summary");
1019
+ if (!summary)
1020
+ fail('Add --summary "one line on what it does", so people know when to use it.');
1021
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/templates/publish", {
1022
+ config,
1023
+ body: { agent, summary, title: flag(args, "--title"), slug: flag(args, "--as"), visibility: args.includes("--company") ? "company" : "team" },
1024
+ });
1025
+ console.log(`${res.updated ? "Updated" : "Published"} ${res.slug} for ${args.includes("--company") ? "your whole company" : "your team"}. Teammates: codiedev agents install ${res.slug} <name>, or Agents → Marketplace.`);
1026
+ }
1027
+ async function cmdInstall(args, config) {
1028
+ const [template, name] = positional(args);
1029
+ if (!template || !name)
1030
+ fail("Usage: codiedev agents install <template> <name>");
1031
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/templates/install", { config, body: { template, name } });
1032
+ console.log(`Deployed ${res.name} (v${res.version}) from ${template}. You own it: run it with codiedev agents run ${res.name}.`);
1033
+ if (res.secretNames.length)
1034
+ console.log(`Set its secrets first: ${res.secretNames.map((s) => `codiedev agents secrets ${res.name} set ${s}=…`).join("\n ")}`);
1035
+ }
1036
+ async function cmdUnpublish(args, config) {
1037
+ const [template] = positional(args);
1038
+ if (!template)
1039
+ fail("Usage: codiedev agents unpublish <template>");
1040
+ await (0, shared_1.apiRequest)("POST", "/api/agents/v1/templates/unpublish", { config, body: { template } });
1041
+ console.log(`Removed ${template} from the marketplace. Agents installed from it keep working.`);
1042
+ }
1043
+ async function cmdCancel(args, config) {
1044
+ const [id] = positional(args);
1045
+ if (!id)
1046
+ fail("Usage: codiedev agents cancel <run-id>");
1047
+ const res = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/cancel", { config, body: { id } });
1048
+ console.log(res.status && res.status !== "cancelled" ? `Run already ${res.status}.` : "Cancelled.");
1049
+ }
1050
+ async function cmdConnect(args, config) {
1051
+ const [name] = positional(args);
1052
+ if (!name)
1053
+ fail('Usage: codiedev agents connect <name> [--description "…"] [--budget <usd>]');
1054
+ const budget = flag(args, "--budget");
1055
+ const out = await (0, shared_1.apiRequest)("POST", "/api/agents/v1/connect", {
1056
+ config,
1057
+ body: { name, description: flag(args, "--description"), ...(budget ? { monthlyBudgetUsd: Number(budget) } : {}) },
1058
+ });
1059
+ console.log(`Connected ${out.agent}. Its key is shown once; put it in your secret manager.\n`);
1060
+ console.log(`CODIEDEV_API_KEY=${out.key}`);
1061
+ console.log(`CODIEDEV_GATEWAY_URL=${out.gatewayUrl}`);
1062
+ console.log(`CODIEDEV_AGENTS_URL=${out.agentsUrl}\n`);
1063
+ console.log("Point its OpenAI-compatible client at CODIEDEV_GATEWAY_URL with that key (one X-Codiedev-Run-Id per job groups its calls into a trace).");
1064
+ console.log(`The same key calls ${out.agentsUrl}/api/agents/v1/approvals and /state. See it: Agents → ${out.agent}.`);
1065
+ }
1066
+ async function cmdDelete(args, config) {
1067
+ const [name] = positional(args);
1068
+ if (!name)
1069
+ fail("Usage: codiedev agents delete <name>");
1070
+ await (0, shared_1.apiRequest)("POST", "/api/agents/v1/delete", { config, body: { agent: name } });
1071
+ console.log(`Deleted ${name}. Its run history stays in Codiedev.`);
1072
+ }
1073
+ async function runAgents(args, configOverride) {
1074
+ const [sub, ...rest] = args;
1075
+ if (sub === "init")
1076
+ return cmdInit(rest).catch((err) => fail(`codiedev agents init: ${err.message}`));
1077
+ if (sub === "templates")
1078
+ return cmdTemplates(rest);
1079
+ if (sub === "run" && rest.includes("--local"))
1080
+ return cmdRunLocal(rest);
1081
+ const commands = {
1082
+ connect: cmdConnect, deploy: cmdDeploy, run: cmdRun, runs: cmdRuns, show: cmdShow, logs: cmdLogs, list: cmdList, ls: cmdList,
1083
+ secrets: cmdSecrets, webhook: cmdWebhook, cancel: cmdCancel, stop: (a, c) => cmdControl(a, c, true), resume: (a, c) => cmdControl(a, c, false), delete: cmdDelete, pull: cmdPull,
1084
+ versions: cmdVersions, rollback: cmdRollback, state: cmdState, approvals: cmdApprovals, decide: cmdDecide,
1085
+ publish: cmdPublish, install: cmdInstall, unpublish: cmdUnpublish,
1086
+ };
1087
+ const fn = sub ? commands[sub] : undefined;
1088
+ if (!fn) {
1089
+ console.log(exports.AGENTS_HELP);
1090
+ if (sub && sub !== "help")
1091
+ process.exit(1);
1092
+ return;
1093
+ }
1094
+ try {
1095
+ const config = configOverride ?? (0, shared_1.requireConfig)();
1096
+ await (0, shared_1.withTelemetry)(config, `codiedev_agents_${sub}`, () => fn(rest, config));
1097
+ }
1098
+ catch (err) {
1099
+ fail(`codiedev agents ${sub}: ${err.message}`);
1100
+ }
1101
+ }