@skill-harness/adapters 0.12.0 → 0.14.0
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/dist/archive-access.d.ts +58 -0
- package/dist/archive-access.js +61 -0
- package/dist/archive-checkpoint.d.ts +47 -0
- package/dist/archive-checkpoint.js +116 -0
- package/dist/archive-facts.d.ts +19 -0
- package/dist/archive-facts.js +20 -0
- package/dist/archive-observer.d.ts +21 -0
- package/dist/archive-observer.js +79 -0
- package/dist/archive-policy.d.ts +107 -0
- package/dist/archive-policy.js +135 -0
- package/dist/archive-read-capability.d.ts +49 -0
- package/dist/archive-read-capability.js +45 -0
- package/dist/archive-retention-policy.d.ts +52 -0
- package/dist/archive-retention-policy.js +49 -0
- package/dist/archived-work.d.ts +44 -0
- package/dist/archived-work.js +64 -0
- package/dist/blind-intervention.d.ts +29 -0
- package/dist/blind-intervention.js +211 -0
- package/dist/codex-diagnostic-model.d.ts +14 -0
- package/dist/codex-diagnostic-model.js +39 -0
- package/dist/codex-host-observer.d.ts +111 -0
- package/dist/codex-host-observer.js +309 -0
- package/dist/codex-https.d.ts +7 -0
- package/dist/codex-https.js +221 -0
- package/dist/codex-model-profile.d.ts +38 -0
- package/dist/codex-model-profile.js +54 -0
- package/dist/codex-producer-ipc.d.ts +55 -0
- package/dist/codex-producer-ipc.js +67 -0
- package/dist/codex-sdk-transport.d.ts +50 -0
- package/dist/codex-sdk-transport.js +294 -0
- package/dist/codex-subscription.d.ts +114 -0
- package/dist/codex-subscription.js +268 -0
- package/dist/evidence-archive.d.ts +57 -0
- package/dist/evidence-archive.js +221 -0
- package/dist/execution-projection-schema.d.ts +10 -0
- package/dist/execution-projection-schema.js +30 -0
- package/dist/execution-retention-archive.d.ts +69 -0
- package/dist/execution-retention-archive.js +154 -0
- package/dist/generated/retention-v2-contract.d.ts +72 -0
- package/dist/generated/retention-v2-contract.js +105 -0
- package/dist/generated/retention-v2-json.d.ts +24 -0
- package/dist/generated/retention-v2-json.js +268 -0
- package/dist/generated/retention-v2-native-json.d.ts +2 -0
- package/dist/generated/retention-v2-native-json.js +33 -0
- package/dist/generated/retention-v2-native.d.ts +58 -0
- package/dist/generated/retention-v2-native.js +155 -0
- package/dist/generated/retention-v2-pin.d.ts +2 -0
- package/dist/generated/retention-v2-pin.js +4 -0
- package/dist/generated/retention-v2-types.d.ts +49 -0
- package/dist/generated/retention-v2-types.js +2 -0
- package/dist/generated/retention-v2-work-types.d.ts +260 -0
- package/dist/generated/retention-v2-work-types.js +13 -0
- package/dist/generated/work-v4/execution-id.d.ts +5 -0
- package/dist/generated/work-v4/execution-id.js +14 -0
- package/dist/generated/work-v4/json.d.ts +24 -0
- package/dist/generated/work-v4/json.js +268 -0
- package/dist/generated/work-v4/occurrences.d.ts +226 -0
- package/dist/generated/work-v4/occurrences.js +116 -0
- package/dist/generated/work-v4/pin.d.ts +1 -0
- package/dist/generated/work-v4/pin.js +3 -0
- package/dist/generated/work-v4/projection.d.ts +294 -0
- package/dist/generated/work-v4/projection.js +238 -0
- package/dist/generated/work-v4/reader.d.ts +24 -0
- package/dist/generated/work-v4/reader.js +109 -0
- package/dist/generated/work-v4/snapshot.d.ts +28 -0
- package/dist/generated/work-v4/snapshot.js +268 -0
- package/dist/generated/work-v4/types.d.ts +260 -0
- package/dist/generated/work-v4/types.js +13 -0
- package/dist/generated/work-v4/validation.d.ts +13 -0
- package/dist/generated/work-v4/validation.js +227 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +22 -0
- package/dist/installed-review-session.d.ts +28 -0
- package/dist/installed-review-session.js +166 -0
- package/dist/intervention-run.d.ts +403 -0
- package/dist/intervention-run.js +169 -0
- package/dist/learning-case.d.ts +12 -0
- package/dist/learning-case.js +15 -0
- package/dist/learning-journal.d.ts +18 -0
- package/dist/learning-journal.js +256 -0
- package/dist/principal-payload-port.d.ts +25 -0
- package/dist/principal-payload-port.js +40 -0
- package/dist/producer-product.d.ts +70 -0
- package/dist/producer-product.js +186 -0
- package/dist/producer-review.d.ts +53 -0
- package/dist/producer-review.js +207 -0
- package/dist/reviewed-archive-export.d.ts +42 -0
- package/dist/reviewed-archive-export.js +78 -0
- package/dist/trust-lifecycle.d.ts +128 -0
- package/dist/trust-lifecycle.js +200 -0
- package/dist/weekly-investigation.d.ts +237 -0
- package/dist/weekly-investigation.js +330 -0
- package/dist/work-candidates.d.ts +29 -0
- package/dist/work-candidates.js +78 -0
- package/dist/work-case-archive.d.ts +25 -0
- package/dist/work-case-archive.js +63 -0
- package/dist/work-case-review.d.ts +45 -0
- package/dist/work-case-review.js +220 -0
- package/dist/work-signal-cases.d.ts +15 -0
- package/dist/work-signal-cases.js +54 -0
- package/dist/work-signal-observation.d.ts +23 -0
- package/dist/work-signal-observation.js +89 -0
- package/package.json +3 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// GENERATED from pi-daddy 7c78769c47177b1972b09e1f5c5474ad44cd2cac by scripts/vendor-work-v4-reader.mjs. Do not hand-edit.
|
|
2
|
+
import { isExecutionId } from "./execution-id.js";
|
|
3
|
+
import { canonicalWorkJson, workDigest } from "./json.js";
|
|
4
|
+
import { WorkInputError } from "./types.js";
|
|
5
|
+
const kinds = ["scope", "goal", "node", "obligation", "artifact", "policy"];
|
|
6
|
+
const fail = () => { throw new WorkInputError("WORK_SCHEMA_INVALID"); };
|
|
7
|
+
function require(value) { if (!value)
|
|
8
|
+
fail(); }
|
|
9
|
+
export function workObject(value) {
|
|
10
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
11
|
+
return fail();
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function closed(value, keys) {
|
|
15
|
+
const object = workObject(value);
|
|
16
|
+
require(Object.keys(object).length === keys.length && keys.every(key => Object.hasOwn(object, key)));
|
|
17
|
+
return object;
|
|
18
|
+
}
|
|
19
|
+
function id(value) { require(typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:/@+\-]{0,127}$/.test(value)); }
|
|
20
|
+
function digest(value) { require(typeof value === "string" && /^[0-9a-f]{64}$/.test(value)); }
|
|
21
|
+
function integer(value) { require(typeof value === "number" && Number.isSafeInteger(value) && value >= 1); }
|
|
22
|
+
function member(value, values) { require(typeof value === "string" && values.includes(value)); }
|
|
23
|
+
function nullable(value, validate) { if (value !== null)
|
|
24
|
+
validate(value); }
|
|
25
|
+
function reference(value, allowed = kinds) {
|
|
26
|
+
const ref = closed(value, ["kind", "id", "revision", "digest"]);
|
|
27
|
+
member(ref.kind, allowed);
|
|
28
|
+
id(ref.id);
|
|
29
|
+
integer(ref.revision);
|
|
30
|
+
digest(ref.digest);
|
|
31
|
+
}
|
|
32
|
+
function identity(value) {
|
|
33
|
+
const ref = closed(value, ["id", "digest"]);
|
|
34
|
+
id(ref.id);
|
|
35
|
+
digest(ref.digest);
|
|
36
|
+
}
|
|
37
|
+
function eventRef(value) {
|
|
38
|
+
const ref = closed(value, ["eventId", "digest"]);
|
|
39
|
+
id(ref.eventId);
|
|
40
|
+
digest(ref.digest);
|
|
41
|
+
}
|
|
42
|
+
/** Internal validation for the exact out-of-band selectedSnapshot shape; no authority is constructed. */
|
|
43
|
+
export function validateWorkSelection(value) {
|
|
44
|
+
if (value === null)
|
|
45
|
+
return;
|
|
46
|
+
const selected = closed(value, ["snapshot", "event"]);
|
|
47
|
+
identity(selected.snapshot);
|
|
48
|
+
eventRef(selected.event);
|
|
49
|
+
}
|
|
50
|
+
function timestamp(value) {
|
|
51
|
+
require(typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value));
|
|
52
|
+
require(!value.startsWith("0000") && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value);
|
|
53
|
+
}
|
|
54
|
+
/** Builder sorts detached copies; reader refuses noncanonical sets instead of repairing them. */
|
|
55
|
+
function set(value, validate, building, key = canonicalWorkJson) {
|
|
56
|
+
require(Array.isArray(value));
|
|
57
|
+
value.forEach(validate);
|
|
58
|
+
const keyed = value.map(item => ({ item, key: key(item) }));
|
|
59
|
+
const sorted = [...keyed].sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
60
|
+
for (let i = 1; i < sorted.length; i++)
|
|
61
|
+
require(sorted[i - 1].key !== sorted[i].key);
|
|
62
|
+
if (building)
|
|
63
|
+
value.splice(0, value.length, ...sorted.map(entry => entry.item));
|
|
64
|
+
else
|
|
65
|
+
require(keyed.every((entry, i) => entry.key === sorted[i].key));
|
|
66
|
+
}
|
|
67
|
+
function ownKeys(keys, building) { return building ? keys : [...keys, "digest"]; }
|
|
68
|
+
function revision(value, building) {
|
|
69
|
+
const r = closed(value, ownKeys(["kind", "id", "revision", "scopeId", "predecessor", "contentDigest",
|
|
70
|
+
"parent", "dependencies", "ownerId", "permittedEffects", "policy"], building));
|
|
71
|
+
member(r.kind, kinds);
|
|
72
|
+
id(r.id);
|
|
73
|
+
integer(r.revision);
|
|
74
|
+
id(r.scopeId);
|
|
75
|
+
id(r.ownerId);
|
|
76
|
+
digest(r.contentDigest);
|
|
77
|
+
nullable(r.predecessor, v => reference(v));
|
|
78
|
+
nullable(r.parent, v => reference(v));
|
|
79
|
+
nullable(r.policy, v => reference(v, ["policy"]));
|
|
80
|
+
set(r.dependencies, v => reference(v, ["obligation"]), building);
|
|
81
|
+
set(r.permittedEffects, id, building, v => v);
|
|
82
|
+
if (r.revision === 1)
|
|
83
|
+
require(r.predecessor === null);
|
|
84
|
+
else {
|
|
85
|
+
require(r.predecessor !== null);
|
|
86
|
+
const predecessor = workObject(r.predecessor);
|
|
87
|
+
require(predecessor.kind === r.kind && predecessor.id === r.id &&
|
|
88
|
+
predecessor.revision === r.revision - 1);
|
|
89
|
+
}
|
|
90
|
+
const noDependencies = r.dependencies.length === 0;
|
|
91
|
+
if (r.kind === "scope")
|
|
92
|
+
require(r.scopeId === r.id && r.parent === null && noDependencies && r.policy === null);
|
|
93
|
+
if (r.kind === "artifact" || r.kind === "policy") {
|
|
94
|
+
require(r.parent === null && noDependencies && r.policy === null && r.permittedEffects.length === 0);
|
|
95
|
+
}
|
|
96
|
+
if (r.kind === "goal" || r.kind === "node" || r.kind === "obligation") {
|
|
97
|
+
reference(r.parent, r.kind === "goal" ? ["scope", "goal"] : ["goal", "node"]);
|
|
98
|
+
if (r.kind === "obligation")
|
|
99
|
+
reference(r.policy, ["policy"]);
|
|
100
|
+
else
|
|
101
|
+
require(noDependencies && r.policy === null);
|
|
102
|
+
}
|
|
103
|
+
if (!building)
|
|
104
|
+
digest(r.digest);
|
|
105
|
+
}
|
|
106
|
+
function obligationBinding(value) {
|
|
107
|
+
const b = closed(value, ["intent", "obligation", "artifact", "policy"]);
|
|
108
|
+
reference(b.intent, ["goal", "node"]);
|
|
109
|
+
reference(b.obligation, ["obligation"]);
|
|
110
|
+
nullable(b.artifact, v => reference(v, ["artifact"]));
|
|
111
|
+
reference(b.policy, ["policy"]);
|
|
112
|
+
}
|
|
113
|
+
function snapshot(value, building) {
|
|
114
|
+
const s = closed(value, ownKeys(["snapshotId", "scope", "revisions", "bindings"], building));
|
|
115
|
+
id(s.snapshotId);
|
|
116
|
+
reference(s.scope, ["scope"]);
|
|
117
|
+
set(s.revisions, v => reference(v, kinds.filter(k => k !== "scope")), building);
|
|
118
|
+
set(s.bindings, obligationBinding, building, v => canonicalWorkJson(workObject(v).obligation));
|
|
119
|
+
if (!building)
|
|
120
|
+
digest(s.digest);
|
|
121
|
+
// Inventory/ancestor/predecessor resolution requires the complete event snapshot, not a guessed head.
|
|
122
|
+
}
|
|
123
|
+
function occurrence(value) {
|
|
124
|
+
const p = closed(value, ["scope", "obligation", "executionId", "parentExecutionId", "childId", "variantId",
|
|
125
|
+
"artifact", "provenance", "state", "labels"]);
|
|
126
|
+
reference(p.scope, ["scope"]);
|
|
127
|
+
reference(p.obligation, ["obligation"]);
|
|
128
|
+
require(isExecutionId(p.executionId));
|
|
129
|
+
require(p.parentExecutionId === null || isExecutionId(p.parentExecutionId));
|
|
130
|
+
require(p.executionId !== p.parentExecutionId);
|
|
131
|
+
nullable(p.childId, id);
|
|
132
|
+
nullable(p.variantId, id);
|
|
133
|
+
nullable(p.artifact, v => reference(v, ["artifact"]));
|
|
134
|
+
member(p.provenance, ["declared", "observed"]);
|
|
135
|
+
member(p.state, ["unknown", "starting", "running", "completed", "failed"]);
|
|
136
|
+
const labels = closed(p.labels, ["sessionId", "branchLeafId", "toolCallId", "taskId", "workspaceId",
|
|
137
|
+
"definitionDigest", "configurationDigest", "modelId", "effortId"]);
|
|
138
|
+
for (const [key, value] of Object.entries(labels))
|
|
139
|
+
nullable(value, key.endsWith("Digest") ? digest : id);
|
|
140
|
+
}
|
|
141
|
+
function evidence(value) {
|
|
142
|
+
const e = closed(value, ["id", "digest", "event"]);
|
|
143
|
+
id(e.id);
|
|
144
|
+
digest(e.digest);
|
|
145
|
+
nullable(e.event, eventRef);
|
|
146
|
+
}
|
|
147
|
+
function acceptance(value, building) {
|
|
148
|
+
const p = closed(value, ["authorityId", "binding"]);
|
|
149
|
+
id(p.authorityId);
|
|
150
|
+
acceptanceBinding(p.binding, building);
|
|
151
|
+
}
|
|
152
|
+
function acceptanceBinding(value, building) {
|
|
153
|
+
const b = closed(value, ["snapshot", "scope", "intent", "obligation", "artifact", "artifactDigest", "policy", "evidence"]);
|
|
154
|
+
identity(b.snapshot);
|
|
155
|
+
reference(b.scope, ["scope"]);
|
|
156
|
+
reference(b.intent, ["goal", "node"]);
|
|
157
|
+
reference(b.obligation, ["obligation"]);
|
|
158
|
+
reference(b.artifact, ["artifact"]);
|
|
159
|
+
digest(b.artifactDigest);
|
|
160
|
+
reference(b.policy, ["policy"]);
|
|
161
|
+
set(b.evidence, evidence, building);
|
|
162
|
+
require(b.evidence.length > 0);
|
|
163
|
+
}
|
|
164
|
+
/** Validate a detached host context. Receipt/availability order and duplicate deliveries have no priority. */
|
|
165
|
+
export function validateWorkContext(value) {
|
|
166
|
+
const c = closed(value, ["selectedSnapshot", "authority"]);
|
|
167
|
+
validateWorkSelection(c.selectedSnapshot);
|
|
168
|
+
if (c.authority === null)
|
|
169
|
+
return;
|
|
170
|
+
const a = closed(c.authority, ["snapshot", "decisions", "availability"]);
|
|
171
|
+
identity(a.snapshot);
|
|
172
|
+
require(Array.isArray(a.decisions));
|
|
173
|
+
require(Array.isArray(a.availability));
|
|
174
|
+
for (const value of a.decisions) {
|
|
175
|
+
const d = closed(value, ["receiptId", "authorityId", "claim", "binding", "decision"]);
|
|
176
|
+
id(d.receiptId);
|
|
177
|
+
id(d.authorityId);
|
|
178
|
+
eventRef(d.claim);
|
|
179
|
+
acceptanceBinding(d.binding, false);
|
|
180
|
+
member(d.decision, ["accept", "reject"]);
|
|
181
|
+
}
|
|
182
|
+
for (const value of a.availability) {
|
|
183
|
+
const row = closed(value, ["kind", "id", "digest", "available"]);
|
|
184
|
+
member(row.kind, ["artifact", "evidence"]);
|
|
185
|
+
id(row.id);
|
|
186
|
+
digest(row.digest);
|
|
187
|
+
require(typeof row.available === "boolean");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function ownDigest(object, building) {
|
|
191
|
+
const { digest: supplied, ...body } = object;
|
|
192
|
+
const computed = workDigest(body);
|
|
193
|
+
if (building)
|
|
194
|
+
object.digest = computed;
|
|
195
|
+
else if (supplied !== computed)
|
|
196
|
+
throw new WorkInputError("WORK_DIGEST_MISMATCH");
|
|
197
|
+
}
|
|
198
|
+
/** All closed shapes/domain checks finish before any own digest is computed or verified. */
|
|
199
|
+
export function validateWorkEvent(value, building = false) {
|
|
200
|
+
const e = workObject(value);
|
|
201
|
+
if (e.ledgerVersion !== 4)
|
|
202
|
+
throw new WorkInputError("WORK_VERSION_UNSUPPORTED");
|
|
203
|
+
closed(e, ownKeys(["ledgerVersion", "event", "eventId", "ts", "payload"], building));
|
|
204
|
+
member(e.event, ["work_revision", "work_snapshot", "work_occurrence", "work_acceptance"]);
|
|
205
|
+
id(e.eventId);
|
|
206
|
+
timestamp(e.ts);
|
|
207
|
+
let nested;
|
|
208
|
+
if (e.event === "work_revision") {
|
|
209
|
+
nested = workObject(closed(e.payload, ["revision"]).revision);
|
|
210
|
+
revision(nested, building);
|
|
211
|
+
}
|
|
212
|
+
else if (e.event === "work_snapshot") {
|
|
213
|
+
nested = workObject(closed(e.payload, ["snapshot"]).snapshot);
|
|
214
|
+
snapshot(nested, building);
|
|
215
|
+
}
|
|
216
|
+
else if (e.event === "work_occurrence")
|
|
217
|
+
occurrence(e.payload);
|
|
218
|
+
else
|
|
219
|
+
acceptance(e.payload, building);
|
|
220
|
+
if (!building)
|
|
221
|
+
digest(e.digest);
|
|
222
|
+
if (nested)
|
|
223
|
+
ownDigest(nested, building);
|
|
224
|
+
ownDigest(e, building);
|
|
225
|
+
return e;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=validation.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './producer-product.js';
|
|
1
2
|
import type { HarnessAdapter } from "@skill-harness/core";
|
|
2
3
|
import { piAdapter } from "./pi.js";
|
|
3
4
|
export declare function getAdapter(name: string): HarnessAdapter;
|
|
@@ -5,3 +6,24 @@ export { piAdapter };
|
|
|
5
6
|
export * from "./prompt-provenance.js";
|
|
6
7
|
export * from "./trajectory.js";
|
|
7
8
|
export * from "./pi-daddy-ledger-v3.js";
|
|
9
|
+
export * from "./evidence-archive.js";
|
|
10
|
+
export * from "./archive-checkpoint.js";
|
|
11
|
+
export * from "./archive-policy.js";
|
|
12
|
+
export * from "./execution-retention-archive.js";
|
|
13
|
+
export * from "./work-candidates.js";
|
|
14
|
+
export * from "./work-case-archive.js";
|
|
15
|
+
export * from "./work-signal-observation.js";
|
|
16
|
+
export * from "./work-signal-cases.js";
|
|
17
|
+
export * from "./work-case-review.js";
|
|
18
|
+
export * from "./archive-read-capability.js";
|
|
19
|
+
export * from "./archived-work.js";
|
|
20
|
+
export * from "./blind-intervention.js";
|
|
21
|
+
export * from "./archive-observer.js";
|
|
22
|
+
export * from "./weekly-investigation.js";
|
|
23
|
+
export * from "./intervention-run.js";
|
|
24
|
+
export * from "./principal-payload-port.js";
|
|
25
|
+
export * from "./reviewed-archive-export.js";
|
|
26
|
+
export * from "./archive-access.js";
|
|
27
|
+
export * from "./archive-facts.js";
|
|
28
|
+
export * from "./trust-lifecycle.js";
|
|
29
|
+
export * from "./producer-review.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './producer-product.js';
|
|
1
2
|
import { piAdapter } from "./pi.js";
|
|
2
3
|
/**
|
|
3
4
|
* Registered harnesses. pi is the only one (per project scope). The interface
|
|
@@ -17,4 +18,25 @@ export { piAdapter };
|
|
|
17
18
|
export * from "./prompt-provenance.js";
|
|
18
19
|
export * from "./trajectory.js";
|
|
19
20
|
export * from "./pi-daddy-ledger-v3.js";
|
|
21
|
+
export * from "./evidence-archive.js";
|
|
22
|
+
export * from "./archive-checkpoint.js";
|
|
23
|
+
export * from "./archive-policy.js";
|
|
24
|
+
export * from "./execution-retention-archive.js";
|
|
25
|
+
export * from "./work-candidates.js";
|
|
26
|
+
export * from "./work-case-archive.js";
|
|
27
|
+
export * from "./work-signal-observation.js";
|
|
28
|
+
export * from "./work-signal-cases.js";
|
|
29
|
+
export * from "./work-case-review.js";
|
|
30
|
+
export * from "./archive-read-capability.js";
|
|
31
|
+
export * from "./archived-work.js";
|
|
32
|
+
export * from "./blind-intervention.js";
|
|
33
|
+
export * from "./archive-observer.js";
|
|
34
|
+
export * from "./weekly-investigation.js";
|
|
35
|
+
export * from "./intervention-run.js";
|
|
36
|
+
export * from "./principal-payload-port.js";
|
|
37
|
+
export * from "./reviewed-archive-export.js";
|
|
38
|
+
export * from "./archive-access.js";
|
|
39
|
+
export * from "./archive-facts.js";
|
|
40
|
+
export * from "./trust-lifecycle.js";
|
|
41
|
+
export * from "./producer-review.js";
|
|
20
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CodexSdkBinding } from './codex-sdk-transport.js';
|
|
2
|
+
export interface InstalledReviewSession {
|
|
3
|
+
version: 'installed-review-session-v1';
|
|
4
|
+
root: string;
|
|
5
|
+
runRoot: string;
|
|
6
|
+
resources: {
|
|
7
|
+
kind: string;
|
|
8
|
+
path: string;
|
|
9
|
+
sha256: string;
|
|
10
|
+
}[];
|
|
11
|
+
subjectId: string;
|
|
12
|
+
judgeId: string;
|
|
13
|
+
}
|
|
14
|
+
export type ReviewRole = 'subject' | 'judge';
|
|
15
|
+
/** Narrow exception for TWO named, isolated installed resources. Never a general .pi pin waiver. */
|
|
16
|
+
export declare function validateInstalledReviewSession(p: InstalledReviewSession): void;
|
|
17
|
+
export declare function installedDelivery(p: InstalledReviewSession, role: ReviewRole): string;
|
|
18
|
+
export declare const installedBase: (p: InstalledReviewSession, role: ReviewRole, base: string) => string;
|
|
19
|
+
export declare const installedInstructions: (p: InstalledReviewSession, role: ReviewRole, base: string) => string;
|
|
20
|
+
/** Compare actual post-extension context; timestamps are not provider input. Nothing is dropped from the wire. */
|
|
21
|
+
export declare function assertInstalledContext(c: any, instructions: string, input: string): string;
|
|
22
|
+
export interface InstalledReviewSessions {
|
|
23
|
+
sessionSha256: string;
|
|
24
|
+
bind(role: ReviewRole, base: string, raw: CodexSdkBinding, record: (v: Record<string, unknown>) => void): CodexSdkBinding;
|
|
25
|
+
}
|
|
26
|
+
/** SDK is the pinned, installed public SDK module. No SDK/auth import occurs during preparation.
|
|
27
|
+
* This is a per-role adapter for the existing producer exchange, not another budget or retry engine. */
|
|
28
|
+
export declare function createInstalledReviewSessions(raw: InstalledReviewSession, sdk: any): InstalledReviewSessions;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { readFileSync, realpathSync, lstatSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute, resolve, join, dirname } from 'node:path';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
5
|
+
import { learningHash, learningCopy } from './learning-journal.js';
|
|
6
|
+
const hash = (s) => createHash('sha256').update(s).digest('hex');
|
|
7
|
+
function closed(v, keys) { if (!v || Array.isArray(v) || Object.keys(v).sort().join() !== keys.sort().join())
|
|
8
|
+
throw Error('closed installed review required'); }
|
|
9
|
+
function canonical(p) { if (typeof p !== 'string' || !isAbsolute(p) || resolve(p) !== p || realpathSync(p) !== p)
|
|
10
|
+
throw Error('installed resource canonical path required'); }
|
|
11
|
+
/** Narrow exception for TWO named, isolated installed resources. Never a general .pi pin waiver. */
|
|
12
|
+
export function validateInstalledReviewSession(p) {
|
|
13
|
+
closed(p, ['version', 'root', 'runRoot', 'resources', 'subjectId', 'judgeId']);
|
|
14
|
+
if (p.version !== 'installed-review-session-v1' || p.root.split('/').includes('.pi') || p.runRoot.split('/').includes('.pi') || p.root !== join(dirname(p.runRoot), 'installed') || !isAbsolute(p.runRoot) || resolve(p.runRoot) !== p.runRoot)
|
|
15
|
+
throw Error('isolated installed roots required');
|
|
16
|
+
canonical(p.root);
|
|
17
|
+
canonical(dirname(p.runRoot));
|
|
18
|
+
if (!/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(p.subjectId) || !/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(p.judgeId) || p.subjectId === p.judgeId)
|
|
19
|
+
throw Error('distinct installed role identities required');
|
|
20
|
+
if (!Array.isArray(p.resources) || p.resources.length !== 4 || p.resources.map(r => r.kind).join() !== 'skill,prompt,extension,extension' || new Set(p.resources.map(r => r.path)).size !== 4)
|
|
21
|
+
throw Error('exact installed resources required');
|
|
22
|
+
const selected = [join(p.root, '.pi/skills/review/SKILL.md'), join(p.root, '.pi/agents/principal-review.md')];
|
|
23
|
+
p.resources.forEach((r, i) => { closed(r, ['kind', 'path', 'sha256']); canonical(r.path); if (i < 2 ? r.path !== selected[i] : r.path.split('/').includes('.pi'))
|
|
24
|
+
throw Error('forbidden installed resource path'); const st = lstatSync(r.path); if (!st.isFile() || st.size > (i < 2 ? 16384 : 8 * 1024 * 1024) || !/^[a-f0-9]{64}$/.test(r.sha256) || hash(readFileSync(r.path)) !== r.sha256)
|
|
25
|
+
throw Error('installed resource pin mismatch'); });
|
|
26
|
+
}
|
|
27
|
+
export function installedDelivery(p, role) {
|
|
28
|
+
return role === 'subject' ? '\n\n<installed-review-instructions>\n' + p.resources.slice(0, 2).map(r => new TextDecoder('utf8', { fatal: true }).decode(readFileSync(r.path))).join('\n\n') + '\n</installed-review-instructions>' : '\n\nAdvisory judgement only; this session cannot authorize adoption or acceptance.';
|
|
29
|
+
}
|
|
30
|
+
export const installedBase = (p, role, base) => base + '\nCurrent working directory: ' + join(p.runRoot, role) + '\n';
|
|
31
|
+
export const installedInstructions = (p, role, base) => installedBase(p, role, base) + installedDelivery(p, role);
|
|
32
|
+
function messageText(m) {
|
|
33
|
+
if (!m || m.role !== 'user' || (m.timestamp !== undefined && (!Number.isSafeInteger(m.timestamp) || m.timestamp < 0)) || Object.keys(m).some(k => !['role', 'content', 'timestamp'].includes(k)))
|
|
34
|
+
throw Error('installed user context required');
|
|
35
|
+
if (typeof m.content === 'string')
|
|
36
|
+
return m.content;
|
|
37
|
+
if (!Array.isArray(m.content) || m.content.length !== 1 || !isDeepStrictEqual(Object.keys(m.content[0]).sort(), ['text', 'type']) || m.content[0].type !== 'text' || typeof m.content[0].text !== 'string')
|
|
38
|
+
throw Error('installed text-only context required');
|
|
39
|
+
return m.content[0].text;
|
|
40
|
+
}
|
|
41
|
+
/** Compare actual post-extension context; timestamps are not provider input. Nothing is dropped from the wire. */
|
|
42
|
+
export function assertInstalledContext(c, instructions, input) {
|
|
43
|
+
if (!c || Object.keys(c).some(k => !['systemPrompt', 'messages', 'tools'].includes(k)) || c.systemPrompt !== instructions || !Array.isArray(c.messages) || c.messages.length !== 1 || messageText(c.messages[0]) !== input || (c.tools !== undefined && (!Array.isArray(c.tools) || c.tools.length)))
|
|
44
|
+
throw Error('installed effective context changed/tools/history');
|
|
45
|
+
if (Buffer.byteLength(instructions) + Buffer.byteLength(input) > 65536)
|
|
46
|
+
throw Error('installed context byte bound');
|
|
47
|
+
return learningHash({ systemPrompt: c.systemPrompt, messages: [{ role: 'user', content: input }], tools: [] });
|
|
48
|
+
}
|
|
49
|
+
/** SDK is the pinned, installed public SDK module. No SDK/auth import occurs during preparation.
|
|
50
|
+
* This is a per-role adapter for the existing producer exchange, not another budget or retry engine. */
|
|
51
|
+
export function createInstalledReviewSessions(raw, sdk) {
|
|
52
|
+
const p = learningCopy(raw);
|
|
53
|
+
validateInstalledReviewSession(p);
|
|
54
|
+
p.resources.forEach(Object.freeze);
|
|
55
|
+
Object.freeze(p.resources);
|
|
56
|
+
Object.freeze(p);
|
|
57
|
+
const used = new Set();
|
|
58
|
+
return { sessionSha256: learningHash(p), bind(role, base, raw, record) {
|
|
59
|
+
if (used.has(role))
|
|
60
|
+
throw Error('installed role reused');
|
|
61
|
+
used.add(role);
|
|
62
|
+
return { model: raw.model, stream: (_model, seed, options) => ({ result: async () => {
|
|
63
|
+
let session, closedSession = false, violation, invocations = 0, before = 0, contexts = 0, payloads = 0, sdkResult;
|
|
64
|
+
const ensure = () => { options.signal.throwIfAborted(); if (closedSession || violation)
|
|
65
|
+
throw violation ?? Error('installed session closed'); };
|
|
66
|
+
const refuse = (message) => { violation = Error(message); throw violation; };
|
|
67
|
+
const input = messageText(seed.messages[0]), instructions = installedInstructions(p, role, base), cwd = join(p.runRoot, role), agentDir = join(cwd, 'agent');
|
|
68
|
+
assertInstalledContext(seed, instructions, input);
|
|
69
|
+
const envKeys = Object.keys(process.env).filter(k => k.startsWith('PI_GRANTS_') || k === 'PI_CODING_AGENT_DIR'), saved = Object.fromEntries(envKeys.map(k => [k, process.env[k]]));
|
|
70
|
+
for (const k of envKeys)
|
|
71
|
+
delete process.env[k];
|
|
72
|
+
process.env.PI_CODING_AGENT_DIR = agentDir;
|
|
73
|
+
process.env.PI_GRANTS_HERDR = '0';
|
|
74
|
+
process.env.PI_GRANTS_GRANT = 'tool:read';
|
|
75
|
+
let abortReject = () => { };
|
|
76
|
+
const aborted = new Promise((_, reject) => { abortReject = reject; });
|
|
77
|
+
const abort = () => { closedSession = true; void session?.abort().catch((e) => { violation = e; }); abortReject(Error('installed session deadline')); };
|
|
78
|
+
options.signal.addEventListener('abort', abort, { once: true });
|
|
79
|
+
try {
|
|
80
|
+
return await Promise.race([aborted, (async () => {
|
|
81
|
+
ensure();
|
|
82
|
+
validateInstalledReviewSession(p);
|
|
83
|
+
if (existsSync(cwd))
|
|
84
|
+
refuse('installed role occurrence already consumed');
|
|
85
|
+
mkdirSync(cwd, { mode: 0o700 });
|
|
86
|
+
mkdirSync(agentDir, { mode: 0o700 });
|
|
87
|
+
const settings = sdk.SettingsManager.inMemory({ packages: [], compaction: { enabled: false }, retry: { enabled: false, maxRetries: 0 }, providerRetry: { maxRetries: 0 }, blockImages: true });
|
|
88
|
+
const loader = new sdk.DefaultResourceLoader({ cwd, agentDir, settingsManager: settings, noExtensions: true, noSkills: true, noPromptTemplates: true, noThemes: true,
|
|
89
|
+
additionalExtensionPaths: p.resources.slice(2).map(r => r.path), additionalSkillPaths: role === 'subject' ? [p.resources[0].path] : [], additionalPromptTemplatePaths: role === 'subject' ? [p.resources[1].path] : [],
|
|
90
|
+
agentsFilesOverride: () => ({ agentsFiles: [] }), systemPromptOverride: () => base, appendSystemPromptOverride: () => '',
|
|
91
|
+
extensionFactories: [{ name: 'installed-review-v1', factory: (pi) => {
|
|
92
|
+
pi.on('before_agent_start', (event) => { ensure(); validateInstalledReviewSession(p); record({ type: 'session-before-agent-observed', role, systemMatches: event.systemPrompt === installedBase(p, role, base), promptMatches: event.prompt === input, systemSha256: hash(event.systemPrompt), expectedSystemSha256: hash(installedBase(p, role, base)) }); if (++before !== 1 || event.systemPrompt !== installedBase(p, role, base) || event.prompt !== input)
|
|
93
|
+
refuse('installed before-agent context changed'); record({ type: 'session-before-agent', role, sessionId: p[role === 'subject' ? 'subjectId' : 'judgeId'], resources: p.resources.slice(0, 2).map(r => r.sha256), delivery: role === 'subject' }); return { systemPrompt: event.systemPrompt + installedDelivery(p, role) }; });
|
|
94
|
+
pi.on('context', (event) => { ensure(); if (++contexts !== 1 || event.messages.length !== 1 || messageText(event.messages[0]) !== input)
|
|
95
|
+
refuse('installed context continuation/changed'); record({ type: 'session-context-hook', role, messages: 1 }); return { messages: event.messages }; });
|
|
96
|
+
pi.on('before_provider_request', () => { ensure(); if (++payloads !== 1)
|
|
97
|
+
refuse('installed provider request repeated'); record({ type: 'session-provider-hook', role }); });
|
|
98
|
+
} }] });
|
|
99
|
+
await loader.reload();
|
|
100
|
+
ensure();
|
|
101
|
+
const loaded = loader.getExtensions();
|
|
102
|
+
if (loaded.errors.length || loaded.extensions.length !== 3 || p.resources.slice(2).some(r => !loaded.extensions.some((e) => (e.resolvedPath ?? e.path) === r.path)))
|
|
103
|
+
refuse('installed extensions not loaded');
|
|
104
|
+
if (role === 'subject' && (loader.getSkills().skills.length !== 1 || loader.getSkills().skills[0].filePath !== p.resources[0].path || loader.getPrompts().prompts.length !== 1 || loader.getPrompts().prompts[0].filePath !== p.resources[1].path))
|
|
105
|
+
refuse('installed selected resources not loaded');
|
|
106
|
+
// All ModelRuntime storage is fresh/private; only an INVALID SDK stand-in is ever supplied.
|
|
107
|
+
const standIn = { type: 'oauth', access: options.apiKey, refresh: 'fixture.invalid', expires: Date.now() + 3600000, accountId: 'fixture-no-account' };
|
|
108
|
+
const credentials = { read: async (id) => id === 'openai-codex' ? standIn : undefined, list: async () => [{ providerId: 'openai-codex', type: 'oauth' }], modify: async () => refuse('installed credential mutation/refresh forbidden'), delete: async () => refuse('installed credential deletion forbidden') };
|
|
109
|
+
const runtime = await sdk.ModelRuntime.create({ credentials, modelsPath: join(agentDir, 'models.json'), modelsStorePath: join(agentDir, 'models-store.json'), allowModelNetwork: false });
|
|
110
|
+
ensure();
|
|
111
|
+
({ session } = await sdk.createAgentSession({ cwd, agentDir, model: raw.model, modelRuntime: runtime, settingsManager: settings, resourceLoader: loader, sessionManager: sdk.SessionManager.inMemory(cwd, { id: p[role === 'subject' ? 'subjectId' : 'judgeId'] }), noTools: 'all', thinkingLevel: 'low' }));
|
|
112
|
+
if (closedSession || options.signal.aborted)
|
|
113
|
+
session.dispose();
|
|
114
|
+
ensure();
|
|
115
|
+
session.extensionRunner.onError((e) => { violation ??= Error('installed extension error: ' + e.event); });
|
|
116
|
+
session.agent.streamFunction = async (model, actual, opts) => {
|
|
117
|
+
ensure();
|
|
118
|
+
if (++invocations !== 1 || before !== 1 || contexts !== 1 || session.sessionId !== p[role === 'subject' ? 'subjectId' : 'judgeId'] || session.sessionFile !== undefined || model.id !== raw.model.id || model.provider !== raw.model.provider || model.api !== raw.model.api || model.baseUrl !== raw.model.baseUrl || session.getActiveToolNames().length)
|
|
119
|
+
refuse('installed SDK invocation/model/tools bound');
|
|
120
|
+
validateInstalledReviewSession(p);
|
|
121
|
+
const contextSha256 = assertInstalledContext(actual, instructions, input);
|
|
122
|
+
record({ type: 'session-sdk-invoked', role, sessionId: session.sessionId, contextSha256, sessionSha256: learningHash(p), tools: [] });
|
|
123
|
+
const result = raw.stream(model, actual, { ...opts, ...options, onPayload: async (payload) => { ensure(); validateInstalledReviewSession(p); const processed = await opts.onPayload(payload, model); ensure(); if (payloads !== 1)
|
|
124
|
+
refuse('installed provider hook missing'); return options.onPayload(processed); }, onResponse: opts.onResponse });
|
|
125
|
+
sdkResult = result.result();
|
|
126
|
+
return result;
|
|
127
|
+
};
|
|
128
|
+
await session.bindExtensions({ mode: 'print', uiContext: { ...session.extensionRunner.createContext().ui, notify: (_message, type) => { if (type === 'error' || type === 'warning')
|
|
129
|
+
violation = Error('installed startup warning/error'); } } });
|
|
130
|
+
ensure();
|
|
131
|
+
if (session.extensionRunner.hasHandlers('before_provider_headers'))
|
|
132
|
+
refuse('undeclared installed header transformation');
|
|
133
|
+
if (session.sessionId !== p[role === 'subject' ? 'subjectId' : 'judgeId'] || session.messages.length || session.getActiveToolNames().length)
|
|
134
|
+
refuse('installed session identity/history/tools');
|
|
135
|
+
record({ type: 'session-bound', role, sessionId: session.sessionId, extensions: p.resources.slice(2), commands: session.extensionRunner.getRegisteredCommands().map((c) => c.name), history: 0, tools: [] });
|
|
136
|
+
await session.prompt(input, { expandPromptTemplates: false });
|
|
137
|
+
ensure();
|
|
138
|
+
if (invocations !== 1 || before !== 1 || contexts !== 1 || payloads !== 1 || session.sessionId !== p[role === 'subject' ? 'subjectId' : 'judgeId'] || session.sessionFile !== undefined || !sdkResult || session.messages.length !== 2 || session.getActiveToolNames().length)
|
|
139
|
+
refuse('installed awaited prompt/continuation mismatch');
|
|
140
|
+
const result = await sdkResult;
|
|
141
|
+
ensure();
|
|
142
|
+
if (!isDeepStrictEqual(session.messages[1], result))
|
|
143
|
+
refuse('installed session final differs from SDK result');
|
|
144
|
+
record({ type: 'session-prompt-completed', role, sessionId: session.sessionId, actualSdkCalls: invocations, beforeAgentHooks: before, contextHooks: contexts, providerHooks: payloads });
|
|
145
|
+
return result;
|
|
146
|
+
})()]);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
record({ type: 'session-refused', role, reason: violation?.message ?? 'installed SDK/session exception', before, contexts, payloads, invocations });
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
closedSession = true;
|
|
154
|
+
options.signal.removeEventListener('abort', abort);
|
|
155
|
+
session?.dispose();
|
|
156
|
+
for (const k of Object.keys(process.env))
|
|
157
|
+
if (k.startsWith('PI_GRANTS_') || k === 'PI_CODING_AGENT_DIR')
|
|
158
|
+
delete process.env[k];
|
|
159
|
+
for (const [k, v] of Object.entries(saved))
|
|
160
|
+
if (v !== undefined)
|
|
161
|
+
process.env[k] = v;
|
|
162
|
+
}
|
|
163
|
+
} }) };
|
|
164
|
+
} };
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=installed-review-session.js.map
|