@kontextmind/kxm 0.7.40 → 0.7.43
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/CHANGELOG.md +41 -7
- package/docs/README.md +5 -3
- package/docs/agent-skills.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/configuration.md +28 -5
- package/docs/{vnext → contracts}/README.md +7 -7
- package/docs/{vnext → contracts}/architecture.md +2 -2
- package/docs/{vnext → contracts}/migration.md +25 -25
- package/docs/{vnext → contracts}/routing.md +2 -2
- package/docs/{vnext → contracts}/synchronization.md +1 -1
- package/docs/{vnext → contracts}/validation.md +7 -7
- package/docs/getting-started.md +1 -1
- package/docs/kb/qa-authentik-authentication.md +47 -0
- package/docs/kb/qa-extension-install-and-hub-bootstrap.md +68 -0
- package/docs/kb/qa-hub-on-a-public-host.md +31 -0
- package/docs/kb/qa-sqlite-vs-duckdb.md +18 -0
- package/docs/kb/qa-what-the-hub-stores.md +47 -0
- package/docs/packages.md +91 -0
- package/docs/templates/architecture.md +1 -1
- package/docs/test-matrix.md +6 -6
- package/docs/tui-components.md +131 -0
- package/examples/README.md +2 -2
- package/examples/{vnext → project}/.kxm/agents/critic-3.yaml +1 -1
- package/examples/{vnext → project}/README.md +4 -4
- package/package.json +18 -8
- package/packages/core/tui/CHANGELOG.md +19 -0
- package/packages/core/tui/LICENSE +21 -0
- package/packages/core/tui/README.md +45 -0
- package/packages/core/tui/dist/index.js +1439 -0
- package/packages/core/tui/src/adapters/pi.ts +73 -0
- package/packages/core/tui/src/adapters/terminal.ts +106 -0
- package/packages/core/tui/src/exports/index.ts +30 -0
- package/packages/core/tui/src/services/registry.ts +274 -0
- package/packages/core/tui/src/tui/keys.ts +130 -0
- package/packages/core/tui/src/tui/layout.ts +117 -0
- package/packages/core/tui/src/tui/panel.ts +435 -0
- package/packages/core/tui/src/tui/panelComponent.ts +208 -0
- package/packages/core/tui/src/tui/render.ts +309 -0
- package/packages/core/tui/src/tui/theme.ts +145 -0
- package/packages/core/tui/src/types/surface.ts +407 -0
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +681 -553
- package/plugins/kxm/dist/extension.js +18 -18
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/{vnext-runtime-supervisor.js → runtime-supervisor.js} +553 -553
- package/plugins/kxm/dist/runtime.js +608 -608
- package/plugins/kxm/dist/server.js +13 -13
- package/plugins/kxm/package.json +2 -2
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +2 -2
- package/plugins/kxm/skills/kxm-runs/SKILL.md +3 -3
- package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-workflow/SKILL.md +1 -1
- package/plugins/kxm/src/autocomplete.ts +4 -4
- package/plugins/kxm/src/{vnext-bindings.ts → bindings.ts} +48 -48
- package/plugins/kxm/src/cli/hub.ts +3 -3
- package/plugins/kxm/src/cli/{vnext.ts → project.ts} +106 -106
- package/plugins/kxm/src/cli/roles.ts +9 -9
- package/plugins/kxm/src/cli/system.ts +2 -2
- package/plugins/kxm/src/cli/tasks.ts +8 -8
- package/plugins/kxm/src/cli/workflows.ts +8 -8
- package/plugins/kxm/src/cli.ts +47 -47
- package/plugins/kxm/src/config.ts +69 -14
- package/plugins/kxm/src/database.ts +4 -4
- package/plugins/kxm/src/{vnext-engine-artifacts.ts → engine-artifacts.ts} +7 -7
- package/plugins/kxm/src/{vnext-engine-command.ts → engine-command.ts} +40 -40
- package/plugins/kxm/src/{vnext-engine-compile.ts → engine-compile.ts} +64 -64
- package/plugins/kxm/src/{vnext-engine-evidence.ts → engine-evidence.ts} +26 -26
- package/plugins/kxm/src/{vnext-engine-fold.ts → engine-fold.ts} +99 -99
- package/plugins/kxm/src/{vnext-engine-gate-records.ts → engine-gate-records.ts} +105 -105
- package/plugins/kxm/src/{vnext-engine-plan.ts → engine-plan.ts} +69 -69
- package/plugins/kxm/src/{vnext-engine.ts → engine.ts} +502 -502
- package/plugins/kxm/src/gate-hash.ts +10 -0
- package/plugins/kxm/src/{vnext-harness.ts → harness.ts} +1 -1
- package/plugins/kxm/src/hub.ts +1 -1
- package/plugins/kxm/src/init-guide-setup.ts +3 -3
- package/plugins/kxm/src/{vnext-init.ts → init.ts} +93 -93
- package/plugins/kxm/src/kxm-install-kind.ts +1 -1
- package/plugins/kxm/src/kxm-update-config.ts +2 -2
- package/plugins/kxm/src/local-snapshot.ts +23 -23
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/{vnext-migrate.ts → migrate.ts} +123 -123
- package/plugins/kxm/src/model-inventory.ts +1 -1
- package/plugins/kxm/src/{vnext-oneshot-evidence.ts → oneshot-evidence.ts} +2 -2
- package/plugins/kxm/src/{vnext-oneshot-process.ts → oneshot-process.ts} +4 -4
- package/plugins/kxm/src/{vnext-oneshot-producer.ts → oneshot-producer.ts} +24 -24
- package/plugins/kxm/src/{vnext-permission.ts → permission.ts} +86 -86
- package/plugins/kxm/src/{vnext-pi-producer.ts → pi-producer.ts} +13 -13
- package/plugins/kxm/src/{vnext-config.ts → project-config.ts} +177 -177
- package/plugins/kxm/src/{vnext-repair.ts → repair.ts} +159 -159
- package/plugins/kxm/src/restricted-yaml.d.mts +3 -3
- package/plugins/kxm/src/restricted-yaml.mjs +4 -4
- package/plugins/kxm/src/{vnext-runtime-owner.ts → runtime-owner.ts} +35 -35
- package/plugins/kxm/src/{vnext-runtime.ts → runtime-service.ts} +136 -136
- package/plugins/kxm/src/{vnext-runtime-store.ts → runtime-store.ts} +145 -145
- package/plugins/kxm/src/{vnext-runtime-supervisor.ts → runtime-supervisor.ts} +80 -80
- package/plugins/kxm/src/runtime.ts +6 -6
- package/plugins/kxm/src/session-work.ts +3 -3
- package/plugins/kxm/src/studio-layout.ts +6 -6
- package/plugins/kxm/src/{vnext-template.ts → template.ts} +33 -33
- package/plugins/kxm/src/tui.ts +10 -24
- package/schemas/{vnext/README.md → README.md} +3 -3
- package/schemas/{vnext/agent.schema.json → agent.schema.json} +1 -1
- package/schemas/{vnext/assignment-result.schema.json → assignment-result.schema.json} +1 -1
- package/schemas/{vnext/backup-manifest.schema.json → backup-manifest.schema.json} +1 -1
- package/schemas/{vnext/candidate.schema.json → candidate.schema.json} +1 -1
- package/schemas/{vnext/common.schema.json → common.schema.json} +2 -2
- package/schemas/{vnext/context-candidate.schema.json → context-candidate.schema.json} +1 -1
- package/schemas/{vnext/context-packet.schema.json → context-packet.schema.json} +1 -1
- package/schemas/{vnext/delivery-manifest.schema.json → delivery-manifest.schema.json} +1 -1
- package/schemas/{vnext/drive-receipt.schema.json → drive-receipt.schema.json} +2 -2
- package/schemas/{vnext/environment.schema.json → environment.schema.json} +1 -1
- package/schemas/{vnext/gate-registry.schema.json → gate-registry.schema.json} +1 -1
- package/schemas/{vnext/handoff-manifest.schema.json → handoff-manifest.schema.json} +1 -1
- package/schemas/{vnext/init-operation.schema.json → init-operation.schema.json} +1 -1
- package/schemas/{vnext/local-repository-bindings.schema.json → local-repository-bindings.schema.json} +1 -1
- package/schemas/{vnext/memory-record.schema.json → memory-record.schema.json} +1 -1
- package/schemas/{vnext/migration-decision.schema.json → migration-decision.schema.json} +1 -1
- package/schemas/{vnext/migration-plan.schema.json → migration-plan.schema.json} +1 -1
- package/schemas/{vnext/migration-receipt.schema.json → migration-receipt.schema.json} +1 -1
- package/schemas/{vnext/model.schema.json → model.schema.json} +1 -1
- package/schemas/{vnext/modes.schema.json → modes.schema.json} +1 -1
- package/schemas/{vnext/permission-diff.schema.json → permission-diff.schema.json} +1 -1
- package/schemas/policy-draft/README.md +2 -2
- package/schemas/{vnext/prices.schema.json → prices.schema.json} +1 -1
- package/schemas/{vnext/project.schema.json → project.schema.json} +1 -1
- package/schemas/{vnext/repository.schema.json → repository.schema.json} +1 -1
- package/schemas/{vnext/role.schema.json → role.schema.json} +1 -1
- package/schemas/{vnext/run-event.schema.json → run-event.schema.json} +1 -1
- package/schemas/{vnext/session-brief.schema.json → session-brief.schema.json} +2 -2
- package/schemas/{vnext/sync-event.schema.json → sync-event.schema.json} +1 -1
- package/schemas/{vnext/template-provenance.schema.json → template-provenance.schema.json} +1 -1
- package/schemas/{vnext/workflow.schema.json → workflow.schema.json} +1 -1
- package/scripts/build-package.mjs +59 -0
- package/scripts/build-runtime.mjs +3 -2
- package/scripts/check-generated.mjs +2 -1
- package/scripts/check-versions.mjs +12 -1
- package/scripts/docker-install-smoke.mjs +268 -0
- package/scripts/emit-codex-artifacts.mjs +1 -1
- package/scripts/kxm-bump-version.mjs +53 -3
- package/scripts/kxm-runtime-supervisor.mjs +3 -3
- package/scripts/package-surfaces.mjs +39 -0
- package/plugins/kxm/src/vnext-gate-hash.ts +0 -10
- /package/docs/{vnext → contracts}/effects-and-recovery.md +0 -0
- /package/docs/{vnext → contracts}/lifecycles.md +0 -0
- /package/docs/{vnext → contracts}/terminology.md +0 -0
- /package/examples/{vnext → project}/.kxm/agents/coordinator.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/critic-1.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/critic-2.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/implementer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/planner.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/reproducer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/reviewer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/gates.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-claude.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-gemini.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-grok.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/implementation.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/primary.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/prices.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/project/env.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/project.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/repo/repo.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/default.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/fix.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/improve.yaml +0 -0
- /package/examples/{vnext → project}/records/assignment-result-recorded.json +0 -0
- /package/examples/{vnext → project}/records/assignment-result.json +0 -0
- /package/examples/{vnext → project}/records/context-candidate.json +0 -0
- /package/examples/{vnext → project}/records/delivery-manifest.json +0 -0
- /package/examples/{vnext → project}/records/effect-uncertainty-resolved-sync.json +0 -0
- /package/examples/{vnext → project}/records/effect-uncertainty-resolved.json +0 -0
- /package/examples/{vnext → project}/records/run-created.json +0 -0
- /package/examples/{vnext → project}/records/sync-event.json +0 -0
- /package/examples/{vnext → project}/repositories/api/.kxm/repo/env.yaml +0 -0
- /package/examples/{vnext → project}/repositories/api/.kxm/repo/repo.yaml +0 -0
- /package/examples/{vnext → project}/repositories/web/.kxm/repo/repo.yaml +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { basename, join, resolve } from "node:path";
|
|
3
3
|
import { parse as parseYaml } from "yaml";
|
|
4
|
-
import { probeHarnessesAsync } from "../
|
|
4
|
+
import { probeHarnessesAsync } from "../harness.ts";
|
|
5
5
|
import { suggestWorkflowAndRoles } from "../suggest.ts";
|
|
6
6
|
import {
|
|
7
7
|
createGoal,
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
type TaskStatus,
|
|
15
15
|
type TrackerType,
|
|
16
16
|
} from "../task-manager.ts";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { discoverKxmProjectRoot } from "../project-config.ts";
|
|
18
|
+
import { compileKxmWorkflow } from "../engine-compile.ts";
|
|
19
19
|
import {
|
|
20
20
|
createStudioServer,
|
|
21
21
|
DEFAULT_STUDIO_PORT,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "../studio-layout.ts";
|
|
24
24
|
import { readSessionTokenFromDisk } from "../commands.ts";
|
|
25
25
|
import { print, type Runtime } from "./types.ts";
|
|
26
|
-
import {
|
|
26
|
+
import { cmdKxmRun } from "./project.ts";
|
|
27
27
|
|
|
28
28
|
export async function cmdSuggest(runtime: Runtime, promptParts: string[]): Promise<number> {
|
|
29
29
|
try {
|
|
@@ -187,7 +187,7 @@ export async function cmdTaskRun(runtime: Runtime, taskId: string): Promise<numb
|
|
|
187
187
|
return 1;
|
|
188
188
|
}
|
|
189
189
|
const workflow = task.assignedWorkflow ?? "default";
|
|
190
|
-
const exitCode = await
|
|
190
|
+
const exitCode = await cmdKxmRun(runtime, workflow, [task.objective]);
|
|
191
191
|
if (exitCode === 0) {
|
|
192
192
|
updateTaskStatus(runtime.cwd, taskId, "in_progress");
|
|
193
193
|
}
|
|
@@ -218,7 +218,7 @@ export async function cmdTaskSync(runtime: Runtime, taskId: string): Promise<num
|
|
|
218
218
|
|
|
219
219
|
export async function cmdStudioLayout(runtime: Runtime, workflowPath?: string | undefined): Promise<number> {
|
|
220
220
|
try {
|
|
221
|
-
const projectRoot =
|
|
221
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
222
222
|
let filePath = workflowPath;
|
|
223
223
|
if (!filePath) {
|
|
224
224
|
filePath = resolve(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
@@ -267,7 +267,7 @@ steps:
|
|
|
267
267
|
`;
|
|
268
268
|
}
|
|
269
269
|
const parsedYaml = parseYaml(yamlContent) as any;
|
|
270
|
-
const plan =
|
|
270
|
+
const plan = compileKxmWorkflow({ id: workflowId, value: parsedYaml });
|
|
271
271
|
const layout = generateStudioLayout(plan);
|
|
272
272
|
print(runtime.io, runtime.json, { ok: true, command: "studio layout", layout }, JSON.stringify(layout, null, 2));
|
|
273
273
|
return 0;
|
|
@@ -317,7 +317,7 @@ export async function cmdStudioServe(
|
|
|
317
317
|
const raw = readFileSync(targetPath, "utf8");
|
|
318
318
|
const parsed = parseYaml(raw) as any;
|
|
319
319
|
const wfId = basename(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
320
|
-
return
|
|
320
|
+
return compileKxmWorkflow({ id: wfId, value: parsed });
|
|
321
321
|
}
|
|
322
322
|
} catch {
|
|
323
323
|
// fallback
|
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
type WorkflowJournalEntry,
|
|
20
20
|
type WorkflowRun,
|
|
21
21
|
} from "../workflow.ts";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { discoverKxmProjectRoot } from "../project-config.ts";
|
|
23
|
+
import { ensureKxmSupervisor, kxmRuntimeRequest } from "../runtime-supervisor.ts";
|
|
24
24
|
import type { WorkerOutcome } from "../envelope.ts";
|
|
25
25
|
import {
|
|
26
26
|
print,
|
|
@@ -517,26 +517,26 @@ export async function cmdSignal(runtime: Runtime, runId: string, signalKey: stri
|
|
|
517
517
|
return 2;
|
|
518
518
|
}
|
|
519
519
|
const worker = gateOf(runtime, "signal");
|
|
520
|
-
const projectRoot =
|
|
520
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
521
521
|
if (projectRoot && /^run_[a-f0-9]{32}$/i.test(runId)) {
|
|
522
522
|
if (runtime.dryRun) {
|
|
523
|
-
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, summary, evidence }, "would post signal to
|
|
523
|
+
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, summary, evidence }, "would post signal to KXM run");
|
|
524
524
|
return 0;
|
|
525
525
|
}
|
|
526
526
|
const deliveryId = String(deliveryIdFlag || `cli-signal:${randomUUID()}`);
|
|
527
527
|
try {
|
|
528
|
-
const supervisor = await
|
|
529
|
-
const posted = await
|
|
528
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
529
|
+
const posted = await kxmRuntimeRequest(
|
|
530
530
|
supervisor,
|
|
531
531
|
"POST",
|
|
532
532
|
`/v1/runs/${encodeURIComponent(runId)}/signal?projectRoot=${encodeURIComponent(projectRoot)}`,
|
|
533
533
|
{ signalKey, status, summary, evidence, deliveryId, ...(recoveryAction ? { action: recoveryAction } : {}) },
|
|
534
534
|
);
|
|
535
|
-
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, unblocked: posted.unblocked === true, deliveryId }, "posted signal to
|
|
535
|
+
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, unblocked: posted.unblocked === true, deliveryId }, "posted signal to KXM run");
|
|
536
536
|
return 0;
|
|
537
537
|
} catch (error) {
|
|
538
538
|
const msg = error instanceof Error ? error.message : "signal_failed";
|
|
539
|
-
printWorker(runtime, worker, { ok: false, command: "signal", error: "signal_failed", detail: msg, deliveryId }, "signal to
|
|
539
|
+
printWorker(runtime, worker, { ok: false, command: "signal", error: "signal_failed", detail: msg, deliveryId }, "signal to KXM run failed");
|
|
540
540
|
return 1;
|
|
541
541
|
}
|
|
542
542
|
}
|
package/plugins/kxm/src/cli.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Role & workflow governance (`kxm role`, `kxm workflow`, `kxm gate`, `kxm signal`)
|
|
8
8
|
* - Task & goal management (`kxm goal`, `kxm task`, `kxm suggest`, `kxm studio`)
|
|
9
9
|
* - Knowledge, skills, and memory (`kxm context`, `kxm skills`, `kxm memory`)
|
|
10
|
-
* -
|
|
10
|
+
* - KXM runtime & initialization (`kxm init`, `kxm migrate`, `kxm trust`, `kxm run`, `kxm harness`)
|
|
11
11
|
* - Hub, workers, and dashboard (`kxm hub`, `kxm worker`, `kxm dash`, `kxm session`, `kxm auth`)
|
|
12
12
|
* - System, update, and configuration (`kxm update`, `kxm config`, `kxm completion`, `kxm improve`)
|
|
13
13
|
*/
|
|
@@ -24,8 +24,8 @@ import {
|
|
|
24
24
|
AGENT_COMMANDS_MAP,
|
|
25
25
|
enforceToolPolicy,
|
|
26
26
|
} from "./commands.ts";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
27
|
+
import { discoverKxmProjectRoot } from "./project-config.ts";
|
|
28
|
+
import { ensureKxmSupervisor, kxmRuntimeRequest } from "./runtime-supervisor.ts";
|
|
29
29
|
|
|
30
30
|
// Submodule imports
|
|
31
31
|
import {
|
|
@@ -97,27 +97,27 @@ import {
|
|
|
97
97
|
} from "./cli/context-skills.ts";
|
|
98
98
|
|
|
99
99
|
import {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
cmdKxmInit,
|
|
101
|
+
cmdKxmMigratePlan,
|
|
102
|
+
cmdKxmMigrateApply,
|
|
103
|
+
cmdKxmMigrateVerify,
|
|
104
104
|
cmdBackup,
|
|
105
105
|
cmdRestore,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
cmdKxmTrust,
|
|
107
|
+
cmdKxmRun,
|
|
108
|
+
cmdKxmRunStatus,
|
|
109
|
+
cmdKxmRunDrive,
|
|
110
|
+
cmdKxmRunReceipt,
|
|
111
|
+
cmdKxmRunCancel,
|
|
112
|
+
cmdKxmRunList,
|
|
113
113
|
cmdHarnessList,
|
|
114
114
|
cmdRouteChange,
|
|
115
115
|
cmdModelsScreen,
|
|
116
116
|
cmdRouteList,
|
|
117
117
|
cmdRouteCount,
|
|
118
118
|
cmdModelInventoryRefresh,
|
|
119
|
-
|
|
120
|
-
} from "./cli/
|
|
119
|
+
cmdKxmRuntime,
|
|
120
|
+
} from "./cli/project.ts";
|
|
121
121
|
|
|
122
122
|
import {
|
|
123
123
|
cmdStatus,
|
|
@@ -260,28 +260,28 @@ async function dispatchAgentCliCommand(
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
// Handle
|
|
263
|
+
// Handle KXM run binding for workflow wait
|
|
264
264
|
if (toolName === "kxm_workflow_wait") {
|
|
265
265
|
const runId = typeof args.runId === "string" ? args.runId : undefined;
|
|
266
|
-
const projectRoot =
|
|
266
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
267
267
|
if (runId && projectRoot && /^run_[a-f0-9]{32}$/i.test(runId)) {
|
|
268
268
|
if (runtime.dryRun) {
|
|
269
|
-
print(runtime.io, runtime.json, { ok: true, command: "workflow wait", runId, dryRun: true }, `would wait for signal on
|
|
269
|
+
print(runtime.io, runtime.json, { ok: true, command: "workflow wait", runId, dryRun: true }, `would wait for signal on KXM run ${runId}`);
|
|
270
270
|
return 0;
|
|
271
271
|
}
|
|
272
272
|
try {
|
|
273
|
-
const supervisor = await
|
|
274
|
-
const result = await
|
|
273
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
274
|
+
const result = await kxmRuntimeRequest(
|
|
275
275
|
supervisor,
|
|
276
276
|
"POST",
|
|
277
277
|
`/v1/runs/${encodeURIComponent(runId)}/wait?projectRoot=${encodeURIComponent(projectRoot)}`,
|
|
278
278
|
args,
|
|
279
279
|
);
|
|
280
|
-
print(runtime.io, runtime.json, result, `waiting for signal on
|
|
280
|
+
print(runtime.io, runtime.json, result, `waiting for signal on KXM run ${runId}`);
|
|
281
281
|
return 0;
|
|
282
282
|
} catch (error) {
|
|
283
|
-
const msg = error instanceof Error ? error.message : "
|
|
284
|
-
print(runtime.io, runtime.json, { ok: false, error: "
|
|
283
|
+
const msg = error instanceof Error ? error.message : "wait_failed";
|
|
284
|
+
print(runtime.io, runtime.json, { ok: false, error: "wait_failed", detail: msg }, `KXM wait failed: ${msg}`);
|
|
285
285
|
return 1;
|
|
286
286
|
}
|
|
287
287
|
}
|
|
@@ -334,14 +334,14 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
334
334
|
.helpCommand("help", "Show help");
|
|
335
335
|
addGlobalOptions(program);
|
|
336
336
|
|
|
337
|
-
program.command("init").description("Create, validate, or plan migration of a
|
|
337
|
+
program.command("init").description("Create, validate, or plan migration of a KXM project")
|
|
338
338
|
.option("--json", "Print machine-readable JSON")
|
|
339
339
|
.option("--dry-run", "Plan without making changes")
|
|
340
340
|
.option("--name <name>", "Project display name for a new project")
|
|
341
341
|
.option("--project-id <id>", "Stable project ID for controlled provisioning")
|
|
342
342
|
.option("--repository <id=absolute-path>", "Bind a member repository outside Git configuration", (value, previous: string[]) => [...previous, value], [])
|
|
343
343
|
.action(async function initAction(this: Command, options: { name?: string; projectId?: string; repository?: string[] }) {
|
|
344
|
-
result.code = await
|
|
344
|
+
result.code = await cmdKxmInit(runtimeFrom(ctx, this), options, {
|
|
345
345
|
maybeOfferCompletionInstall,
|
|
346
346
|
maybeOfferGuideSetup,
|
|
347
347
|
});
|
|
@@ -349,20 +349,20 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
349
349
|
|
|
350
350
|
const migrate = addGlobalOptions(program.command("migrate").description("Plan, apply, and verify legacy JSON configuration migration"));
|
|
351
351
|
migrate.helpCommand("help", "Show migrate help");
|
|
352
|
-
addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-
|
|
352
|
+
addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-KXM migration plan without writes"))
|
|
353
353
|
.action(async function migratePlanAction(this: Command) {
|
|
354
|
-
result.code = await
|
|
354
|
+
result.code = await cmdKxmMigratePlan(runtimeFrom(ctx, this));
|
|
355
355
|
});
|
|
356
356
|
addGlobalOptions(migrate.command("apply").description("Install a reviewed migration with a hash-linked receipt"))
|
|
357
357
|
.option("--decisions <file>", "Reviewed kxm.migration-decision.v1 YAML file")
|
|
358
358
|
.option("--project-id <id>", "Stable project ID for controlled provisioning")
|
|
359
359
|
.option("--name <name>", "Project display name")
|
|
360
360
|
.action(async function migrateApplyAction(this: Command, options: { decisions?: string; projectId?: string; name?: string }) {
|
|
361
|
-
result.code = await
|
|
361
|
+
result.code = await cmdKxmMigrateApply(runtimeFrom(ctx, this), options);
|
|
362
362
|
});
|
|
363
363
|
addGlobalOptions(migrate.command("verify").description("Verify a migration receipt against current sources and target bundle"))
|
|
364
364
|
.action(async function migrateVerifyAction(this: Command) {
|
|
365
|
-
result.code = await
|
|
365
|
+
result.code = await cmdKxmMigrateVerify(runtimeFrom(ctx, this));
|
|
366
366
|
});
|
|
367
367
|
|
|
368
368
|
addGlobalOptions(program.command("backup").description("Create a verified SQLite backup of all stores with a hashed manifest"))
|
|
@@ -376,18 +376,18 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
376
376
|
result.code = await cmdRestore(runtimeFrom(ctx, this), manifest);
|
|
377
377
|
});
|
|
378
378
|
|
|
379
|
-
addGlobalOptions(program.command("run").description("Create a
|
|
379
|
+
addGlobalOptions(program.command("run").description("Create a KXM run (offline-first; no steps execute until the run engine lands)")
|
|
380
380
|
.argument("[workflow]", "Workflow id to run")
|
|
381
381
|
.argument("[prompt...]", "Run prompt (hashed, never stored raw)")
|
|
382
382
|
.action(async function runAction(this: Command, workflow: string | undefined, promptParts: string[]) {
|
|
383
|
-
result.code = await
|
|
383
|
+
result.code = await cmdKxmRun(runtimeFrom(ctx, this), workflow, promptParts);
|
|
384
384
|
}));
|
|
385
|
-
const runCmd = addGlobalOptions(program.command("runs").description("Inspect
|
|
385
|
+
const runCmd = addGlobalOptions(program.command("runs").description("Inspect KXM runs"));
|
|
386
386
|
runCmd.helpCommand("help", "Show runs help");
|
|
387
387
|
addGlobalOptions(runCmd.command("status").description("Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned)"))
|
|
388
388
|
.argument("<runId>", "Run id")
|
|
389
389
|
.action(async function runStatusAction(this: Command, runId: string) {
|
|
390
|
-
result.code = await
|
|
390
|
+
result.code = await cmdKxmRunStatus(runtimeFrom(ctx, this), runId);
|
|
391
391
|
});
|
|
392
392
|
addGlobalOptions(runCmd.command("drive").description("Drive a run with an explicit model-free simulation"))
|
|
393
393
|
.argument("<runId>", "Run id")
|
|
@@ -395,7 +395,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
395
395
|
.option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement")
|
|
396
396
|
.option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)")
|
|
397
397
|
.action(async function runDriveAction(this: Command, runId: string, options: { simulated?: boolean; wait?: boolean; timeoutMs?: string }) {
|
|
398
|
-
result.code = await
|
|
398
|
+
result.code = await cmdKxmRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true, {
|
|
399
399
|
wait: options.wait === true,
|
|
400
400
|
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
401
401
|
});
|
|
@@ -404,16 +404,16 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
404
404
|
.argument("<runId>", "Run id")
|
|
405
405
|
.option("--all", "Print the capped receipt list for the run")
|
|
406
406
|
.action(async function runReceiptAction(this: Command, runId: string, options: { all?: boolean }) {
|
|
407
|
-
result.code = await
|
|
407
|
+
result.code = await cmdKxmRunReceipt(runtimeFrom(ctx, this), runId, { all: options.all === true });
|
|
408
408
|
});
|
|
409
409
|
addGlobalOptions(runCmd.command("cancel").description("Durably request cancellation of a run"))
|
|
410
410
|
.argument("<runId>", "Run id")
|
|
411
411
|
.action(async function runCancelAction(this: Command, runId: string) {
|
|
412
|
-
result.code = await
|
|
412
|
+
result.code = await cmdKxmRunCancel(runtimeFrom(ctx, this), runId);
|
|
413
413
|
});
|
|
414
414
|
addGlobalOptions(runCmd.command("list").description("List recent runs for the current project"))
|
|
415
415
|
.action(async function runListAction(this: Command) {
|
|
416
|
-
result.code = await
|
|
416
|
+
result.code = await cmdKxmRunList(runtimeFrom(ctx, this));
|
|
417
417
|
});
|
|
418
418
|
|
|
419
419
|
const modelsCmd = addGlobalOptions(program.command("models").description("Manage model catalogs, roles, and route state"));
|
|
@@ -462,32 +462,32 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
462
462
|
result.code = await cmdUpdate(runtimeFrom(ctx, this), harness, options);
|
|
463
463
|
});
|
|
464
464
|
|
|
465
|
-
const runtimeCmd = addGlobalOptions(program.command("runtime").description("Manage the
|
|
465
|
+
const runtimeCmd = addGlobalOptions(program.command("runtime").description("Manage the KXM Runtime supervisor"));
|
|
466
466
|
runtimeCmd.helpCommand("help", "Show runtime help");
|
|
467
467
|
addGlobalOptions(runtimeCmd.command("start").description("Start the Runtime supervisor if not running"))
|
|
468
468
|
.action(async function runtimeStartAction(this: Command) {
|
|
469
|
-
result.code = await
|
|
469
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "start");
|
|
470
470
|
});
|
|
471
471
|
addGlobalOptions(runtimeCmd.command("status").description("Show Runtime supervisor liveness"))
|
|
472
472
|
.action(async function runtimeStatusAction(this: Command) {
|
|
473
|
-
result.code = await
|
|
473
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "status");
|
|
474
474
|
});
|
|
475
475
|
addGlobalOptions(runtimeCmd.command("stop").description("Gracefully stop the Runtime supervisor"))
|
|
476
476
|
.action(async function runtimeStopAction(this: Command) {
|
|
477
|
-
result.code = await
|
|
477
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "stop");
|
|
478
478
|
});
|
|
479
479
|
|
|
480
|
-
const trust = addGlobalOptions(program.command("trust").description("Permission-diff trust review for
|
|
480
|
+
const trust = addGlobalOptions(program.command("trust").description("Permission-diff trust review for KXM configuration"));
|
|
481
481
|
trust.helpCommand("help", "Show trust help");
|
|
482
482
|
addGlobalOptions(trust.command("diff").description("Show the structured permission diff against a base Git revision"))
|
|
483
483
|
.option("--base <revision>", "Base Git revision (default: HEAD)")
|
|
484
484
|
.action(async function trustDiffAction(this: Command, options: { base?: string }) {
|
|
485
|
-
result.code = await
|
|
485
|
+
result.code = await cmdKxmTrust(runtimeFrom(ctx, this), false, options);
|
|
486
486
|
});
|
|
487
487
|
addGlobalOptions(trust.command("check").description("Exit non-zero when the working tree expands permissions against the base revision"))
|
|
488
488
|
.option("--base <revision>", "Base Git revision (default: HEAD)")
|
|
489
489
|
.action(async function trustCheckAction(this: Command, options: { base?: string }) {
|
|
490
|
-
result.code = await
|
|
490
|
+
result.code = await cmdKxmTrust(runtimeFrom(ctx, this), true, options);
|
|
491
491
|
});
|
|
492
492
|
|
|
493
493
|
const agent = addGlobalOptions(program.command("agent").description("Run and supervise agents"));
|
|
@@ -686,7 +686,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
686
686
|
};
|
|
687
687
|
result.code = await dispatchAgentCliCommand(runtimeFrom(ctx, this), "kxm_workflow_wait", options);
|
|
688
688
|
});
|
|
689
|
-
addGlobalOptions(workflow.command("signal").description("Post a signed workflow callback or unblock a
|
|
689
|
+
addGlobalOptions(workflow.command("signal").description("Post a signed workflow callback or unblock a KXM run"))
|
|
690
690
|
.argument("<runId>", "Workflow run ID")
|
|
691
691
|
.argument("<signalKey>", "Wait signal key")
|
|
692
692
|
.argument("<status>", "passed, warning, or failed")
|
|
@@ -824,7 +824,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
824
824
|
.argument("<summary>", "Callback summary")
|
|
825
825
|
.argument("[evidence...]", "required-key=evidence pairs")
|
|
826
826
|
.option("--delivery-id <id>", "Stable callback delivery ID")
|
|
827
|
-
.option("--recovery-action <action>", "
|
|
827
|
+
.option("--recovery-action <action>", "KXM recovery action: retry, fail, cancel, unblock")
|
|
828
828
|
.action(async function signalAction(this: Command, runId: string, signalKey: string, status: string, summary: string, evidence: string[], options: { deliveryId?: string; recoveryAction?: string }) {
|
|
829
829
|
result.code = await cmdSignal(runtimeFrom(ctx, this), runId, signalKey, status, summary, evidence ?? [], options.deliveryId, options.recoveryAction);
|
|
830
830
|
});
|
|
@@ -261,32 +261,53 @@ export function getKxmConfigValue(config: KxmResolvedConfig, keyPath: string): u
|
|
|
261
261
|
return current;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
|
|
264
|
+
/** Resolve the file a scope writes, shared by set and delete. */
|
|
265
|
+
export function kxmConfigFileForScope(
|
|
265
266
|
repoRoot: string,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const targetFile = scope === "user"
|
|
272
|
-
? join(userConfigDirectory(options.userConfigDir), "config.yaml")
|
|
267
|
+
scope: "user" | "project",
|
|
268
|
+
userConfigDir?: string,
|
|
269
|
+
): string {
|
|
270
|
+
return scope === "user"
|
|
271
|
+
? join(userConfigDirectory(userConfigDir), "config.yaml")
|
|
273
272
|
: join(repoConfigDirectory(repoRoot), "config.yaml");
|
|
273
|
+
}
|
|
274
274
|
|
|
275
|
-
|
|
275
|
+
function configKeyParts(keyPath: string): string[] {
|
|
276
|
+
const parts = keyPath.split(".");
|
|
277
|
+
if (parts.some((part) => !part || part === "__proto__" || part === "prototype" || part === "constructor")) {
|
|
278
|
+
throw new Error("invalid config key path");
|
|
279
|
+
}
|
|
280
|
+
return parts;
|
|
281
|
+
}
|
|
276
282
|
|
|
283
|
+
function readConfigFile(targetFile: string): Record<string, unknown> {
|
|
277
284
|
let existing: Record<string, unknown> = {};
|
|
278
285
|
if (existsSync(targetFile)) {
|
|
279
286
|
try {
|
|
280
287
|
existing = (parse(readFileSync(targetFile, "utf8")) as Record<string, unknown>) ?? {};
|
|
281
288
|
} catch {
|
|
289
|
+
// A malformed file is repaired by the next write, the same way the
|
|
290
|
+
// existing set path behaves: refuse nothing here or `set` would regress.
|
|
282
291
|
existing = {};
|
|
283
292
|
}
|
|
284
293
|
}
|
|
294
|
+
return existing;
|
|
295
|
+
}
|
|
285
296
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
297
|
+
function writeConfigFile(targetFile: string, value: Record<string, unknown>): void {
|
|
298
|
+
mkdirSync(dirname(targetFile), { recursive: true });
|
|
299
|
+
writeFileSync(targetFile, stringify(value).trim() + "\n", "utf8");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function setKxmConfigValue(
|
|
303
|
+
repoRoot: string,
|
|
304
|
+
keyPath: string,
|
|
305
|
+
value: unknown,
|
|
306
|
+
options: { scope?: "user" | "project"; userConfigDir?: string } = {},
|
|
307
|
+
): void {
|
|
308
|
+
const targetFile = kxmConfigFileForScope(repoRoot, options.scope ?? "project", options.userConfigDir);
|
|
309
|
+
const existing = readConfigFile(targetFile);
|
|
310
|
+
const parts = configKeyParts(keyPath);
|
|
290
311
|
let cursor = existing;
|
|
291
312
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
292
313
|
const p = parts[i]!;
|
|
@@ -296,8 +317,42 @@ export function setKxmConfigValue(
|
|
|
296
317
|
cursor = cursor[p] as Record<string, unknown>;
|
|
297
318
|
}
|
|
298
319
|
cursor[parts[parts.length - 1]!] = value;
|
|
320
|
+
writeConfigFile(targetFile, existing);
|
|
321
|
+
}
|
|
299
322
|
|
|
300
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Remove a key so the next scope, then the built-in default, applies.
|
|
325
|
+
*
|
|
326
|
+
* Writing `null` is not the same thing: `defaults.harness: null` reads back as a
|
|
327
|
+
* set value. "Inherit" has to delete, and empty parents are pruned so an unset
|
|
328
|
+
* does not leave a skeleton behind.
|
|
329
|
+
*/
|
|
330
|
+
export function deleteKxmConfigValue(
|
|
331
|
+
repoRoot: string,
|
|
332
|
+
keyPath: string,
|
|
333
|
+
options: { scope?: "user" | "project"; userConfigDir?: string } = {},
|
|
334
|
+
): boolean {
|
|
335
|
+
const targetFile = kxmConfigFileForScope(repoRoot, options.scope ?? "project", options.userConfigDir);
|
|
336
|
+
if (!existsSync(targetFile)) return false;
|
|
337
|
+
const existing = readConfigFile(targetFile);
|
|
338
|
+
const parts = configKeyParts(keyPath);
|
|
339
|
+
const parents: Record<string, unknown>[] = [existing];
|
|
340
|
+
let cursor = existing;
|
|
341
|
+
for (const part of parts.slice(0, -1)) {
|
|
342
|
+
const next = cursor[part];
|
|
343
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return false;
|
|
344
|
+
cursor = next as Record<string, unknown>;
|
|
345
|
+
parents.push(cursor);
|
|
346
|
+
}
|
|
347
|
+
const leaf = parts[parts.length - 1]!;
|
|
348
|
+
if (!Object.prototype.hasOwnProperty.call(cursor, leaf)) return false;
|
|
349
|
+
delete cursor[leaf];
|
|
350
|
+
for (let i = parents.length - 1; i > 0; i -= 1) {
|
|
351
|
+
if (Object.keys(parents[i]!).length > 0) break;
|
|
352
|
+
delete parents[i - 1]![parts[i - 1]!];
|
|
353
|
+
}
|
|
354
|
+
writeConfigFile(targetFile, existing);
|
|
355
|
+
return true;
|
|
301
356
|
}
|
|
302
357
|
|
|
303
358
|
export function formatKxmConfig(config: KxmResolvedConfig): string {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "node:fs";
|
|
13
13
|
import { basename, dirname, join, resolve } from "node:path";
|
|
14
14
|
import { DatabaseSync } from "./sqlite.ts";
|
|
15
|
-
import {
|
|
15
|
+
import { KxmConfigError, type KxmConfigIssue } from "./project-config.ts";
|
|
16
16
|
|
|
17
17
|
export interface DatabaseMigrationStep {
|
|
18
18
|
fromVersion: number;
|
|
@@ -61,9 +61,9 @@ export interface RestoreResult {
|
|
|
61
61
|
restoredStores: RestoreStoreRecord[];
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export function databaseError(code: string, file: string, message: string):
|
|
65
|
-
const issue:
|
|
66
|
-
return new
|
|
64
|
+
export function databaseError(code: string, file: string, message: string): KxmConfigError {
|
|
65
|
+
const issue: KxmConfigIssue = { phase: "semantic", code, file, message };
|
|
66
|
+
return new KxmConfigError([issue]);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export function checkedParent(path: string, description: string): void {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { verifyArtifactExists } from "./artifacts-exist.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { KxmRuntimeContext } from "./runtime-service.ts";
|
|
4
4
|
|
|
5
|
-
export interface
|
|
5
|
+
export interface KxmArtifactsObservation {
|
|
6
6
|
completeness: "complete";
|
|
7
7
|
spawned: 0;
|
|
8
8
|
pid: null;
|
|
@@ -26,7 +26,7 @@ export interface VnextArtifactsObservation {
|
|
|
26
26
|
finishedAt: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export interface
|
|
29
|
+
export interface KxmArtifactsGateSeams {
|
|
30
30
|
afterPathChecked?: ((input: {
|
|
31
31
|
path: string;
|
|
32
32
|
index: number;
|
|
@@ -35,16 +35,16 @@ export interface VnextArtifactsGateSeams {
|
|
|
35
35
|
}) => void) | undefined;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export const
|
|
38
|
+
export const kxmArtifactsGateSeams: KxmArtifactsGateSeams = {};
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Check every pinned path under control `.kxm/assets`. Normal helper failures
|
|
42
42
|
* are complete failed facts. Exceptions after checks begin must propagate.
|
|
43
43
|
*/
|
|
44
44
|
export function evaluateArtifactsGate(
|
|
45
|
-
context:
|
|
45
|
+
context: KxmRuntimeContext,
|
|
46
46
|
definition: { readonly kind: "artifacts-exist"; readonly paths: readonly string[] },
|
|
47
|
-
):
|
|
47
|
+
): KxmArtifactsObservation {
|
|
48
48
|
const root = join(context.projectRoot, ".kxm", "assets");
|
|
49
49
|
const startedAt = new Date().toISOString();
|
|
50
50
|
const startTime = process.hrtime.bigint();
|
|
@@ -55,7 +55,7 @@ export function evaluateArtifactsGate(
|
|
|
55
55
|
checkedCount += 1;
|
|
56
56
|
const result = verifyArtifactExists(root, join(root, path));
|
|
57
57
|
if (!result.ok) failedCount += 1;
|
|
58
|
-
|
|
58
|
+
kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const elapsedNs = process.hrtime.bigint() - startTime;
|