@tangle-network/agent-profile-materialize 1.1.6 → 1.1.8
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/index.d.ts +1226 -29
- package/dist/index.js +4987 -23
- package/package.json +7 -5
- package/dist/candidate-types.d.ts +0 -36
- package/dist/candidate-types.js +0 -1
- package/dist/candidate.d.ts +0 -9
- package/dist/candidate.js +0 -283
- package/dist/commands.d.ts +0 -2
- package/dist/commands.js +0 -32
- package/dist/control-maps.d.ts +0 -58
- package/dist/control-maps.js +0 -277
- package/dist/execution-controls.d.ts +0 -5
- package/dist/execution-controls.js +0 -199
- package/dist/harness-prompt.d.ts +0 -22
- package/dist/harness-prompt.js +0 -64
- package/dist/harness.d.ts +0 -131
- package/dist/harness.js +0 -416
- package/dist/hooks.d.ts +0 -6
- package/dist/hooks.js +0 -250
- package/dist/managed-workspace-bind.d.ts +0 -4
- package/dist/managed-workspace-bind.js +0 -112
- package/dist/managed-workspace-stage.d.ts +0 -25
- package/dist/managed-workspace-stage.js +0 -199
- package/dist/managed-workspace-types.d.ts +0 -38
- package/dist/managed-workspace-types.js +0 -1
- package/dist/managed-workspace.d.ts +0 -37
- package/dist/managed-workspace.js +0 -290
- package/dist/mcp-config-ownership.d.ts +0 -13
- package/dist/mcp-config-ownership.js +0 -79
- package/dist/mcp-opencode.d.ts +0 -25
- package/dist/mcp-opencode.js +0 -52
- package/dist/mcp-timeouts.d.ts +0 -7
- package/dist/mcp-timeouts.js +0 -48
- package/dist/mcp.d.ts +0 -4
- package/dist/mcp.js +0 -246
- package/dist/model-id.d.ts +0 -55
- package/dist/model-id.js +0 -67
- package/dist/pi-models-config.d.ts +0 -32
- package/dist/pi-models-config.js +0 -65
- package/dist/plan-application.d.ts +0 -10
- package/dist/plan-application.js +0 -190
- package/dist/plan-digest.d.ts +0 -18
- package/dist/plan-digest.js +0 -116
- package/dist/plan-json.d.ts +0 -13
- package/dist/plan-json.js +0 -91
- package/dist/plan-normalize.d.ts +0 -12
- package/dist/plan-normalize.js +0 -168
- package/dist/plan-prompt.d.ts +0 -38
- package/dist/plan-prompt.js +0 -49
- package/dist/plan-support.d.ts +0 -9
- package/dist/plan-support.js +0 -22
- package/dist/plan-types.d.ts +0 -341
- package/dist/plan-types.js +0 -105
- package/dist/prime-agent-dir.d.ts +0 -64
- package/dist/prime-agent-dir.js +0 -173
- package/dist/prime-fork.d.ts +0 -155
- package/dist/prime-fork.js +0 -262
- package/dist/prime-profile.d.ts +0 -88
- package/dist/prime-profile.js +0 -297
- package/dist/profile-bundle-cache.d.ts +0 -37
- package/dist/profile-bundle-cache.js +0 -320
- package/dist/profile-bundle-key.d.ts +0 -69
- package/dist/profile-bundle-key.js +0 -62
- package/dist/profile-bundle-lru.d.ts +0 -56
- package/dist/profile-bundle-lru.js +0 -220
- package/dist/profile-materializer.d.ts +0 -24
- package/dist/profile-materializer.js +0 -114
- package/dist/profile-plan.d.ts +0 -16
- package/dist/profile-plan.js +0 -90
- package/dist/profile-prompt.d.ts +0 -4
- package/dist/profile-prompt.js +0 -107
- package/dist/profile-support.d.ts +0 -8
- package/dist/profile-support.js +0 -6
- package/dist/resource-lowering.d.ts +0 -6
- package/dist/resource-lowering.js +0 -103
- package/dist/resource-resolution.d.ts +0 -27
- package/dist/resource-resolution.js +0 -265
- package/dist/secret-concurrent-revision.d.ts +0 -30
- package/dist/secret-concurrent-revision.js +0 -291
- package/dist/secret-session-view.d.ts +0 -36
- package/dist/secret-session-view.js +0 -179
- package/dist/subagents.d.ts +0 -6
- package/dist/subagents.js +0 -137
- package/dist/tool-bin-path.d.ts +0 -23
- package/dist/tool-bin-path.js +0 -61
- package/dist/workspace-apply-files.d.ts +0 -57
- package/dist/workspace-apply-files.js +0 -193
- package/dist/workspace-apply-publish.d.ts +0 -22
- package/dist/workspace-apply-publish.js +0 -178
- package/dist/workspace-apply.d.ts +0 -11
- package/dist/workspace-apply.js +0 -124
- package/dist/workspace-files.d.ts +0 -8
- package/dist/workspace-files.js +0 -46
- package/dist/workspace-launch.d.ts +0 -3
- package/dist/workspace-launch.js +0 -13
package/dist/plan-digest.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare const sha256: (value: string) => string;
|
|
2
|
-
export declare function hashWorkspacePlan(plan: WorkspacePlan): string;
|
|
3
|
-
/** Build the exact digest-free identity document required by agent-interface. */
|
|
4
|
-
export declare function agentCandidateProfilePlanMaterial(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanMaterial;
|
|
5
|
-
/**
|
|
6
|
-
* Return the RFC 8785 UTF-8 bytes and SHA-256 identity of a candidate profile
|
|
7
|
-
* plan. The returned bytes are the exact bytes embedded in receipt evidence.
|
|
8
|
-
*/
|
|
9
|
-
export declare function canonicalizeAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): {
|
|
10
|
-
material: AgentCandidateProfilePlanMaterial;
|
|
11
|
-
bytes: Uint8Array;
|
|
12
|
-
digest: Sha256Digest;
|
|
13
|
-
};
|
|
14
|
-
/** Capture portable evidence of the exact canonical profile-plan bytes. */
|
|
15
|
-
export declare function captureAgentCandidateProfilePlan(plan: AgentCandidateWorkspacePlan): AgentCandidateProfilePlanEvidence;
|
|
16
|
-
import type { AgentCandidateProfilePlanEvidence, AgentCandidateProfilePlanMaterial, Sha256Digest } from "@tangle-network/agent-interface";
|
|
17
|
-
import type { AgentCandidateWorkspacePlan } from "./candidate-types.js";
|
|
18
|
-
import type { WorkspacePlan } from "./plan-types.js";
|
package/dist/plan-digest.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
export const sha256 = (value) => createHash("sha256").update(value, "utf8").digest("hex");
|
|
2
|
-
export function hashWorkspacePlan(plan) {
|
|
3
|
-
const files = normalizePlanFiles(plan.files).map((file) => ({
|
|
4
|
-
relPath: file.relPath,
|
|
5
|
-
...(file.root === "workspace" ? {} : { root: file.root }),
|
|
6
|
-
mode: file.mode,
|
|
7
|
-
contentSha256: sha256(file.content),
|
|
8
|
-
// Ownership decides whether re-application may replace the file, so two
|
|
9
|
-
// plans identical in bytes but different here behave differently in the
|
|
10
|
-
// same workspace — the digest a receipt proves must say which one ran.
|
|
11
|
-
ownership: file.ownership,
|
|
12
|
-
...(file.secretSlots.length === 0
|
|
13
|
-
? {}
|
|
14
|
-
: {
|
|
15
|
-
secretSlots: [...file.secretSlots].sort((left, right) => compareStrings(JSON.stringify(left.path), JSON.stringify(right.path))),
|
|
16
|
-
}),
|
|
17
|
-
}));
|
|
18
|
-
const env = Object.fromEntries(Object.entries(plan.env)
|
|
19
|
-
.sort(([a], [b]) => compareStrings(a, b))
|
|
20
|
-
.map(([name, value]) => [
|
|
21
|
-
name,
|
|
22
|
-
typeof value === "string"
|
|
23
|
-
? value
|
|
24
|
-
: agentProfileSecretRefSchema.parse(value),
|
|
25
|
-
]));
|
|
26
|
-
const unsupported = [...plan.unsupported].sort((a, b) => compareStrings(`${a.dimension}\0${a.reason}`, `${b.dimension}\0${b.reason}`));
|
|
27
|
-
// A plan that needs an extension is not the same plan as one that does not, even when every
|
|
28
|
-
// byte it writes is identical — the digest is what a receipt proves, so it must say so.
|
|
29
|
-
const requires = [...(plan.requires ?? [])].sort((a, b) => compareStrings(`${a.kind}\0${a.id}`, `${b.kind}\0${b.id}`));
|
|
30
|
-
const canonical = JSON.stringify({
|
|
31
|
-
harness: plan.harness,
|
|
32
|
-
files,
|
|
33
|
-
env,
|
|
34
|
-
flags: plan.flags.map(normalizeWorkspacePlanArgument),
|
|
35
|
-
...promptIntentFields(plan, samePromptIntentValue),
|
|
36
|
-
// A plan that owes a launcher a replacement is not the same plan as one
|
|
37
|
-
// that owes nothing, even when every byte it writes is identical.
|
|
38
|
-
...systemPromptBindingField(plan),
|
|
39
|
-
unsupported,
|
|
40
|
-
...(requires.length === 0 ? {} : { requires }),
|
|
41
|
-
});
|
|
42
|
-
return `sha256:${sha256(canonical)}`;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Candidate material records prompt intents as public values only: a secret
|
|
46
|
-
* reference there would put credential identity into sealed evidence.
|
|
47
|
-
*/
|
|
48
|
-
function publicPromptValue(value) {
|
|
49
|
-
if (value.kind !== "public") {
|
|
50
|
-
throw new Error("Candidate plan material accepts public prompt values only");
|
|
51
|
-
}
|
|
52
|
-
return { kind: "public", value: value.value };
|
|
53
|
-
}
|
|
54
|
-
/** Build the exact digest-free identity document required by agent-interface. */
|
|
55
|
-
export function agentCandidateProfilePlanMaterial(plan) {
|
|
56
|
-
const files = normalizePlanFiles(plan.files);
|
|
57
|
-
const materialFiles = files.map((file) => ({
|
|
58
|
-
relPath: file.relPath,
|
|
59
|
-
mode: file.mode,
|
|
60
|
-
contentSha256: `sha256:${sha256(file.content)}`,
|
|
61
|
-
...(file.root === "agent" ? { root: "agent" } : {}),
|
|
62
|
-
}));
|
|
63
|
-
const material = {
|
|
64
|
-
sourceProfileDigest: plan.sourceProfileDigest,
|
|
65
|
-
harness: plan.harness,
|
|
66
|
-
// Interface 1 has the same candidate material shape without the optional
|
|
67
|
-
// root field. Keep the local file model richer, then validate against the
|
|
68
|
-
// installed peer schema at the compatibility boundary.
|
|
69
|
-
files: materialFiles,
|
|
70
|
-
env: Object.fromEntries(Object.entries(plan.env).sort(([left], [right]) => compareStrings(left, right))),
|
|
71
|
-
flags: [...plan.flags],
|
|
72
|
-
...promptIntentFields(plan, publicPromptValue),
|
|
73
|
-
unsupported: [...plan.unsupported].sort((left, right) => compareStrings(`${left.dimension}\0${left.reason}`, `${right.dimension}\0${right.reason}`)),
|
|
74
|
-
};
|
|
75
|
-
const hasAgentRoot = materialFiles.some((file) => file.root === "agent");
|
|
76
|
-
if (!hasAgentRoot) {
|
|
77
|
-
return agentCandidateProfilePlanMaterialSchema.parse(material);
|
|
78
|
-
}
|
|
79
|
-
const parsed = agentCandidateProfilePlanMaterialSchema.safeParse(material);
|
|
80
|
-
if (!parsed.success) {
|
|
81
|
-
throw new Error("Agent-root candidate evidence requires @tangle-network/agent-interface >=2.1.1; " +
|
|
82
|
-
'the installed peer schema cannot preserve root:"agent". Upgrade the peer before applying this candidate plan.');
|
|
83
|
-
}
|
|
84
|
-
return parsed.data;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Return the RFC 8785 UTF-8 bytes and SHA-256 identity of a candidate profile
|
|
88
|
-
* plan. The returned bytes are the exact bytes embedded in receipt evidence.
|
|
89
|
-
*/
|
|
90
|
-
export function canonicalizeAgentCandidateProfilePlan(plan) {
|
|
91
|
-
const material = agentCandidateProfilePlanMaterial(plan);
|
|
92
|
-
const bytes = canonicalCandidateBytes(material);
|
|
93
|
-
const digest = canonicalCandidateDigest(material);
|
|
94
|
-
return { material, bytes, digest };
|
|
95
|
-
}
|
|
96
|
-
/** Capture portable evidence of the exact canonical profile-plan bytes. */
|
|
97
|
-
export function captureAgentCandidateProfilePlan(plan) {
|
|
98
|
-
const canonical = canonicalizeAgentCandidateProfilePlan(plan);
|
|
99
|
-
const artifact = {
|
|
100
|
-
encoding: "base64",
|
|
101
|
-
content: Buffer.from(canonical.bytes).toString("base64"),
|
|
102
|
-
sha256: canonical.digest,
|
|
103
|
-
byteLength: canonical.bytes.byteLength,
|
|
104
|
-
};
|
|
105
|
-
return agentCandidateProfilePlanEvidenceSchema.parse({
|
|
106
|
-
kind: "agent-profile-workspace-plan",
|
|
107
|
-
digest: canonical.digest,
|
|
108
|
-
material: canonical.material,
|
|
109
|
-
artifact,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
import { createHash } from "node:crypto";
|
|
113
|
-
import { agentCandidateProfilePlanEvidenceSchema, agentCandidateProfilePlanMaterialSchema, agentProfileSecretRefSchema, canonicalCandidateBytes, canonicalCandidateDigest, } from "@tangle-network/agent-interface";
|
|
114
|
-
import { normalizePlanFiles, normalizeWorkspacePlanArgument, } from "./plan-normalize.js";
|
|
115
|
-
import { promptIntentFields, samePromptIntentValue, systemPromptBindingField, } from "./plan-prompt.js";
|
|
116
|
-
import { compareStrings } from "./workspace-files.js";
|
package/dist/plan-json.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare const tomlStr: (s: string) => string;
|
|
2
|
-
export interface SerializedPlanFileContent {
|
|
3
|
-
content: string;
|
|
4
|
-
secretSlots?: PlanFileSecretSlot[];
|
|
5
|
-
}
|
|
6
|
-
export type AddPlanFile = (path: string, content: string | SerializedPlanFileContent, mode?: number) => void;
|
|
7
|
-
export declare function workspacePlanConfigValue(value: AgentProfileConfigValue): WorkspacePlanConfigValue;
|
|
8
|
-
export declare function serializeWorkspacePlanJson(value: unknown): SerializedPlanFileContent;
|
|
9
|
-
export declare function concatWorkspacePlanArguments(...values: WorkspacePlanArgument[]): WorkspacePlanArgument;
|
|
10
|
-
export declare function joinWorkspacePlanArguments(values: WorkspacePlanArgument[], separator: string): WorkspacePlanArgument;
|
|
11
|
-
export declare function tomlProfileConfigValue(value: AgentProfileConfigValue): WorkspacePlanArgument;
|
|
12
|
-
import type { AgentProfileConfigValue } from "@tangle-network/agent-interface";
|
|
13
|
-
import type { PlanFileSecretSlot, WorkspacePlanArgument, WorkspacePlanConfigValue } from "./plan-types.js";
|
package/dist/plan-json.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
export const tomlStr = (s) => JSON.stringify(s); // valid TOML basic string
|
|
2
|
-
function isProfilePublicConfigValue(value) {
|
|
3
|
-
return (typeof value === "object" &&
|
|
4
|
-
value !== null &&
|
|
5
|
-
!Array.isArray(value) &&
|
|
6
|
-
value.kind === "public" &&
|
|
7
|
-
typeof value.value === "string");
|
|
8
|
-
}
|
|
9
|
-
function isProfileSecretRef(value) {
|
|
10
|
-
return (typeof value === "object" &&
|
|
11
|
-
value !== null &&
|
|
12
|
-
!Array.isArray(value) &&
|
|
13
|
-
value.kind === "secret-ref" &&
|
|
14
|
-
typeof value.key === "string");
|
|
15
|
-
}
|
|
16
|
-
export function workspacePlanConfigValue(value) {
|
|
17
|
-
return isProfilePublicConfigValue(value) ? value.value : { ...value };
|
|
18
|
-
}
|
|
19
|
-
export function serializeWorkspacePlanJson(value) {
|
|
20
|
-
const secretSlots = [];
|
|
21
|
-
const lower = (current, path, arrayEntry = false) => {
|
|
22
|
-
if (isProfilePublicConfigValue(current))
|
|
23
|
-
return current.value;
|
|
24
|
-
if (isProfileSecretRef(current)) {
|
|
25
|
-
secretSlots.push({ path: [...path], ref: { ...current } });
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
if (Array.isArray(current)) {
|
|
29
|
-
return current.map((entry, index) => lower(entry, [...path, index], true));
|
|
30
|
-
}
|
|
31
|
-
if (current && typeof current === "object") {
|
|
32
|
-
const output = Object.create(null);
|
|
33
|
-
for (const [key, entry] of Object.entries(current)) {
|
|
34
|
-
const lowered = lower(entry, [...path, key]);
|
|
35
|
-
if (lowered !== undefined) {
|
|
36
|
-
Object.defineProperty(output, key, {
|
|
37
|
-
value: lowered,
|
|
38
|
-
enumerable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
writable: true,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return output;
|
|
45
|
-
}
|
|
46
|
-
return current === undefined && arrayEntry ? null : current;
|
|
47
|
-
};
|
|
48
|
-
const content = JSON.stringify(lower(value, []), null, 2);
|
|
49
|
-
if (content === undefined) {
|
|
50
|
-
throw new Error("Generated profile JSON must have a serializable root");
|
|
51
|
-
}
|
|
52
|
-
return {
|
|
53
|
-
content,
|
|
54
|
-
...(secretSlots.length === 0 ? {} : { secretSlots }),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function workspacePlanArgumentSegments(value) {
|
|
58
|
-
return typeof value === "string" ? [value] : [...value.segments];
|
|
59
|
-
}
|
|
60
|
-
export function concatWorkspacePlanArguments(...values) {
|
|
61
|
-
const segments = values.flatMap(workspacePlanArgumentSegments);
|
|
62
|
-
if (segments.every((segment) => typeof segment === "string")) {
|
|
63
|
-
return segments.join("");
|
|
64
|
-
}
|
|
65
|
-
return { kind: "workspace-plan-argument-template", segments };
|
|
66
|
-
}
|
|
67
|
-
export function joinWorkspacePlanArguments(values, separator) {
|
|
68
|
-
if (values.length === 0)
|
|
69
|
-
return "";
|
|
70
|
-
const joined = [];
|
|
71
|
-
for (const [index, value] of values.entries()) {
|
|
72
|
-
if (index > 0)
|
|
73
|
-
joined.push(separator);
|
|
74
|
-
joined.push(value);
|
|
75
|
-
}
|
|
76
|
-
return concatWorkspacePlanArguments(...joined);
|
|
77
|
-
}
|
|
78
|
-
export function tomlProfileConfigValue(value) {
|
|
79
|
-
if (isProfilePublicConfigValue(value))
|
|
80
|
-
return tomlStr(value.value);
|
|
81
|
-
return {
|
|
82
|
-
kind: "workspace-plan-argument-template",
|
|
83
|
-
segments: [
|
|
84
|
-
{
|
|
85
|
-
kind: "secret",
|
|
86
|
-
ref: { ...value },
|
|
87
|
-
encoding: "json-string",
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
};
|
|
91
|
-
}
|
package/dist/plan-normalize.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare function mergeJsonFiles(files: PlanFile[]): PlanFile[];
|
|
2
|
-
export interface NormalizedPlanFile {
|
|
3
|
-
relPath: string;
|
|
4
|
-
content: string;
|
|
5
|
-
root: PlanFileRoot;
|
|
6
|
-
mode: number;
|
|
7
|
-
ownership: NonNullable<PlanFile["ownership"]>;
|
|
8
|
-
secretSlots: PlanFileSecretSlot[];
|
|
9
|
-
}
|
|
10
|
-
export declare function normalizePlanFiles(files: PlanFile[]): NormalizedPlanFile[];
|
|
11
|
-
export declare function normalizeWorkspacePlanArgument(value: WorkspacePlanArgument): WorkspacePlanArgument;
|
|
12
|
-
import type { PlanFile, PlanFileRoot, PlanFileSecretSlot, WorkspacePlanArgument } from "./plan-types.js";
|
package/dist/plan-normalize.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
export function mergeJsonFiles(files) {
|
|
2
|
-
const byPath = new Map();
|
|
3
|
-
for (const f of files) {
|
|
4
|
-
const root = normalizePlanFileRoot(f.root);
|
|
5
|
-
const identity = `${root}\0${f.relPath}`;
|
|
6
|
-
const prev = byPath.get(identity);
|
|
7
|
-
if (!prev) {
|
|
8
|
-
byPath.set(identity, f);
|
|
9
|
-
continue;
|
|
10
|
-
}
|
|
11
|
-
if (f.relPath.endsWith(".json")) {
|
|
12
|
-
try {
|
|
13
|
-
const next = JSON.parse(f.content);
|
|
14
|
-
const merged = {
|
|
15
|
-
...JSON.parse(prev.content),
|
|
16
|
-
...next,
|
|
17
|
-
};
|
|
18
|
-
const replacedRoots = new Set(Object.keys(next));
|
|
19
|
-
const secretSlots = [
|
|
20
|
-
...(prev.secretSlots ?? []).filter((slot) => typeof slot.path[0] === "string" &&
|
|
21
|
-
!replacedRoots.has(slot.path[0])),
|
|
22
|
-
...(f.secretSlots ?? []),
|
|
23
|
-
];
|
|
24
|
-
const { secretSlots: _previousSecretSlots, ...previousFile } = prev;
|
|
25
|
-
byPath.set(identity, {
|
|
26
|
-
...previousFile,
|
|
27
|
-
content: JSON.stringify(merged, null, 2),
|
|
28
|
-
...(secretSlots.length > 0 ? { mode: PRIVATE_FILE_MODE } : {}),
|
|
29
|
-
...(secretSlots.length === 0 ? {} : { secretSlots }),
|
|
30
|
-
});
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
/* fall through to last-wins */
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
byPath.set(identity, f); // non-JSON or parse-fail: last wins
|
|
38
|
-
}
|
|
39
|
-
return [...byPath.values()];
|
|
40
|
-
}
|
|
41
|
-
function normalizePlanFileRoot(root) {
|
|
42
|
-
if (root === undefined || root === "workspace")
|
|
43
|
-
return "workspace";
|
|
44
|
-
if (root === "agent")
|
|
45
|
-
return root;
|
|
46
|
-
throw new Error(`Unsupported workspace plan file root: ${String(root)}`);
|
|
47
|
-
}
|
|
48
|
-
function valueAtJsonPath(root, path) {
|
|
49
|
-
let current = root;
|
|
50
|
-
for (const segment of path) {
|
|
51
|
-
if (current === null ||
|
|
52
|
-
typeof current !== "object" ||
|
|
53
|
-
!Object.hasOwn(current, segment)) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
current = current[segment];
|
|
57
|
-
}
|
|
58
|
-
return current;
|
|
59
|
-
}
|
|
60
|
-
function normalizePlanFileSecretSlots(file) {
|
|
61
|
-
if (file.secretSlots === undefined)
|
|
62
|
-
return [];
|
|
63
|
-
if (file.source !== "generated" ||
|
|
64
|
-
!file.relPath.endsWith(".json") ||
|
|
65
|
-
file.secretSlots.length === 0) {
|
|
66
|
-
throw new Error(`Workspace secret slots require a generated JSON file: ${file.relPath}`);
|
|
67
|
-
}
|
|
68
|
-
let parsed;
|
|
69
|
-
try {
|
|
70
|
-
parsed = JSON.parse(file.content);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
throw new Error(`Workspace secret slots require valid JSON content: ${file.relPath}`);
|
|
74
|
-
}
|
|
75
|
-
const seen = new Set();
|
|
76
|
-
return file.secretSlots.map((slot) => {
|
|
77
|
-
if (!Array.isArray(slot.path) || slot.path.length === 0) {
|
|
78
|
-
throw new Error(`Workspace secret slot path must be non-empty: ${file.relPath}`);
|
|
79
|
-
}
|
|
80
|
-
const path = slot.path.map((segment) => {
|
|
81
|
-
if ((typeof segment !== "string" && typeof segment !== "number") ||
|
|
82
|
-
(typeof segment === "number" &&
|
|
83
|
-
(!Number.isSafeInteger(segment) || segment < 0))) {
|
|
84
|
-
throw new Error(`Workspace secret slot path is invalid: ${file.relPath}`);
|
|
85
|
-
}
|
|
86
|
-
return segment;
|
|
87
|
-
});
|
|
88
|
-
const identity = JSON.stringify(path);
|
|
89
|
-
if (seen.has(identity)) {
|
|
90
|
-
throw new Error(`Duplicate workspace secret slot path: ${file.relPath} ${identity}`);
|
|
91
|
-
}
|
|
92
|
-
seen.add(identity);
|
|
93
|
-
if (valueAtJsonPath(parsed, path) !== null) {
|
|
94
|
-
throw new Error(`Workspace secret slot must point at a null placeholder: ${file.relPath} ${identity}`);
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
path,
|
|
98
|
-
ref: agentProfileSecretRefSchema.parse(slot.ref),
|
|
99
|
-
};
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
export function normalizePlanFiles(files) {
|
|
103
|
-
const seen = new Set();
|
|
104
|
-
return files
|
|
105
|
-
.map((file) => {
|
|
106
|
-
const root = normalizePlanFileRoot(file.root);
|
|
107
|
-
const relPath = normalizeWorkspaceRelativePath(file.relPath);
|
|
108
|
-
const identity = `${root}\0${relPath}`;
|
|
109
|
-
if (seen.has(identity)) {
|
|
110
|
-
throw new Error(`Duplicate ${root} plan file: ${relPath}`);
|
|
111
|
-
}
|
|
112
|
-
seen.add(identity);
|
|
113
|
-
if (typeof file.content !== "string") {
|
|
114
|
-
throw new Error(`Workspace file content must be a string: ${relPath}`);
|
|
115
|
-
}
|
|
116
|
-
const mode = validateFileMode(file.mode);
|
|
117
|
-
const secretSlots = normalizePlanFileSecretSlots(file);
|
|
118
|
-
if (secretSlots.length > 0 && (mode & 0o077) !== 0) {
|
|
119
|
-
throw new Error(`Workspace secret-bearing file must not grant group or other access: ${relPath}`);
|
|
120
|
-
}
|
|
121
|
-
return {
|
|
122
|
-
relPath,
|
|
123
|
-
content: file.content,
|
|
124
|
-
root,
|
|
125
|
-
mode,
|
|
126
|
-
ownership: file.ownership ?? "shared",
|
|
127
|
-
secretSlots,
|
|
128
|
-
};
|
|
129
|
-
})
|
|
130
|
-
.sort((a, b) => compareStrings(`${a.root}\0${a.relPath}`, `${b.root}\0${b.relPath}`));
|
|
131
|
-
}
|
|
132
|
-
export function normalizeWorkspacePlanArgument(value) {
|
|
133
|
-
if (typeof value === "string")
|
|
134
|
-
return value;
|
|
135
|
-
if (value.kind !== "workspace-plan-argument-template" ||
|
|
136
|
-
!Array.isArray(value.segments) ||
|
|
137
|
-
value.segments.length === 0) {
|
|
138
|
-
throw new Error("Workspace plan argument template is malformed");
|
|
139
|
-
}
|
|
140
|
-
const segments = [];
|
|
141
|
-
for (const segment of value.segments) {
|
|
142
|
-
if (typeof segment === "string") {
|
|
143
|
-
const previous = segments.at(-1);
|
|
144
|
-
if (typeof previous === "string") {
|
|
145
|
-
segments[segments.length - 1] = previous + segment;
|
|
146
|
-
}
|
|
147
|
-
else if (segment.length > 0) {
|
|
148
|
-
segments.push(segment);
|
|
149
|
-
}
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
if (segment.kind !== "secret" ||
|
|
153
|
-
(segment.encoding !== "raw" && segment.encoding !== "json-string")) {
|
|
154
|
-
throw new Error("Workspace plan secret argument segment is malformed");
|
|
155
|
-
}
|
|
156
|
-
segments.push({
|
|
157
|
-
kind: "secret",
|
|
158
|
-
ref: agentProfileSecretRefSchema.parse(segment.ref),
|
|
159
|
-
encoding: segment.encoding,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
if (segments.every((segment) => typeof segment === "string")) {
|
|
163
|
-
return segments.join("");
|
|
164
|
-
}
|
|
165
|
-
return { kind: "workspace-plan-argument-template", segments };
|
|
166
|
-
}
|
|
167
|
-
import { agentProfileSecretRefSchema } from "@tangle-network/agent-interface";
|
|
168
|
-
import { compareStrings, normalizeWorkspaceRelativePath, PRIVATE_FILE_MODE, validateFileMode, } from "./workspace-files.js";
|
package/dist/plan-prompt.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export declare function promptIntentFields<In, Out>(source: {
|
|
2
|
-
systemPrompt?: In;
|
|
3
|
-
appendSystemPrompt?: In;
|
|
4
|
-
}, project: (value: In) => Out): {
|
|
5
|
-
systemPrompt?: Out;
|
|
6
|
-
appendSystemPrompt?: Out;
|
|
7
|
-
};
|
|
8
|
-
/** Identity projection for boundaries that pass the prompt intents through. */
|
|
9
|
-
export declare const samePromptIntentValue: <T>(value: T) => T;
|
|
10
|
-
/**
|
|
11
|
-
* The launcher-bound intent, projected onto an outgoing object and omitted when
|
|
12
|
-
* the source does not carry one.
|
|
13
|
-
*
|
|
14
|
-
* Beside {@link promptIntentFields} rather than inside it, because the two
|
|
15
|
-
* disagree on both ends: the candidate boundaries that helper also serves have
|
|
16
|
-
* no field for a binding — an {@link AgentCandidateWorkspacePlan} is built by a
|
|
17
|
-
* caller that declares none, so it can never hold one — and a value projection
|
|
18
|
-
* such as `candidatePublicString` has nothing to do to a structured binding.
|
|
19
|
-
* Every boundary that carries the plan's own prompt intents calls both.
|
|
20
|
-
*/
|
|
21
|
-
export declare function systemPromptBindingField(source: {
|
|
22
|
-
systemPromptBinding?: WorkspacePlanSystemPromptBinding;
|
|
23
|
-
}): {
|
|
24
|
-
systemPromptBinding?: WorkspacePlanSystemPromptBinding;
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* The replacement text this launcher must bind to `control`, or `undefined`
|
|
28
|
-
* when the plan carries no launcher-bound intent.
|
|
29
|
-
*
|
|
30
|
-
* Throws for a binding addressed to a DIFFERENT control: the reader cannot
|
|
31
|
-
* execute it, and answering `undefined` would start the agent with the
|
|
32
|
-
* harness's own prompt still in force while nothing reported a problem — the
|
|
33
|
-
* silent downgrade the binding exists to prevent. This is the seam where an
|
|
34
|
-
* executor that cannot bind an intent says so, by name, instead of running a
|
|
35
|
-
* profile whose prompt never took effect.
|
|
36
|
-
*/
|
|
37
|
-
export declare function takeSystemPromptBinding(spawn: Pick<WorkspacePlanSpawnInputs, "systemPromptBinding">, control: ExecutorSystemPromptBinding): string | undefined;
|
|
38
|
-
import type { ExecutorSystemPromptBinding, WorkspacePlanSpawnInputs, WorkspacePlanSystemPromptBinding } from "./plan-types.js";
|
package/dist/plan-prompt.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
export function promptIntentFields(source, project) {
|
|
2
|
-
return {
|
|
3
|
-
...(source.systemPrompt === undefined
|
|
4
|
-
? {}
|
|
5
|
-
: { systemPrompt: project(source.systemPrompt) }),
|
|
6
|
-
...(source.appendSystemPrompt === undefined
|
|
7
|
-
? {}
|
|
8
|
-
: { appendSystemPrompt: project(source.appendSystemPrompt) }),
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/** Identity projection for boundaries that pass the prompt intents through. */
|
|
12
|
-
export const samePromptIntentValue = (value) => value;
|
|
13
|
-
/**
|
|
14
|
-
* The launcher-bound intent, projected onto an outgoing object and omitted when
|
|
15
|
-
* the source does not carry one.
|
|
16
|
-
*
|
|
17
|
-
* Beside {@link promptIntentFields} rather than inside it, because the two
|
|
18
|
-
* disagree on both ends: the candidate boundaries that helper also serves have
|
|
19
|
-
* no field for a binding — an {@link AgentCandidateWorkspacePlan} is built by a
|
|
20
|
-
* caller that declares none, so it can never hold one — and a value projection
|
|
21
|
-
* such as `candidatePublicString` has nothing to do to a structured binding.
|
|
22
|
-
* Every boundary that carries the plan's own prompt intents calls both.
|
|
23
|
-
*/
|
|
24
|
-
export function systemPromptBindingField(source) {
|
|
25
|
-
return source.systemPromptBinding === undefined
|
|
26
|
-
? {}
|
|
27
|
-
: { systemPromptBinding: { ...source.systemPromptBinding } };
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* The replacement text this launcher must bind to `control`, or `undefined`
|
|
31
|
-
* when the plan carries no launcher-bound intent.
|
|
32
|
-
*
|
|
33
|
-
* Throws for a binding addressed to a DIFFERENT control: the reader cannot
|
|
34
|
-
* execute it, and answering `undefined` would start the agent with the
|
|
35
|
-
* harness's own prompt still in force while nothing reported a problem — the
|
|
36
|
-
* silent downgrade the binding exists to prevent. This is the seam where an
|
|
37
|
-
* executor that cannot bind an intent says so, by name, instead of running a
|
|
38
|
-
* profile whose prompt never took effect.
|
|
39
|
-
*/
|
|
40
|
-
export function takeSystemPromptBinding(spawn, control) {
|
|
41
|
-
const binding = spawn.systemPromptBinding;
|
|
42
|
-
if (!binding)
|
|
43
|
-
return undefined;
|
|
44
|
-
if (binding.control !== control) {
|
|
45
|
-
throw new Error(`Workspace plan carries a system-prompt ${binding.intent} bound to ` +
|
|
46
|
-
`${binding.control}, which this executor cannot apply; it binds ${control}`);
|
|
47
|
-
}
|
|
48
|
-
return binding.systemPrompt;
|
|
49
|
-
}
|
package/dist/plan-support.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Unsupported, WorkspacePlan } from "./plan-types.js";
|
|
2
|
-
export declare function formatUnsupported(unsupported: Unsupported[]): string;
|
|
3
|
-
/** Fail when a profile asks for controls the chosen harness cannot execute. */
|
|
4
|
-
export declare function assertWorkspacePlanSupported(plan: Pick<WorkspacePlan, "unsupported">): void;
|
|
5
|
-
/**
|
|
6
|
-
* Enforce supportability under the profile's failOnError policy.
|
|
7
|
-
* Strict mode throws; best-effort mode returns visible warnings.
|
|
8
|
-
*/
|
|
9
|
-
export declare function enforceWorkspacePlanSupport(plan: Pick<WorkspacePlan, "unsupported">, failOnError: boolean | undefined): string[];
|
package/dist/plan-support.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export function formatUnsupported(unsupported) {
|
|
2
|
-
return `Unable to materialize ${unsupported.length} profile resource(s):\n${unsupported
|
|
3
|
-
.map(({ dimension, reason }) => `- ${dimension}: ${reason}`)
|
|
4
|
-
.join("\n")}`;
|
|
5
|
-
}
|
|
6
|
-
/** Fail when a profile asks for controls the chosen harness cannot execute. */
|
|
7
|
-
export function assertWorkspacePlanSupported(plan) {
|
|
8
|
-
if (plan.unsupported.length > 0) {
|
|
9
|
-
throw new Error(formatUnsupported(plan.unsupported));
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Enforce supportability under the profile's failOnError policy.
|
|
14
|
-
* Strict mode throws; best-effort mode returns visible warnings.
|
|
15
|
-
*/
|
|
16
|
-
export function enforceWorkspacePlanSupport(plan, failOnError) {
|
|
17
|
-
if (failOnError !== false) {
|
|
18
|
-
assertWorkspacePlanSupported(plan);
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
return plan.unsupported.map(({ dimension, reason }) => `${dimension}: ${reason}`);
|
|
22
|
-
}
|