@kontextmind/kxm 0.7.40 → 0.7.44
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 +45 -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-hub.mjs +36 -0
- 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
|
@@ -4,26 +4,26 @@ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, join, resolve, sep } from "node:path";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
KxmConfigError,
|
|
8
|
+
loadKxmProject,
|
|
9
9
|
parseRestrictedYaml,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
kxmCanonicalJson,
|
|
11
|
+
kxmPortablePath,
|
|
12
|
+
kxmResourceIdentifier,
|
|
13
13
|
type JsonObject,
|
|
14
14
|
type JsonValue,
|
|
15
|
-
type
|
|
16
|
-
type
|
|
17
|
-
type
|
|
18
|
-
type
|
|
19
|
-
type
|
|
20
|
-
} from "./
|
|
15
|
+
type KxmConfigIssue,
|
|
16
|
+
type KxmConfigOptions,
|
|
17
|
+
type KxmProjectBundle,
|
|
18
|
+
type KxmResource,
|
|
19
|
+
type KxmResourceKind,
|
|
20
|
+
} from "./project-config.ts";
|
|
21
21
|
|
|
22
22
|
/* ------------------------------------------------------------------ *
|
|
23
23
|
* Structured authority projections
|
|
24
24
|
* ------------------------------------------------------------------ */
|
|
25
25
|
|
|
26
|
-
export type
|
|
26
|
+
export type KxmPermissionField =
|
|
27
27
|
| "repository-access"
|
|
28
28
|
| "tools"
|
|
29
29
|
| "secrets"
|
|
@@ -41,17 +41,17 @@ export type VnextPermissionField =
|
|
|
41
41
|
| "gate"
|
|
42
42
|
| "delivery";
|
|
43
43
|
|
|
44
|
-
export type
|
|
44
|
+
export type KxmPermissionDirection = "expansion" | "narrowing" | "neutral";
|
|
45
45
|
|
|
46
|
-
export interface
|
|
46
|
+
export interface KxmAuthorityEntry {
|
|
47
47
|
/** Resource-relative pointer, e.g. /repositories/api or /steps/3/tools/preset. */
|
|
48
48
|
path: string;
|
|
49
|
-
field:
|
|
49
|
+
field: KxmPermissionField;
|
|
50
50
|
/** Canonical JSON of the comparable value (never secret material). */
|
|
51
51
|
value: string;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const PROSE_FIELDS: Readonly<Record<
|
|
54
|
+
const PROSE_FIELDS: Readonly<Record<KxmResourceKind, ReadonlySet<string>>> = {
|
|
55
55
|
project: new Set(["name", "description"]),
|
|
56
56
|
repository: new Set(["description"]),
|
|
57
57
|
agent: new Set(["purpose", "instructions"]),
|
|
@@ -66,7 +66,7 @@ const NETWORK_RANK: Readonly<Record<string, number>> = { none: 0, "provider-only
|
|
|
66
66
|
const UNTRACKED_RANK: Readonly<Record<string, number>> = { "tracked-only": 0, ask: 1, bounded: 2 };
|
|
67
67
|
|
|
68
68
|
function canonical(value: JsonValue | undefined): string {
|
|
69
|
-
return
|
|
69
|
+
return kxmCanonicalJson(value === undefined ? null : value);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function asObject(value: JsonValue | undefined): JsonObject | undefined {
|
|
@@ -101,9 +101,9 @@ function secretGrantKeys(grants: JsonValue[]): Map<number, string> {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/** Extract the authority-bearing fields of one resource as comparable entries. */
|
|
104
|
-
export function
|
|
105
|
-
const entries:
|
|
106
|
-
const push = (path: string, field:
|
|
104
|
+
export function kxmAuthorityEntries(resource: { kind: KxmResourceKind; id?: string; value: JsonObject }): KxmAuthorityEntry[] {
|
|
105
|
+
const entries: KxmAuthorityEntry[] = [];
|
|
106
|
+
const push = (path: string, field: KxmPermissionField, value: JsonValue | undefined): void => {
|
|
107
107
|
entries.push({ path, field, value: canonical(value) });
|
|
108
108
|
};
|
|
109
109
|
const value = resource.value;
|
|
@@ -252,7 +252,7 @@ export function vnextAuthorityEntries(resource: { kind: VnextResourceKind; id?:
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/** Prose/non-authority fields, surfaced separately so reviewers see them as neutral. */
|
|
255
|
-
export function
|
|
255
|
+
export function kxmProseEntries(resource: { kind: KxmResourceKind; value: JsonObject }): Map<string, string> {
|
|
256
256
|
const entries = new Map<string, string>();
|
|
257
257
|
for (const field of PROSE_FIELDS[resource.kind]) {
|
|
258
258
|
if (resource.value[field] !== undefined) entries.set(`/${field}`, canonical(resource.value[field]));
|
|
@@ -273,24 +273,24 @@ export function vnextProseEntries(resource: { kind: VnextResourceKind; value: Js
|
|
|
273
273
|
* Diff
|
|
274
274
|
* ------------------------------------------------------------------ */
|
|
275
275
|
|
|
276
|
-
export interface
|
|
276
|
+
export interface KxmPermissionChange {
|
|
277
277
|
resource: string;
|
|
278
278
|
path: string;
|
|
279
|
-
field:
|
|
280
|
-
direction:
|
|
279
|
+
field: KxmPermissionField;
|
|
280
|
+
direction: KxmPermissionDirection;
|
|
281
281
|
summary: string;
|
|
282
282
|
baseValueSha256?: string;
|
|
283
283
|
candidateValueSha256?: string;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
export interface
|
|
286
|
+
export interface KxmPermissionDiff {
|
|
287
287
|
schema: "kxm.permission-diff.v1";
|
|
288
288
|
baseRevision: string;
|
|
289
289
|
candidateRevision: string;
|
|
290
|
-
changes:
|
|
291
|
-
expansions:
|
|
292
|
-
narrowings:
|
|
293
|
-
neutralChanges:
|
|
290
|
+
changes: KxmPermissionChange[];
|
|
291
|
+
expansions: KxmPermissionChange[];
|
|
292
|
+
narrowings: KxmPermissionChange[];
|
|
293
|
+
neutralChanges: KxmPermissionChange[];
|
|
294
294
|
requiresReview: boolean;
|
|
295
295
|
}
|
|
296
296
|
|
|
@@ -298,7 +298,7 @@ function valueHash(canonicalValue: string): string {
|
|
|
298
298
|
return `sha256:${createHash("sha256").update(canonicalValue, "utf8").digest("hex")}`;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string, candidateValue: string):
|
|
301
|
+
function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string, candidateValue: string): KxmPermissionDirection {
|
|
302
302
|
const base = JSON.parse(baseValue) as unknown;
|
|
303
303
|
const candidate = JSON.parse(candidateValue) as unknown;
|
|
304
304
|
const baseRank = typeof base === "string" && base in rank ? rank[base] as number : undefined;
|
|
@@ -310,7 +310,7 @@ function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
/** Direction for a numeric bound: raising limits is expansion. */
|
|
313
|
-
function numericBoundDirection(baseValue: string, candidateValue: string):
|
|
313
|
+
function numericBoundDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
|
|
314
314
|
const base = JSON.parse(baseValue) as unknown;
|
|
315
315
|
const candidate = JSON.parse(candidateValue) as unknown;
|
|
316
316
|
if (typeof base !== "number" || typeof candidate !== "number") return "expansion";
|
|
@@ -319,7 +319,7 @@ function numericBoundDirection(baseValue: string, candidateValue: string): Vnext
|
|
|
319
319
|
return "neutral";
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
function budgetDirection(baseValue: string, candidateValue: string):
|
|
322
|
+
function budgetDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
|
|
323
323
|
const base = asObject(JSON.parse(baseValue) as JsonValue);
|
|
324
324
|
const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
|
|
325
325
|
if (!base || !candidate) return "expansion";
|
|
@@ -335,7 +335,7 @@ function budgetDirection(baseValue: string, candidateValue: string): VnextPermis
|
|
|
335
335
|
return sawNarrowing ? "narrowing" : "neutral";
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
function quorumDirection(baseValue: string, candidateValue: string):
|
|
338
|
+
function quorumDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
|
|
339
339
|
const base = asObject(JSON.parse(baseValue) as JsonValue);
|
|
340
340
|
const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
|
|
341
341
|
if (!base || !candidate) return "expansion";
|
|
@@ -376,7 +376,7 @@ function quorumDirection(baseValue: string, candidateValue: string): VnextPermis
|
|
|
376
376
|
};
|
|
377
377
|
// Residual fail-closed check runs BEFORE any narrowing return: unknown or
|
|
378
378
|
// future fields always expand, even alongside an ordered narrowing.
|
|
379
|
-
if (
|
|
379
|
+
if (kxmCanonicalJson(residualOf(baseValue)) !== kxmCanonicalJson(residualOf(candidateValue))) return "expansion";
|
|
380
380
|
const basePolicy = asObject(base.producerPolicy as JsonValue | undefined);
|
|
381
381
|
const candidatePolicy = asObject(candidate.producerPolicy as JsonValue | undefined);
|
|
382
382
|
if (!basePolicy && !candidatePolicy) return sawNarrowing ? "narrowing" : "neutral";
|
|
@@ -404,7 +404,7 @@ function quorumDirection(baseValue: string, candidateValue: string): VnextPermis
|
|
|
404
404
|
return sawNarrowing ? "narrowing" : "neutral";
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
-
function snapshotDirection(baseValue: string, candidateValue: string):
|
|
407
|
+
function snapshotDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
|
|
408
408
|
const base = asObject(JSON.parse(baseValue) as JsonValue);
|
|
409
409
|
const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
|
|
410
410
|
if (!base || !candidate) return "expansion";
|
|
@@ -426,16 +426,16 @@ function snapshotDirection(baseValue: string, candidateValue: string): VnextPerm
|
|
|
426
426
|
// Residual fail-closed check: unknown future snapshot keys expand.
|
|
427
427
|
const CLASSIFIED_SNAPSHOT = new Set(["untracked", "maxUntrackedFileBytes", "maxUntrackedTotalBytes", "dirtySubmodules"]);
|
|
428
428
|
const residualOf = (snapshot: JsonObject): JsonValue => Object.fromEntries(Object.entries(snapshot).filter(([key]) => !CLASSIFIED_SNAPSHOT.has(key)));
|
|
429
|
-
if (
|
|
429
|
+
if (kxmCanonicalJson(residualOf(baseSnapshot)) !== kxmCanonicalJson(residualOf(candidateSnapshot))) return "expansion";
|
|
430
430
|
return bounds === "narrowing" || untracked === "narrowing" ? "narrowing" : "neutral";
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
function classifyChange(
|
|
434
|
-
field:
|
|
434
|
+
field: KxmPermissionField,
|
|
435
435
|
baseValue: string | undefined,
|
|
436
436
|
candidateValue: string | undefined,
|
|
437
437
|
context?: { fallbackRank?: number; baseFallbackRank?: number },
|
|
438
|
-
):
|
|
438
|
+
): KxmPermissionDirection {
|
|
439
439
|
if (baseValue === candidateValue) return "neutral";
|
|
440
440
|
if (baseValue === undefined || candidateValue === undefined) {
|
|
441
441
|
if (candidateValue === undefined) {
|
|
@@ -489,7 +489,7 @@ function classifyChange(
|
|
|
489
489
|
// review-required expansion; then order by required (default true).
|
|
490
490
|
const { required: _b, ...baseRest } = base;
|
|
491
491
|
const { required: _c, ...candidateRest } = candidate;
|
|
492
|
-
if (
|
|
492
|
+
if (kxmCanonicalJson(baseRest as JsonValue) !== kxmCanonicalJson(candidateRest as JsonValue)) return "expansion";
|
|
493
493
|
const baseRequired = (base.required ?? true) === true;
|
|
494
494
|
const candidateRequired = (candidate.required ?? true) === true;
|
|
495
495
|
if (baseRequired && !candidateRequired) return "narrowing";
|
|
@@ -506,14 +506,14 @@ function classifyChange(
|
|
|
506
506
|
}
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
-
function summarize(resource: string, path: string, field:
|
|
509
|
+
function summarize(resource: string, path: string, field: KxmPermissionField, direction: KxmPermissionDirection, baseValue: string | undefined, candidateValue: string | undefined): string {
|
|
510
510
|
const verb = baseValue === undefined ? "added" : candidateValue === undefined ? "removed" : "changed";
|
|
511
511
|
return `${resource} ${path} ${field} ${verb} (${direction})`;
|
|
512
512
|
}
|
|
513
513
|
|
|
514
514
|
/** Diff two complete bundles into a deterministic, classified permission report. */
|
|
515
|
-
export function
|
|
516
|
-
const changes:
|
|
515
|
+
export function computeKxmPermissionDiff(base: KxmProjectBundle, candidate: KxmProjectBundle): KxmPermissionDiff {
|
|
516
|
+
const changes: KxmPermissionChange[] = [];
|
|
517
517
|
const baseByPath = new Map(base.resources.map((resource) => [resource.logicalPath, resource]));
|
|
518
518
|
const candidateByPath = new Map(candidate.resources.map((resource) => [resource.logicalPath, resource]));
|
|
519
519
|
|
|
@@ -528,8 +528,8 @@ export function computeVnextPermissionDiff(base: VnextProjectBundle, candidate:
|
|
|
528
528
|
// Resource added or removed: shape change. Added resources expand
|
|
529
529
|
// authority; removed resources narrow it — except models: removing one
|
|
530
530
|
// can retarget tag-based consumers onto another profile (an expansion).
|
|
531
|
-
const resource = candidateResource ?? baseResource as
|
|
532
|
-
const direction:
|
|
531
|
+
const resource = candidateResource ?? baseResource as KxmResource;
|
|
532
|
+
const direction: KxmPermissionDirection = candidateResource
|
|
533
533
|
? "expansion"
|
|
534
534
|
: ((resource.kind === "model" || resource.kind === "gate-registry") ? "expansion" : "narrowing");
|
|
535
535
|
changes.push({
|
|
@@ -560,27 +560,27 @@ export function computeVnextPermissionDiff(base: VnextProjectBundle, candidate:
|
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
/** Diff two values of one resource kind (e.g. template baseline vs target). */
|
|
563
|
-
export function
|
|
564
|
-
kind:
|
|
563
|
+
export function computeKxmResourcePermissionDiff(
|
|
564
|
+
kind: KxmResourceKind,
|
|
565
565
|
resourcePath: string,
|
|
566
566
|
baseValue: JsonObject,
|
|
567
567
|
candidateValue: JsonObject,
|
|
568
|
-
):
|
|
569
|
-
const changes:
|
|
570
|
-
const base:
|
|
571
|
-
const candidate:
|
|
568
|
+
): KxmPermissionChange[] {
|
|
569
|
+
const changes: KxmPermissionChange[] = [];
|
|
570
|
+
const base: KxmResource = { kind, file: resourcePath, logicalPath: resourcePath, value: baseValue };
|
|
571
|
+
const candidate: KxmResource = { kind, file: resourcePath, logicalPath: resourcePath, value: candidateValue };
|
|
572
572
|
diffResource(resourcePath, base, candidate, changes);
|
|
573
573
|
return changes.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
-
function diffResource(logicalPath: string, base:
|
|
577
|
-
const baseEntries = new Map(
|
|
578
|
-
const candidateEntries = new Map(
|
|
576
|
+
function diffResource(logicalPath: string, base: KxmResource, candidate: KxmResource, changes: KxmPermissionChange[]): void {
|
|
577
|
+
const baseEntries = new Map(kxmAuthorityEntries(base).map((entry) => [entry.path, entry]));
|
|
578
|
+
const candidateEntries = new Map(kxmAuthorityEntries(candidate).map((entry) => [entry.path, entry]));
|
|
579
579
|
const paths = [...new Set([...baseEntries.keys(), ...candidateEntries.keys()])].sort();
|
|
580
580
|
for (const path of paths) {
|
|
581
581
|
const baseEntry = baseEntries.get(path);
|
|
582
582
|
const candidateEntry = candidateEntries.get(path);
|
|
583
|
-
const field = (candidateEntry ?? baseEntry as
|
|
583
|
+
const field = (candidateEntry ?? baseEntry as KxmAuthorityEntry).field;
|
|
584
584
|
// For per-repository overrides, the effective fallback is the resource-
|
|
585
585
|
// level defaultRepositoryAccess (the loader's ceiling rule). Removal
|
|
586
586
|
// compares against the candidate's default; addition against the base's.
|
|
@@ -609,8 +609,8 @@ function diffResource(logicalPath: string, base: VnextResource, candidate: Vnext
|
|
|
609
609
|
});
|
|
610
610
|
}
|
|
611
611
|
// Prose changes are surfaced as neutral for reviewer visibility.
|
|
612
|
-
const baseProse =
|
|
613
|
-
const candidateProse =
|
|
612
|
+
const baseProse = kxmProseEntries(base);
|
|
613
|
+
const candidateProse = kxmProseEntries(candidate);
|
|
614
614
|
for (const path of [...new Set([...baseProse.keys(), ...candidateProse.keys()])].sort()) {
|
|
615
615
|
if (baseProse.get(path) === candidateProse.get(path)) continue;
|
|
616
616
|
changes.push({
|
|
@@ -642,7 +642,7 @@ function git(root: string, args: string[]): string {
|
|
|
642
642
|
maxBuffer: 64 * 1024 * 1024,
|
|
643
643
|
});
|
|
644
644
|
if (result.status !== 0 || result.error) {
|
|
645
|
-
throw new
|
|
645
|
+
throw new KxmConfigError([{
|
|
646
646
|
phase: "discovery",
|
|
647
647
|
code: "git_base_unavailable",
|
|
648
648
|
file: args[0] ?? "<git>",
|
|
@@ -660,7 +660,7 @@ function gitBuffer(root: string, args: string[]): Buffer {
|
|
|
660
660
|
maxBuffer: 256 * 1024 * 1024,
|
|
661
661
|
});
|
|
662
662
|
if (result.status !== 0 || result.error) {
|
|
663
|
-
throw new
|
|
663
|
+
throw new KxmConfigError([{
|
|
664
664
|
phase: "discovery",
|
|
665
665
|
code: "git_base_unavailable",
|
|
666
666
|
file: args[0] ?? "<git>",
|
|
@@ -673,7 +673,7 @@ function gitBuffer(root: string, args: string[]): Buffer {
|
|
|
673
673
|
/** Resolve a revision to its tree SHA once so a moving ref cannot mix bases. */
|
|
674
674
|
function resolveTreeRevision(root: string, revision: string): string {
|
|
675
675
|
if (!/^[A-Za-z0-9._/^~-]+$/.test(revision) || revision.includes("..") || revision.startsWith("-")) {
|
|
676
|
-
throw new
|
|
676
|
+
throw new KxmConfigError([{
|
|
677
677
|
phase: "discovery",
|
|
678
678
|
code: "git_revision_invalid",
|
|
679
679
|
file: revision,
|
|
@@ -684,7 +684,7 @@ function resolveTreeRevision(root: string, revision: string): string {
|
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
/** Load the bundle as of a Git revision by materializing tracked files into a temporary shadow root. */
|
|
687
|
-
export function
|
|
687
|
+
export function loadKxmProjectAtRevision(root: string, revision: string, options: KxmConfigOptions = {}): KxmProjectBundle {
|
|
688
688
|
const tree = resolveTreeRevision(root, revision);
|
|
689
689
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
690
690
|
const paths = listing
|
|
@@ -697,7 +697,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
697
697
|
for (const path of paths) {
|
|
698
698
|
const segments = path.split("/");
|
|
699
699
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
700
|
-
throw new
|
|
700
|
+
throw new KxmConfigError([{
|
|
701
701
|
phase: "path",
|
|
702
702
|
code: "git_tree_path_invalid",
|
|
703
703
|
file: path,
|
|
@@ -707,7 +707,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
707
707
|
const absolute = join(shadowResolved, ...segments);
|
|
708
708
|
const resolved = resolve(absolute);
|
|
709
709
|
if (!resolved.startsWith(`${shadowResolved}${sep}`)) {
|
|
710
|
-
throw new
|
|
710
|
+
throw new KxmConfigError([{
|
|
711
711
|
phase: "path",
|
|
712
712
|
code: "git_tree_path_invalid",
|
|
713
713
|
file: path,
|
|
@@ -733,16 +733,16 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
733
733
|
try {
|
|
734
734
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
735
735
|
} catch (error) {
|
|
736
|
-
if (error instanceof
|
|
737
|
-
throw new
|
|
736
|
+
if (error instanceof KxmConfigError) {
|
|
737
|
+
throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
|
|
738
738
|
}
|
|
739
739
|
throw error;
|
|
740
740
|
}
|
|
741
741
|
const shadowBindings: Record<string, string> = {};
|
|
742
742
|
for (const member of baseProject) {
|
|
743
743
|
if (member.role !== "member") continue;
|
|
744
|
-
if (!
|
|
745
|
-
throw new
|
|
744
|
+
if (!kxmResourceIdentifier(member.repositoryId)) {
|
|
745
|
+
throw new KxmConfigError([{
|
|
746
746
|
phase: "path",
|
|
747
747
|
code: "git_tree_path_invalid",
|
|
748
748
|
file: ".kxm/project.yaml",
|
|
@@ -750,7 +750,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
750
750
|
}]);
|
|
751
751
|
}
|
|
752
752
|
if (member.pathHint !== undefined && !portableMemberPathHint(member.pathHint)) {
|
|
753
|
-
throw new
|
|
753
|
+
throw new KxmConfigError([{
|
|
754
754
|
phase: "path",
|
|
755
755
|
code: "git_tree_path_invalid",
|
|
756
756
|
file: ".kxm/project.yaml",
|
|
@@ -767,7 +767,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
767
767
|
: undefined;
|
|
768
768
|
if (!memberWorktree || !existsSync(memberWorktree)) {
|
|
769
769
|
if (member.required === false) continue; // optional member absent on this host (loader tolerates it)
|
|
770
|
-
throw new
|
|
770
|
+
throw new KxmConfigError([{
|
|
771
771
|
phase: "discovery",
|
|
772
772
|
code: "trust_scope_unsupported",
|
|
773
773
|
file: ".kxm/project.yaml",
|
|
@@ -781,7 +781,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
781
781
|
if (gitlink.length > 0) {
|
|
782
782
|
const match = /^160000 commit ([0-9a-f]{40,64})\t/.exec(gitlink);
|
|
783
783
|
if (!match) {
|
|
784
|
-
throw new
|
|
784
|
+
throw new KxmConfigError([{
|
|
785
785
|
phase: "discovery",
|
|
786
786
|
code: "trust_scope_unsupported",
|
|
787
787
|
file: ".kxm/project.yaml",
|
|
@@ -794,7 +794,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
794
794
|
// the only reviewable base is the member's own HEAD commit.
|
|
795
795
|
pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
|
|
796
796
|
} else {
|
|
797
|
-
throw new
|
|
797
|
+
throw new KxmConfigError([{
|
|
798
798
|
phase: "discovery",
|
|
799
799
|
code: "trust_scope_unsupported",
|
|
800
800
|
file: ".kxm/project.yaml",
|
|
@@ -807,7 +807,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
807
807
|
pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
|
|
808
808
|
}
|
|
809
809
|
if (!pinnedCommit) {
|
|
810
|
-
throw new
|
|
810
|
+
throw new KxmConfigError([{
|
|
811
811
|
phase: "discovery",
|
|
812
812
|
code: "trust_scope_unsupported",
|
|
813
813
|
file: ".kxm/project.yaml",
|
|
@@ -819,7 +819,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
819
819
|
const memberPaths = memberListing.split("\u0000").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
820
820
|
const memberShadowRoot = join(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
821
821
|
if (!resolve(memberShadowRoot).startsWith(`${resolve(shadowResolved, shadowMembersDir)}${sep}`)) {
|
|
822
|
-
throw new
|
|
822
|
+
throw new KxmConfigError([{
|
|
823
823
|
phase: "path",
|
|
824
824
|
code: "git_tree_path_invalid",
|
|
825
825
|
file: ".kxm/project.yaml",
|
|
@@ -829,12 +829,12 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
829
829
|
for (const path of memberPaths) {
|
|
830
830
|
const segments = path.split("/");
|
|
831
831
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
832
|
-
throw new
|
|
832
|
+
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
833
833
|
}
|
|
834
834
|
const absolute = join(memberShadowRoot, ...segments);
|
|
835
835
|
const resolved = resolve(absolute);
|
|
836
836
|
if (!resolved.startsWith(`${resolve(memberShadowRoot)}${sep}`)) {
|
|
837
|
-
throw new
|
|
837
|
+
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry escapes the shadow root" }]);
|
|
838
838
|
}
|
|
839
839
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path}`]);
|
|
840
840
|
mkdirSync(dirname(absolute), { recursive: true });
|
|
@@ -844,10 +844,10 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
|
|
|
844
844
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
845
845
|
}
|
|
846
846
|
try {
|
|
847
|
-
return
|
|
847
|
+
return loadKxmProject(shadowResolved, { ...options, repositoryBindings: shadowBindings });
|
|
848
848
|
} catch (error) {
|
|
849
|
-
if (error instanceof
|
|
850
|
-
throw new
|
|
849
|
+
if (error instanceof KxmConfigError) {
|
|
850
|
+
throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
|
|
851
851
|
}
|
|
852
852
|
throw error;
|
|
853
853
|
}
|
|
@@ -865,7 +865,7 @@ interface BaseProjectMember {
|
|
|
865
865
|
|
|
866
866
|
/** Portable member pathHint predicate (mirrors the loader's portable path rules; "." is never a member). */
|
|
867
867
|
function portableMemberPathHint(pathHint: string): boolean {
|
|
868
|
-
return pathHint !== "." &&
|
|
868
|
+
return pathHint !== "." && kxmPortablePath(pathHint);
|
|
869
869
|
}
|
|
870
870
|
|
|
871
871
|
|
|
@@ -898,7 +898,7 @@ function initShadowGitRoot(directory: string): void {
|
|
|
898
898
|
windowsHide: true,
|
|
899
899
|
});
|
|
900
900
|
if (result.status !== 0 || result.error) {
|
|
901
|
-
throw new
|
|
901
|
+
throw new KxmConfigError([{
|
|
902
902
|
phase: "discovery",
|
|
903
903
|
code: "git_base_unavailable",
|
|
904
904
|
file: directory,
|
|
@@ -908,18 +908,18 @@ function initShadowGitRoot(directory: string): void {
|
|
|
908
908
|
}
|
|
909
909
|
|
|
910
910
|
/** Diff the working tree against a Git revision. */
|
|
911
|
-
export function
|
|
911
|
+
export function diffKxmProjectAgainstRevision(
|
|
912
912
|
root: string,
|
|
913
913
|
revision: string,
|
|
914
|
-
options:
|
|
915
|
-
):
|
|
916
|
-
const base =
|
|
917
|
-
const candidate =
|
|
918
|
-
return
|
|
914
|
+
options: KxmConfigOptions = {},
|
|
915
|
+
): KxmPermissionDiff {
|
|
916
|
+
const base = loadKxmProjectAtRevision(root, revision, options);
|
|
917
|
+
const candidate = loadKxmProject(root, options);
|
|
918
|
+
return computeKxmPermissionDiff(base, candidate);
|
|
919
919
|
}
|
|
920
920
|
|
|
921
921
|
/** Human-readable report lines for the CLI. */
|
|
922
|
-
export function
|
|
922
|
+
export function formatKxmPermissionDiff(diff: KxmPermissionDiff): string {
|
|
923
923
|
const lines: string[] = [];
|
|
924
924
|
lines.push(`permission diff: ${diff.baseRevision.slice(0, 19)}… -> ${diff.candidateRevision.slice(0, 19)}…`);
|
|
925
925
|
if (diff.changes.length === 0) {
|
|
@@ -3,16 +3,16 @@ import { join } from "node:path";
|
|
|
3
3
|
import { StringDecoder } from "node:string_decoder";
|
|
4
4
|
import {
|
|
5
5
|
registerTrustedProducer,
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
-
type
|
|
9
|
-
} from "./
|
|
6
|
+
type KxmProducer,
|
|
7
|
+
type KxmProducerRequest,
|
|
8
|
+
type KxmProducerResult,
|
|
9
|
+
} from "./engine.ts";
|
|
10
10
|
import {
|
|
11
11
|
probeHarnessAssignmentAsync,
|
|
12
12
|
type HarnessAssignmentProbeOptions,
|
|
13
13
|
type HarnessInventory,
|
|
14
14
|
type HarnessStatus,
|
|
15
|
-
} from "./
|
|
15
|
+
} from "./harness.ts";
|
|
16
16
|
import {
|
|
17
17
|
calculateModelCost,
|
|
18
18
|
loadPriceCatalogForEstimate,
|
|
@@ -380,7 +380,7 @@ export class PiSession {
|
|
|
380
380
|
}
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
-
export interface
|
|
383
|
+
export interface KxmPiProducerOptions {
|
|
384
384
|
projectRoot?: string | undefined;
|
|
385
385
|
sessionDir?: string | undefined;
|
|
386
386
|
piCommand?: string | undefined;
|
|
@@ -394,15 +394,15 @@ export interface VnextPiProducerOptions {
|
|
|
394
394
|
defaultProvider?: string | undefined;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
export interface
|
|
397
|
+
export interface KxmPiProducer extends KxmProducer {
|
|
398
398
|
readonly id: "pi";
|
|
399
399
|
readonly sessions: ReadonlyMap<string, PiSession>;
|
|
400
|
-
produce(request:
|
|
400
|
+
produce(request: KxmProducerRequest): Promise<KxmProducerResult>;
|
|
401
401
|
close(): Promise<void>;
|
|
402
402
|
closeRun(runId: string): Promise<void>;
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
-
export function
|
|
405
|
+
export function createKxmPiProducer(options: KxmPiProducerOptions = {}): KxmPiProducer {
|
|
406
406
|
const sessions = new Map<string, PiSession>();
|
|
407
407
|
const defaultModel = options.defaultModel ?? "xai/grok-4.6";
|
|
408
408
|
const defaultProvider = options.defaultProvider ?? "xai";
|
|
@@ -416,7 +416,7 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
|
|
|
416
416
|
return { provider: defaultProvider, model: trimmed };
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
function resolveModelForRequest(request:
|
|
419
|
+
function resolveModelForRequest(request: KxmProducerRequest): { provider: string; model: string; thinking?: string | undefined } {
|
|
420
420
|
if (request.model) {
|
|
421
421
|
const parsed = parseModelString(request.model);
|
|
422
422
|
return {
|
|
@@ -466,7 +466,7 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
-
async function getOrCreateSession(request:
|
|
469
|
+
async function getOrCreateSession(request: KxmProducerRequest, model: string): Promise<PiSession> {
|
|
470
470
|
const key = formatPiSessionKey({
|
|
471
471
|
runId: request.runId,
|
|
472
472
|
agentId: request.agentId,
|
|
@@ -532,13 +532,13 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
|
|
|
532
532
|
return session;
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
-
const producer:
|
|
535
|
+
const producer: KxmPiProducer = {
|
|
536
536
|
id: "pi",
|
|
537
537
|
get sessions(): ReadonlyMap<string, PiSession> {
|
|
538
538
|
return sessions;
|
|
539
539
|
},
|
|
540
540
|
|
|
541
|
-
async produce(request:
|
|
541
|
+
async produce(request: KxmProducerRequest): Promise<KxmProducerResult> {
|
|
542
542
|
const startTime = Date.now();
|
|
543
543
|
const resolved = resolveModelForRequest(request);
|
|
544
544
|
|