@yitom/agy-acp-map 0.1.16 → 0.1.17

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 CHANGED
@@ -95,7 +95,7 @@ Configure on **`session/new`** (preferred) and/or env fallbacks. Stored on the S
95
95
  | `--sandbox` | `sandbox: true` | `AGY_ACP_SANDBOX=1` |
96
96
  | `--json-schema` | `jsonSchema` (string or object→stringify) | `AGY_ACP_JSON_SCHEMA` (string or path) |
97
97
  | `--conversation` | `conversationId` (resume / switch-model flow) | _(from prior turn)_ |
98
- | `--dangerously-skip-permissions` | `safety: 'autonomous' \| 'autonomous-unsandboxed'` or `skipPermissions: true` | `AGY_ACP_SAFETY=…` / `AGY_ACP_SKIP_PERMISSIONS=1` if safety unset (**default off / safe**) |
98
+ | `--dangerously-skip-permissions` | `safety: 'autonomous' \| 'autonomous-unsandboxed'` or `skipPermissions: true` | `AGY_ACP_SAFETY=…` / `AGY_ACP_SKIP_PERMISSIONS=1` if safety unset (**default: skip on, unsandboxed**) |
99
99
  | `--disable-slash-commands` | `disableSlashCommands` (default **true**) | `AGY_ACP_DISABLE_SLASH_COMMANDS=0` to omit |
100
100
  | `--print-timeout` | `printTimeout` (e.g. `30m`, `120s`, `0`) | `AGY_ACP_PRINT_TIMEOUT` (default `0`) |
101
101
 
@@ -159,7 +159,7 @@ Display-history path: `~/.agy-acp-map/history/`. Override with `AGY_ACP_HISTORY_
159
159
  | Env | Default | Meaning |
160
160
  |-----|---------|---------|
161
161
  | `AGY_ACP_SAFETY` | `safe` | `safe` \| `autonomous` \| `autonomous-unsandboxed` (aliases: `unsandboxed`, `autonomous_unsandboxed`). See Safety modes table. |
162
- | `AGY_ACP_SKIP_PERMISSIONS` | `0` | If **safety unset**: `1` ≈ treat as `autonomous`; `0` ≈ `safe`. Explicit `AGY_ACP_SAFETY` / `session.safety` wins. |
162
+ | `AGY_ACP_SKIP_PERMISSIONS` | `0` | If **safety unset**: `1` ≈ treat as `autonomous-unsandboxed`; `0` ≈ `safe`. Explicit `AGY_ACP_SAFETY` / `session.safety` wins. |
163
163
  | `AGY_ACP_DISABLE_SLASH_COMMANDS` | `1` | When `1` (default), pass `--disable-slash-commands`. Set `0` to omit. |
164
164
  | `AGY_ACP_PRINT_TIMEOUT` | `0` | Passed as `--print-timeout` (e.g. `30m`, `120s`, `0` = wait until turn completes). |
165
165
  | `AGY_BIN` | `agy` | Override binary |
@@ -167,7 +167,7 @@ Display-history path: `~/.agy-acp-map/history/`. Override with `AGY_ACP_HISTORY_
167
167
  | `AGY_ACP_EFFORT` | — | Default `--effort` |
168
168
  | `AGY_ACP_MODE` | — | Default `--mode` |
169
169
  | `AGY_ACP_AGENT` | — | Default `--agent` |
170
- | `AGY_ACP_SANDBOX` | — | `1`/`0` → force sandbox on/off for `safe`/`autonomous`. Ignored for `autonomous-unsandboxed` (never sandboxed). |
170
+ | `AGY_ACP_SANDBOX` | — | `1`/`0` → force sandbox on/off for `safe`/`autonomous`/defaulted tier. Ignored only when `autonomous-unsandboxed` was explicitly selected. |
171
171
  | `AGY_ACP_JSON_SCHEMA` | — | Schema string or file path for `--json-schema` |
172
172
  | `AGY_ACP_KEEP_STAGING` | — | `1` → keep `.agy-acp-staging` files after turn/close (debug) |
173
173
  | `AGY_ACP_STORE` / `AGY_ACP_SESSION_STORE` | `~/.agy-acp-map/sessions.json` | Disk session index path (`SESSION_STORE` wins if both set) |
