@voybio/ace-swarm 2.4.2 → 2.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/assets/agent-state/INTERFACE_REGISTRY.md +2 -2
  3. package/assets/agent-state/MODULES/gates/gate-autonomy.json +4 -2
  4. package/assets/agent-state/MODULES/gates/gate-completeness.json +4 -2
  5. package/assets/agent-state/MODULES/gates/gate-operability.json +4 -2
  6. package/assets/agent-state/MODULES/gates/gate-security.json +3 -1
  7. package/assets/agent-state/MODULES/registry.json +1 -4
  8. package/assets/agent-state/MODULES/roles/capability-build.json +1 -2
  9. package/assets/agent-state/MODULES/roles/capability-eval.json +1 -1
  10. package/assets/agent-state/MODULES/roles/capability-qa.json +1 -2
  11. package/assets/agent-state/QUALITY_GATES.md +25 -9
  12. package/assets/agent-state/TEAL_CONFIG.md +2 -11
  13. package/dist/astgrep-index.d.ts +7 -1
  14. package/dist/astgrep-index.js +66 -39
  15. package/dist/cli.js +1 -1
  16. package/dist/gate-contract.d.ts +63 -0
  17. package/dist/gate-contract.js +178 -0
  18. package/dist/helpers/bootstrap.js +4 -4
  19. package/dist/runtime-executor.js +45 -2
  20. package/dist/runtime-tool-specs.d.ts +8 -1
  21. package/dist/runtime-tool-specs.js +19 -1
  22. package/dist/schemas.js +16 -15
  23. package/dist/store/bootstrap-store.js +30 -6
  24. package/dist/store/gate-contract-migration.d.ts +10 -0
  25. package/dist/store/gate-contract-migration.js +413 -0
  26. package/dist/store/materializers/host-file-materializer.js +9 -1
  27. package/dist/tools-files.js +68 -5
  28. package/dist/tools-framework.js +115 -37
  29. package/package.json +3 -1
  30. package/assets/agent-state/MODULES/gates/gate-correctness.json +0 -7
  31. package/assets/agent-state/MODULES/gates/gate-evaluation.json +0 -7
  32. package/assets/agent-state/MODULES/gates/gate-typescript-public-surface.json +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.3] - 2026-05-23
4
+
5
+ ### Changed
6
+
7
+ - Reduced default packaged workspace gates to portable ACE lifecycle gates only (`gate-autonomy`, `gate-completeness`, `gate-security`, `gate-operability`).
8
+ - Made `execute_gates({})` resolve the active ACE stage from `STATUS.md` and `TEAL_CONFIG.md` and only run stage-activated workspace gates by default.
9
+ - Added automatic exact-match migration for legacy package-seeded gate assets during store bootstrap and `ace repair`, while preserving customized project gates.
10
+ - Kept TypeScript public-surface verification in the package maintenance path instead of default workspace gate execution.
11
+
3
12
  ## [2.4.1] - 2026-05-08
4
13
 
5
14
  ### Changed
@@ -54,9 +54,9 @@
54
54
 
55
55
  ## Public Surface Gate
56
56
 
57
- - `audit_public_surface` is the canonical TypeScript public-surface gate for MCP tools, resources, prompts, and registered event names.
57
+ - `audit_public_surface` is the canonical TypeScript public-surface audit for MCP tools, resources, prompts, and registered event names.
58
58
  - `PUBLIC_SURFACE_REPORT.md` is the durable audit artifact written by that gate.
59
- - `MODULES/gates/gate-typescript-public-surface.json` is the executable gate manifest for CI or operator use.
59
+ - The package-level public-surface check remains an explicit package maintenance tool or CI gate; it is not seeded into initialized ACE workspaces as a default stage gate.
60
60
 
61
61
  ## Provenance Contract
62
62
 
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-autonomy",
3
3
  "type": "artifact_scan",
4
- "invariant": "Every execution cycle records objective, strategy, evidence, and next state",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "ACE lifecycle state records objective, evidence, and handoff continuity for the active stage",
5
7
  "command": "",
