@cargo-ai/cli 1.0.92 → 1.0.95
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/README.md +17 -17
- package/build/commands/ai/chat.d.ts.map +1 -1
- package/build/commands/ai/chat.js +2 -1
- package/build/commands/ai/message.d.ts.map +1 -1
- package/build/commands/ai/message.js +2 -1
- package/build/commands/ai/release.d.ts.map +1 -1
- package/build/commands/ai/release.js +7 -6
- package/build/commands/ask/harness/approvals.d.ts +7 -0
- package/build/commands/ask/harness/approvals.d.ts.map +1 -0
- package/build/commands/ask/harness/approvals.js +82 -0
- package/build/commands/ask/harness/artifacts.d.ts.map +1 -0
- package/build/commands/ask/harness/claudeConfig.d.ts.map +1 -0
- package/build/commands/ask/harness/create.d.ts +59 -0
- package/build/commands/ask/harness/create.d.ts.map +1 -0
- package/build/commands/ask/harness/create.js +292 -0
- package/build/commands/ask/harness/index.d.ts +8 -0
- package/build/commands/ask/harness/index.d.ts.map +1 -0
- package/build/commands/ask/harness/index.js +7 -0
- package/build/commands/ask/harness/ingest.d.ts +25 -0
- package/build/commands/ask/harness/ingest.d.ts.map +1 -0
- package/build/commands/ask/harness/ingest.js +35 -0
- package/build/commands/ask/harness/instructions.d.ts +13 -0
- package/build/commands/ask/harness/instructions.d.ts.map +1 -0
- package/build/commands/ask/harness/instructions.js +41 -0
- package/build/commands/ask/harness/layout.d.ts +23 -0
- package/build/commands/ask/harness/layout.d.ts.map +1 -0
- package/build/commands/ask/harness/layout.js +32 -0
- package/build/commands/ask/harness/mcp.d.ts +25 -0
- package/build/commands/ask/harness/mcp.d.ts.map +1 -0
- package/build/commands/ask/harness/mcp.js +72 -0
- package/build/commands/ask/harness/pnpmShim.d.ts.map +1 -0
- package/build/commands/ask/harness/release.d.ts +18 -0
- package/build/commands/ask/harness/release.d.ts.map +1 -0
- package/build/commands/ask/harness/release.js +117 -0
- package/build/commands/ask/harness/sandbox.d.ts +9 -0
- package/build/commands/ask/harness/sandbox.d.ts.map +1 -0
- package/build/commands/ask/harness/sandbox.js +27 -0
- package/build/commands/ask/harness/timing.d.ts +16 -0
- package/build/commands/ask/harness/timing.d.ts.map +1 -0
- package/build/commands/ask/harness/timing.js +72 -0
- package/build/commands/ask/harness/turn.d.ts +145 -0
- package/build/commands/ask/harness/turn.d.ts.map +1 -0
- package/build/commands/ask/harness/turn.js +626 -0
- package/build/commands/ask/harness/usage.d.ts +50 -0
- package/build/commands/ask/harness/usage.d.ts.map +1 -0
- package/build/commands/ask/harness/usage.js +87 -0
- package/build/commands/ask/index.d.ts +9 -0
- package/build/commands/ask/index.d.ts.map +1 -1
- package/build/commands/ask/index.js +7 -7
- package/build/commands/ask/input/completer.d.ts.map +1 -0
- package/build/commands/ask/input/index.d.ts +5 -0
- package/build/commands/ask/input/index.d.ts.map +1 -0
- package/build/commands/ask/input/index.js +4 -0
- package/build/commands/ask/input/prompt.d.ts.map +1 -0
- package/build/commands/ask/{prompt.js → input/prompt.js} +1 -1
- package/build/commands/ask/input/slash.d.ts.map +1 -0
- package/build/commands/ask/{slash.js → input/slash.js} +2 -2
- package/build/commands/ask/input/typeAhead.d.ts.map +1 -0
- package/build/commands/ask/{history.d.ts → persist/history.d.ts} +1 -1
- package/build/commands/ask/persist/history.d.ts.map +1 -0
- package/build/commands/ask/persist/index.d.ts +4 -0
- package/build/commands/ask/persist/index.d.ts.map +1 -0
- package/build/commands/ask/persist/index.js +3 -0
- package/build/commands/ask/persist/persist.d.ts.map +1 -0
- package/build/commands/ask/persist/state.d.ts.map +1 -0
- package/build/commands/ask/session/claim.d.ts +56 -0
- package/build/commands/ask/session/claim.d.ts.map +1 -0
- package/build/commands/ask/session/claim.js +76 -0
- package/build/commands/ask/session/index.d.ts +5 -0
- package/build/commands/ask/session/index.d.ts.map +1 -0
- package/build/commands/ask/session/index.js +4 -0
- package/build/commands/ask/session/run.d.ts +36 -0
- package/build/commands/ask/session/run.d.ts.map +1 -0
- package/build/commands/ask/session/run.js +832 -0
- package/build/commands/ask/session/thinking.d.ts.map +1 -0
- package/build/commands/ask/session/tree.d.ts +90 -0
- package/build/commands/ask/session/tree.d.ts.map +1 -0
- package/build/commands/ask/session/tree.js +318 -0
- package/build/commands/start/brief.js +1 -1
- package/build/commands/start/index.d.ts +1 -1
- package/build/commands/start/index.d.ts.map +1 -1
- package/build/commands/start/index.js +7 -7
- package/build/index.js +6 -1
- package/build/paletteLayout.d.ts.map +1 -1
- package/build/paletteLayout.js +9 -8
- package/build/utils/cdkState.js +2 -2
- package/build/utils/loadCompiledAgent.js +1 -1
- package/package.json +6 -5
- package/build/commands/ask/artifacts.d.ts.map +0 -1
- package/build/commands/ask/binding.d.ts +0 -13
- package/build/commands/ask/binding.d.ts.map +0 -1
- package/build/commands/ask/binding.js +0 -19
- package/build/commands/ask/claudeConfig.d.ts.map +0 -1
- package/build/commands/ask/completer.d.ts.map +0 -1
- package/build/commands/ask/history.d.ts.map +0 -1
- package/build/commands/ask/localHarness.d.ts +0 -278
- package/build/commands/ask/localHarness.d.ts.map +0 -1
- package/build/commands/ask/localHarness.js +0 -1300
- package/build/commands/ask/messageStream.d.ts +0 -33
- package/build/commands/ask/messageStream.d.ts.map +0 -1
- package/build/commands/ask/messageStream.js +0 -114
- package/build/commands/ask/persist.d.ts.map +0 -1
- package/build/commands/ask/pnpmShim.d.ts.map +0 -1
- package/build/commands/ask/prompt.d.ts.map +0 -1
- package/build/commands/ask/session.d.ts +0 -101
- package/build/commands/ask/session.d.ts.map +0 -1
- package/build/commands/ask/session.js +0 -1328
- package/build/commands/ask/slash.d.ts.map +0 -1
- package/build/commands/ask/state.d.ts.map +0 -1
- package/build/commands/ask/thinking.d.ts.map +0 -1
- package/build/commands/ask/typeAhead.d.ts.map +0 -1
- /package/build/commands/ask/{artifacts.d.ts → harness/artifacts.d.ts} +0 -0
- /package/build/commands/ask/{artifacts.js → harness/artifacts.js} +0 -0
- /package/build/commands/ask/{claudeConfig.d.ts → harness/claudeConfig.d.ts} +0 -0
- /package/build/commands/ask/{claudeConfig.js → harness/claudeConfig.js} +0 -0
- /package/build/commands/ask/{pnpmShim.d.ts → harness/pnpmShim.d.ts} +0 -0
- /package/build/commands/ask/{pnpmShim.js → harness/pnpmShim.js} +0 -0
- /package/build/commands/ask/{completer.d.ts → input/completer.d.ts} +0 -0
- /package/build/commands/ask/{completer.js → input/completer.js} +0 -0
- /package/build/commands/ask/{prompt.d.ts → input/prompt.d.ts} +0 -0
- /package/build/commands/ask/{slash.d.ts → input/slash.d.ts} +0 -0
- /package/build/commands/ask/{typeAhead.d.ts → input/typeAhead.d.ts} +0 -0
- /package/build/commands/ask/{typeAhead.js → input/typeAhead.js} +0 -0
- /package/build/commands/ask/{history.js → persist/history.js} +0 -0
- /package/build/commands/ask/{persist.d.ts → persist/persist.d.ts} +0 -0
- /package/build/commands/ask/{persist.js → persist/persist.js} +0 -0
- /package/build/commands/ask/{state.d.ts → persist/state.d.ts} +0 -0
- /package/build/commands/ask/{state.js → persist/state.js} +0 -0
- /package/build/commands/ask/{thinking.d.ts → session/thinking.d.ts} +0 -0
- /package/build/commands/ask/{thinking.js → session/thinking.js} +0 -0
package/README.md
CHANGED
|
@@ -152,23 +152,23 @@ cargo-ai orchestration workflow --help
|
|
|
152
152
|
|
|
153
153
|
### Domains and example commands
|
|
154
154
|
|
|
155
|
-
| Domain | Description | Example commands
|
|
156
|
-
| ------------------------ | ----------------------------------------------------------------- |
|
|
157
|
-
| **orchestration** | Workflows, plays, runs, batches, tools, templates | `cargo-ai orchestration workflow list`, `cargo-ai orchestration run list --workflow-uuid <uuid>`
|
|
158
|
-
| **workspaceManagement** | Workspaces, users, tokens, roles, folders | `cargo-ai workspaceManagement workspaces list`, `cargo-ai workspaceManagement token list`
|
|
159
|
-
| **storage** | Datasets, models, relationships, runs, records | `cargo-ai storage dataset list`, `cargo-ai storage model list`
|
|
160
|
-
| **connection** | Connectors and integrations | `cargo-ai connection connector list`, `cargo-ai connection integration list`
|
|
161
|
-
| **billing** | Usage and subscription | `cargo-ai billing subscription get`, `cargo-ai billing usage get-metrics --payload '{"from":"2025-01-01","to":"2025-01-31"}'`
|
|
162
|
-
| **segmentation** | Segments and changes | `cargo-ai segmentation segment list`, `cargo-ai segmentation change list --payload '{}'`
|
|
163
|
-
| **revenue-organization** | Allocations, capacities, members, territories | `cargo-ai revenue-organization member list`, `cargo-ai revenue-organization territory list`
|
|
164
|
-
| **expression** | Recipes and expression evaluation | `cargo-ai expression recipe list`, `cargo-ai expression eval evaluate --payload '{}'`
|
|
165
|
-
| **system-of-record** | System of record, client, logs | `cargo-ai system-of-record sor list`, `cargo-ai system-of-record log list --payload '{}'`
|
|
166
|
-
| **user-management** | Current user (no workspace context) | `cargo-ai user-management user get-current`
|
|
167
|
-
| **ai** | AI templates, agents, releases, chats, MCP, files | `cargo-ai ai template list`, `cargo-ai ai agent list`, `cargo-ai ai file list`
|
|
168
|
-
| **context** | Context repository, runtime sandbox, and knowledge graph | `cargo-ai context repository get`, `cargo-ai context runtime browse --path <path>`, `cargo-ai context graph get`
|
|
169
|
-
| **hosting** | Cargo Hosting apps (Vite SPAs), workers, and deployments | `cargo-ai hosting app list`, `cargo-ai hosting worker list`, `cargo-ai hosting deployment list --payload '{}'`
|
|
170
|
-
| **mailboxManagement** | Owned sending mailboxes, threads, events, suppressions, pricing | `cargo-ai mailboxManagement mailbox list`, `cargo-ai mailboxManagement mailbox get-send-allowance <uuid>`
|
|
171
|
-
| **
|
|
155
|
+
| Domain | Description | Example commands |
|
|
156
|
+
| ------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
157
|
+
| **orchestration** | Workflows, plays, runs, batches, tools, templates | `cargo-ai orchestration workflow list`, `cargo-ai orchestration run list --workflow-uuid <uuid>` |
|
|
158
|
+
| **workspaceManagement** | Workspaces, users, tokens, roles, folders | `cargo-ai workspaceManagement workspaces list`, `cargo-ai workspaceManagement token list` |
|
|
159
|
+
| **storage** | Datasets, models, relationships, runs, records | `cargo-ai storage dataset list`, `cargo-ai storage model list` |
|
|
160
|
+
| **connection** | Connectors and integrations | `cargo-ai connection connector list`, `cargo-ai connection integration list` |
|
|
161
|
+
| **billing** | Usage and subscription | `cargo-ai billing subscription get`, `cargo-ai billing usage get-metrics --payload '{"from":"2025-01-01","to":"2025-01-31"}'` |
|
|
162
|
+
| **segmentation** | Segments and changes | `cargo-ai segmentation segment list`, `cargo-ai segmentation change list --payload '{}'` |
|
|
163
|
+
| **revenue-organization** | Allocations, capacities, members, territories | `cargo-ai revenue-organization member list`, `cargo-ai revenue-organization territory list` |
|
|
164
|
+
| **expression** | Recipes and expression evaluation | `cargo-ai expression recipe list`, `cargo-ai expression eval evaluate --payload '{}'` |
|
|
165
|
+
| **system-of-record** | System of record, client, logs | `cargo-ai system-of-record sor list`, `cargo-ai system-of-record log list --payload '{}'` |
|
|
166
|
+
| **user-management** | Current user (no workspace context) | `cargo-ai user-management user get-current` |
|
|
167
|
+
| **ai** | AI templates, agents, releases, chats, MCP, files | `cargo-ai ai template list`, `cargo-ai ai agent list`, `cargo-ai ai file list` |
|
|
168
|
+
| **context** | Context repository, runtime sandbox, and knowledge graph | `cargo-ai context repository get`, `cargo-ai context runtime browse --path <path>`, `cargo-ai context graph get` |
|
|
169
|
+
| **hosting** | Cargo Hosting apps (Vite SPAs), workers, and deployments | `cargo-ai hosting app list`, `cargo-ai hosting worker list`, `cargo-ai hosting deployment list --payload '{}'` |
|
|
170
|
+
| **mailboxManagement** | Owned sending mailboxes, threads, events, suppressions, pricing | `cargo-ai mailboxManagement mailbox list`, `cargo-ai mailboxManagement mailbox get-send-allowance <uuid>` |
|
|
171
|
+
| **project** | Declarative IaC: define resources in code, deploy, generate types | `cargo-ai project init <dir>`, `cargo-ai project types`, `cargo-ai project plan`, `cargo-ai project deploy` (`cdk` is an alias) |
|
|
172
172
|
|
|
173
173
|
Commands that accept complex payloads use a `--payload <json>` option (e.g. `cargo-ai orchestration play create --payload '{"name":"My Play",...}'`). Use `--help` on any subcommand for options.
|
|
174
174
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/chat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAyI7E"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AiUtils } from "@cargo-ai/types";
|
|
1
2
|
import { handleApiCall, outputJson, parseJson } from "../runHandler.js";
|
|
2
3
|
export function registerChatCommands(parent, getApi) {
|
|
3
4
|
const chat = parent
|
|
@@ -41,7 +42,7 @@ export function registerChatCommands(parent, getApi) {
|
|
|
41
42
|
.option("--name <name>", "Chat name (string)")
|
|
42
43
|
.option("--agent-uuid <uuid>", "Agent UUID to associate with (string)")
|
|
43
44
|
.option("--release-uuid <uuid>", "Release UUID to pin to (string)")
|
|
44
|
-
.option("--harness-slug <slug>",
|
|
45
|
+
.option("--harness-slug <slug>", `Coding-agent runtime: ${AiUtils.harnessSlugs.join(", ")}. When omitted, later turns use the agent's pinned release, if any.`)
|
|
45
46
|
.option("--repository <json>", "Git workspace for a coding harness (JSON object: connectorUuid, repository as owner/name, defaultBranch, rootDirectory, env)")
|
|
46
47
|
.addHelpText("after", `
|
|
47
48
|
Examples:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/message.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/message.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAoCxC,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAmTN"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AiUtils } from "@cargo-ai/types";
|
|
1
2
|
import { parseBooleanOption } from "../../utils/booleanOption.js";
|
|
2
3
|
import { loadCompiledAgent, resolveCompiledAgentFromState, } from "../../utils/loadCompiledAgent.js";
|
|
3
4
|
import { ExitCodes, failWith, handleApiCall, info, outputJson, parseJson, pollUntilFinished, } from "../runHandler.js";
|
|
@@ -27,7 +28,7 @@ export function registerMessageCommands(parent, getApi) {
|
|
|
27
28
|
.option("--integration-slug <slug>", "Integration slug (string)")
|
|
28
29
|
.option("--connector-uuid <uuid>", "Connector UUID (string)")
|
|
29
30
|
.option("--language-model-slug <slug>", "Language model slug (string)")
|
|
30
|
-
.option("--harness-slug <slug>",
|
|
31
|
+
.option("--harness-slug <slug>", `Coding-agent runtime: ${AiUtils.harnessSlugs.join(", ")}. When omitted, later turns use the agent's pinned release, if any.`)
|
|
31
32
|
.option("--repository <json>", "Git workspace for a coding harness (JSON object: connectorUuid, repository as owner/name, defaultBranch, rootDirectory, env)")
|
|
32
33
|
.option("--output <json>", 'Output format for the assistant message (JSON object, e.g. \'{"type":"text"}\' or \'{"type":"jsonSchema","jsonSchema":{...}}\'). Defaults to text when omitted.')
|
|
33
34
|
.option("--wait-until-finished [true|false]", "Poll the assistant message until finished before returning (defaults to true when passed bare)", parseBooleanOption)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/release.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../src/commands/ai/release.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAIxC,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAoVN"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AiUtils } from "@cargo-ai/types";
|
|
1
2
|
import { parseBooleanOption } from "../../utils/booleanOption.js";
|
|
2
3
|
import { handleApiCall, outputJson, parseJson } from "../runHandler.js";
|
|
3
4
|
export function registerReleaseCommands(parent, getApi) {
|
|
@@ -63,7 +64,7 @@ export function registerReleaseCommands(parent, getApi) {
|
|
|
63
64
|
.option("--integration-slug <slug>", "LLM integration slug (string)")
|
|
64
65
|
.option("--connector-uuid <uuid>", "Connector UUID (string)")
|
|
65
66
|
.option("--language-model-slug <slug>", "Language model slug (string)")
|
|
66
|
-
.option("--harness-slug <slug>",
|
|
67
|
+
.option("--harness-slug <slug>", `Coding-agent runtime: ${AiUtils.harnessSlugs.join(", ")}.`)
|
|
67
68
|
.option("--repository <json>", "Git workspace for a coding harness (JSON object: connectorUuid, repository as owner/name, defaultBranch, rootDirectory, env)")
|
|
68
69
|
.option("--actions <json>", "Actions configuration (JSON array of action objects)")
|
|
69
70
|
.option("--mcp-clients <json>", "MCP clients configuration (JSON array of MCP client objects)")
|
|
@@ -126,9 +127,9 @@ Set "isReadOnly": false on a model resource to grant the agent write tools (inse
|
|
|
126
127
|
.command("deploy-draft")
|
|
127
128
|
.description("Deploy the draft release to production")
|
|
128
129
|
.requiredOption("--agent-uuid <uuid>", "Agent UUID (string, required)")
|
|
129
|
-
.option("--integration-slug <slug>", "LLM integration slug (string)
|
|
130
|
-
.option("--language-model-slug <slug>", "Language model slug (string)
|
|
131
|
-
.option("--harness-slug <slug>",
|
|
130
|
+
.option("--integration-slug <slug>", "LLM integration slug (string)")
|
|
131
|
+
.option("--language-model-slug <slug>", "Language model slug (string)")
|
|
132
|
+
.option("--harness-slug <slug>", `Coding-agent runtime: ${AiUtils.harnessSlugs.join(", ")}.`)
|
|
132
133
|
.option("--repository <json>", "Git workspace for a coding harness (JSON object: connectorUuid, repository as owner/name, defaultBranch, rootDirectory, env)")
|
|
133
134
|
.option("--version <version>", "Semver release version, e.g. 1.0.0 (string, auto-incremented if omitted)")
|
|
134
135
|
.requiredOption("--actions <json>", "Actions configuration (JSON array of action objects, required)")
|
|
@@ -152,12 +153,12 @@ Examples:
|
|
|
152
153
|
|
|
153
154
|
$ cargo-ai ai release deploy-draft --agent-uuid <uuid> \\
|
|
154
155
|
--harness-slug claudeCode \\
|
|
156
|
+
--integration-slug anthropic --language-model-slug claude-sonnet-5 \\
|
|
155
157
|
--repository '{"connectorUuid":"<github-uuid>","repository":"acme/app"}' \\
|
|
156
158
|
--actions '[]' --mcp-clients '[]' --resources '[]' \\
|
|
157
159
|
--capabilities '[]' --suggested-actions '[]'
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
--harness-slug claudeCode agent does not — those flags are unused.`)
|
|
161
|
+
`)
|
|
161
162
|
.action(async (opts) => {
|
|
162
163
|
const api = getApi();
|
|
163
164
|
const result = await handleApiCall(() => api.ai.release.deployDraft({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function isAutoApproved(toolName: string, options?: {
|
|
2
|
+
unattended?: boolean;
|
|
3
|
+
}): boolean;
|
|
4
|
+
export declare const DENIED_TOOL_REASON = "Spawning a subagent is not available in this session. Do the work in this turn instead, asking for each tool you need.";
|
|
5
|
+
/** Exported for tests. */
|
|
6
|
+
export declare function isAlwaysDenied(toolName: string): boolean;
|
|
7
|
+
//# sourceMappingURL=approvals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/approvals.ts"],"names":[],"mappings":"AA2CA,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CA2BT;AAqBD,eAAO,MAAM,kBAAkB,2HAC2F,CAAC;AAE3H,0BAA0B;AAC1B,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { CARGO_MCP_SERVER_NAME } from "./mcp.js";
|
|
2
|
+
import { CARGO_AGENT_MCP_NAME_PREFIX } from "./release.js";
|
|
3
|
+
/**
|
|
4
|
+
* Claude Code's own bookkeeping. `allow-reads` classifies these as edits
|
|
5
|
+
* because they call a write-shaped tool, but they touch nothing outside the
|
|
6
|
+
* session — prompting for a todo-list update is noise, and Claude Code
|
|
7
|
+
* rewrites its list on every step of any multi-step task.
|
|
8
|
+
*/
|
|
9
|
+
const AUTO_APPROVED_TOOL_NAMES = new Set([
|
|
10
|
+
"TodoWrite",
|
|
11
|
+
"EnterPlanMode",
|
|
12
|
+
"ExitPlanMode",
|
|
13
|
+
"TaskCreate",
|
|
14
|
+
"TaskUpdate",
|
|
15
|
+
"TaskStop",
|
|
16
|
+
"AskUserQuestion",
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Cargo's MCP tools run unattended in an interactive session, `execute_action`
|
|
20
|
+
* included: a turn can spend credits and write to a connected system on its
|
|
21
|
+
* own. That is the deliberate trade for a chat that answers without being
|
|
22
|
+
* nursed, and it is defensible only because this server reaches the workspace
|
|
23
|
+
* with the user's own credentials — it can do nothing they could not do from
|
|
24
|
+
* the CLI. `--print` is the exception: there is nobody to approve, so mutating
|
|
25
|
+
* workspace tools are denied there.
|
|
26
|
+
*
|
|
27
|
+
* Only this server's tools. Claude Code names them `mcp__<server>__<tool>`,
|
|
28
|
+
* and matching the bare `mcp__` was safe only while Ask owned the config
|
|
29
|
+
* directory: `CLAUDE_CONFIG_DIR` reinstates the user's own MCP servers, whose
|
|
30
|
+
* tools write and shell out with none of the above reasoning behind them.
|
|
31
|
+
* Those go through approval like anything else that touches the machine.
|
|
32
|
+
*
|
|
33
|
+
* Built from the mount key so renaming the server cannot silently widen this.
|
|
34
|
+
*/
|
|
35
|
+
const CARGO_MCP_TOOL_PREFIX = `mcp__${CARGO_MCP_SERVER_NAME}__`;
|
|
36
|
+
const CARGO_AGENT_MCP_TOOL_PREFIX = `mcp__${CARGO_AGENT_MCP_NAME_PREFIX}`;
|
|
37
|
+
const CARGO_EXECUTE_ACTION_TOOL = `${CARGO_MCP_TOOL_PREFIX}execute_action`;
|
|
38
|
+
const CARGO_EXECUTE_ACTION_BATCH_TOOL = `${CARGO_MCP_TOOL_PREFIX}execute_action_batch`;
|
|
39
|
+
export function isAutoApproved(toolName, options) {
|
|
40
|
+
const unattended = options === undefined ? false : options.unattended === true;
|
|
41
|
+
if (unattended === true) {
|
|
42
|
+
if (toolName === CARGO_EXECUTE_ACTION_TOOL) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (toolName === CARGO_EXECUTE_ACTION_BATCH_TOOL) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (toolName.startsWith(CARGO_AGENT_MCP_TOOL_PREFIX) === true) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (toolName.startsWith(CARGO_MCP_TOOL_PREFIX) === true) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (toolName.startsWith(CARGO_AGENT_MCP_TOOL_PREFIX) === true) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return AUTO_APPROVED_TOOL_NAMES.has(toolName);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `Agent` spawns a subagent to run a task of its own, and approving one is a
|
|
62
|
+
* different kind of decision from approving a `Bash`: the subagent runs its
|
|
63
|
+
* own tools, can be asked for with `mode: "bypassPermissions"`, and whether
|
|
64
|
+
* its calls come back here for individual approval is not something we control
|
|
65
|
+
* or currently know.
|
|
66
|
+
*
|
|
67
|
+
* The refusal that actually stops it is in `claudeConfig.ts`, as a deny rule
|
|
68
|
+
* in Claude Code's own settings — this never fired, because the approval
|
|
69
|
+
* request it waits for is never sent. The bridge writes `ask` rules only for
|
|
70
|
+
* the tools in its `NATIVE_TOOL_KINDS` map, the subagent tools are not in it,
|
|
71
|
+
* and so `allow-reads` left them running unattended.
|
|
72
|
+
*
|
|
73
|
+
* Kept as the second line: a user who points `CLAUDE_CONFIG_DIR` at their own
|
|
74
|
+
* Claude Code config gets no deny rule written for them, and a future bridge
|
|
75
|
+
* that does surface the approval should find an answer waiting.
|
|
76
|
+
*/
|
|
77
|
+
const DENIED_TOOL_NAMES = new Set(["Agent", "Task"]);
|
|
78
|
+
export const DENIED_TOOL_REASON = "Spawning a subagent is not available in this session. Do the work in this turn instead, asking for each tool you need.";
|
|
79
|
+
/** Exported for tests. */
|
|
80
|
+
export function isAlwaysDenied(toolName) {
|
|
81
|
+
return DENIED_TOOL_NAMES.has(toolName);
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/artifacts.ts"],"names":[],"mappings":"AAwBA,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI,CAGzE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeConfig.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/claudeConfig.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Ai } from "@cargo-ai/api";
|
|
2
|
+
import type { Api } from "../../../api.js";
|
|
3
|
+
import { type LocalStreamOptions } from "./turn.js";
|
|
4
|
+
export type LocalHarness = {
|
|
5
|
+
streamPrompt: (question: string, options?: LocalStreamOptions) => Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* When a turn last reached Anthropic, or undefined if none has. The proxy
|
|
8
|
+
* token re-arms on every call it makes, so this — not the mint time — is
|
|
9
|
+
* what its real expiry runs from.
|
|
10
|
+
*/
|
|
11
|
+
proxyLastUsedAtMs: () => number | undefined;
|
|
12
|
+
/** Stops Claude Code and its bridge; the session is not resumable. */
|
|
13
|
+
close: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export declare function createLocalHarness(input: {
|
|
16
|
+
api: Api;
|
|
17
|
+
/**
|
|
18
|
+
* Cargo API origin (`config.baseUrl`). The Anthropic proxy is mounted on
|
|
19
|
+
* the API as `/sandbox/anthropic` — same host the backend uses via
|
|
20
|
+
* `config.app.url` (which is the API URL, not the web app).
|
|
21
|
+
*/
|
|
22
|
+
apiBaseUrl: string;
|
|
23
|
+
dir: string;
|
|
24
|
+
chatUuid: string;
|
|
25
|
+
agentUuid?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Deployed release of the selected agent. Applied the way `/stream` applies
|
|
28
|
+
* a harness agent's release: prompt, actions, resources, MCP, capabilities.
|
|
29
|
+
* Does not change the local harness or --dir.
|
|
30
|
+
*/
|
|
31
|
+
release?: Ai.Release;
|
|
32
|
+
proxyToken: string;
|
|
33
|
+
/**
|
|
34
|
+
* Connector the mint picked for this session, plus the integration and
|
|
35
|
+
* model it resolved. Sent with ingest so usage is attributed to the same
|
|
36
|
+
* provider the proxy spent against — not reconstructed from the harness slug.
|
|
37
|
+
*/
|
|
38
|
+
connectorUuid: string;
|
|
39
|
+
integrationSlug: string;
|
|
40
|
+
languageModelSlug: string;
|
|
41
|
+
/**
|
|
42
|
+
* Earlier turns of this chat, from `loadChatHistoryPreamble`. The session is
|
|
43
|
+
* always new, so this is the only thing that carries a `--continue` chat
|
|
44
|
+
* across CLI runs.
|
|
45
|
+
*/
|
|
46
|
+
history?: string;
|
|
47
|
+
/**
|
|
48
|
+
* The id the caller claimed the chat with. Sent with the ingest so recording
|
|
49
|
+
* a turn releases this session's claim and not one taken after it.
|
|
50
|
+
*/
|
|
51
|
+
turnOwnerId?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Interactive Ask can run host tools and custom agent MCP unattended.
|
|
54
|
+
* `--print` cannot: nobody is there to approve, and host tools never
|
|
55
|
+
* prompt under `allow-reads`.
|
|
56
|
+
*/
|
|
57
|
+
allowWorkspaceMutations: boolean;
|
|
58
|
+
}): Promise<LocalHarness>;
|
|
59
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAmB3C,OAAO,EAGL,KAAK,kBAAkB,EAKxB,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAcF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,YAAY,CAAC,CA4SxB"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { HarnessAgent } from "@ai-sdk/harness/agent";
|
|
2
|
+
import { createClaudeCode } from "@ai-sdk/harness-claude-code";
|
|
3
|
+
import { createLocalSandbox } from "ai-sdk-sandbox-local";
|
|
4
|
+
import { pruneHarnessArtifacts } from "./artifacts.js";
|
|
5
|
+
import { askClaudeConfigDir } from "./claudeConfig.js";
|
|
6
|
+
import { ingestTurn } from "./ingest.js";
|
|
7
|
+
import { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
|
|
8
|
+
import { resolveWorkspaceLayout } from "./layout.js";
|
|
9
|
+
import { CARGO_MCP_SERVER_NAME, cargoMcpServer } from "./mcp.js";
|
|
10
|
+
import { ensureHarnessPnpmOnPath } from "./pnpmShim.js";
|
|
11
|
+
import { buildReleaseHostTools, buildReleaseMcpServers } from "./release.js";
|
|
12
|
+
import { withGetPortEndpoint } from "./sandbox.js";
|
|
13
|
+
import { ASK_TIMING_ENABLED, createPhaseLog, reportHarnessDiagnostic, timeStreamParts, } from "./timing.js";
|
|
14
|
+
import { HarnessTurnStuck, runPromptTurn, settleWithin, } from "./turn.js";
|
|
15
|
+
import { createTurnAccumulator, didReachAnthropic } from "./usage.js";
|
|
16
|
+
/**
|
|
17
|
+
* How long teardown may take before the session is abandoned. Short, because
|
|
18
|
+
* the caller is usually someone who just pressed Ctrl-C.
|
|
19
|
+
*/
|
|
20
|
+
const SESSION_DESTROY_TIMEOUT_MS = 5_000;
|
|
21
|
+
/**
|
|
22
|
+
* How long winding down a previous unfinished turn may take before it is cut
|
|
23
|
+
* off and the question refused.
|
|
24
|
+
*/
|
|
25
|
+
const TURN_DRAIN_TIMEOUT_MS = 30_000;
|
|
26
|
+
export async function createLocalHarness(input) {
|
|
27
|
+
const setupPhase = createPhaseLog("setup");
|
|
28
|
+
// Claude Code bootstrap shells out to `pnpm`; Volta often has a dead shim
|
|
29
|
+
// and pnpm 9 refuses this npm packageManager root — put pnpm@10 first.
|
|
30
|
+
ensureHarnessPnpmOnPath();
|
|
31
|
+
setupPhase("pnpm shim written to PATH");
|
|
32
|
+
const workspace = resolveWorkspaceLayout(input.dir);
|
|
33
|
+
pruneHarnessArtifacts(workspace.sandboxCwd);
|
|
34
|
+
// Earlier versions rooted the sandbox at the project, so its artifacts are
|
|
35
|
+
// still in there to collect.
|
|
36
|
+
if (workspace.sandboxCwd !== input.dir) {
|
|
37
|
+
pruneHarnessArtifacts(input.dir);
|
|
38
|
+
}
|
|
39
|
+
setupPhase("stale harness artifacts pruned");
|
|
40
|
+
const anthropicBaseUrl = `${input.apiBaseUrl.replace(/\/$/, "")}/sandbox/anthropic`;
|
|
41
|
+
const release = input.release;
|
|
42
|
+
const hostTools = input.allowWorkspaceMutations === false || release === undefined
|
|
43
|
+
? {}
|
|
44
|
+
: buildReleaseHostTools(input.api, release.actions);
|
|
45
|
+
const mcpServers = {
|
|
46
|
+
[CARGO_MCP_SERVER_NAME]: cargoMcpServer(input.apiBaseUrl),
|
|
47
|
+
};
|
|
48
|
+
if (release !== undefined && input.allowWorkspaceMutations === true) {
|
|
49
|
+
const extra = buildReleaseMcpServers(release.mcpClients);
|
|
50
|
+
for (const [name, server] of Object.entries(extra)) {
|
|
51
|
+
mcpServers[name] = server;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const harnessAgent = new HarnessAgent({
|
|
55
|
+
// Pin auth the same way the backend harness stream does. Credentials go
|
|
56
|
+
// through `auth`, not `env`: passing them via `env` alone lets
|
|
57
|
+
// createClaudeCode auto-detect AI Gateway from the host process and ignore
|
|
58
|
+
// the Cargo proxy.
|
|
59
|
+
harness: createClaudeCode({
|
|
60
|
+
auth: {
|
|
61
|
+
ANTHROPIC_BASE_URL: anthropicBaseUrl,
|
|
62
|
+
ANTHROPIC_API_KEY: input.proxyToken,
|
|
63
|
+
},
|
|
64
|
+
env: { CLAUDE_CONFIG_DIR: askClaudeConfigDir() },
|
|
65
|
+
mcpServers,
|
|
66
|
+
}),
|
|
67
|
+
id: "cargo-ai-ask",
|
|
68
|
+
sandbox: withGetPortEndpoint(createLocalSandbox({ cwd: workspace.sandboxCwd })),
|
|
69
|
+
sandboxConfig: workspace.workDir === undefined ? {} : { workDir: workspace.workDir },
|
|
70
|
+
instructions: localHarnessInstructions(input.dir, release),
|
|
71
|
+
skills: localHarnessSkills(input.dir),
|
|
72
|
+
model: input.languageModelSlug,
|
|
73
|
+
// Nested @ai-sdk/harness ships its own @ai-sdk/provider-utils, so its
|
|
74
|
+
// ToolSet does not unify with this package's. Runtime shape is the same.
|
|
75
|
+
tools: hostTools,
|
|
76
|
+
permissionMode: "allow-reads",
|
|
77
|
+
...(ASK_TIMING_ENABLED === false
|
|
78
|
+
? {}
|
|
79
|
+
: { debug: { enabled: true }, onLog: reportHarnessDiagnostic }),
|
|
80
|
+
});
|
|
81
|
+
setupPhase("harness agent constructed");
|
|
82
|
+
// Local sandbox cannot broker credentials via request transforms; the
|
|
83
|
+
// harness always warns. Keep that off the Ask tree (stderr mid-reply).
|
|
84
|
+
const session = await withMutedCredentialBrokerWarning(() => harnessAgent.createSession());
|
|
85
|
+
setupPhase("harness session created");
|
|
86
|
+
// Consumed by the first prompt: this session has never seen the chat, so it
|
|
87
|
+
// is told the story once rather than on every question.
|
|
88
|
+
let pendingHistory = input.history;
|
|
89
|
+
let proxyLastUsedAtMs;
|
|
90
|
+
// Approvals the previous turn asked about and never answered — a turn
|
|
91
|
+
// cancelled at the confirmation prompt leaves one here.
|
|
92
|
+
const unanswered = [];
|
|
93
|
+
return {
|
|
94
|
+
streamPrompt: async (question, options) => {
|
|
95
|
+
const turnPhase = createPhaseLog("turn ");
|
|
96
|
+
turnPhase("prompt submitted");
|
|
97
|
+
const abortSignal = options === undefined ? undefined : options.abortSignal;
|
|
98
|
+
// The turn is stored and shown as the user wrote it; only what Claude
|
|
99
|
+
// Code is asked carries the replayed history.
|
|
100
|
+
const prompt = pendingHistory === undefined
|
|
101
|
+
? question
|
|
102
|
+
: `${pendingHistory}\n\n${question}`;
|
|
103
|
+
// A cancelled turn stays unfinished, and the harness refuses a new
|
|
104
|
+
// prompt until it is drained. Do that here rather than making the next
|
|
105
|
+
// question fail with "must be continued before accepting a new prompt".
|
|
106
|
+
if (session.hasUnfinishedTurn() === true) {
|
|
107
|
+
// Anything the last turn asked about and never got an answer for is
|
|
108
|
+
// denied. Draining with no continuations leaves the runtime waiting
|
|
109
|
+
// on a response that is never coming, and the honest reading of a
|
|
110
|
+
// user who walked away from the prompt is "no" — carrying the
|
|
111
|
+
// question into a turn they did not ask for would be worse.
|
|
112
|
+
const denials = unanswered.map((approval) => ({
|
|
113
|
+
approvalResponse: {
|
|
114
|
+
type: "tool-approval-response",
|
|
115
|
+
approvalId: approval.approvalId,
|
|
116
|
+
approved: false,
|
|
117
|
+
},
|
|
118
|
+
toolCall: {
|
|
119
|
+
type: "tool-call",
|
|
120
|
+
toolCallId: approval.toolCallId,
|
|
121
|
+
toolName: approval.toolName,
|
|
122
|
+
input: approval.input,
|
|
123
|
+
},
|
|
124
|
+
}));
|
|
125
|
+
unanswered.length = 0;
|
|
126
|
+
// The drain gets its own controller so the timeout can stop it rather
|
|
127
|
+
// than walk away from it. Nothing watches this call the way the stall
|
|
128
|
+
// watchdog watches a turn's stream, so a runtime that never settles
|
|
129
|
+
// would otherwise hang the question just asked — but abandoning the
|
|
130
|
+
// promise and carrying on is no better: `continueGenerate` keeps
|
|
131
|
+
// running, and submitting the new prompt to the same session races the
|
|
132
|
+
// turn we failed to wind down. Chained to the turn's signal so ctrl-c
|
|
133
|
+
// still gets out of it.
|
|
134
|
+
const drain = new AbortController();
|
|
135
|
+
const abortDrain = () => drain.abort();
|
|
136
|
+
if (abortSignal !== undefined) {
|
|
137
|
+
if (abortSignal.aborted === true) {
|
|
138
|
+
drain.abort();
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
abortSignal.addEventListener("abort", abortDrain, { once: true });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const drainTimer = setTimeout(abortDrain, TURN_DRAIN_TIMEOUT_MS);
|
|
145
|
+
try {
|
|
146
|
+
await harnessAgent.continueGenerate({
|
|
147
|
+
session,
|
|
148
|
+
toolApprovalContinuations: denials,
|
|
149
|
+
abortSignal: drain.signal,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Whether it failed or was cut off, the session itself is the only
|
|
154
|
+
// thing that can say if a new prompt is allowed.
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
clearTimeout(drainTimer);
|
|
158
|
+
if (abortSignal !== undefined) {
|
|
159
|
+
abortSignal.removeEventListener("abort", abortDrain);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (session.hasUnfinishedTurn() === true) {
|
|
163
|
+
throw new HarnessTurnStuck();
|
|
164
|
+
}
|
|
165
|
+
turnPhase("unfinished previous turn drained");
|
|
166
|
+
}
|
|
167
|
+
const accumulator = createTurnAccumulator();
|
|
168
|
+
let answer;
|
|
169
|
+
try {
|
|
170
|
+
answer = await runPromptTurn({
|
|
171
|
+
driver: {
|
|
172
|
+
start: async () => {
|
|
173
|
+
turnPhase("harness stream() called");
|
|
174
|
+
const stream = (await harnessAgent.stream({
|
|
175
|
+
prompt,
|
|
176
|
+
session,
|
|
177
|
+
abortSignal,
|
|
178
|
+
}));
|
|
179
|
+
turnPhase("harness stream() returned");
|
|
180
|
+
// The prompt is in the session now, so the replayed history has
|
|
181
|
+
// been told. Cleared here rather than before submitting: a turn
|
|
182
|
+
// that never reached the harness must keep it for the retry, or
|
|
183
|
+
// a cancelled first question would leave every later one in this
|
|
184
|
+
// process without the earlier conversation.
|
|
185
|
+
pendingHistory = undefined;
|
|
186
|
+
return timeStreamParts(stream, turnPhase);
|
|
187
|
+
},
|
|
188
|
+
continueWithApprovals: async (continuations) => {
|
|
189
|
+
turnPhase("harness continueStream() called");
|
|
190
|
+
const stream = (await harnessAgent.continueStream({
|
|
191
|
+
session,
|
|
192
|
+
toolApprovalContinuations: continuations,
|
|
193
|
+
abortSignal,
|
|
194
|
+
}));
|
|
195
|
+
turnPhase("harness continueStream() returned");
|
|
196
|
+
return timeStreamParts(stream, turnPhase);
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
handlers: options,
|
|
200
|
+
accumulator,
|
|
201
|
+
unanswered,
|
|
202
|
+
// Interrupt Claude Code through the turn's abort signal so the
|
|
203
|
+
// bridge stops cleanly. Without this the host walks away from the
|
|
204
|
+
// stream and teardown looks like "bridge closed before the turn
|
|
205
|
+
// finished" rather than an intentional stop.
|
|
206
|
+
onStall: options === undefined ? undefined : options.onStall,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
// Cancelled or failed after Claude Code already spent tokens. Record
|
|
211
|
+
// what it spent, then let the caller handle the failure.
|
|
212
|
+
if (didReachAnthropic(accumulator.usage) === true) {
|
|
213
|
+
proxyLastUsedAtMs = Date.now();
|
|
214
|
+
}
|
|
215
|
+
await ingestTurn({
|
|
216
|
+
api: input.api,
|
|
217
|
+
chatUuid: input.chatUuid,
|
|
218
|
+
agentUuid: input.agentUuid,
|
|
219
|
+
connectorUuid: input.connectorUuid,
|
|
220
|
+
integrationSlug: input.integrationSlug,
|
|
221
|
+
languageModelSlug: input.languageModelSlug,
|
|
222
|
+
question,
|
|
223
|
+
answer: accumulator.chunks.join(""),
|
|
224
|
+
usage: accumulator.usage,
|
|
225
|
+
// Whatever it managed to say is a fragment, not the answer. Stored
|
|
226
|
+
// as cancelled so a later session does not replay it as work done.
|
|
227
|
+
cancelled: true,
|
|
228
|
+
turnOwnerId: input.turnOwnerId,
|
|
229
|
+
onNotice: options === undefined ? undefined : options.onNotice,
|
|
230
|
+
});
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
if (didReachAnthropic(accumulator.usage) === true) {
|
|
234
|
+
proxyLastUsedAtMs = Date.now();
|
|
235
|
+
}
|
|
236
|
+
// A turn that spent tokens or edited files is recorded even when it
|
|
237
|
+
// produced no prose, so history and billing match what actually ran.
|
|
238
|
+
await ingestTurn({
|
|
239
|
+
api: input.api,
|
|
240
|
+
chatUuid: input.chatUuid,
|
|
241
|
+
agentUuid: input.agentUuid,
|
|
242
|
+
connectorUuid: input.connectorUuid,
|
|
243
|
+
integrationSlug: input.integrationSlug,
|
|
244
|
+
languageModelSlug: input.languageModelSlug,
|
|
245
|
+
question,
|
|
246
|
+
answer,
|
|
247
|
+
usage: accumulator.usage,
|
|
248
|
+
turnOwnerId: input.turnOwnerId,
|
|
249
|
+
onNotice: options === undefined ? undefined : options.onNotice,
|
|
250
|
+
});
|
|
251
|
+
// Nothing said and nothing spent means the harness never reached
|
|
252
|
+
// Anthropic — a misconfigured proxy rather than a quiet tool-only turn.
|
|
253
|
+
// Same predicate `ingestTurn` uses, so a turn that reached Anthropic
|
|
254
|
+
// is never also reported as unreachable.
|
|
255
|
+
if (answer.length === 0 &&
|
|
256
|
+
didReachAnthropic(accumulator.usage) === false) {
|
|
257
|
+
throw new Error(`Local Claude Code returned no text. The harness called ${anthropicBaseUrl} with the minted proxy token — confirm CARGO_BASE_URL points at your API and that /sandbox/anthropic is reachable.`);
|
|
258
|
+
}
|
|
259
|
+
return answer;
|
|
260
|
+
},
|
|
261
|
+
proxyLastUsedAtMs: () => proxyLastUsedAtMs,
|
|
262
|
+
close: async () => {
|
|
263
|
+
// `detach` would leave the bridge and Claude Code running for a resume
|
|
264
|
+
// that never comes, which is how orphaned bridges piled up. Nothing here
|
|
265
|
+
// is resumable by design, so take the runtime down with the session.
|
|
266
|
+
//
|
|
267
|
+
// Bounded, because Ctrl-C at the prompt now unwinds through here: a
|
|
268
|
+
// destroy that never settles would turn "stop" into a hang, which is
|
|
269
|
+
// what pressing it was meant to escape. Giving up can leave the orphan
|
|
270
|
+
// this call exists to prevent, but a teardown already stuck is no more
|
|
271
|
+
// likely to finish while the user waits on it.
|
|
272
|
+
await settleWithin(session.destroy().catch(() => undefined), SESSION_DESTROY_TIMEOUT_MS);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
async function withMutedCredentialBrokerWarning(run) {
|
|
277
|
+
const originalWarn = console.warn;
|
|
278
|
+
console.warn = (...args) => {
|
|
279
|
+
const first = args[0];
|
|
280
|
+
if (typeof first === "string" &&
|
|
281
|
+
first.includes("credential brokering does not work")) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
originalWarn.apply(console, args);
|
|
285
|
+
};
|
|
286
|
+
try {
|
|
287
|
+
return await run();
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
console.warn = originalWarn;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
|
|
2
|
+
export { createLocalHarness, type LocalHarness } from "./create.js";
|
|
3
|
+
export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
|
|
4
|
+
export { resolveWorkspaceLayout } from "./layout.js";
|
|
5
|
+
export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
|
|
6
|
+
export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, type LocalStreamHandlers, type LocalStreamOptions, type LocalToolActivity, type LocalToolApproval, runPromptTurn, settleWithin, type StreamLike, type TurnDriver, } from "./turn.js";
|
|
7
|
+
export { createTurnAccumulator, type LocalTurnAccumulator, type LocalTurnUsage, readClaudeCodeCostUsd, } from "./usage.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
|
|
2
|
+
export { createLocalHarness } from "./create.js";
|
|
3
|
+
export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
|
|
4
|
+
export { resolveWorkspaceLayout } from "./layout.js";
|
|
5
|
+
export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
|
|
6
|
+
export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, runPromptTurn, settleWithin, } from "./turn.js";
|
|
7
|
+
export { createTurnAccumulator, readClaudeCodeCostUsd, } from "./usage.js";
|