@tangle-network/agent-profile-materialize 0.8.0 → 0.9.1
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 +10 -5
- package/dist/index.js +41 -33
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
* cli-bridge and agent-dev-container — this is the single source those re-export.
|
|
23
23
|
*/
|
|
24
24
|
import type { AgentCandidateConfigValue, AgentCandidateProfile, AgentCandidateProfileActivation, AgentCandidateProfileApplication, AgentCandidateProfilePlanEvidence, AgentCandidateProfilePlanMaterial, AgentProfile, AgentProfileMcpServer, Sha256Digest } from "@tangle-network/agent-interface";
|
|
25
|
-
export
|
|
25
|
+
export declare const MATERIALIZER_HARNESSES: readonly ["claude-code", "nanoclaw", "codex", "opencode", "kimi-code", "pi", "gemini", "hermes", "openclaw"];
|
|
26
|
+
export type HarnessId = (typeof MATERIALIZER_HARNESSES)[number];
|
|
27
|
+
export declare function isMaterializerHarness(harness: string): harness is HarnessId;
|
|
26
28
|
export interface PlanFile {
|
|
27
29
|
relPath: string;
|
|
28
30
|
content: string;
|
|
@@ -157,9 +159,8 @@ export declare function harnessContextFile(harness: HarnessId): string;
|
|
|
157
159
|
export declare const HARNESS_SKILL_DIRS: Readonly<Record<HarnessId, string | null>>;
|
|
158
160
|
/**
|
|
159
161
|
* Resolve the cwd-relative directory `resources.skills` refs materialize
|
|
160
|
-
* into on `harness`
|
|
161
|
-
*
|
|
162
|
-
* cwd skills — the same condition that surfaces as an `unsupported`
|
|
162
|
+
* into on `harness`. `null` means the harness cannot receive cwd skills, the
|
|
163
|
+
* same condition that surfaces as an `unsupported`
|
|
163
164
|
* "skills" entry (and an {@link assertWorkspacePlanSupported} throw) at
|
|
164
165
|
* materialize time, exposed here as branchable data.
|
|
165
166
|
*/
|
|
@@ -170,7 +171,10 @@ export interface ResolveAgentProfileResourcesOptions {
|
|
|
170
171
|
fetch?: typeof globalThis.fetch;
|
|
171
172
|
timeoutMs?: number;
|
|
172
173
|
}
|
|
173
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* Resolve every GitHub resource to exact inline bytes before materialization.
|
|
176
|
+
* The profile's default harness does not affect resource resolution.
|
|
177
|
+
*/
|
|
174
178
|
export declare function resolveAgentProfileResources(inputProfile: AgentProfile, options?: ResolveAgentProfileResourcesOptions): Promise<AgentProfile>;
|
|
175
179
|
/** Normalize any skill markdown (VB frontmatter `skill:`/`description:`, or raw) into a
|
|
176
180
|
* harness SKILL.md with `name:`/`description:` frontmatter the harnesses require. */
|
|
@@ -178,6 +182,7 @@ export declare function normalizeSkillMd(name: string, raw: string): string;
|
|
|
178
182
|
/**
|
|
179
183
|
* Build the WorkspacePlan for `profile` on `harness`. Pure — no IO. The caller
|
|
180
184
|
* writes plan.files into the run cwd and applies plan.env/plan.flags to the spawn.
|
|
185
|
+
* The explicit target harness takes precedence over the profile's default.
|
|
181
186
|
*/
|
|
182
187
|
export declare function materializeProfile(inputProfile: AgentProfile, harness: HarnessId, opts?: {
|
|
183
188
|
skip?: Unsupported["dimension"][];
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,26 @@ function resolveInlineRef(ref) {
|
|
|
54
54
|
}
|
|
55
55
|
return null; // github / unresolved
|
|
56
56
|
}
|
|
57
|
+
export const MATERIALIZER_HARNESSES = [
|
|
58
|
+
"claude-code",
|
|
59
|
+
"nanoclaw",
|
|
60
|
+
"codex",
|
|
61
|
+
"opencode",
|
|
62
|
+
"kimi-code",
|
|
63
|
+
"pi",
|
|
64
|
+
"gemini",
|
|
65
|
+
"hermes",
|
|
66
|
+
"openclaw",
|
|
67
|
+
];
|
|
68
|
+
const MATERIALIZER_HARNESS_SET = new Set(MATERIALIZER_HARNESSES);
|
|
69
|
+
export function isMaterializerHarness(harness) {
|
|
70
|
+
return MATERIALIZER_HARNESS_SET.has(harness);
|
|
71
|
+
}
|
|
72
|
+
function assertMaterializerHarness(harness) {
|
|
73
|
+
if (!isMaterializerHarness(harness)) {
|
|
74
|
+
throw new Error(`Unsupported profile materialization harness "${harness}"`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
57
77
|
/** The plan was applied, but one or more private staging files remain. */
|
|
58
78
|
export class WorkspacePlanCleanupError extends AggregateError {
|
|
59
79
|
receipt;
|
|
@@ -97,7 +117,8 @@ export function enforceWorkspacePlanSupport(plan, failOnError) {
|
|
|
97
117
|
* lowering below, and the interactive TUI's persona fold.
|
|
98
118
|
*/
|
|
99
119
|
export function harnessAutoLoadsContextFile(harness) {
|
|
100
|
-
|
|
120
|
+
assertMaterializerHarness(harness);
|
|
121
|
+
return harness !== "opencode";
|
|
101
122
|
}
|
|
102
123
|
/**
|
|
103
124
|
* The project context file this harness reads from cwd — its stable, documented
|
|
@@ -107,11 +128,12 @@ export function harnessAutoLoadsContextFile(harness) {
|
|
|
107
128
|
* of this per-harness map.
|
|
108
129
|
*/
|
|
109
130
|
export function harnessContextFile(harness) {
|
|
131
|
+
assertMaterializerHarness(harness);
|
|
110
132
|
// The map is keyed by HarnessId, but callers reach this from runtime strings
|
|
111
133
|
// (a registry spec name, a request field). A miss would otherwise return
|
|
112
134
|
// undefined behind a `string` return type and surface as an undefined write
|
|
113
135
|
// path much later.
|
|
114
|
-
const path = CONTEXT_FILE[
|
|
136
|
+
const path = CONTEXT_FILE[harness];
|
|
115
137
|
if (!path) {
|
|
116
138
|
throw new Error(`No project context file is known for harness "${harness}"`);
|
|
117
139
|
}
|
|
@@ -120,13 +142,10 @@ export function harnessContextFile(harness) {
|
|
|
120
142
|
/** Project context file each harness actually reads from cwd. NEVER a constant. */
|
|
121
143
|
const CONTEXT_FILE = {
|
|
122
144
|
"claude-code": "CLAUDE.md",
|
|
123
|
-
claude: "CLAUDE.md",
|
|
124
|
-
claudish: "CLAUDE.md",
|
|
125
145
|
nanoclaw: "CLAUDE.md",
|
|
126
146
|
codex: "AGENTS.md",
|
|
127
147
|
opencode: ".opencode/profile-instructions.md",
|
|
128
148
|
"kimi-code": "AGENTS.md",
|
|
129
|
-
kimi: "AGENTS.md",
|
|
130
149
|
pi: "AGENTS.md",
|
|
131
150
|
gemini: "GEMINI.md", // current default; AGENTS.md only via .gemini/settings.json context.fileName
|
|
132
151
|
hermes: "HERMES.md", // highest-priority native name; only ONE context loads (first match)
|
|
@@ -142,13 +161,10 @@ const CONTEXT_FILE = {
|
|
|
142
161
|
*/
|
|
143
162
|
export const HARNESS_SKILL_DIRS = {
|
|
144
163
|
"claude-code": ".claude/skills",
|
|
145
|
-
claude: ".claude/skills",
|
|
146
|
-
claudish: ".claude/skills",
|
|
147
164
|
nanoclaw: ".claude/skills",
|
|
148
165
|
codex: ".codex/skills",
|
|
149
166
|
opencode: ".opencode/skills",
|
|
150
167
|
"kimi-code": ".kimi/skills",
|
|
151
|
-
kimi: ".kimi/skills",
|
|
152
168
|
pi: ".pi/skills",
|
|
153
169
|
gemini: ".gemini/skills",
|
|
154
170
|
hermes: null, // skills are ~/.hermes/skills (user) only — no cwd discovery
|
|
@@ -157,21 +173,14 @@ export const HARNESS_SKILL_DIRS = {
|
|
|
157
173
|
const SKILL_DIR = HARNESS_SKILL_DIRS;
|
|
158
174
|
/**
|
|
159
175
|
* Resolve the cwd-relative directory `resources.skills` refs materialize
|
|
160
|
-
* into on `harness`
|
|
161
|
-
*
|
|
162
|
-
* cwd skills — the same condition that surfaces as an `unsupported`
|
|
176
|
+
* into on `harness`. `null` means the harness cannot receive cwd skills, the
|
|
177
|
+
* same condition that surfaces as an `unsupported`
|
|
163
178
|
* "skills" entry (and an {@link assertWorkspacePlanSupported} throw) at
|
|
164
179
|
* materialize time, exposed here as branchable data.
|
|
165
180
|
*/
|
|
166
181
|
export function skillDirForHarness(harness) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
function canonicalHarness(h) {
|
|
170
|
-
if (h === "claude" || h === "claudish")
|
|
171
|
-
return "claude-code";
|
|
172
|
-
if (h === "kimi")
|
|
173
|
-
return "kimi-code";
|
|
174
|
-
return h;
|
|
182
|
+
assertMaterializerHarness(harness);
|
|
183
|
+
return HARNESS_SKILL_DIRS[harness];
|
|
175
184
|
}
|
|
176
185
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
177
186
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
@@ -283,7 +292,10 @@ function validateFileMode(mode) {
|
|
|
283
292
|
}
|
|
284
293
|
return normalized;
|
|
285
294
|
}
|
|
286
|
-
/**
|
|
295
|
+
/**
|
|
296
|
+
* Resolve every GitHub resource to exact inline bytes before materialization.
|
|
297
|
+
* The profile's default harness does not affect resource resolution.
|
|
298
|
+
*/
|
|
287
299
|
export async function resolveAgentProfileResources(inputProfile, options = {}) {
|
|
288
300
|
const profile = agentProfileSchema.parse(inputProfile);
|
|
289
301
|
const resources = profile.resources;
|
|
@@ -429,10 +441,12 @@ const tomlStr = (s) => JSON.stringify(s); // valid TOML basic string
|
|
|
429
441
|
/**
|
|
430
442
|
* Build the WorkspacePlan for `profile` on `harness`. Pure — no IO. The caller
|
|
431
443
|
* writes plan.files into the run cwd and applies plan.env/plan.flags to the spawn.
|
|
444
|
+
* The explicit target harness takes precedence over the profile's default.
|
|
432
445
|
*/
|
|
433
446
|
export function materializeProfile(inputProfile, harness, opts = {}) {
|
|
447
|
+
assertMaterializerHarness(harness);
|
|
434
448
|
const profile = agentProfileSchema.parse(inputProfile);
|
|
435
|
-
const h =
|
|
449
|
+
const h = harness;
|
|
436
450
|
const skip = new Set(opts.skip ?? []);
|
|
437
451
|
const plan = {
|
|
438
452
|
harness: h,
|
|
@@ -637,14 +651,7 @@ function activeMcpServers(servers) {
|
|
|
637
651
|
return Object.fromEntries(Object.entries(servers ?? {}).filter((entry) => entry[1].enabled !== false));
|
|
638
652
|
}
|
|
639
653
|
function extensionNamespaces(harness) {
|
|
640
|
-
|
|
641
|
-
case "claude-code":
|
|
642
|
-
return ["claude-code", "claude"];
|
|
643
|
-
case "kimi-code":
|
|
644
|
-
return ["kimi-code", "kimi"];
|
|
645
|
-
default:
|
|
646
|
-
return [harness];
|
|
647
|
-
}
|
|
654
|
+
return [harness];
|
|
648
655
|
}
|
|
649
656
|
/**
|
|
650
657
|
* Materialize a sealed candidate profile without weakening its process values.
|
|
@@ -652,6 +659,7 @@ function extensionNamespaces(harness) {
|
|
|
652
659
|
* argv, and environment values separately. Other hook formats fail closed.
|
|
653
660
|
*/
|
|
654
661
|
export function materializeCandidateProfile(profile, harness, opts = {}) {
|
|
662
|
+
assertMaterializerHarness(harness);
|
|
655
663
|
const candidate = agentCandidateProfileSchema.parse(profile);
|
|
656
664
|
verifyCandidateInlineResources(candidate);
|
|
657
665
|
const hookLowering = lowerCandidateHooks(candidate.hooks, harness);
|
|
@@ -692,7 +700,7 @@ export function materializeCandidateProfile(profile, harness, opts = {}) {
|
|
|
692
700
|
function lowerCandidateHooks(hooks, harness) {
|
|
693
701
|
if (!hooks || Object.keys(hooks).length === 0)
|
|
694
702
|
return { wrapperFiles: [] };
|
|
695
|
-
const nativeHarness =
|
|
703
|
+
const nativeHarness = harness;
|
|
696
704
|
if (nativeHarness !== "codex" && nativeHarness !== "claude-code") {
|
|
697
705
|
return {
|
|
698
706
|
wrapperFiles: [],
|
|
@@ -939,7 +947,7 @@ export function hashWorkspacePlan(plan) {
|
|
|
939
947
|
const env = Object.fromEntries(Object.entries(plan.env).sort(([a], [b]) => compareStrings(a, b)));
|
|
940
948
|
const unsupported = [...plan.unsupported].sort((a, b) => compareStrings(`${a.dimension}\0${a.reason}`, `${b.dimension}\0${b.reason}`));
|
|
941
949
|
const canonical = JSON.stringify({
|
|
942
|
-
harness:
|
|
950
|
+
harness: plan.harness,
|
|
943
951
|
files,
|
|
944
952
|
env,
|
|
945
953
|
flags: [...plan.flags],
|
|
@@ -954,7 +962,7 @@ export function hashWorkspacePlan(plan) {
|
|
|
954
962
|
export function agentCandidateProfilePlanMaterial(plan) {
|
|
955
963
|
const material = {
|
|
956
964
|
sourceProfileDigest: plan.sourceProfileDigest,
|
|
957
|
-
harness:
|
|
965
|
+
harness: plan.harness,
|
|
958
966
|
files: normalizePlanFiles(plan.files).map((file) => ({
|
|
959
967
|
relPath: file.relPath,
|
|
960
968
|
mode: file.mode,
|
|
@@ -1884,7 +1892,7 @@ const GEMINI_HOOK_EVENTS = new Set([
|
|
|
1884
1892
|
"SessionStart",
|
|
1885
1893
|
]);
|
|
1886
1894
|
function hookEventSupported(harness, event) {
|
|
1887
|
-
switch (
|
|
1895
|
+
switch (harness) {
|
|
1888
1896
|
case "claude-code":
|
|
1889
1897
|
return CLAUDE_HOOK_EVENTS.has(event);
|
|
1890
1898
|
case "codex":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-profile-materialize",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Materialize an AgentProfile into the native per-harness workspace files (the one shared materializer for cli-bridge, agent-dev-container, and VB).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@tangle-network/agent-interface": "0.
|
|
19
|
+
"@tangle-network/agent-interface": "0.35.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "25.6.0",
|
|
23
23
|
"typescript": "^6.0.3",
|
|
24
|
-
"vitest": "^4.1.
|
|
24
|
+
"vitest": "^4.1.10"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "tsc -p tsconfig.json",
|