@kontextmind/kxm 0.6.0 → 0.7.10
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/.claude-plugin/marketplace.json +1 -1
- package/.kxm/agents/coordinator.yaml +9 -0
- package/.kxm/agents/critic-arch.yaml +13 -0
- package/.kxm/agents/critic-cli.yaml +13 -0
- package/.kxm/agents/implementer.yaml +13 -0
- package/.kxm/gates.yaml +8 -0
- package/.kxm/producers.yaml +22 -0
- package/.kxm/project.yaml +15 -0
- package/.kxm/roles/writer.yaml +7 -0
- package/.kxm/workflows/default.yaml +47 -0
- package/CHANGELOG.md +39 -7
- package/README.md +1 -0
- package/docs/README.md +5 -0
- package/docs/adr/ADR-0002-browser-automation-steel-doks.md +103 -0
- package/docs/agent-skills.md +135 -0
- package/docs/architecture.md +1 -1
- package/docs/assignment-runner.md +21 -8
- package/docs/browser-automation.md +116 -0
- package/docs/configuration.md +11 -2
- package/docs/getting-started.md +21 -0
- package/docs/kb/how-credentials-retrieved-safely.md +31 -0
- package/docs/kb/how-to-capture-and-annotate-section.md +60 -0
- package/docs/kb/how-to-connect-playwright-to-steel.md +54 -0
- package/docs/kb/how-to-recover-expired-session-or-orphan.md +54 -0
- package/docs/kb/how-to-resume-after-mfa.md +28 -0
- package/docs/kb/how-to-take-over-session.md +32 -0
- package/docs/kb/why-authentication-disappeared.md +32 -0
- package/docs/kb/why-automation-opened-different-browser.md +32 -0
- package/docs/kb/why-session-viewer-cannot-control.md +31 -0
- package/docs/kxm-handbook.md +3 -3
- package/docs/operations.md +24 -0
- package/docs/operator-pi-packages.md +63 -0
- package/docs/prompts/browser-annotate-feedback.md +41 -0
- package/docs/prompts/browser-diagnose-recover.md +38 -0
- package/docs/prompts/browser-explore.md +42 -0
- package/docs/prompts/browser-repro-fix.md +48 -0
- package/docs/prompts/browser-start.md +41 -0
- package/docs/prompts/browser-takeover.md +50 -0
- package/docs/skills/repo-work-delivery.md +107 -0
- package/docs/skills.md +2 -0
- package/docs/test-matrix.md +4 -3
- package/docs/troubleshooting.md +41 -1
- package/docs/vnext/validation.md +9 -0
- package/docs/webhook-workflows.md +2 -2
- package/examples/README.md +1 -1
- package/package.json +16 -17
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/README.md +1 -1
- package/plugins/kxm/dist/cli.js +41620 -35578
- package/plugins/kxm/dist/core.js +271 -34
- package/plugins/kxm/dist/extension.js +7759 -86
- package/plugins/kxm/dist/mcp-server.js +75 -21
- package/plugins/kxm/dist/runtime.js +8218 -2328
- package/plugins/kxm/dist/server.js +3125 -2260
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +5961 -661
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/SUITE.md +5 -0
- package/plugins/kxm/skills/hints.json +103 -0
- package/plugins/kxm/skills/kxm/SKILL.md +30 -83
- package/plugins/kxm/skills/kxm-browser-annotate/SKILL.md +90 -0
- package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +47 -0
- package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-browser-session/SKILL.md +94 -0
- package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +87 -0
- package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +71 -0
- package/plugins/kxm/skills/kxm-context-memory/SKILL.md +69 -0
- package/plugins/kxm/skills/kxm-definitions/SKILL.md +65 -0
- package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +34 -0
- package/plugins/kxm/skills/kxm-harvest/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +43 -0
- package/plugins/kxm/skills/kxm-insights/SKILL.md +48 -0
- package/plugins/kxm/skills/kxm-mind/SKILL.md +59 -0
- package/plugins/kxm/skills/kxm-peer/SKILL.md +110 -0
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +42 -0
- package/plugins/kxm/skills/kxm-projects/SKILL.md +43 -0
- package/plugins/kxm/skills/kxm-protocol/SKILL.md +66 -0
- package/plugins/kxm/skills/kxm-query/SKILL.md +45 -0
- package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +30 -0
- package/plugins/kxm/skills/kxm-runs/SKILL.md +29 -0
- package/plugins/kxm/skills/kxm-setup/SKILL.md +55 -0
- package/plugins/kxm/skills/kxm-skill-lifecycle/SKILL.md +31 -0
- package/plugins/kxm/skills/kxm-tasks/SKILL.md +33 -0
- package/plugins/kxm/skills/kxm-triage/SKILL.md +47 -0
- package/plugins/kxm/skills/kxm-work/SKILL.md +44 -0
- package/plugins/kxm/skills/kxm-workflow/SKILL.md +45 -0
- package/plugins/kxm/src/autocomplete.ts +9 -3
- package/plugins/kxm/src/browser.ts +603 -0
- package/plugins/kxm/src/cli/context-skills.ts +373 -0
- package/plugins/kxm/src/cli/hub.ts +614 -0
- package/plugins/kxm/src/cli/roles.ts +615 -0
- package/plugins/kxm/src/cli/system.ts +906 -0
- package/plugins/kxm/src/cli/tasks.ts +364 -0
- package/plugins/kxm/src/cli/types.ts +270 -0
- package/plugins/kxm/src/cli/vnext.ts +698 -0
- package/plugins/kxm/src/cli/workflows.ts +699 -0
- package/plugins/kxm/src/cli.ts +362 -2849
- package/plugins/kxm/src/commands.ts +150 -8
- package/plugins/kxm/src/completion-install.ts +223 -0
- package/plugins/kxm/src/config.ts +7 -4
- package/plugins/kxm/src/context-packet.ts +172 -0
- package/plugins/kxm/src/database.ts +1 -1
- package/plugins/kxm/src/extension.ts +36 -1
- package/plugins/kxm/src/external-effects.ts +357 -8
- package/plugins/kxm/src/hub-env.ts +193 -0
- package/plugins/kxm/src/hub.ts +2 -4
- package/plugins/kxm/src/improve.ts +72 -0
- package/plugins/kxm/src/init-guide-setup.ts +547 -0
- package/plugins/kxm/src/local-snapshot.ts +1 -1
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/model-inventory.ts +127 -0
- package/plugins/kxm/src/modes.ts +348 -0
- package/plugins/kxm/src/policy-draft.d.mts +55 -0
- package/plugins/kxm/src/policy-draft.mjs +565 -0
- package/plugins/kxm/src/price-calc.ts +17 -18
- package/plugins/kxm/src/prices.ts +32 -16
- package/plugins/kxm/src/producers.ts +71 -0
- package/plugins/kxm/src/protocol.ts +111 -0
- package/plugins/kxm/src/restricted-yaml.d.mts +31 -0
- package/plugins/kxm/src/restricted-yaml.mjs +145 -0
- package/plugins/kxm/src/role.ts +710 -0
- package/plugins/kxm/src/routing.ts +99 -1
- package/plugins/kxm/src/runtime.ts +4 -0
- package/plugins/kxm/src/safety-integrity.ts +76 -0
- package/plugins/kxm/src/session-work.ts +9 -2
- package/plugins/kxm/src/sqlite.ts +76 -0
- package/plugins/kxm/src/ssh-remote.ts +560 -0
- package/plugins/kxm/src/store.ts +1 -1
- package/plugins/kxm/src/studio-layout.ts +660 -17
- package/plugins/kxm/src/subagent-control.ts +312 -0
- package/plugins/kxm/src/suggest.ts +7 -13
- package/plugins/kxm/src/telemetry.ts +82 -0
- package/plugins/kxm/src/tui.ts +140 -0
- package/plugins/kxm/src/vnext-bindings.ts +1 -1
- package/plugins/kxm/src/vnext-config.ts +53 -111
- package/plugins/kxm/src/vnext-engine-command.ts +2 -0
- package/plugins/kxm/src/vnext-engine.ts +214 -62
- package/plugins/kxm/src/vnext-harness.ts +336 -84
- package/plugins/kxm/src/vnext-oneshot-evidence.ts +117 -0
- package/plugins/kxm/src/vnext-oneshot-process.ts +187 -0
- package/plugins/kxm/src/vnext-oneshot-producer.ts +182 -224
- package/plugins/kxm/src/vnext-pi-producer.ts +11 -7
- package/plugins/kxm/src/vnext-runtime-store.ts +36 -2
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +122 -5
- package/plugins/kxm/src/vnext-runtime.ts +14 -0
- package/plugins/kxm/src/workflow-manager.ts +392 -0
- package/plugins/kxm/src/workflow-tui.ts +255 -0
- package/plugins/kxm/src/workflow.ts +144 -0
- package/schemas/policy-draft/README.md +17 -0
- package/schemas/policy-draft/model.v2.schema.json +140 -0
- package/schemas/policy-draft/role.v2.schema.json +91 -0
- package/schemas/vnext/modes.schema.json +56 -0
- package/schemas/vnext/role.schema.json +76 -0
- package/schemas/vnext/run-event.schema.json +1 -0
- package/scripts/assignment-run.d.mts +1 -1
- package/scripts/assignment-run.mjs +44 -35
- package/scripts/check-generated.mjs +33 -9
- package/scripts/emit-codex-artifacts.mjs +255 -11
- package/scripts/harness-run.d.mts +12 -4
- package/scripts/harness-run.mjs +65 -17
- package/scripts/kxm-bump-version.mjs +146 -0
- package/scripts/kxm-hub.mjs +150 -2
- package/scripts/kxm-publish-npm.mjs +3 -1
- package/scripts/kxm-release-github.mjs +3 -1
- package/scripts/kxm.mjs +0 -0
- package/scripts/native-critic.d.mts +5 -0
- package/scripts/native-critic.mjs +60 -0
- package/.kxm/config/README.md +0 -5
- package/.kxm/config/agents.json +0 -43
- package/.kxm/config/env.example +0 -56
- package/.kxm/config/update.example.yaml +0 -9
- package/.kxm/config/workflows/fix.json +0 -160
- package/.kxm/config/workflows/jira-development.json +0 -116
- package/.kxm/config/workflows/provenance-quorum.json +0 -150
- package/.kxm/config/workflows/v04-dogfood.json +0 -72
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.kxm.dev/policy-draft/role.v2.schema.json",
|
|
4
|
+
"title": "KXM policy-draft role",
|
|
5
|
+
"description": "Passive kxm.role.v2 scaffolding. Specialty identity is separate from purpose. Roster order is configured preference, not a measured ranking. Not live admission or operator settings.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "purpose", "permission", "description", "roster"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"schema": { "const": "kxm.role.v2" },
|
|
11
|
+
"id": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"pattern": "^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$",
|
|
14
|
+
"minLength": 1,
|
|
15
|
+
"maxLength": 64
|
|
16
|
+
},
|
|
17
|
+
"purpose": {
|
|
18
|
+
"enum": ["writer", "planner", "reviewer-arch", "reviewer-cli", "experiment"]
|
|
19
|
+
},
|
|
20
|
+
"permission": { "enum": ["edit", "read-only"] },
|
|
21
|
+
"description": { "type": "string", "minLength": 1, "maxLength": 2000 },
|
|
22
|
+
"roster": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"maxItems": 32,
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"required": ["route"],
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"properties": {
|
|
30
|
+
"route": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"maxLength": 64
|
|
35
|
+
},
|
|
36
|
+
"effort": {
|
|
37
|
+
"enum": ["off", "minimal", "low", "medium", "high", "xhigh", "max"]
|
|
38
|
+
},
|
|
39
|
+
"mode": { "enum": ["headless", "interactive", "either"] }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"skills": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
46
|
+
"maxItems": 64
|
|
47
|
+
},
|
|
48
|
+
"tools": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"properties": {
|
|
52
|
+
"preset": { "type": "string" },
|
|
53
|
+
"allow": { "type": "array", "items": { "type": "string" } },
|
|
54
|
+
"deny": { "type": "array", "items": { "type": "string" } }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"produces": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"required": ["template"],
|
|
62
|
+
"additionalProperties": false,
|
|
63
|
+
"properties": {
|
|
64
|
+
"template": { "type": "string" },
|
|
65
|
+
"schema": { "type": "string" }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"consumes": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"items": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"required": ["template"],
|
|
74
|
+
"additionalProperties": false,
|
|
75
|
+
"properties": {
|
|
76
|
+
"template": { "type": "string" },
|
|
77
|
+
"schema": { "type": "string" }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"policy": {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"additionalProperties": false,
|
|
84
|
+
"properties": {
|
|
85
|
+
"vendorIndependenceRequired": { "type": "boolean" },
|
|
86
|
+
"maxTransitions": { "type": "integer", "minimum": 1 },
|
|
87
|
+
"requiresGateVerification": { "type": "boolean" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.kxm.dev/vnext/modes.schema.json",
|
|
4
|
+
"title": "KXM Modes Configuration",
|
|
5
|
+
"description": "Declarative major modes and domain modules for selective tool loading and context scoping",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "majorModes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "kxm.modes.v1" },
|
|
10
|
+
"majorModes": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["baseTools"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"description": { "type": "string" },
|
|
17
|
+
"baseTools": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": { "type": "string" }
|
|
20
|
+
},
|
|
21
|
+
"contextFiles": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": { "type": "string" }
|
|
24
|
+
},
|
|
25
|
+
"thinkingLevel": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"enum": ["low", "medium", "high", "xhigh"]
|
|
28
|
+
},
|
|
29
|
+
"model": { "type": "string" }
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"domains": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": ["tools"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"description": { "type": "string" },
|
|
41
|
+
"tools": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": { "type": "string" }
|
|
44
|
+
},
|
|
45
|
+
"contextFiles": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": { "type": "string" }
|
|
48
|
+
},
|
|
49
|
+
"promptSnippet": { "type": "string" }
|
|
50
|
+
},
|
|
51
|
+
"additionalProperties": false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": false
|
|
56
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.kxm.dev/vnext/role.schema.json",
|
|
4
|
+
"title": "KXM role definition",
|
|
5
|
+
"description": "The filename determines the role identity unless explicitly declared.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "description"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "kxm.role.v1" },
|
|
10
|
+
"id": { "$ref": "common.schema.json#/$defs/identifier" },
|
|
11
|
+
"description": { "type": "string", "minLength": 1, "maxLength": 2000 },
|
|
12
|
+
"skills": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
15
|
+
"maxItems": 64
|
|
16
|
+
},
|
|
17
|
+
"tools": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"preset": { "type": "string" },
|
|
21
|
+
"allow": { "type": "array", "items": { "type": "string" } },
|
|
22
|
+
"deny": { "type": "array", "items": { "type": "string" } }
|
|
23
|
+
},
|
|
24
|
+
"additionalProperties": false
|
|
25
|
+
},
|
|
26
|
+
"produces": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": ["template"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"template": { "type": "string" },
|
|
33
|
+
"schema": { "type": "string" }
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"consumes": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["template"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"template": { "type": "string" },
|
|
45
|
+
"schema": { "type": "string" }
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": false
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"roster": {
|
|
51
|
+
"type": "array",
|
|
52
|
+
"items": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"required": ["harness", "model"],
|
|
55
|
+
"properties": {
|
|
56
|
+
"harness": { "$ref": "common.schema.json#/$defs/identifier" },
|
|
57
|
+
"model": { "$ref": "common.schema.json#/$defs/modelSelector" },
|
|
58
|
+
"provider": { "type": "string" },
|
|
59
|
+
"effort": { "enum": ["low", "medium", "high", "xhigh"] },
|
|
60
|
+
"mode": { "enum": ["headless", "interactive", "either"] }
|
|
61
|
+
},
|
|
62
|
+
"additionalProperties": false
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"policy": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"properties": {
|
|
68
|
+
"vendorIndependenceRequired": { "type": "boolean" },
|
|
69
|
+
"maxTransitions": { "type": "integer", "minimum": 1 },
|
|
70
|
+
"requiresGateVerification": { "type": "boolean" }
|
|
71
|
+
},
|
|
72
|
+
"additionalProperties": false
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"additionalProperties": false
|
|
76
|
+
}
|
|
@@ -323,6 +323,7 @@
|
|
|
323
323
|
"properties": {
|
|
324
324
|
"workflowId": { "$ref": "common.schema.json#/$defs/identifier" },
|
|
325
325
|
"displayTitle": { "type": "string", "minLength": 1, "maxLength": 200 },
|
|
326
|
+
"prompt": { "type": "string", "maxLength": 64000 },
|
|
326
327
|
"promptHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
327
328
|
"runPlanHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
328
329
|
"capabilityHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
@@ -33,7 +33,7 @@ export function resolveRequiredCritics(policy: unknown): Readonly<Record<string,
|
|
|
33
33
|
vendor: string;
|
|
34
34
|
route_id?: string;
|
|
35
35
|
}>>>;
|
|
36
|
-
export function getRosterPolicy(deps?: Record<string, unknown>):
|
|
36
|
+
export function getRosterPolicy(deps?: Record<string, unknown>): import("./roster-policy.mjs").RosterPolicy;
|
|
37
37
|
export const ASSIGNMENT_KINDS: readonly string[];
|
|
38
38
|
export const KIND_ROLES: Readonly<Record<string, string>>;
|
|
39
39
|
export const REVIEW_KINDS: readonly string[];
|
|
@@ -746,30 +746,35 @@ function validateRework(reworkOf, taskDir, taskId, assignmentId, deps) {
|
|
|
746
746
|
return priorId;
|
|
747
747
|
}
|
|
748
748
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
return deps.rosterPolicy.policy ?? deps.rosterPolicy;
|
|
749
|
+
function requireRosterPolicyShape(policy) {
|
|
750
|
+
if (!policy || typeof policy !== "object" || Array.isArray(policy)) {
|
|
751
|
+
throw failClosed("roster policy is invalid or unparsed", "route_invalid");
|
|
753
752
|
}
|
|
754
|
-
if (typeof
|
|
755
|
-
|
|
756
|
-
return loaded?.policy ?? loaded;
|
|
753
|
+
if (!policy.routes || typeof policy.routes !== "object" || Array.isArray(policy.routes) || Object.keys(policy.routes).length === 0) {
|
|
754
|
+
throw failClosed("roster policy is invalid or unparsed", "route_invalid");
|
|
757
755
|
}
|
|
756
|
+
if (!policy.lineup || typeof policy.lineup !== "object" || Array.isArray(policy.lineup)) {
|
|
757
|
+
throw failClosed("roster policy is invalid or unparsed", "route_invalid");
|
|
758
|
+
}
|
|
759
|
+
return policy;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function unwrapRosterPolicy(loaded) {
|
|
763
|
+
return requireRosterPolicyShape(loaded?.policy ?? loaded);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
export function getRosterPolicy(deps = {}) {
|
|
758
767
|
try {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
if (!cachedDiskPolicy) {
|
|
765
|
-
try {
|
|
766
|
-
const diskPath = join(fileURLToPath(new URL(".", import.meta.url)), "..", ".kxm/roster.json");
|
|
767
|
-
cachedDiskPolicy = Object.freeze(JSON.parse(readFileSync(diskPath, "utf8")));
|
|
768
|
-
} catch {
|
|
769
|
-
throw failClosed(error?.message ?? "roster policy unavailable", "route_invalid");
|
|
770
|
-
}
|
|
768
|
+
if (Object.hasOwn(deps, "rosterPolicy")) {
|
|
769
|
+
return unwrapRosterPolicy(deps.rosterPolicy);
|
|
770
|
+
}
|
|
771
|
+
if (typeof deps.loadTrustedRosterPolicy === "function") {
|
|
772
|
+
return unwrapRosterPolicy(deps.loadTrustedRosterPolicy());
|
|
771
773
|
}
|
|
772
|
-
return
|
|
774
|
+
return unwrapRosterPolicy(loadTrustedRosterPolicy());
|
|
775
|
+
} catch (error) {
|
|
776
|
+
if (error?.runnerCode === "route_invalid") throw error;
|
|
777
|
+
throw failClosed(error?.message ?? "roster policy unavailable", "route_invalid");
|
|
773
778
|
}
|
|
774
779
|
}
|
|
775
780
|
|
|
@@ -979,6 +984,15 @@ const MODEL_CLAIM_OVERRIDE_KEYS = Object.freeze([
|
|
|
979
984
|
"usage",
|
|
980
985
|
"transport",
|
|
981
986
|
]);
|
|
987
|
+
function injectedPolicyDeps(source = {}) {
|
|
988
|
+
const deps = {};
|
|
989
|
+
if (Object.hasOwn(source, "rosterPolicy")) deps.rosterPolicy = source.rosterPolicy;
|
|
990
|
+
if (typeof source.loadTrustedRosterPolicy === "function") {
|
|
991
|
+
deps.loadTrustedRosterPolicy = source.loadTrustedRosterPolicy;
|
|
992
|
+
}
|
|
993
|
+
return deps;
|
|
994
|
+
}
|
|
995
|
+
|
|
982
996
|
function ioDeps(deps = {}) {
|
|
983
997
|
return {
|
|
984
998
|
spawnSync: deps.spawnSync ?? spawnSync,
|
|
@@ -996,8 +1010,7 @@ function ioDeps(deps = {}) {
|
|
|
996
1010
|
rmSync: deps.rmSync ?? rmSync,
|
|
997
1011
|
manifestBytes: deps.manifestBytes,
|
|
998
1012
|
now: deps.now,
|
|
999
|
-
|
|
1000
|
-
loadTrustedRosterPolicy: deps.loadTrustedRosterPolicy,
|
|
1013
|
+
...injectedPolicyDeps(deps),
|
|
1001
1014
|
};
|
|
1002
1015
|
}
|
|
1003
1016
|
|
|
@@ -3374,7 +3387,7 @@ function closedObserved(pr, ci) {
|
|
|
3374
3387
|
|
|
3375
3388
|
export function resolveRequiredCritics(policy) {
|
|
3376
3389
|
if (!policy || typeof policy !== "object" || !policy.required_critics || !policy.routes) {
|
|
3377
|
-
|
|
3390
|
+
throw failClosed("roster policy is invalid or unparsed", "route_invalid");
|
|
3378
3391
|
}
|
|
3379
3392
|
const result = {};
|
|
3380
3393
|
for (const [kind, routeId] of Object.entries(policy.required_critics)) {
|
|
@@ -3409,11 +3422,10 @@ function assertEligibleWriter(bound, policy) {
|
|
|
3409
3422
|
if (!(transport?.status === "completed" && transport?.ok === true)) {
|
|
3410
3423
|
throw failClosed("writer transport is not completed/ok", "witness_binding_invalid");
|
|
3411
3424
|
}
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
}
|
|
3425
|
+
requireRosterPolicyShape(policy);
|
|
3426
|
+
const matched = findLineupRoute(policy, "writer", bound.identity.harness, bound.identity.model);
|
|
3427
|
+
if (!matched) {
|
|
3428
|
+
throw failClosed(`writer ${bound.identity.harness}/${bound.identity.model} is not admitted in lineup`, "witness_binding_invalid");
|
|
3417
3429
|
}
|
|
3418
3430
|
}
|
|
3419
3431
|
|
|
@@ -3669,12 +3681,7 @@ export async function acceptAssignment(request, deps = {}) {
|
|
|
3669
3681
|
const commitValue = request?.commit;
|
|
3670
3682
|
const writerRecordValue = request?.recordDir ?? request?.record_dir;
|
|
3671
3683
|
const criticValues = request?.critics;
|
|
3672
|
-
|
|
3673
|
-
try {
|
|
3674
|
-
policy = getRosterPolicy(deps);
|
|
3675
|
-
} catch {
|
|
3676
|
-
policy = null;
|
|
3677
|
-
}
|
|
3684
|
+
const policy = getRosterPolicy(deps);
|
|
3678
3685
|
const criticSpecs = resolveRequiredCritics(policy);
|
|
3679
3686
|
const requiredKinds = Object.keys(criticSpecs);
|
|
3680
3687
|
if (!Array.isArray(criticValues) || criticValues.length !== requiredKinds.length) {
|
|
@@ -4337,6 +4344,7 @@ export async function main(argv = process.argv, io = { stdin: process.stdin, std
|
|
|
4337
4344
|
spawnSync: io.spawnSync ?? spawnSync,
|
|
4338
4345
|
env: io.env,
|
|
4339
4346
|
now: io.now,
|
|
4347
|
+
...injectedPolicyDeps(io),
|
|
4340
4348
|
});
|
|
4341
4349
|
io.stdout.write(`${JSON.stringify(accepted, undefined, 2)}\n`);
|
|
4342
4350
|
process.exitCode = 0;
|
|
@@ -4395,6 +4403,7 @@ export async function main(argv = process.argv, io = { stdin: process.stdin, std
|
|
|
4395
4403
|
spawnSync: io.spawnSync ?? spawnSync,
|
|
4396
4404
|
env: io.env,
|
|
4397
4405
|
now: io.now,
|
|
4406
|
+
...injectedPolicyDeps(io),
|
|
4398
4407
|
});
|
|
4399
4408
|
io.stdout.write(`${JSON.stringify(receipt, undefined, 2)}\n`);
|
|
4400
4409
|
process.exitCode = receipt.result === "passed" ? 0 : 1;
|
|
@@ -4418,7 +4427,7 @@ export async function main(argv = process.argv, io = { stdin: process.stdin, std
|
|
|
4418
4427
|
const bytes = readFileSync(manifestPath);
|
|
4419
4428
|
const manifest = parseJsonFile(manifestPath, bytes, "assignment manifest");
|
|
4420
4429
|
try {
|
|
4421
|
-
const completion = await runAssignment(manifest, { manifestBytes: bytes });
|
|
4430
|
+
const completion = await runAssignment(manifest, { manifestBytes: bytes, ...injectedPolicyDeps(io) });
|
|
4422
4431
|
io.stdout.write(`${JSON.stringify(completion, undefined, 2)}\n`);
|
|
4423
4432
|
process.exitCode = completion.transport?.ok === true && completion.recording?.status === "ok" ? 0 : 1;
|
|
4424
4433
|
return completion;
|
|
@@ -4,8 +4,9 @@ import { existsSync } from "node:fs";
|
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { listSkillMirrorArtifacts, loadSkillSuiteManifest } from "./emit-codex-artifacts.mjs";
|
|
7
8
|
|
|
8
|
-
export const
|
|
9
|
+
export const STATIC_GENERATED_ARTIFACTS = Object.freeze([
|
|
9
10
|
"plugins/kxm/dist/cli.js",
|
|
10
11
|
"plugins/kxm/dist/server.js",
|
|
11
12
|
"plugins/kxm/dist/mcp-server.js",
|
|
@@ -14,13 +15,34 @@ export const GENERATED_ARTIFACTS = [
|
|
|
14
15
|
"plugins/kxm/dist/runtime.js",
|
|
15
16
|
"plugins/kxm/dist/client.js",
|
|
16
17
|
"plugins/kxm/dist/extension.js",
|
|
17
|
-
".agents/skills/kxm/SKILL.md",
|
|
18
|
-
".agents/skills/kxm/references/protocol.md",
|
|
19
|
-
".agents/skills/kxm-session/SKILL.md",
|
|
20
18
|
"AGENTS.md",
|
|
21
19
|
"CLAUDE.md",
|
|
22
20
|
"GEMINI.md",
|
|
23
|
-
];
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Compute the generated artifact list from the committed suite manifest.
|
|
25
|
+
* The manifest is required; missing or invalid manifests fail closed.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} [repository]
|
|
28
|
+
* @returns {string[]}
|
|
29
|
+
*/
|
|
30
|
+
export function computeGeneratedArtifacts(repository = process.cwd()) {
|
|
31
|
+
const root = resolve(repository);
|
|
32
|
+
loadSkillSuiteManifest(root);
|
|
33
|
+
return Object.freeze([
|
|
34
|
+
...STATIC_GENERATED_ARTIFACTS,
|
|
35
|
+
...listSkillMirrorArtifacts(root),
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Synchronous snapshot for the current repository. Tests that need a
|
|
41
|
+
* fixture-specific list should call computeGeneratedArtifacts(root).
|
|
42
|
+
*
|
|
43
|
+
* @type {readonly string[]}
|
|
44
|
+
*/
|
|
45
|
+
export const GENERATED_ARTIFACTS = computeGeneratedArtifacts();
|
|
24
46
|
|
|
25
47
|
function runGit(repository, args, allowFailure = false) {
|
|
26
48
|
const result = spawnSync("git", args, {
|
|
@@ -39,12 +61,14 @@ export function checkGeneratedArtifacts(repository = process.cwd()) {
|
|
|
39
61
|
const requestedRoot = resolve(repository);
|
|
40
62
|
const topLevel = runGit(requestedRoot, ["rev-parse", "--show-toplevel"]).stdout.trim();
|
|
41
63
|
const root = resolve(topLevel);
|
|
42
|
-
const
|
|
64
|
+
const artifacts = computeGeneratedArtifacts(root);
|
|
65
|
+
|
|
66
|
+
const missing = artifacts.filter((path) => !existsSync(resolve(root, path)));
|
|
43
67
|
if (missing.length > 0) {
|
|
44
68
|
throw new Error(`generated artifacts are missing: ${missing.join(", ")}`);
|
|
45
69
|
}
|
|
46
70
|
|
|
47
|
-
const untracked =
|
|
71
|
+
const untracked = artifacts.filter((path) => runGit(
|
|
48
72
|
root,
|
|
49
73
|
["--literal-pathspecs", "ls-files", "--error-unmatch", "--", path],
|
|
50
74
|
true,
|
|
@@ -58,12 +82,12 @@ export function checkGeneratedArtifacts(repository = process.cwd()) {
|
|
|
58
82
|
"diff",
|
|
59
83
|
"--name-only",
|
|
60
84
|
"--",
|
|
61
|
-
...
|
|
85
|
+
...artifacts,
|
|
62
86
|
]).stdout.trim();
|
|
63
87
|
if (status) {
|
|
64
88
|
throw new Error(`generated artifacts changed after build:\n${status}`);
|
|
65
89
|
}
|
|
66
|
-
return { root, artifacts: [...
|
|
90
|
+
return { root, artifacts: [...artifacts] };
|
|
67
91
|
}
|
|
68
92
|
|
|
69
93
|
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|