@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
|
@@ -4,30 +4,19 @@ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync } from "
|
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { Ajv2020, type ErrorObject, type ValidateFunction } from "ajv/dist/2020.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
RestrictedYamlError,
|
|
9
|
+
VNEXT_YAML_LIMITS,
|
|
10
|
+
parseRestrictedYaml as parseRestrictedYamlShared,
|
|
11
|
+
type VnextYamlLimits,
|
|
12
|
+
} from "./restricted-yaml.mjs";
|
|
8
13
|
import { resolveVnextTemplateBaseline } from "./vnext-template.ts";
|
|
9
14
|
import { BUILTIN_HARNESS_IDS, DEFAULT_HARNESS, validateHarnessModelPair } from "./vnext-harness.ts";
|
|
10
15
|
|
|
11
16
|
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
|
|
12
17
|
export type JsonObject = { [key: string]: JsonValue };
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
maxDocumentBytes: number;
|
|
16
|
-
maxDepth: number;
|
|
17
|
-
maxScalarBytes: number;
|
|
18
|
-
maxCollectionItems: number;
|
|
19
|
-
maxTotalNodes: number;
|
|
20
|
-
maxKeys: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const VNEXT_YAML_LIMITS: Readonly<VnextYamlLimits> = Object.freeze({
|
|
24
|
-
maxDocumentBytes: 256 * 1024,
|
|
25
|
-
maxDepth: 32,
|
|
26
|
-
maxScalarBytes: 64 * 1024,
|
|
27
|
-
maxCollectionItems: 4096,
|
|
28
|
-
maxTotalNodes: 16_384,
|
|
29
|
-
maxKeys: 8192,
|
|
30
|
-
});
|
|
18
|
+
export type { VnextYamlLimits };
|
|
19
|
+
export { VNEXT_YAML_LIMITS };
|
|
31
20
|
|
|
32
21
|
export type VnextValidationPhase = "discovery" | "parse" | "schema" | "path" | "reference" | "semantic";
|
|
33
22
|
|
|
@@ -120,16 +109,6 @@ const SECRET_VALUE_PATTERNS: readonly RegExp[] = [
|
|
|
120
109
|
/\bAKIA[A-Z0-9]{16}\b/,
|
|
121
110
|
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/,
|
|
122
111
|
];
|
|
123
|
-
const ALLOWED_YAML_TAGS = new Set([
|
|
124
|
-
"tag:yaml.org,2002:map",
|
|
125
|
-
"tag:yaml.org,2002:seq",
|
|
126
|
-
"tag:yaml.org,2002:str",
|
|
127
|
-
"tag:yaml.org,2002:null",
|
|
128
|
-
"tag:yaml.org,2002:bool",
|
|
129
|
-
"tag:yaml.org,2002:int",
|
|
130
|
-
"tag:yaml.org,2002:float",
|
|
131
|
-
]);
|
|
132
|
-
|
|
133
112
|
function compareCodeUnits(left: string, right: string): number {
|
|
134
113
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
135
114
|
}
|
|
@@ -149,97 +128,22 @@ function fail(phase: VnextValidationPhase, code: string, file: string, message:
|
|
|
149
128
|
throw new VnextConfigError([issue(phase, code, file, message)]);
|
|
150
129
|
}
|
|
151
130
|
|
|
152
|
-
function decodeUtf8(input: string | Uint8Array, label: string): string {
|
|
153
|
-
if (typeof input === "string") return input;
|
|
154
|
-
try {
|
|
155
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(input);
|
|
156
|
-
} catch {
|
|
157
|
-
fail("parse", "invalid_utf8", label, "document is not valid UTF-8");
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
131
|
function isJsonObject(value: JsonValue): value is JsonObject {
|
|
162
132
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
163
133
|
}
|
|
164
134
|
|
|
165
|
-
function assertJsonValue(value: unknown, label: string, path = "$", seen = new Set<unknown>()): asserts value is JsonValue {
|
|
166
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
167
|
-
if (typeof value === "number") {
|
|
168
|
-
if (!Number.isFinite(value)) fail("parse", "non_json_number", label, `${path} is not a finite JSON number`);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (!value || typeof value !== "object") fail("parse", "non_json_value", label, `${path} is not JSON-compatible`);
|
|
172
|
-
if (seen.has(value)) fail("parse", "cyclic_value", label, `${path} is cyclic`);
|
|
173
|
-
seen.add(value);
|
|
174
|
-
if (Array.isArray(value)) {
|
|
175
|
-
for (const [index, candidate] of value.entries()) assertJsonValue(candidate, label, `${path}[${index}]`, seen);
|
|
176
|
-
} else {
|
|
177
|
-
const prototype = Object.getPrototypeOf(value) as unknown;
|
|
178
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
179
|
-
fail("parse", "constructed_object", label, `${path} has a forbidden constructed type`);
|
|
180
|
-
}
|
|
181
|
-
for (const [key, candidate] of Object.entries(value)) assertJsonValue(candidate, label, `${path}.${key}`, seen);
|
|
182
|
-
}
|
|
183
|
-
seen.delete(value);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
135
|
/** Parse the restricted, JSON-compatible YAML profile used by all vNext configuration. */
|
|
187
136
|
export function parseRestrictedYaml(
|
|
188
137
|
input: string | Uint8Array,
|
|
189
138
|
label = "<yaml>",
|
|
190
139
|
limits: Readonly<VnextYamlLimits> = VNEXT_YAML_LIMITS,
|
|
191
140
|
): JsonObject {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
customTags: [],
|
|
199
|
-
strict: true,
|
|
200
|
-
uniqueKeys: true,
|
|
201
|
-
});
|
|
202
|
-
if (document.errors.length > 0) {
|
|
203
|
-
fail("parse", "invalid_yaml", label, document.errors.map((error) => error.message).join("; "));
|
|
204
|
-
}
|
|
205
|
-
if (document.warnings.length > 0) {
|
|
206
|
-
fail("parse", "yaml_warning", label, document.warnings.map((warning) => warning.message).join("; "));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let nodes = 0;
|
|
210
|
-
let keys = 0;
|
|
211
|
-
visit(document, (_key, node, path) => {
|
|
212
|
-
nodes += 1;
|
|
213
|
-
if (nodes > limits.maxTotalNodes) fail("parse", "node_limit", label, `document exceeds ${limits.maxTotalNodes} nodes`);
|
|
214
|
-
if (path.length > limits.maxDepth) fail("parse", "depth_limit", label, `document exceeds nesting depth ${limits.maxDepth}`);
|
|
215
|
-
if (isAlias(node)) fail("parse", "alias_forbidden", label, "aliases are forbidden");
|
|
216
|
-
if (node && typeof node === "object" && "anchor" in node && typeof node.anchor === "string") {
|
|
217
|
-
fail("parse", "anchor_forbidden", label, "anchors are forbidden");
|
|
218
|
-
}
|
|
219
|
-
if (isCollection(node) && node.items.length > limits.maxCollectionItems) {
|
|
220
|
-
fail("parse", "collection_limit", label, `collection exceeds ${limits.maxCollectionItems} items`);
|
|
221
|
-
}
|
|
222
|
-
if (isMap(node)) {
|
|
223
|
-
keys += node.items.length;
|
|
224
|
-
if (keys > limits.maxKeys) fail("parse", "key_limit", label, `document exceeds ${limits.maxKeys} mapping keys`);
|
|
225
|
-
for (const pair of node.items) {
|
|
226
|
-
if (!isScalar(pair.key) || typeof pair.key.value !== "string") {
|
|
227
|
-
fail("parse", "non_string_key", label, "mapping keys must be strings");
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (isScalar(node) && typeof node.value === "string" && Buffer.byteLength(node.value, "utf8") > limits.maxScalarBytes) {
|
|
232
|
-
fail("parse", "scalar_limit", label, `scalar exceeds ${limits.maxScalarBytes} bytes`);
|
|
233
|
-
}
|
|
234
|
-
if (node && typeof node === "object" && "tag" in node && typeof node.tag === "string" && !ALLOWED_YAML_TAGS.has(node.tag)) {
|
|
235
|
-
fail("parse", "tag_forbidden", label, `tag ${node.tag} is forbidden`);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
const value = document.toJS({ maxAliasCount: 0 }) as unknown;
|
|
240
|
-
assertJsonValue(value, label);
|
|
241
|
-
if (!isJsonObject(value)) fail("parse", "root_not_object", label, "resource root must be a mapping");
|
|
242
|
-
return value;
|
|
141
|
+
try {
|
|
142
|
+
return parseRestrictedYamlShared(input, label, limits);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (error instanceof RestrictedYamlError) throw new VnextConfigError(error.issues);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
243
147
|
}
|
|
244
148
|
|
|
245
149
|
function readJsonObject(file: string): Record<string, unknown> {
|
|
@@ -570,6 +474,7 @@ function listNamedResources(
|
|
|
570
474
|
continue;
|
|
571
475
|
}
|
|
572
476
|
const id = basename(entry.name, ".yaml");
|
|
477
|
+
if (kind === "model" && id === "inventory") continue;
|
|
573
478
|
if (!resourceIdentifier(id)) {
|
|
574
479
|
issues.push(issue("path", "resource_id_invalid", displayPath(root, join(directory, entry.name)), `filename-derived identity ${id} is invalid or platform-reserved`));
|
|
575
480
|
continue;
|
|
@@ -1128,6 +1033,7 @@ function validateBundle(
|
|
|
1128
1033
|
environments: readonly VnextResource[],
|
|
1129
1034
|
options: VnextConfigOptions,
|
|
1130
1035
|
gateRegistry?: VnextResource,
|
|
1036
|
+
projectRoot?: string,
|
|
1131
1037
|
): VnextConfigIssue[] {
|
|
1132
1038
|
const issues: VnextConfigIssue[] = [];
|
|
1133
1039
|
const entries = valuesOf(project.value, "repositories").map((candidate) => objectValue(candidate)).filter((candidate): candidate is JsonObject => Boolean(candidate));
|
|
@@ -1200,6 +1106,42 @@ function validateBundle(
|
|
|
1200
1106
|
const defaultWorkflow = stringValue(project.value.defaultWorkflow) ?? "default";
|
|
1201
1107
|
if (!workflows.has(defaultWorkflow)) issues.push(issue("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
1202
1108
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
1109
|
+
|
|
1110
|
+
if (projectRoot) {
|
|
1111
|
+
const writerRolePath = join(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
1112
|
+
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
1113
|
+
if (existsSync(writerRolePath) && implementerAgent) {
|
|
1114
|
+
try {
|
|
1115
|
+
const rawRole = parseRestrictedYaml(readFileSync(writerRolePath, "utf8"));
|
|
1116
|
+
const roleObj = objectValue(rawRole);
|
|
1117
|
+
const rosterEntries = valuesOf(roleObj ?? {}, "roster")
|
|
1118
|
+
.map((candidate) => objectValue(candidate))
|
|
1119
|
+
.filter((entry): entry is JsonObject => Boolean(entry));
|
|
1120
|
+
const enabledRosterModels = rosterEntries
|
|
1121
|
+
.filter((entry) => entry.enabled !== false)
|
|
1122
|
+
.map((entry) => stringValue(entry.model))
|
|
1123
|
+
.filter((m): m is string => Boolean(m));
|
|
1124
|
+
|
|
1125
|
+
const agentModelObj = objectValue(implementerAgent.value.model);
|
|
1126
|
+
const agentModelStr = stringValue(implementerAgent.value.model);
|
|
1127
|
+
const agentProvider = agentModelObj ? stringValue(agentModelObj.provider) : undefined;
|
|
1128
|
+
const agentModel = agentModelObj ? stringValue(agentModelObj.model) : agentModelStr;
|
|
1129
|
+
const canonicalAgentModel = agentProvider && agentModel ? `${agentProvider}/${agentModel}` : agentModel;
|
|
1130
|
+
|
|
1131
|
+
if (enabledRosterModels.length > 0 && canonicalAgentModel) {
|
|
1132
|
+
const matches = enabledRosterModels.some((rm) => rm === canonicalAgentModel || rm === agentModel || rm.endsWith(`/${agentModel}`));
|
|
1133
|
+
if (!matches) {
|
|
1134
|
+
issues.push(issue("semantic", "role_roster_conflicts_with_agent", ".kxm/roles/writer.yaml", `role roster in .kxm/roles/writer.yaml does not include agent model ${canonicalAgentModel} from ${implementerAgent.logicalPath}`));
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
if (error instanceof VnextConfigError) {
|
|
1139
|
+
issues.push(...error.issues);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1203
1145
|
return sortIssues(issues);
|
|
1204
1146
|
}
|
|
1205
1147
|
|
|
@@ -1401,7 +1343,7 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
|
|
|
1401
1343
|
}
|
|
1402
1344
|
if (loadIssues.length > 0) throw new VnextConfigError(loadIssues);
|
|
1403
1345
|
|
|
1404
|
-
const issues = validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry);
|
|
1346
|
+
const issues = validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry, root);
|
|
1405
1347
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
1406
1348
|
const resources = [project, ...repositories.values(), ...agents.values(), ...models.values(), ...workflows.values(), ...environments, ...(gateRegistry ? [gateRegistry] : [])]
|
|
1407
1349
|
.sort((left, right) => compareCodeUnits(left.logicalPath, right.logicalPath));
|
|
@@ -3,6 +3,7 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import type { VnextGateObservationInput } from "./vnext-engine-gate-records.ts";
|
|
4
4
|
import type { VnextGateErrorClass, VnextGateStopCause } from "./vnext-runtime-store.ts";
|
|
5
5
|
import { runtimeError } from "./vnext-runtime-store.ts";
|
|
6
|
+
import { assertCommandSeatbelt } from "./safety-integrity.ts";
|
|
6
7
|
|
|
7
8
|
const MAX_DIRECT_TIMER_MS = 2_147_483_647;
|
|
8
9
|
export const COMMAND_TERM_GRACE_MS = 2000;
|
|
@@ -176,6 +177,7 @@ class CommandObserver implements VnextCommandObserver {
|
|
|
176
177
|
) {
|
|
177
178
|
throw runtimeError("run_events_illegal", "command", "command timeoutMs exceeds the direct timer bound");
|
|
178
179
|
}
|
|
180
|
+
assertCommandSeatbelt(this.definition.argv.join(" "));
|
|
179
181
|
this.startedAt = new Date().toISOString();
|
|
180
182
|
let child: ChildProcess;
|
|
181
183
|
try {
|