@tangle-network/agent-profile-materialize 0.28.3 → 0.28.5
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.
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
|
+
import { CODEX_SYSTEM_PROMPT_FILE } from "./harness.js";
|
|
3
|
+
import { bindWorkspaceLaunchFlags } from "./workspace-launch.js";
|
|
2
4
|
/**
|
|
3
5
|
* Paths a secret OpenCode revision serves from its own immutable tree:
|
|
4
6
|
* read-only profile content under `reference/`, skills, and OpenCode's
|
|
@@ -6,21 +8,6 @@ import { dirname, join } from "node:path";
|
|
|
6
8
|
* `.opencode/{agent,agents}/**\/*.md` and `.opencode/{command,commands}/**\/*.md`).
|
|
7
9
|
*/
|
|
8
10
|
const SECRET_REVISION_NATIVE_PATH = /^(?:reference\/|\.opencode\/skills\/|\.opencode\/(?:agents?|commands?)\/(?:[^./][^/]*\/)*[^./][^/]*\.md$)/u;
|
|
9
|
-
/**
|
|
10
|
-
* A secret OpenCode turn launches with its revision's `workspace` as cwd and
|
|
11
|
-
* that tree's `.opencode` as its explicit config directory (the sealed launch
|
|
12
|
-
* in sdk-provider-opencode). So skills, agents and commands load from the
|
|
13
|
-
* digest-attested revision, and a cwd-relative `reference/` path resolves to
|
|
14
|
-
* this revision's own read-only copy, never to the shared workspace that
|
|
15
|
-
* concurrent revisions share. The binding stays limited to these paths, never
|
|
16
|
-
* an app's own directory.
|
|
17
|
-
*/
|
|
18
|
-
function ridesSecretRevision(plan, file, options) {
|
|
19
|
-
return (options.secretOpenCodeRevision === true &&
|
|
20
|
-
plan.harness === "opencode" &&
|
|
21
|
-
(file.root ?? "workspace") === "workspace" &&
|
|
22
|
-
SECRET_REVISION_NATIVE_PATH.test(file.relPath));
|
|
23
|
-
}
|
|
24
11
|
export function bindConcurrentLaunch(plan, application, revisionWorkspaceDir, options = {}) {
|
|
25
12
|
if (plan.requires?.length) {
|
|
26
13
|
throw new Error(`Concurrent ${plan.harness} profile needs a native extension that this launcher cannot attest`);
|
|
@@ -28,7 +15,7 @@ export function bindConcurrentLaunch(plan, application, revisionWorkspaceDir, op
|
|
|
28
15
|
if (application.spawn.systemPromptBinding) {
|
|
29
16
|
throw new Error(`Concurrent ${plan.harness} profile has an unbound system prompt control`);
|
|
30
17
|
}
|
|
31
|
-
const flags =
|
|
18
|
+
const flags = bindWorkspaceLaunchFlags(plan, application.spawn.flags, revisionWorkspaceDir);
|
|
32
19
|
const env = { ...application.spawn.env };
|
|
33
20
|
const supportedFiles = new Set();
|
|
34
21
|
const bindFlagFile = (flag, relPath) => {
|
|
@@ -50,14 +37,11 @@ export function bindConcurrentLaunch(plan, application, revisionWorkspaceDir, op
|
|
|
50
37
|
}
|
|
51
38
|
break;
|
|
52
39
|
case "codex":
|
|
53
|
-
if (plan.files.some((file) => file.relPath ===
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (index < 0)
|
|
40
|
+
if (plan.files.some((file) => file.relPath === CODEX_SYSTEM_PROMPT_FILE)) {
|
|
41
|
+
if (!plan.flags.some((value, at) => value === `model_instructions_file=${CODEX_SYSTEM_PROMPT_FILE}` &&
|
|
42
|
+
plan.flags[at - 1] === "-c"))
|
|
57
43
|
throw new Error("Concurrent codex profile lacks model_instructions_file binding");
|
|
58
|
-
|
|
59
|
-
`model_instructions_file=${join(revisionWorkspaceDir, ".codex/system-prompt.md")}`;
|
|
60
|
-
supportedFiles.add(".codex/system-prompt.md");
|
|
44
|
+
supportedFiles.add(CODEX_SYSTEM_PROMPT_FILE);
|
|
61
45
|
}
|
|
62
46
|
break;
|
|
63
47
|
// kimi-code has no case: kimi-code 2.x discovers MCP only from
|
|
@@ -91,7 +75,13 @@ export function bindConcurrentLaunch(plan, application, revisionWorkspaceDir, op
|
|
|
91
75
|
// its directory, absolute in that revision, joins the launch PATH.
|
|
92
76
|
const toolBinDirs = [];
|
|
93
77
|
for (const file of plan.files) {
|
|
94
|
-
|
|
78
|
+
// Secret OpenCode launches from its immutable revision workspace, with
|
|
79
|
+
// that revision's .opencode as config directory. These relative native
|
|
80
|
+
// resources therefore read the revision, never the shared workspace.
|
|
81
|
+
if (options.secretOpenCodeRevision === true &&
|
|
82
|
+
plan.harness === "opencode" &&
|
|
83
|
+
(file.root ?? "workspace") === "workspace" &&
|
|
84
|
+
SECRET_REVISION_NATIVE_PATH.test(file.relPath)) {
|
|
95
85
|
if (file.relPath.startsWith("reference/") &&
|
|
96
86
|
((file.mode ?? 0) & 0o111) !== 0) {
|
|
97
87
|
const dir = join(revisionWorkspaceDir, dirname(file.relPath));
|
|
@@ -4,6 +4,7 @@ import { basename, dirname, extname, join, resolve, sep } from "node:path";
|
|
|
4
4
|
import { applyWorkspacePlanWithSecretProvider } from "./plan-application.js";
|
|
5
5
|
import { hashWorkspacePlan } from "./plan-digest.js";
|
|
6
6
|
import { normalizeWorkspaceRelativePath } from "./workspace-files.js";
|
|
7
|
+
import { bindWorkspaceLaunchFlags } from "./workspace-launch.js";
|
|
7
8
|
export function assertPrivateManagedRoot(root) {
|
|
8
9
|
if (!root || resolve(root) !== root) {
|
|
9
10
|
throw new Error("Managed workspace root must be an absolute path");
|
|
@@ -88,7 +89,10 @@ export async function prepareManagedWorkspacePlan(plan, managedRoot, sharedWorks
|
|
|
88
89
|
sha256: createHash("sha256").update(content).digest("hex"),
|
|
89
90
|
}));
|
|
90
91
|
const spawnDigest = createHash("sha256")
|
|
91
|
-
.update(JSON.stringify(
|
|
92
|
+
.update(JSON.stringify({
|
|
93
|
+
...application.spawn,
|
|
94
|
+
flags: bindWorkspaceLaunchFlags(plan, application.spawn.flags),
|
|
95
|
+
}))
|
|
92
96
|
.digest("hex");
|
|
93
97
|
const materializedDigest = `sha256:${createHash("sha256")
|
|
94
98
|
.update(JSON.stringify({
|
|
@@ -94,7 +94,14 @@ export async function preparePublicConcurrentProfileRevision(input) {
|
|
|
94
94
|
return {
|
|
95
95
|
directory,
|
|
96
96
|
manifest: prepared.manifest,
|
|
97
|
-
application: {
|
|
97
|
+
application: {
|
|
98
|
+
...prepared.application,
|
|
99
|
+
receipt: {
|
|
100
|
+
...prepared.application.receipt,
|
|
101
|
+
flags: [...spawn.flags],
|
|
102
|
+
},
|
|
103
|
+
spawn,
|
|
104
|
+
},
|
|
98
105
|
};
|
|
99
106
|
}
|
|
100
107
|
catch (error) {
|
package/dist/workspace-apply.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
const receiptFile = (file) => ({
|
|
2
|
-
root: file.root,
|
|
3
|
-
relPath: file.relPath,
|
|
4
|
-
});
|
|
5
1
|
function readApplyInput(publicPlan, workspaceDir, options) {
|
|
6
2
|
const workspaceRoot = resolve(workspaceDir);
|
|
7
3
|
if (options.agentDir !== undefined && !isAbsolute(options.agentDir)) {
|
|
@@ -47,27 +43,42 @@ function selectResumeFiles(files, ownership, privateFilePaths) {
|
|
|
47
43
|
return matches && !hasCurrentOwnership;
|
|
48
44
|
});
|
|
49
45
|
}
|
|
50
|
-
function spawnFor(resolvedPlan) {
|
|
51
|
-
return {
|
|
52
|
-
env: { ...resolvedPlan.env },
|
|
53
|
-
flags: [...resolvedPlan.flags],
|
|
54
|
-
...promptIntentFields(resolvedPlan, samePromptIntentValue),
|
|
55
|
-
...systemPromptBindingField(resolvedPlan),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
46
|
export function applyResolvedWorkspacePlan(publicPlan, resolvedPlan, workspaceDir, options, publicPlanDigest = hashWorkspacePlan(publicPlan)) {
|
|
59
47
|
const { rootFor, runtimeOnlyFiles, ownership, privateFilePaths, existingFiles, } = readApplyInput(publicPlan, workspaceDir, options);
|
|
60
|
-
const
|
|
61
|
-
const privateRuntimeFiles = Object.fromEntries(resolvedFiles
|
|
48
|
+
const privateRuntimeFiles = Object.fromEntries(resolvedPlan.files
|
|
62
49
|
.filter((file) => file.root === "workspace" && runtimeOnlyFiles.has(file.relPath))
|
|
63
50
|
.map((file) => [file.relPath, file.content]));
|
|
64
|
-
const files =
|
|
51
|
+
const files = resolvedPlan.files
|
|
65
52
|
.filter((file) => file.root !== "workspace" || !runtimeOnlyFiles.has(file.relPath))
|
|
66
53
|
.map((file) => ({
|
|
67
54
|
...file,
|
|
68
55
|
rootDir: rootFor(file.root),
|
|
69
56
|
absPath: resolveWorkspaceFilePath(rootFor(file.root), file.relPath),
|
|
70
57
|
}));
|
|
58
|
+
const application = {
|
|
59
|
+
receipt: {
|
|
60
|
+
workspacePlanDigest: publicPlanDigest,
|
|
61
|
+
env: Object.fromEntries(Object.entries(publicPlan.env).map(([name, value]) => [
|
|
62
|
+
name,
|
|
63
|
+
typeof value === "string" ? value : { ...value },
|
|
64
|
+
])),
|
|
65
|
+
flags: bindWorkspaceLaunchFlags(publicPlan, publicPlan.flags, workspaceDir).map(normalizeWorkspacePlanArgument),
|
|
66
|
+
...promptIntentFields(publicPlan, samePromptIntentValue),
|
|
67
|
+
...systemPromptBindingField(publicPlan),
|
|
68
|
+
unsupported: publicPlan.unsupported.map((entry) => ({ ...entry })),
|
|
69
|
+
written: files
|
|
70
|
+
.filter((file) => file.root === "workspace")
|
|
71
|
+
.map((file) => file.relPath),
|
|
72
|
+
writtenFiles: files.map(({ root, relPath }) => ({ root, relPath })),
|
|
73
|
+
},
|
|
74
|
+
spawn: {
|
|
75
|
+
env: { ...resolvedPlan.env },
|
|
76
|
+
flags: bindWorkspaceLaunchFlags(publicPlan, resolvedPlan.flags, workspaceDir),
|
|
77
|
+
...promptIntentFields(resolvedPlan, samePromptIntentValue),
|
|
78
|
+
...systemPromptBindingField(resolvedPlan),
|
|
79
|
+
},
|
|
80
|
+
runtimeOnlyFiles: privateRuntimeFiles,
|
|
81
|
+
};
|
|
71
82
|
// `reject` does not resume because it requires an empty target.
|
|
72
83
|
const resumeSamePlan = existingFiles === "allow-identical" &&
|
|
73
84
|
options.appliedPlanDigest !== undefined &&
|
|
@@ -76,11 +87,7 @@ export function applyResolvedWorkspacePlan(publicPlan, resolvedPlan, workspaceDi
|
|
|
76
87
|
? selectResumeFiles(files, ownership, privateFilePaths)
|
|
77
88
|
: files;
|
|
78
89
|
if (resumeSamePlan && filesToApply.length === 0) {
|
|
79
|
-
return
|
|
80
|
-
receipt: safeWorkspacePlanReceipt(publicPlan, files.map(receiptFile), publicPlanDigest),
|
|
81
|
-
spawn: spawnFor(resolvedPlan),
|
|
82
|
-
runtimeOnlyFiles: privateRuntimeFiles,
|
|
83
|
-
};
|
|
90
|
+
return application;
|
|
84
91
|
}
|
|
85
92
|
const context = {
|
|
86
93
|
rootFor,
|
|
@@ -94,8 +101,6 @@ export function applyResolvedWorkspacePlan(publicPlan, resolvedPlan, workspaceDi
|
|
|
94
101
|
// workspace state that this call does not own.
|
|
95
102
|
for (const file of writes) {
|
|
96
103
|
mkdirSync(dirname(file.absPath), { recursive: true });
|
|
97
|
-
}
|
|
98
|
-
for (const file of writes) {
|
|
99
104
|
assertNoSymlinkPathComponents(file.rootDir, file.absPath);
|
|
100
105
|
}
|
|
101
106
|
const prepared = [];
|
|
@@ -105,30 +110,8 @@ export function applyResolvedWorkspacePlan(publicPlan, resolvedPlan, workspaceDi
|
|
|
105
110
|
catch (error) {
|
|
106
111
|
rollbackPublished(prepared, error);
|
|
107
112
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
receipt,
|
|
112
|
-
spawn: spawnFor(resolvedPlan),
|
|
113
|
-
runtimeOnlyFiles: privateRuntimeFiles,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function safeWorkspacePlanReceipt(plan, writtenFiles, workspacePlanDigest = hashWorkspacePlan(plan)) {
|
|
117
|
-
return {
|
|
118
|
-
workspacePlanDigest,
|
|
119
|
-
env: Object.fromEntries(Object.entries(plan.env).map(([name, value]) => [
|
|
120
|
-
name,
|
|
121
|
-
typeof value === "string" ? value : { ...value },
|
|
122
|
-
])),
|
|
123
|
-
flags: plan.flags.map(normalizeWorkspacePlanArgument),
|
|
124
|
-
...promptIntentFields(plan, samePromptIntentValue),
|
|
125
|
-
...systemPromptBindingField(plan),
|
|
126
|
-
unsupported: plan.unsupported.map((entry) => ({ ...entry })),
|
|
127
|
-
written: writtenFiles
|
|
128
|
-
.filter((file) => file.root === "workspace")
|
|
129
|
-
.map((file) => file.relPath),
|
|
130
|
-
writtenFiles: writtenFiles.map((file) => ({ ...file })),
|
|
131
|
-
};
|
|
113
|
+
removeTemporaries(prepared, application.receipt);
|
|
114
|
+
return application;
|
|
132
115
|
}
|
|
133
116
|
import { mkdirSync } from "node:fs";
|
|
134
117
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
@@ -138,3 +121,4 @@ import { promptIntentFields, samePromptIntentValue, systemPromptBindingField, }
|
|
|
138
121
|
import { assertNoSymlinkPathComponents, resolveWorkspaceFilePath, validateWorkspaceOwnership, workspaceFileExists, workspaceFileMatches, } from "./workspace-apply-files.js";
|
|
139
122
|
import { fileIdentity, holdsCurrentOwnership, planWrites, publishWrites, removeTemporaries, rollbackPublished, } from "./workspace-apply-publish.js";
|
|
140
123
|
import { normalizeWorkspaceRelativePath } from "./workspace-files.js";
|
|
124
|
+
import { bindWorkspaceLaunchFlags } from "./workspace-launch.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { CODEX_SYSTEM_PROMPT_FILE } from "./harness.js";
|
|
3
|
+
import { tomlStr } from "./plan-json.js";
|
|
4
|
+
/** Bind launch paths; omit the workspace to hash portable content identity. */
|
|
5
|
+
export function bindWorkspaceLaunchFlags(plan, flags, workspaceDir) {
|
|
6
|
+
return flags.map((flag, at) => plan.harness === "codex" &&
|
|
7
|
+
plan.flags[at - 1] === "-c" &&
|
|
8
|
+
plan.flags[at] === `model_instructions_file=${CODEX_SYSTEM_PROMPT_FILE}`
|
|
9
|
+
? workspaceDir === undefined
|
|
10
|
+
? `model_instructions_file=${CODEX_SYSTEM_PROMPT_FILE}`
|
|
11
|
+
: `model_instructions_file=${tomlStr(resolve(workspaceDir, CODEX_SYSTEM_PROMPT_FILE))}`
|
|
12
|
+
: flag);
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-profile-materialize",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.5",
|
|
4
4
|
"description": "Materialize an AgentProfile into the native per-harness workspace files (the one shared materializer for cli-bridge, agent-container, and VB).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@tangle-network/agent-interface": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
|
36
36
|
},
|
|
37
37
|
"tangleRelease": {
|
|
38
|
-
"sourceSha": "
|
|
39
|
-
"mergedAt": "2026-10-
|
|
38
|
+
"sourceSha": "02fcaa7cdd12f1cea201a8e929a7772232549e3e",
|
|
39
|
+
"mergedAt": "2026-10-26T14:54:59-06:00"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -p tsconfig.json",
|