6
- "evidence_requirement": "STATUS + EVIDENCE_LOG + HANDOFF pointers"
8
+ "evidence_requirement": "STATUS.md + EVIDENCE_LOG.md + HANDOFF.json"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-completeness",
3
3
  "type": "artifact_scan",
4
- "invariant": "All required artifacts exist and are non-empty",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "Required ACE lifecycle state artifacts exist and are non-empty",
5
7
  "command": "",
6
- "evidence_requirement": "File presence and section completeness evidence"
8
+ "evidence_requirement": "TASK.md + SCOPE.md + QUALITY_GATES.md + STATUS.md + HANDOFF.json + EVIDENCE_LOG.md + DECISIONS.md + RISKS.md + TEAL_CONFIG.md + PROVENANCE_LOG.md + ARTIFACT_MANIFEST.json"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-operability",
3
3
  "type": "artifact_scan",
4
- "invariant": "Runbooks, ownership, and incident routing are defined for release",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "Release-stage operability evidence records observability coverage and a release decision",
5
7
  "command": "",
6
- "evidence_requirement": "COMMUNICATION_CHANNELS.md + observability/release artifacts"
8
+ "evidence_requirement": "OBSERVABILITY_REPORT.md + RELEASE_DECISION.md"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-security",
3
3
  "type": "manual_review",
4
+ "scope": "workspace",
5
+ "activation": "stage",
4
6
  "invariant": "No unmitigated high-severity security or policy risks",
5
7
  "command": "",
6
- "evidence_requirement": "SECURITY_REPORT.md with explicit mitigations or accepted residual risk"
8
+ "evidence_requirement": "RISKS.md + SECURITY_REPORT.md"
7
9
  }
@@ -19,12 +19,9 @@
19
19
  ],
20
20
  "gates": [
21
21
  "gate-completeness",
22
- "gate-correctness",
23
22
  "gate-autonomy",
24
23
  "gate-security",
25
- "gate-operability",
26
- "gate-evaluation",
27
- "gate-typescript-public-surface"
24
+ "gate-operability"
28
25
  ],
29
26
  "schemas": [
30
27
  "STATUS_EVENT.schema.json",
@@ -18,8 +18,7 @@
18
18
  ],
19
19
  "outputs": [
20
20
  {
21
- "file": "ARTIFACT_MANIFEST.json",
22
- "validation_gate": "gate-correctness"
21
+ "file": "ARTIFACT_MANIFEST.json"
23
22
  }
24
23
  ],
25
24
  "events": {
@@ -11,7 +11,7 @@
11
11
  {"file": "EVIDENCE_LOG.md", "critical": true}
12
12
  ],
13
13
  "outputs": [
14
- {"file": "EVAL_REPORT.md", "validation_gate": "gate-evaluation"}
14
+ {"file": "EVAL_REPORT.md"}
15
15
  ],
16
16
  "failure_routing": {
17
17
  "missing_input": "BLOCK_AND_REQUEST_INFO",
@@ -18,8 +18,7 @@
18
18
  ],
19
19
  "outputs": [
20
20
  {
21
- "file": "VERIFICATION_REPORT.md",
22
- "validation_gate": "gate-correctness"
21
+ "file": "VERIFICATION_REPORT.md"
23
22
  }
24
23
  ],
