@cargo-ai/cli 1.0.94 → 1.0.96
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/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 +81 -0
- package/build/commands/ask/harness/artifacts.d.ts.map +1 -0
- package/build/commands/ask/harness/askUserQuestion.d.ts +69 -0
- package/build/commands/ask/harness/askUserQuestion.d.ts.map +1 -0
- package/build/commands/ask/harness/askUserQuestion.js +218 -0
- package/build/commands/ask/harness/claudeConfig.d.ts.map +1 -0
- package/build/commands/ask/{claudeConfig.js → harness/claudeConfig.js} +28 -13
- 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 +314 -0
- package/build/commands/ask/harness/index.d.ts +9 -0
- package/build/commands/ask/harness/index.d.ts.map +1 -0
- package/build/commands/ask/harness/index.js +8 -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 +43 -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 +152 -0
- package/build/commands/ask/harness/turn.d.ts.map +1 -0
- package/build/commands/ask/harness/turn.js +676 -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} +1 -1
- 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 +846 -0
- package/build/commands/ask/session/thinking.d.ts.map +1 -0
- package/build/commands/ask/session/tree.d.ts +99 -0
- package/build/commands/ask/session/tree.d.ts.map +1 -0
- package/build/commands/ask/session/tree.js +356 -0
- 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/{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
|
@@ -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":"AA0CA,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,81 @@
|
|
|
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
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Cargo's MCP tools run unattended in an interactive session, `execute_action`
|
|
19
|
+
* included: a turn can spend credits and write to a connected system on its
|
|
20
|
+
* own. That is the deliberate trade for a chat that answers without being
|
|
21
|
+
* nursed, and it is defensible only because this server reaches the workspace
|
|
22
|
+
* with the user's own credentials — it can do nothing they could not do from
|
|
23
|
+
* the CLI. `--print` is the exception: there is nobody to approve, so mutating
|
|
24
|
+
* workspace tools are denied there.
|
|
25
|
+
*
|
|
26
|
+
* Only this server's tools. Claude Code names them `mcp__<server>__<tool>`,
|
|
27
|
+
* and matching the bare `mcp__` was safe only while Ask owned the config
|
|
28
|
+
* directory: `CLAUDE_CONFIG_DIR` reinstates the user's own MCP servers, whose
|
|
29
|
+
* tools write and shell out with none of the above reasoning behind them.
|
|
30
|
+
* Those go through approval like anything else that touches the machine.
|
|
31
|
+
*
|
|
32
|
+
* Built from the mount key so renaming the server cannot silently widen this.
|
|
33
|
+
*/
|
|
34
|
+
const CARGO_MCP_TOOL_PREFIX = `mcp__${CARGO_MCP_SERVER_NAME}__`;
|
|
35
|
+
const CARGO_AGENT_MCP_TOOL_PREFIX = `mcp__${CARGO_AGENT_MCP_NAME_PREFIX}`;
|
|
36
|
+
const CARGO_EXECUTE_ACTION_TOOL = `${CARGO_MCP_TOOL_PREFIX}execute_action`;
|
|
37
|
+
const CARGO_EXECUTE_ACTION_BATCH_TOOL = `${CARGO_MCP_TOOL_PREFIX}execute_action_batch`;
|
|
38
|
+
export function isAutoApproved(toolName, options) {
|
|
39
|
+
const unattended = options === undefined ? false : options.unattended === true;
|
|
40
|
+
if (unattended === true) {
|
|
41
|
+
if (toolName === CARGO_EXECUTE_ACTION_TOOL) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (toolName === CARGO_EXECUTE_ACTION_BATCH_TOOL) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (toolName.startsWith(CARGO_AGENT_MCP_TOOL_PREFIX) === true) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (toolName.startsWith(CARGO_MCP_TOOL_PREFIX) === true) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (toolName.startsWith(CARGO_AGENT_MCP_TOOL_PREFIX) === true) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return AUTO_APPROVED_TOOL_NAMES.has(toolName);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `Agent` spawns a subagent to run a task of its own, and approving one is a
|
|
61
|
+
* different kind of decision from approving a `Bash`: the subagent runs its
|
|
62
|
+
* own tools, can be asked for with `mode: "bypassPermissions"`, and whether
|
|
63
|
+
* its calls come back here for individual approval is not something we control
|
|
64
|
+
* or currently know.
|
|
65
|
+
*
|
|
66
|
+
* The refusal that actually stops it is in `claudeConfig.ts`, as a deny rule
|
|
67
|
+
* in Claude Code's own settings — this never fired, because the approval
|
|
68
|
+
* request it waits for is never sent. The bridge writes `ask` rules only for
|
|
69
|
+
* the tools in its `NATIVE_TOOL_KINDS` map, the subagent tools are not in it,
|
|
70
|
+
* and so `allow-reads` left them running unattended.
|
|
71
|
+
*
|
|
72
|
+
* Kept as the second line: a user who points `CLAUDE_CONFIG_DIR` at their own
|
|
73
|
+
* Claude Code config gets no deny rule written for them, and a future bridge
|
|
74
|
+
* that does surface the approval should find an answer waiting.
|
|
75
|
+
*/
|
|
76
|
+
const DENIED_TOOL_NAMES = new Set(["Agent", "Task"]);
|
|
77
|
+
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.";
|
|
78
|
+
/** Exported for tests. */
|
|
79
|
+
export function isAlwaysDenied(toolName) {
|
|
80
|
+
return DENIED_TOOL_NAMES.has(toolName);
|
|
81
|
+
}
|
|
@@ -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,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's `AskUserQuestion` — a structured multiple-choice prompt.
|
|
3
|
+
*
|
|
4
|
+
* The native picker cannot run here: `allow-reads` classifies it as readonly,
|
|
5
|
+
* so Claude Code starts it without asking us, then waits on a UI this session
|
|
6
|
+
* does not have. The native tool is withheld for that reason, via session
|
|
7
|
+
* `disallowedTools` — not a settings.json deny of the same name, which would
|
|
8
|
+
* also disable this host replacement. This session implements the tool as a
|
|
9
|
+
* host tool: the questions are shown in Ask's own picker, and the answers are
|
|
10
|
+
* the tool result.
|
|
11
|
+
*
|
|
12
|
+
* The input schema has to name `questions`. The Claude Code bridge turns host
|
|
13
|
+
* tool schemas into a Zod object shape; an empty shape strips every argument,
|
|
14
|
+
* and the picker sees `{}`.
|
|
15
|
+
*/
|
|
16
|
+
import { jsonSchema } from "ai";
|
|
17
|
+
export declare const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
|
|
18
|
+
export declare const ASK_USER_QUESTION_DENIED_REASON = "Nobody is at the terminal to answer. Ask in your reply text instead.";
|
|
19
|
+
export declare const ASK_USER_QUESTION_MISSING_INPUT_REASON = "AskUserQuestion requires `questions`: an array of 1\u20134 items, each with `question`, `header`, `options` (each `{ label, description }`), and `multiSelect`. Call it again with those fields filled in.";
|
|
20
|
+
type AskUserQuestionHostTool = {
|
|
21
|
+
description: string;
|
|
22
|
+
inputSchema: ReturnType<typeof jsonSchema>;
|
|
23
|
+
execute: (data: unknown) => Promise<unknown>;
|
|
24
|
+
};
|
|
25
|
+
export type AskUserQuestionAsk = (input: unknown) => Promise<Record<string, string> | undefined>;
|
|
26
|
+
type BuiltinToolFiltering = {
|
|
27
|
+
mode: "allow" | "deny";
|
|
28
|
+
toolNames: string[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Withhold Claude Code's native `AskUserQuestion` without dropping a host tool
|
|
32
|
+
* of the same name.
|
|
33
|
+
*
|
|
34
|
+
* HarnessAgent `inactiveTools` cannot do this: it also filters the user tool
|
|
35
|
+
* out of `toolSpecs`, so the replacement is never registered. A settings.json
|
|
36
|
+
* deny of `AskUserQuestion` matches the host tool too. Merging a deny into the
|
|
37
|
+
* session's builtin filtering becomes `disallowedTools` for the native tool
|
|
38
|
+
* only; host `execute` still runs.
|
|
39
|
+
*/
|
|
40
|
+
export declare function denyNativeAskUserQuestion(existing: BuiltinToolFiltering | undefined): BuiltinToolFiltering;
|
|
41
|
+
/**
|
|
42
|
+
* Host-side `AskUserQuestion`. Same name as the builtin so the model keeps
|
|
43
|
+
* calling it; HarnessAgent runs `execute` on the host instead of Claude Code.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildAskUserQuestionHostTool(getAsk: () => AskUserQuestionAsk | undefined): Record<string, AskUserQuestionHostTool>;
|
|
46
|
+
export type AskUserQuestionOption = {
|
|
47
|
+
label: string;
|
|
48
|
+
description: string | undefined;
|
|
49
|
+
};
|
|
50
|
+
export type AskUserQuestionItem = {
|
|
51
|
+
question: string;
|
|
52
|
+
header: string | undefined;
|
|
53
|
+
options: AskUserQuestionOption[];
|
|
54
|
+
multiSelect: boolean;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Pull the questions out of a tool input, whether the bridge sent a JSON
|
|
58
|
+
* string or the parsed object.
|
|
59
|
+
*/
|
|
60
|
+
export declare function readAskUserQuestions(toolInput: unknown): AskUserQuestionItem[] | undefined;
|
|
61
|
+
/** First question, for the spinner — not the whole JSON payload. */
|
|
62
|
+
export declare function summarizeAskUserQuestion(toolInput: unknown): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Told to the model as the denial reason so it can continue with the answers
|
|
65
|
+
* rather than asking again.
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatAskUserQuestionAnswers(answers: Record<string, string>): string;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=askUserQuestion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"askUserQuestion.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/askUserQuestion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAoB,MAAM,IAAI,CAAC;AAElD,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAE7D,eAAO,MAAM,+BAA+B,yEAC4B,CAAC;AAEzE,eAAO,MAAM,sCAAsC,+MACsJ,CAAC;AA4C1M,KAAK,uBAAuB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;AAEjD,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GACzC,oBAAoB,CAsBtB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,kBAAkB,GAAG,SAAS,GAC3C,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CA2BzC;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,OAAO,GACjB,mBAAmB,EAAE,GAAG,SAAS,CA0BnC;AAED,oEAAoE;AACpE,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,OAAO,GACjB,MAAM,GAAG,SAAS,CAkBpB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAER"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's `AskUserQuestion` — a structured multiple-choice prompt.
|
|
3
|
+
*
|
|
4
|
+
* The native picker cannot run here: `allow-reads` classifies it as readonly,
|
|
5
|
+
* so Claude Code starts it without asking us, then waits on a UI this session
|
|
6
|
+
* does not have. The native tool is withheld for that reason, via session
|
|
7
|
+
* `disallowedTools` — not a settings.json deny of the same name, which would
|
|
8
|
+
* also disable this host replacement. This session implements the tool as a
|
|
9
|
+
* host tool: the questions are shown in Ask's own picker, and the answers are
|
|
10
|
+
* the tool result.
|
|
11
|
+
*
|
|
12
|
+
* The input schema has to name `questions`. The Claude Code bridge turns host
|
|
13
|
+
* tool schemas into a Zod object shape; an empty shape strips every argument,
|
|
14
|
+
* and the picker sees `{}`.
|
|
15
|
+
*/
|
|
16
|
+
import { jsonSchema } from "ai";
|
|
17
|
+
export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
|
|
18
|
+
export const ASK_USER_QUESTION_DENIED_REASON = "Nobody is at the terminal to answer. Ask in your reply text instead.";
|
|
19
|
+
export const ASK_USER_QUESTION_MISSING_INPUT_REASON = "AskUserQuestion requires `questions`: an array of 1–4 items, each with `question`, `header`, `options` (each `{ label, description }`), and `multiSelect`. Call it again with those fields filled in.";
|
|
20
|
+
const ASK_USER_QUESTION_JSON_SCHEMA = {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
questions: {
|
|
24
|
+
type: "array",
|
|
25
|
+
description: "1–4 multiple-choice questions to present to the user in this terminal.",
|
|
26
|
+
items: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
question: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "The question to ask.",
|
|
32
|
+
},
|
|
33
|
+
header: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Short label shown above the question.",
|
|
36
|
+
},
|
|
37
|
+
options: {
|
|
38
|
+
type: "array",
|
|
39
|
+
items: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
label: { type: "string" },
|
|
43
|
+
description: { type: "string" },
|
|
44
|
+
preview: { type: "string" },
|
|
45
|
+
},
|
|
46
|
+
required: ["label", "description"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
multiSelect: {
|
|
50
|
+
type: "boolean",
|
|
51
|
+
description: "Whether the user may pick more than one option.",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: ["question", "header", "options", "multiSelect"],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
required: ["questions"],
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Withhold Claude Code's native `AskUserQuestion` without dropping a host tool
|
|
62
|
+
* of the same name.
|
|
63
|
+
*
|
|
64
|
+
* HarnessAgent `inactiveTools` cannot do this: it also filters the user tool
|
|
65
|
+
* out of `toolSpecs`, so the replacement is never registered. A settings.json
|
|
66
|
+
* deny of `AskUserQuestion` matches the host tool too. Merging a deny into the
|
|
67
|
+
* session's builtin filtering becomes `disallowedTools` for the native tool
|
|
68
|
+
* only; host `execute` still runs.
|
|
69
|
+
*/
|
|
70
|
+
export function denyNativeAskUserQuestion(existing) {
|
|
71
|
+
if (existing === undefined) {
|
|
72
|
+
return { mode: "deny", toolNames: [ASK_USER_QUESTION_TOOL_NAME] };
|
|
73
|
+
}
|
|
74
|
+
if (existing.mode === "deny") {
|
|
75
|
+
if (existing.toolNames.includes(ASK_USER_QUESTION_TOOL_NAME) === true) {
|
|
76
|
+
return existing;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
mode: "deny",
|
|
80
|
+
toolNames: [...existing.toolNames, ASK_USER_QUESTION_TOOL_NAME],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
mode: "allow",
|
|
85
|
+
toolNames: existing.toolNames.filter((name) => name !== ASK_USER_QUESTION_TOOL_NAME),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Host-side `AskUserQuestion`. Same name as the builtin so the model keeps
|
|
90
|
+
* calling it; HarnessAgent runs `execute` on the host instead of Claude Code.
|
|
91
|
+
*/
|
|
92
|
+
export function buildAskUserQuestionHostTool(getAsk) {
|
|
93
|
+
return {
|
|
94
|
+
[ASK_USER_QUESTION_TOOL_NAME]: {
|
|
95
|
+
description: "Ask the user multiple-choice questions via a structured UI. This session presents the options in the terminal and returns their answers.",
|
|
96
|
+
inputSchema: jsonSchema(ASK_USER_QUESTION_JSON_SCHEMA),
|
|
97
|
+
execute: async (data) => {
|
|
98
|
+
const ask = getAsk();
|
|
99
|
+
if (ask === undefined) {
|
|
100
|
+
return { error: ASK_USER_QUESTION_DENIED_REASON };
|
|
101
|
+
}
|
|
102
|
+
if (readAskUserQuestions(data) === undefined) {
|
|
103
|
+
return { error: ASK_USER_QUESTION_MISSING_INPUT_REASON };
|
|
104
|
+
}
|
|
105
|
+
const answers = await ask(data);
|
|
106
|
+
if (answers === undefined || Object.keys(answers).length === 0) {
|
|
107
|
+
return { error: ASK_USER_QUESTION_DENIED_REASON };
|
|
108
|
+
}
|
|
109
|
+
return { answers };
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Pull the questions out of a tool input, whether the bridge sent a JSON
|
|
116
|
+
* string or the parsed object.
|
|
117
|
+
*/
|
|
118
|
+
export function readAskUserQuestions(toolInput) {
|
|
119
|
+
const record = asRecord(toolInput);
|
|
120
|
+
if (record === undefined) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const rawQuestions = record["questions"];
|
|
124
|
+
if (Array.isArray(rawQuestions) === false || rawQuestions.length === 0) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const questions = [];
|
|
128
|
+
for (const rawQuestion of rawQuestions) {
|
|
129
|
+
const parsed = readQuestion(rawQuestion);
|
|
130
|
+
if (parsed === undefined) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
questions.push(parsed);
|
|
134
|
+
}
|
|
135
|
+
return questions;
|
|
136
|
+
}
|
|
137
|
+
/** First question, for the spinner — not the whole JSON payload. */
|
|
138
|
+
export function summarizeAskUserQuestion(toolInput) {
|
|
139
|
+
const questions = readAskUserQuestions(toolInput);
|
|
140
|
+
if (questions === undefined) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const first = questions[0];
|
|
144
|
+
if (first === undefined) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
if (questions.length === 1) {
|
|
148
|
+
return first.question;
|
|
149
|
+
}
|
|
150
|
+
return `${first.question} (+${String(questions.length - 1)} more)`;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Told to the model as the denial reason so it can continue with the answers
|
|
154
|
+
* rather than asking again.
|
|
155
|
+
*/
|
|
156
|
+
export function formatAskUserQuestionAnswers(answers) {
|
|
157
|
+
return `The user answered: ${JSON.stringify(answers)}. Continue with these answers. Do not call AskUserQuestion again for these questions.`;
|
|
158
|
+
}
|
|
159
|
+
function readQuestion(raw) {
|
|
160
|
+
const record = asRecord(raw);
|
|
161
|
+
if (record === undefined) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
const question = record["question"];
|
|
165
|
+
const rawOptions = record["options"];
|
|
166
|
+
if (typeof question !== "string" || question.length === 0) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
if (Array.isArray(rawOptions) === false || rawOptions.length === 0) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
const options = [];
|
|
173
|
+
for (const rawOption of rawOptions) {
|
|
174
|
+
const parsed = readOption(rawOption);
|
|
175
|
+
if (parsed === undefined) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
options.push(parsed);
|
|
179
|
+
}
|
|
180
|
+
const header = record["header"];
|
|
181
|
+
return {
|
|
182
|
+
question,
|
|
183
|
+
header: typeof header === "string" ? header : undefined,
|
|
184
|
+
options,
|
|
185
|
+
multiSelect: record["multiSelect"] === true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function readOption(raw) {
|
|
189
|
+
const record = asRecord(raw);
|
|
190
|
+
if (record === undefined) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
const label = record["label"];
|
|
194
|
+
const description = record["description"];
|
|
195
|
+
if (typeof label !== "string" || label.length === 0) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
label,
|
|
200
|
+
description: typeof description === "string" ? description : undefined,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function asRecord(value) {
|
|
204
|
+
if (typeof value === "string") {
|
|
205
|
+
try {
|
|
206
|
+
const parsed = JSON.parse(value);
|
|
207
|
+
return typeof parsed === "object" && parsed !== null
|
|
208
|
+
? parsed
|
|
209
|
+
: undefined;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return typeof value === "object" && value !== null
|
|
216
|
+
? value
|
|
217
|
+
: undefined;
|
|
218
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeConfig.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/claudeConfig.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { getConfigDir } from "@cargo-ai/cdk/cli";
|
|
4
|
+
import { ASK_USER_QUESTION_TOOL_NAME } from "./askUserQuestion.js";
|
|
4
5
|
/**
|
|
5
6
|
* Tools that spawn a subagent, refused at source.
|
|
6
7
|
*
|
|
@@ -22,6 +23,16 @@ import { getConfigDir } from "@cargo-ai/cdk/cli";
|
|
|
22
23
|
* Code versions and a rule for a tool that does not exist costs nothing.
|
|
23
24
|
*/
|
|
24
25
|
const SUBAGENT_TOOL_NAMES = ["Agent", "Task"];
|
|
26
|
+
/**
|
|
27
|
+
* Native `AskUserQuestion` used to live on this list. A deny-by-name rule
|
|
28
|
+
* matches the host replacement of the same name, so model calls came back
|
|
29
|
+
* disabled instead of reaching host `execute`. Native withholding is now
|
|
30
|
+
* session `disallowedTools` — see `denyNativeAskUserQuestion`. Names here
|
|
31
|
+
* are stripped from an existing deny array so a previous Ask run cannot
|
|
32
|
+
* keep the collision around.
|
|
33
|
+
*/
|
|
34
|
+
const SETTINGS_DENIED_TOOL_NAMES = SUBAGENT_TOOL_NAMES;
|
|
35
|
+
const SETTINGS_UNDENIED_TOOL_NAMES = [ASK_USER_QUESTION_TOOL_NAME];
|
|
25
36
|
/**
|
|
26
37
|
* The Claude Agent SDK loads every filesystem settings source it can find when
|
|
27
38
|
* `settingSources` is omitted, and the harness bridge omits it. A local turn
|
|
@@ -52,24 +63,23 @@ export function askClaudeConfigDir() {
|
|
|
52
63
|
}
|
|
53
64
|
const dir = join(getConfigDir(), "ask-claude-config");
|
|
54
65
|
mkdirSync(dir, { recursive: true });
|
|
55
|
-
|
|
66
|
+
denySettingsTools(dir);
|
|
56
67
|
return dir;
|
|
57
68
|
}
|
|
58
69
|
/**
|
|
59
|
-
* Add the
|
|
60
|
-
*
|
|
70
|
+
* Add the deny rules to the settings file in Ask's own config directory,
|
|
71
|
+
* keeping whatever else is in there.
|
|
61
72
|
*
|
|
62
73
|
* Merged rather than written whole, because Claude Code keeps its own state
|
|
63
74
|
* under this directory.
|
|
64
75
|
*
|
|
65
76
|
* A failure here is reported rather than swallowed. There is no second line of
|
|
66
|
-
* defence to fall back on
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* must not fail the question they just asked.
|
|
77
|
+
* defence to fall back on for tools `allow-reads` never asks about — so a
|
|
78
|
+
* settings file that could not be written means those tools run unattended,
|
|
79
|
+
* and the user is the only one who can tell whether that matters. Reported,
|
|
80
|
+
* not thrown: it must not fail the question they just asked.
|
|
71
81
|
*/
|
|
72
|
-
function
|
|
82
|
+
function denySettingsTools(dir) {
|
|
73
83
|
const path = join(dir, "settings.json");
|
|
74
84
|
try {
|
|
75
85
|
const existing = existsSync(path)
|
|
@@ -84,16 +94,21 @@ function denySubagentTools(dir) {
|
|
|
84
94
|
: {};
|
|
85
95
|
const denyValue = permissions["deny"];
|
|
86
96
|
const deny = Array.isArray(denyValue) ? denyValue : [];
|
|
87
|
-
const
|
|
88
|
-
|
|
97
|
+
const kept = deny.filter((name) => {
|
|
98
|
+
return typeof name === "string"
|
|
99
|
+
? SETTINGS_UNDENIED_TOOL_NAMES.includes(name) === false
|
|
100
|
+
: true;
|
|
101
|
+
});
|
|
102
|
+
const missing = SETTINGS_DENIED_TOOL_NAMES.filter((name) => kept.includes(name) === false);
|
|
103
|
+
if (missing.length === 0 && kept.length === deny.length) {
|
|
89
104
|
return;
|
|
90
105
|
}
|
|
91
106
|
writeFileSync(path, `${JSON.stringify({
|
|
92
107
|
...settings,
|
|
93
|
-
permissions: { ...permissions, deny: [...
|
|
108
|
+
permissions: { ...permissions, deny: [...kept, ...missing] },
|
|
94
109
|
}, null, 2)}\n`);
|
|
95
110
|
}
|
|
96
111
|
catch (error) {
|
|
97
|
-
process.stderr.write(`Could not write ${path}, so
|
|
112
|
+
process.stderr.write(`Could not write ${path}, so Agent and Task are not withheld from this session: ${error instanceof Error ? error.message : "unknown error"}\n`);
|
|
98
113
|
}
|
|
99
114
|
}
|
|
@@ -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;AAuB3C,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,CAsUxB"}
|