@@ -209,15 +209,15 @@ No interactive ACP permission UI — **launch strategies only** (`resolveSafety`
209
209
 
210
210
  | Mode / 模式 | Skip permissions / 跳过权限 | Sandbox / 沙箱 |
211
211
  |-------------|------------------------------|----------------|
212
- | **safe** (default) | no — rely on agy `settings.json` allow/deny + soft-deny messages | only if user sets `sandbox: true` / `AGY_ACP_SANDBOX=1` |
212
+ | **safe** | no — rely on agy `settings.json` allow/deny + soft-deny messages | only if user sets `sandbox: true` / `AGY_ACP_SANDBOX=1` |
213
213
  | **autonomous** | yes (`--dangerously-skip-permissions`) | **default `--sandbox`** unless user sets `sandbox: false` / `AGY_ACP_SANDBOX=0` |
214
- | **autonomous-unsandboxed** (aliases: `autonomous_unsandboxed`, `unsandboxed`) | yes (`--dangerously-skip-permissions`) | **never** pass `--sandbox` (explicit dangerous tier; ignores sandbox overrides) |
214
+ | **autonomous-unsandboxed** (default; aliases: `autonomous_unsandboxed`, `unsandboxed`) | yes (`--dangerously-skip-permissions`) | **never** when explicitly selected (ignores sandbox overrides); the defaulted tier honors explicit `sandbox: true` / `AGY_ACP_SANDBOX=1` |
215
215
 
216
216
  Accept via:
217
217
  - `session/new` field `safety`: `'safe' | 'autonomous' | 'autonomous-unsandboxed'`
218
218
  - env `AGY_ACP_SAFETY` (same values)
219
219
  - idle `session/set_config_option` with `configId: "safety"`
220
- - Backward compat: `AGY_ACP_SKIP_PERMISSIONS=1` ≈ `autonomous` **if safety unset**; `=0` ≈ `safe`
220
+ - Backward compat: `AGY_ACP_SKIP_PERMISSIONS=1` ≈ `autonomous-unsandboxed` **if safety unset**; `=0` ≈ `safe`
221
221
 
222
222
  输入:`session/new.safety` / `AGY_ACP_SAFETY` / `set_config_option`;兼容 `AGY_ACP_SKIP_PERMISSIONS`(仅在未设 safety 时生效)。
223
223
 
Binary file
package/dist/bin.js CHANGED
@@ -10750,14 +10750,15 @@ function normalizePrintTimeout(v) {
10750
10750
  return s === "" ? undefined : s;
10751
10751
  }
10752
10752
  function resolveSafety(session = {}, env = process.env) {
10753
- let safety = normalizeSafety(session.safety) ?? normalizeSafety(env.AGY_ACP_SAFETY) ?? undefined;
10753
+ const explicitSafety = normalizeSafety(session.safety) ?? normalizeSafety(env.AGY_ACP_SAFETY) ?? undefined;
10754
+ let safety = explicitSafety;
10754
10755
  if (!safety) {
10755
10756
  const envSkip = env.AGY_ACP_SKIP_PERMISSIONS;
10756
10757
  if (envSkip !== undefined && envSkip !== "") {
10757
10758
  const skip = !(envSkip === "0" || envSkip === "false" || envSkip === "no");
10758
- safety = skip ? "autonomous" : "safe";
10759
+ safety = skip ? "autonomous-unsandboxed" : "safe";
10759
10760
  } else {
10760
- safety = "autonomous";
10761
+ safety = "autonomous-unsandboxed";
10761
10762
  }
10762
10763
  }
10763
10764
  let skipPermissions = safety === "autonomous" || safety === "autonomous-unsandboxed";
@@ -10765,7 +10766,7 @@ function resolveSafety(session = {}, env = process.env) {
10765
10766
  skipPermissions = Boolean(session.skipPermissions);
10766
10767
  }
10767
10768
  let sandbox;
10768
- if (safety === "autonomous-unsandboxed") {
10769
+ if (safety === "autonomous-unsandboxed" && explicitSafety === "autonomous-unsandboxed") {
10769
10770
  sandbox = false;
10770
10771
  } else if (session.sandbox !== undefined) {
10771
10772
  sandbox = Boolean(session.sandbox);
@@ -11692,7 +11693,7 @@ function formatSoftDenyMessage(denies) {
11692
11693
  bits.push(`(via ${d.source})`);
11693
11694
  lines.push(bits.join(" "));
11694
11695
  }
11695
- lines.push("Or set AGY_ACP_SAFETY=safe / AGY_ACP_SKIP_PERMISSIONS=0 to re-enable permission checks (autonomous + sandbox is the bridge default).");
11696
+ lines.push("Or set AGY_ACP_SAFETY=safe / AGY_ACP_SKIP_PERMISSIONS=0 to re-enable permission checks (autonomous-unsandboxed — full permissions, no sandbox — is the bridge default; AGY_ACP_SAFETY=autonomous re-enables sandbox containment).");
11696
11697
  if (denies.some((d) => d.source?.includes("sandbox"))) {
11697
11698
  lines.push("Sandbox note: --sandbox = terminal restrictions, not verified offline. Built-in search may still work; if `curl`/`Invoke-WebRequest` failed, retry once with safety=autonomous-unsandboxed (or sandbox:false) to confirm it is a sandbox network block.");
11698
11699
  }
@@ -12632,7 +12633,7 @@ function mcpServerToAgyAddArgs(s) {
12632
12633
  if (s.kind === "stdio") {
12633
12634
  for (const e of s.env)
12634
12635
  argv.push("--env", `${e.name}=${e.value}`);
12635
- argv.push(s.name, s.command, ...s.args);
12636
+ argv.push(s.name, "--", s.command, ...s.args);
12636
12637
  return argv;
12637
12638
  }
12638
12639
  for (const h of s.headers)
@@ -12673,6 +12674,21 @@ ${r.stderr}`)}`);
12673
12674
  }
12674
12675
  added.push(s.name);
12675
12676
  }
12677
+ if (added.length) {
12678
+ let listed = "";
12679
+ try {
12680
+ const lr = await runFn(bin, ["mcp", "list"], { timeoutMs });
12681
+ listed = String(lr.stdout ?? "");
12682
+ } catch (err) {
12683
+ throw new RequestError(-32603, `registered MCP server(s) [${added.join(", ")}] but 'mcp list' verification failed: ${err?.message || err}`);
12684
+ }
12685
+ const lines = listed.split(`
12686
+ `);
12687
+ const missing = added.filter((n) => !lines.some((ln) => ln.includes(n)));
12688
+ if (missing.length) {
12689
+ throw new RequestError(-32603, `MCP server(s) [${missing.join(", ")}] exited 0 on 'mcp add' but are absent from 'mcp list' ` + `(agy swallows its global --version/--help flags even after '--'; check server args). ` + `List tail: ${tail(listed, 300)}`);
12690
+ }
12691
+ }
12676
12692
  return { added };
12677
12693
  }
12678
12694
  async function removeMcpServers(bin, names, runFn = defaultMcpRunFn, timeoutMs = 30000) {
@@ -12701,7 +12717,7 @@ ${r.stderr}`, 200)}`);
12701
12717
  var AGENT_INFO = {
12702
12718
  name: "agy-acp",
12703
12719
  title: "agy ACP (stream-json)",
12704
- version: "0.1.16"
12720
+ version: "0.1.17"
12705
12721
  };
12706
12722
  var BRIDGE_CAPABILITIES = {
12707
12723
  prompt: true,
package/dist/index.js CHANGED
@@ -10421,14 +10421,15 @@ function normalizePrintTimeout(v) {
10421
10421
  return s === "" ? undefined : s;
10422
10422
  }
10423
10423
  function resolveSafety(session = {}, env = process.env) {
10424
- let safety = normalizeSafety(session.safety) ?? normalizeSafety(env.AGY_ACP_SAFETY) ?? undefined;
10424
+ const explicitSafety = normalizeSafety(session.safety) ?? normalizeSafety(env.AGY_ACP_SAFETY) ?? undefined;
10425
+ let safety = explicitSafety;
10425
10426
  if (!safety) {
10426
10427
  const envSkip = env.AGY_ACP_SKIP_PERMISSIONS;
10427
10428
  if (envSkip !== undefined && envSkip !== "") {
10428
10429
  const skip = !(envSkip === "0" || envSkip === "false" || envSkip === "no");
10429
- safety = skip ? "autonomous" : "safe";
10430
+ safety = skip ? "autonomous-unsandboxed" : "safe";
10430
10431
  } else {
10431
- safety = "autonomous";
10432
+ safety = "autonomous-unsandboxed";
10432
10433
  }
10433
10434
  }
10434
10435
  let skipPermissions = safety === "autonomous" || safety === "autonomous-unsandboxed";
@@ -10436,7 +10437,7 @@ function resolveSafety(session = {}, env = process.env) {
10436
10437
  skipPermissions = Boolean(session.skipPermissions);
10437
10438
  }
10438
10439
  let sandbox;
10439
- if (safety === "autonomous-unsandboxed") {
10440
+ if (safety === "autonomous-unsandboxed" && explicitSafety === "autonomous-unsandboxed") {
10440
10441
  sandbox = false;
10441
10442
  } else if (session.sandbox !== undefined) {
10442
10443
  sandbox = Boolean(session.sandbox);
@@ -11402,7 +11403,7 @@ function formatSoftDenyMessage(denies) {
11402
11403
  bits.push(`(via ${d.source})`);
11403
11404
  lines.push(bits.join(" "));
11404
11405
  }
11405
- lines.push("Or set AGY_ACP_SAFETY=safe / AGY_ACP_SKIP_PERMISSIONS=0 to re-enable permission checks (autonomous + sandbox is the bridge default).");
11406
+ lines.push("Or set AGY_ACP_SAFETY=safe / AGY_ACP_SKIP_PERMISSIONS=0 to re-enable permission checks (autonomous-unsandboxed — full permissions, no sandbox — is the bridge default; AGY_ACP_SAFETY=autonomous re-enables sandbox containment).");
11406
11407
  if (denies.some((d) => d.source?.includes("sandbox"))) {
11407
11408
  lines.push("Sandbox note: --sandbox = terminal restrictions, not verified offline. Built-in search may still work; if `curl`/`Invoke-WebRequest` failed, retry once with safety=autonomous-unsandboxed (or sandbox:false) to confirm it is a sandbox network block.");
11408
11409
  }
@@ -12419,7 +12420,7 @@ function mcpServerToAgyAddArgs(s) {
12419
12420
  if (s.kind === "stdio") {
12420
12421
  for (const e of s.env)
12421
12422
  argv.push("--env", `${e.name}=${e.value}`);
12422
- argv.push(s.name, s.command, ...s.args);
12423
+ argv.push(s.name, "--", s.command, ...s.args);
12423
12424
  return argv;
12424
12425
  }
12425
12426
  for (const h of s.headers)
@@ -12460,6 +12461,21 @@ ${r.stderr}`)}`);
12460
12461
  }
12461
12462
  added.push(s.name);
12462
12463
  }
12464
+ if (added.length) {
12465
+ let listed = "";
12466
+ try {
12467
+ const lr = await runFn(bin, ["mcp", "list"], { timeoutMs });
12468
+ listed = String(lr.stdout ?? "");
12469
+ } catch (err) {
12470
+ throw new RequestError(-32603, `registered MCP server(s) [${added.join(", ")}] but 'mcp list' verification failed: ${err?.message || err}`);
12471
+ }
12472
+ const lines = listed.split(`
12473
+ `);
12474
+ const missing = added.filter((n) => !lines.some((ln) => ln.includes(n)));
12475
+ if (missing.length) {
12476
+ throw new RequestError(-32603, `MCP server(s) [${missing.join(", ")}] exited 0 on 'mcp add' but are absent from 'mcp list' ` + `(agy swallows its global --version/--help flags even after '--'; check server args). ` + `List tail: ${tail(listed, 300)}`);
12477
+ }
12478
+ }
12463
12479
  return { added };
12464
12480
  }
12465
12481
  async function removeMcpServers(bin, names, runFn = defaultMcpRunFn, timeoutMs = 30000) {
@@ -12488,7 +12504,7 @@ ${r.stderr}`, 200)}`);
12488
12504
  var AGENT_INFO = {
12489
12505
  name: "agy-acp",
12490
12506
  title: "agy ACP (stream-json)",
12491
- version: "0.1.16"
12507
+ version: "0.1.17"
12492
12508
  };
12493
12509
  var BRIDGE_CAPABILITIES = {
12494
12510
  prompt: true,
@@ -114,14 +114,17 @@ export type SafetyResolveInput = {
114
114
  *
115
115
  * Tiers:
116
116
  * safe — no skip-permissions; sandbox only if explicitly true
117
- * autonomous (default) — skip-permissions; default --sandbox unless sandbox:false
118
- * autonomous-unsandboxed — skip-permissions; NEVER --sandbox
117
+ * autonomous — skip-permissions; default --sandbox unless sandbox:false
118
+ * (opt-in containment; explicit safety/autonomous only)
119
+ * autonomous-unsandboxed — skip-permissions; NEVER --sandbox (the default:
120
+ * full permissions, no terminal restrictions)
119
121
  *
120
122
  * Inputs:
121
123
  * session.safety / AGY_ACP_SAFETY
122
- * AGY_ACP_SKIP_PERMISSIONS=0 ≈ safe if safety unset; otherwise autonomous
124
+ * AGY_ACP_SKIP_PERMISSIONS=0 ≈ safe if safety unset; otherwise autonomous-unsandboxed
123
125
  * explicit session.skipPermissions overrides the skip flag only
124
- * explicit session.sandbox / AGY_ACP_SANDBOX override sandbox except unsandboxed tier
126
+ * explicit session.sandbox / AGY_ACP_SANDBOX override sandbox except when the
127
+ * unsandboxed tier was explicitly selected (defaulted tier honors opt-in)
125
128
  */
126
129
  export declare function resolveSafety(session?: SafetyResolveInput, env?: NodeJS.ProcessEnv): ResolvedSafety;
127
130
  /**
@@ -53,6 +53,10 @@ export declare function validateMcpServers(input: unknown): NormalizedMcpServer[
53
53
  * Build `agy mcp add` argv. agy rejects flags placed after <name>, so all
54
54
  * flags come first: mcp add [--env K=V] [--header K:V] [--type t] <name>
55
55
  * <commandOrUrl> [args...].
56
+ * stdio ALWAYS inserts `--` after <name>: agy consumes a global `--version`
57
+ * (and may misparse other dash-args) even in post-positional slots, which
58
+ * exits 0 while registering nothing (verified against agy 1.2.8). `--` ends
59
+ * flag parsing so command/args pass through verbatim.
56
60
  */
57
61
  export declare function mcpServerToAgyAddArgs(s: NormalizedMcpServer): string[];
58
62
  export interface McpRunResult {
@@ -70,6 +74,9 @@ export declare const defaultMcpRunFn: McpRunFn;
70
74
  * Register every server via `agy mcp add` (idempotent: add == upsert).
71
75
  * Any failure throws RequestError — a client that asked for MCP must never
72
76
  * get a silent tools-less session.
77
+ * Verify-after-add: agy exits 0 while registering NOTHING when argv contains
78
+ * its global flags (`--version`/`--help` are swallowed even after `--`),
79
+ * so every add is confirmed via `mcp list`. Absent-after-add throws loud.
73
80
  */
74
81
  export declare function syncMcpServers(bin: string, servers: NormalizedMcpServer[], runFn?: McpRunFn, timeoutMs?: number): Promise<{
75
82
  added: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yitom/agy-acp-map",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -48,8 +48,11 @@
48
48
  "smoke:permissions": "bun tests/smoke/smoke-permissions.ts",
49
49
  "smoke:image-in": "bun tests/smoke/smoke-image-in.ts",
50
50
  "smoke:image-out": "bun tests/smoke/smoke-image-out.ts",
51
+ "smoke:mcp": "bun tests/smoke/smoke-mcp.ts",
52
+ "smoke:mcp-resume": "bun tests/smoke/smoke-mcp-resume.ts",
53
+ "smoke:mcp-e2e": "bun tests/smoke/smoke-mcp-e2e.ts",
51
54
  "smoke:robustness": "bun tests/smoke/smoke-robustness.ts",
52
- "smoke:all": "bun test src/lib && bun tests/test-agy-args.ts && bun tests/smoke/smoke-basic.ts && bun tests/smoke/smoke-flags.ts && bun tests/smoke/smoke-permissions.ts && bun tests/smoke/smoke-image-in.ts && bun tests/smoke/smoke-image-out.ts && bun tests/smoke/smoke-robustness.ts"
55
+ "smoke:all": "bun test src/lib && bun tests/test-agy-args.ts && bun tests/smoke/smoke-mcp.ts && bun tests/smoke/smoke-mcp-resume.ts && bun tests/smoke/smoke-basic.ts && bun tests/smoke/smoke-flags.ts && bun tests/smoke/smoke-permissions.ts && bun tests/smoke/smoke-image-in.ts && bun tests/smoke/smoke-image-out.ts && bun tests/smoke/smoke-robustness.ts"
53
56
  },
54
57
  "keywords": [
55
58
  "antigravity",