25
24
  "events": {
@@ -1,15 +1,31 @@
1
1
  # QUALITY GATES
2
2
 
3
+ Portable default workspace gates cover ACE lifecycle verification only. Product correctness, evaluation, and package public-surface checks must be added explicitly when a project needs them.
4
+
3
5
  ## gate-completeness
4
6
 
5
- - Invariant: required artifacts exist and are non-empty.
6
- - Pass condition: all required files are present with required sections.
7
- - Fail condition: any missing required artifact or empty required section.
8
- - Evidence: file list + section checks in `EVIDENCE_LOG.md`.
7
+ - Invariant: required ACE lifecycle state artifacts exist and are non-empty.
8
+ - Pass condition: the seeded ACE state surface is present and readable.
9
+ - Fail condition: any required ACE state artifact is missing or empty.
10
+ - Evidence: `TASK.md`, `SCOPE.md`, `QUALITY_GATES.md`, `STATUS.md`, `HANDOFF.json`, `EVIDENCE_LOG.md`, `DECISIONS.md`, `RISKS.md`, `TEAL_CONFIG.md`, `PROVENANCE_LOG.md`, and `ARTIFACT_MANIFEST.json`.
11
+
12
+ ## gate-autonomy
13
+
14
+ - Invariant: the active ACE stage records status, evidence, and handoff continuity.
15
+ - Pass condition: `STATUS.md`, `EVIDENCE_LOG.md`, and `HANDOFF.json` exist for the active stage.
16
+ - Fail condition: any of those lifecycle artifacts is missing.
17
+ - Evidence: `STATUS.md`, `EVIDENCE_LOG.md`, and `HANDOFF.json`.
18
+
19
+ ## gate-security
20
+
21
+ - Invariant: security review has explicit risk context and a review artifact.
22
+ - Pass condition: the active security review records `RISKS.md` and `SECURITY_REPORT.md`, then the manual review is completed.
23
+ - Fail condition: required review artifacts are missing or manual review is still pending.
24
+ - Evidence: `RISKS.md` and `SECURITY_REPORT.md`.
9
25
 
10
- ## gate-correctness
26
+ ## gate-operability
11
27
 
12
- - Invariant: behavior satisfies spec acceptance criteria.
13
- - Pass condition: mapped tests pass and no unresolved critical failures.
14
- - Fail condition: failing mapped test, unresolved regression, or invalid provenance.
15
- - Evidence: test output and verification report pointers.
28
+ - Invariant: release readiness includes observability evidence and a release decision.
29
+ - Pass condition: `OBSERVABILITY_REPORT.md` and `RELEASE_DECISION.md` exist for the release stage.
30
+ - Fail condition: either release-stage artifact is missing.
31
+ - Evidence: `OBSERVABILITY_REPORT.md` and `RELEASE_DECISION.md`.
@@ -37,7 +37,7 @@ modules:
37
37
  qa:
38
38
  version: "1.0.0"
39
39
  depends_on: ["build"]
40
- gates: ["gate-completeness", "gate-correctness", "gate-autonomy"]
40
+ gates: ["gate-completeness"]
41
41
 
42
42
  docs:
43
43
  version: "1.0.0"
@@ -64,7 +64,6 @@ modules:
64
64
  eval:
65
65
  version: "1.0.0"
66
66
  depends_on: ["qa"]
67
- gates: ["gate-evaluation"]
68
67
 
69
68
  release:
70
69
  version: "1.0.0"
@@ -93,11 +92,7 @@ pipelines:
93
92
  gates:
94
93
  gate-completeness:
95
94
  module: qa
96
- inputs: ["SPEC_CONTRACT.json", "artifact_set"]
97
-
98
- gate-correctness:
99
- module: qa
100
- inputs: ["test_results", "EVIDENCE_LOG.md"]
95
+ inputs: ["TASK.md", "SCOPE.md", "QUALITY_GATES.md", "STATUS.md", "HANDOFF.json", "EVIDENCE_LOG.md", "DECISIONS.md", "RISKS.md", "TEAL_CONFIG.md", "PROVENANCE_LOG.md", "ARTIFACT_MANIFEST.json"]
101
96
 
102
97
  gate-autonomy:
103
98
  module: skeptic
@@ -107,10 +102,6 @@ gates:
107
102
  module: security
108
103
  inputs: ["RISKS.md", "SECURITY_REPORT.md"]
109
104
 
110
- gate-evaluation:
111
- module: eval
112
- inputs: ["EVAL_REPORT.md"]
113
-
114
105
  gate-operability:
115
106
  module: release
116
107
  inputs: ["OBSERVABILITY_REPORT.md", "RELEASE_DECISION.md"]
@@ -10,11 +10,17 @@ interface AstGrepMatch {
10
10
  line?: number;
11
11
  column?: number;
12
12
  };
13
+ byteOffset?: {
14
+ start?: number;
15
+ end?: number;
16
+ };
13
17
  };
14
- metaVariables?: Record<string, unknown>;
18
+ metaVariables?: unknown;
15
19
  kind?: string;
16
20
  nodeKind?: string;
21
+ replacement?: string;
17
22
  }
23
+ export declare function flattenMetaVariables(raw: unknown): Record<string, string>;
18
24
  export interface AstgrepMatch {
19
25
  file: string;
20
26
  line: number;
@@ -4,6 +4,57 @@ import { isAbsolute, relative, resolve } from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { appendStatusEventSafe } from "./status-events.js";
6
6
  import { safeRead, safeWrite, WORKSPACE_ROOT, wsPath } from "./helpers.js";
7
+ function textFromMetaValue(value) {
8
+ if (typeof value === "string")
9
+ return value;
10
+ if (value && typeof value === "object") {
11
+ const text = value.text;
12
+ if (typeof text === "string")
13
+ return text;
14
+ }
15
+ return undefined;
16
+ }
17
+ const META_SINGLE_BUCKETS = ["single", "transformed"];
18
+ const META_MULTI_BUCKETS = ["multi"];
19
+ export function flattenMetaVariables(raw) {
20
+ const out = {};
21
+ if (!raw || typeof raw !== "object")
22
+ return out;
23
+ const root = raw;
24
+ for (const bucketKey of META_SINGLE_BUCKETS) {
25
+ const bucket = root[bucketKey];
26
+ if (bucket && typeof bucket === "object") {
27
+ for (const [name, value] of Object.entries(bucket)) {
28
+ const text = textFromMetaValue(value);
29
+ if (typeof text === "string" && text.length > 0)
30
+ out[name] = text;
31
+ }
32
+ }
33
+ }
34
+ for (const bucketKey of META_MULTI_BUCKETS) {
35
+ const bucket = root[bucketKey];
36
+ if (bucket && typeof bucket === "object") {
37
+ for (const [name, value] of Object.entries(bucket)) {
38
+ if (!Array.isArray(value))
39
+ continue;
40
+ const texts = value
41
+ .map(textFromMetaValue)
42
+ .filter((text) => typeof text === "string" && text.length > 0);
43
+ if (texts.length > 0)
44
+ out[name] = texts.join("");
45
+ }
46
+ }
47
+ }
48
+ const reserved = new Set([...META_SINGLE_BUCKETS, ...META_MULTI_BUCKETS]);
49
+ for (const [name, value] of Object.entries(root)) {
50
+ if (reserved.has(name) || out[name] !== undefined)
51
+ continue;
52
+ const text = textFromMetaValue(value);
53
+ if (typeof text === "string" && text.length > 0)
54
+ out[name] = text;
55
+ }
56
+ return out;
57
+ }
7
58
  export function runAstgrepQuery(pattern, lang, roots, _contextLines) {
8
59
  const cmd = detectAstgrepCommand();
9
60
  const raw = runAstgrep(cmd, pattern, lang, roots);
@@ -32,15 +83,8 @@ function nodeKindForMatch(match) {
32
83
  return undefined;
33
84
  }
34
85
  function captureMapForMatch(match) {
35
- if (!match.metaVariables)
36
- return undefined;
37
- const captures = Object.entries(match.metaVariables).reduce((acc, [key]) => {
38
- const text = extractMetaVarText(match, key);
39
- if (typeof text === "string" && text.length > 0)
40
- acc[key] = text;
41
- return acc;
42
- }, {});
43
- return Object.keys(captures).length > 0 ? captures : undefined;
86
+ const flat = flattenMetaVariables(match.metaVariables);
87
+ return Object.keys(flat).length > 0 ? flat : undefined;
44
88
  }
45
89
  function computeMatchId(input) {
46
90
  const encoded = [
@@ -59,12 +103,8 @@ function computeMatchId(input) {
59
103
  function matchUsesSymbolHint(match, symbolHint) {
60
104
  if ((match.text ?? "").includes(symbolHint))
61
105
  return true;
62
- if (!match.metaVariables)
63
- return false;
64
- return Object.keys(match.metaVariables).some((key) => {
65
- const text = extractMetaVarText(match, key);
66
- return typeof text === "string" && text.includes(symbolHint);
67
- });
106
+ const flat = flattenMetaVariables(match.metaVariables);
107
+ return Object.values(flat).some((text) => text.includes(symbolHint));
68
108
  }
69
109
  export function locateAstgrepMatches(input) {
70
110
  const scope = resolveScope(input.scope ?? "src");
@@ -109,6 +149,14 @@ export function locateAstgrepMatches(input) {
109
149
  line: match.range.end?.line ?? 0,
110
150
  column: match.range.end?.column ?? 0,
111
151
  },
152
+ ...(match.range.byteOffset
153
+ ? {
154
+ byteOffset: {
155
+ start: match.range.byteOffset.start ?? 0,
156
+ end: match.range.byteOffset.end ?? 0,
157
+ },
158
+ }
159
+ : {}),
112
160
  };
113
161
  return [{
114
162
  match_id: computeMatchId({
@@ -270,27 +318,6 @@ function runAstgrep(astgrepCmd, pattern, lang, paths) {
270
318
  return [];
271
319
  return parseAstgrepOutput(res.stdout);
272
320
  }
273
- function extractMetaVarText(match, key) {
274
- const raw = match.metaVariables?.[key];
275
- if (!raw)
276
- return undefined;
277
- if (typeof raw === "string")
278
- return raw;
279
- if (raw && typeof raw === "object" && "text" in raw && typeof raw.text === "string") {
280
- return raw.text;
281
- }
282
- if (Array.isArray(raw)) {
283
- const first = raw[0];
284
- if (typeof first === "string")
285
- return first;
286
- if (first && typeof first === "object" && "text" in first) {
287
- const text = first.text;
288
- if (typeof text === "string")
289
- return text;
290
- }
291
- }
292
- return undefined;
293
- }
294
321
  function uniqueSorted(values, limit) {
295
322
  return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b)).slice(0, limit);
296
323
  }
@@ -357,13 +384,13 @@ export async function refreshAstgrepIndex(input = {}) {
357
384
  const pyTestMatches = runAstgrep(astgrepCmd, "def test_$NAME($$$ARGS):", "python", pyRoots);
358
385
  const handoffRefMatches = runAstgrep(astgrepCmd, '$X(\"SWARM_HANDOFF.$Y\")', "ts", tsRoots);
359
386
  const exportedFunctions = uniqueSorted(exportedFnMatches
360
- .map((m) => extractMetaVarText(m, "NAME"))
387
+ .map((m) => flattenMetaVariables(m.metaVariables).NAME)
361
388
  .filter((v) => Boolean(v)), 40);
362
389
  const exportedClasses = uniqueSorted(exportedClassMatches
363
- .map((m) => extractMetaVarText(m, "NAME"))
390
+ .map((m) => flattenMetaVariables(m.metaVariables).NAME)
364
391
  .filter((v) => Boolean(v)), 30);
365
392
  const asyncFunctions = uniqueSorted(asyncFnMatches
366
- .map((m) => extractMetaVarText(m, "NAME"))
393
+ .map((m) => flattenMetaVariables(m.metaVariables).NAME)
367
394
  .filter((v) => Boolean(v)), 40);
368
395
  // Fallback symbol extraction when AST match shapes differ across language versions.
369
396
  const tsFiles = codeFiles.filter((file) => /\.(ts|tsx|js)$/i.test(file));
package/dist/cli.js CHANGED
@@ -554,7 +554,7 @@ function getStoredMcpConfigKey(client) {
554
554
  if (client === "vscode")
555
555
  return "knowledge/host/.vscode/mcp.json";
556
556
  if (client === "claude")
557
- return "knowledge/host/.mcp-config/claude_desktop_config.json";
557
+ return "knowledge/host/.mcp-config/claude_code.mcp.json";
558
558
  if (client === "cursor")
559
559
  return "knowledge/host/.mcp-config/cursor.mcp.json";
560
560
  return "knowledge/host/.mcp-config/antigravity.mcp.json";
@@ -0,0 +1,63 @@
1
+ export type GateScope = "workspace" | "package";
2
+ export type GateActivation = "stage" | "explicit_only";
3
+ export type GateManifestType = "executable" | "artifact_scan" | "manual_review";
4
+ export type GateManifestSource = "workspace" | "store" | "none";
5
+ export type GateSelectionMode = "explicit" | "active_stage";
6
+ export interface GateManifest {
7
+ id: string;
8
+ type: GateManifestType;
9
+ invariant: string;
10
+ command: string;
11
+ evidence_requirement: string;
12
+ scope?: GateScope;
13
+ activation?: GateActivation;
14
+ source_ref?: string;
15
+ }
16
+ export interface GateSelectionContext {
17
+ active_role?: string;
18
+ active_module?: string;
19
+ active_pipeline?: string;
20
+ }
21
+ export interface TealModuleConfig {
22
+ version?: string;
23
+ interface?: string;
24
+ sidecar?: boolean;
25
+ depends_on?: string[];
26
+ outputs?: string[];
27
+ gates?: string[];
28
+ }
29
+ export interface TealGateConfig {
30
+ module?: string;
31
+ inputs?: string[];
32
+ }
33
+ export interface TealConfig {
34
+ modules?: Record<string, TealModuleConfig>;
35
+ pipelines?: Record<string, unknown>;
36
+ gates?: Record<string, TealGateConfig>;
37
+ }
38
+ export interface GateSelectionResult extends GateSelectionContext {
39
+ selection_mode: GateSelectionMode;
40
+ manifest_source: GateManifestSource;
41
+ selected: GateManifest[];
42
+ selected_gate_ids: string[];
43
+ skipped_gate_ids: string[];
44
+ all_gate_ids: string[];
45
+ missing_explicit_gate_ids: string[];
46
+ note?: string;
47
+ }
48
+ export declare function normalizeActiveModuleName(value?: string): string | undefined;
49
+ export declare function parseGateManifest(raw: string, sourceRef: string): GateManifest | undefined;
50
+ export declare function extractFencedYamlBlock(content: string): {
51
+ language: string;
52
+ yaml: string;
53
+ } | undefined;
54
+ export declare function parseTealConfigMarkdown(content: string): TealConfig | undefined;
55
+ export declare function parseStatusStageContext(content: string): GateSelectionContext;
56
+ export declare function resolveGateSelection(params: {
57
+ gates: GateManifest[];
58
+ manifestSource: GateManifestSource;
59
+ statusRaw: string;
60
+ tealRaw: string;
61
+ gateIds?: string[];
62
+ }): GateSelectionResult;
63
+ //# sourceMappingURL=gate-contract.d.ts.map
@@ -0,0 +1,178 @@
1
+ import { parseDocument } from "yaml";
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function normalizeLineEndings(value) {
6
+ return value.replace(/\r\n/g, "\n");
7
+ }
8
+ function uniquePush(target, value) {
9
+ if (!target.includes(value))
10
+ target.push(value);
11
+ }
12
+ export function normalizeActiveModuleName(value) {
13
+ if (typeof value !== "string")
14
+ return undefined;
15
+ const trimmed = value.trim().replace(/^`|`$/g, "");
16
+ if (!trimmed)
17
+ return undefined;
18
+ return trimmed.replace(/^(capability|agent)-/, "");
19
+ }
20
+ export function parseGateManifest(raw, sourceRef) {
21
+ try {
22
+ const gate = JSON.parse(raw);
23
+ if (!isRecord(gate))
24
+ return undefined;
25
+ const id = typeof gate.id === "string" ? gate.id.trim() : "";
26
+ if (!id)
27
+ return undefined;
28
+ const type = gate.type === "executable" || gate.type === "artifact_scan" || gate.type === "manual_review"
29
+ ? gate.type
30
+ : "manual_review";
31
+ const scope = gate.scope === "workspace" || gate.scope === "package" ? gate.scope : undefined;
32
+ const activation = gate.activation === "stage" || gate.activation === "explicit_only"
33
+ ? gate.activation
34
+ : undefined;
35
+ return {
36
+ id,
37
+ type,
38
+ invariant: typeof gate.invariant === "string" ? gate.invariant : "",
39
+ command: typeof gate.command === "string" ? gate.command : "",
40
+ evidence_requirement: typeof gate.evidence_requirement === "string" ? gate.evidence_requirement : "",
41
+ ...(scope ? { scope } : {}),
42
+ ...(activation ? { activation } : {}),
43
+ source_ref: sourceRef,
44
+ };
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ export function extractFencedYamlBlock(content) {
51
+ const normalized = normalizeLineEndings(content);
52
+ const fenceCount = (normalized.match(/```/g) ?? []).length;
53
+ const fencedBlocks = [...normalized.matchAll(/```([^\n]*)\n([\s\S]*?)```/g)];
54
+ if (fenceCount !== 2 || fencedBlocks.length !== 1) {
55
+ return undefined;
56
+ }
57
+ const block = fencedBlocks[0];
58
+ return {
59
+ language: block[1].trim().toLowerCase(),
60
+ yaml: block[2].trim(),
61
+ };
62
+ }
63
+ export function parseTealConfigMarkdown(content) {
64
+ const block = extractFencedYamlBlock(content);
65
+ if (!block || block.language !== "yaml" || !block.yaml) {
66
+ return undefined;
67
+ }
68
+ const document = parseDocument(block.yaml);
69
+ if (document.errors.length > 0) {
70
+ return undefined;
71
+ }
72
+ const parsed = document.toJS();
73
+ return isRecord(parsed) ? parsed : undefined;
74
+ }
75
+ function extractStatusField(content, label) {
76
+ const normalized = normalizeLineEndings(content);
77
+ const escapedLabel = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
78
+ const match = normalized.match(new RegExp(`^-\\s*${escapedLabel}:\\s*(.+)$`, "im"));
79
+ if (!match)
80
+ return undefined;
81
+ const value = match[1].trim().replace(/^`|`$/g, "");
82
+ return value || undefined;
83
+ }
84
+ export function parseStatusStageContext(content) {
85
+ const activeRole = extractStatusField(content, "Current role");
86
+ const explicitModule = extractStatusField(content, "Current module");
87
+ return {
88
+ active_role: activeRole,
89
+ active_module: normalizeActiveModuleName(explicitModule ?? activeRole),
90
+ active_pipeline: extractStatusField(content, "Active pipeline"),
91
+ };
92
+ }
93
+ function readStageAssignedGateIds(tealConfig, activeModule) {
94
+ if (!tealConfig || !activeModule)
95
+ return [];
96
+ const gateIds = [];
97
+ const moduleConfig = tealConfig.modules?.[activeModule];
98
+ if (moduleConfig && Array.isArray(moduleConfig.gates)) {
99
+ for (const gateId of moduleConfig.gates) {
100
+ if (typeof gateId === "string" && gateId.trim()) {
101
+ uniquePush(gateIds, gateId.trim());
102
+ }
103
+ }
104
+ }
105
+ if (tealConfig.gates) {
106
+ for (const [gateId, gateConfig] of Object.entries(tealConfig.gates)) {
107
+ if (gateConfig &&
108
+ typeof gateConfig.module === "string" &&
109
+ normalizeActiveModuleName(gateConfig.module) === activeModule) {
110
+ uniquePush(gateIds, gateId);
111
+ }
112
+ }
113
+ }
114
+ return gateIds;
115
+ }
116
+ function effectiveGateScope(gate) {
117
+ return gate.scope ?? "workspace";
118
+ }
119
+ function effectiveGateActivation(gate, assignedStageGateIds) {
120
+ return gate.activation ?? (assignedStageGateIds.has(gate.id) ? "stage" : "explicit_only");
121
+ }
122
+ export function resolveGateSelection(params) {
123
+ const { gates, manifestSource, statusRaw, tealRaw, gateIds } = params;
124
+ const allGateIds = gates.map((gate) => gate.id);
125
+ const statusContext = parseStatusStageContext(statusRaw);
126
+ if (Array.isArray(gateIds) && gateIds.length > 0) {
127
+ const gateMap = new Map(gates.map((gate) => [gate.id, gate]));
128
+ const selected = [];
129
+ const missingExplicitGateIds = [];
130
+ for (const gateId of gateIds) {
131
+ const gate = gateMap.get(gateId);
132
+ if (gate) {
133
+ selected.push(gate);
134
+ }
135
+ else if (!missingExplicitGateIds.includes(gateId)) {
136
+ missingExplicitGateIds.push(gateId);
137
+ }
138
+ }
139
+ return {
140
+ selection_mode: "explicit",
141
+ manifest_source: manifestSource,
142
+ selected,
143
+ selected_gate_ids: selected.map((gate) => gate.id),
144
+ skipped_gate_ids: allGateIds.filter((gateId) => !selected.some((gate) => gate.id === gateId)),
145
+ all_gate_ids: allGateIds,
146
+ missing_explicit_gate_ids: missingExplicitGateIds,
147
+ ...statusContext,
148
+ };
149
+ }
150
+ const tealConfig = parseTealConfigMarkdown(tealRaw);
151
+ const mappedGateIds = readStageAssignedGateIds(tealConfig, statusContext.active_module);
152
+ const mappedGateIdSet = new Set(mappedGateIds);
153
+ const selected = gates.filter((gate) => mappedGateIdSet.has(gate.id) &&
154
+ effectiveGateScope(gate) === "workspace" &&
155
+ effectiveGateActivation(gate, mappedGateIdSet) === "stage");
156
+ let note;
157
+ if (!statusContext.active_module) {
158
+ note = "No active ACE role/module could be resolved from STATUS.md. Use explicit gate_ids when needed.";
159
+ }
160
+ else if (mappedGateIds.length === 0) {
161
+ note = `No stage-activated workspace gates are configured for active module "${statusContext.active_module}". Use explicit gate_ids when needed.`;
162
+ }
163
+ else if (selected.length === 0) {
164
+ note = `No implicitly runnable workspace gates matched active module "${statusContext.active_module}". Package-scope and explicit-only gates require explicit gate_ids.`;
165
+ }
166
+ return {
167
+ selection_mode: "active_stage",
168
+ manifest_source: manifestSource,
169
+ selected,
170
+ selected_gate_ids: selected.map((gate) => gate.id),
171
+ skipped_gate_ids: allGateIds.filter((gateId) => !selected.some((gate) => gate.id === gateId)),
172
+ all_gate_ids: allGateIds,
173
+ missing_explicit_gate_ids: [],
174
+ note,
175
+ ...statusContext,
176
+ };
177
+ }
178
+ //# sourceMappingURL=gate-contract.js.map
@@ -473,7 +473,7 @@ export function getMcpClientBundlePath(client) {
473
473
  if (client === "copilot")
474
474
  return wsPath(".mcp.json");
475
475
  if (client === "claude")
476
- return wsPath(".mcp-config", "claude_desktop_config.json");
476
+ return wsPath(".mcp-config", "claude_code.mcp.json");
477
477
  if (client === "cursor")
478
478
  return wsPath(".mcp-config", "cursor.mcp.json");
479
479
  return wsPath(".mcp-config", "antigravity.mcp.json");
@@ -491,8 +491,8 @@ export function getMcpClientInstallHint(client) {
491
491
  }
492
492
  if (client === "claude") {
493
493
  return [
494
- `${resolve(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json")} (macOS, merge output from \`ace mcp-config --client claude\`)`,
495
- `${resolve(homedir(), ".config", "Claude", "claude_desktop_config.json")} (Linux, merge output from \`ace mcp-config --client claude\`)`,
494
+ `Claude Code CLI: project scope is already wired via ${wsPath(".mcp.json")} (written by \`ace preconfig\`) just run \`claude\` in this workspace`,
495
+ `User scope: \`claude mcp add-json ace-swarm "$(ace mcp-config --client claude)"\` (or merge into ${resolve(homedir(), ".claude.json")})`,
496
496
  ].join(" | ");
497
497
  }
498
498
  if (client === "cursor") {
@@ -829,7 +829,7 @@ export function bootstrapAceWorkspace(options = {}) {
829
829
  "## Files",
830
830
  "- `codex.config.toml`",
831
831
  "- `vscode.mcp.json`",
832
- "- `claude_desktop_config.json`",
832
+ "- `claude_code.mcp.json`",
833
833
  "- `cursor.mcp.json`",
834
834
  "- `antigravity.mcp.json`",
835
835
  "",