@agentworkforce/persona-kit 0.19.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/README.md +93 -0
- package/dist/config-files.d.ts +21 -0
- package/dist/config-files.d.ts.map +1 -0
- package/dist/config-files.js +81 -0
- package/dist/config-files.js.map +1 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +78 -0
- package/dist/constants.js.map +1 -0
- package/dist/detect.d.ts +28 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +63 -0
- package/dist/detect.js.map +1 -0
- package/dist/env-refs.d.ts +56 -0
- package/dist/env-refs.d.ts.map +1 -0
- package/dist/env-refs.js +105 -0
- package/dist/env-refs.js.map +1 -0
- package/dist/env-refs.test.d.ts +2 -0
- package/dist/env-refs.test.d.ts.map +1 -0
- package/dist/env-refs.test.js +84 -0
- package/dist/env-refs.test.js.map +1 -0
- package/dist/execute.d.ts +47 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +68 -0
- package/dist/execute.js.map +1 -0
- package/dist/execute.test.d.ts +2 -0
- package/dist/execute.test.d.ts.map +1 -0
- package/dist/execute.test.js +255 -0
- package/dist/execute.test.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +234 -0
- package/dist/index.test.js.map +1 -0
- package/dist/inputs.d.ts +13 -0
- package/dist/inputs.d.ts.map +1 -0
- package/dist/inputs.js +57 -0
- package/dist/inputs.js.map +1 -0
- package/dist/inputs.test.d.ts +2 -0
- package/dist/inputs.test.d.ts.map +1 -0
- package/dist/inputs.test.js +51 -0
- package/dist/inputs.test.js.map +1 -0
- package/dist/interactive-spec.d.ts +117 -0
- package/dist/interactive-spec.d.ts.map +1 -0
- package/dist/interactive-spec.js +260 -0
- package/dist/interactive-spec.js.map +1 -0
- package/dist/interactive-spec.test.d.ts +2 -0
- package/dist/interactive-spec.test.d.ts.map +1 -0
- package/dist/interactive-spec.test.js +308 -0
- package/dist/interactive-spec.test.js.map +1 -0
- package/dist/mcp.d.ts +35 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +86 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mount.d.ts +44 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +51 -0
- package/dist/mount.js.map +1 -0
- package/dist/parse.d.ts +47 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +475 -0
- package/dist/parse.js.map +1 -0
- package/dist/plan.d.ts +118 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +150 -0
- package/dist/plan.js.map +1 -0
- package/dist/plan.test.d.ts +2 -0
- package/dist/plan.test.d.ts.map +1 -0
- package/dist/plan.test.js +191 -0
- package/dist/plan.test.js.map +1 -0
- package/dist/sidecars.d.ts +17 -0
- package/dist/sidecars.d.ts.map +1 -0
- package/dist/sidecars.js +101 -0
- package/dist/sidecars.js.map +1 -0
- package/dist/skill-runner.d.ts +30 -0
- package/dist/skill-runner.d.ts.map +1 -0
- package/dist/skill-runner.js +94 -0
- package/dist/skill-runner.js.map +1 -0
- package/dist/skills.d.ts +41 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +322 -0
- package/dist/skills.js.map +1 -0
- package/dist/types.d.ts +321 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { HARNESS_SKILL_TARGETS, HARNESS_VALUES, PERSONA_INTENTS, materializeSkills, resolveSidecar } from './index.js';
|
|
4
|
+
const prpmSkill = {
|
|
5
|
+
id: 'prpm/npm-trusted-publishing',
|
|
6
|
+
source: '@prpm/npm-trusted-publishing',
|
|
7
|
+
description: 'trusted publishing skill'
|
|
8
|
+
};
|
|
9
|
+
const skillShSkill = {
|
|
10
|
+
id: 'skill.sh/find-skills',
|
|
11
|
+
source: 'https://github.com/vercel-labs/skills#find-skills',
|
|
12
|
+
description: 'skill.sh discovery skill'
|
|
13
|
+
};
|
|
14
|
+
function syntheticSpec(over = {}) {
|
|
15
|
+
const baseRuntime = {
|
|
16
|
+
harness: 'claude',
|
|
17
|
+
model: 'claude-3-5-sonnet',
|
|
18
|
+
systemPrompt: 'base',
|
|
19
|
+
harnessSettings: { reasoning: 'medium', timeoutSeconds: 300 }
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
id: 's',
|
|
23
|
+
intent: 'documentation',
|
|
24
|
+
tags: ['documentation'],
|
|
25
|
+
description: 'd',
|
|
26
|
+
skills: [],
|
|
27
|
+
tiers: { best: baseRuntime, 'best-value': baseRuntime, minimum: baseRuntime },
|
|
28
|
+
...over
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
test('PERSONA_INTENTS includes the unrouted "review" intent for pack consumers', () => {
|
|
32
|
+
assert.ok(PERSONA_INTENTS.includes('review'));
|
|
33
|
+
});
|
|
34
|
+
test('claude is a recognized harness value', () => {
|
|
35
|
+
assert.ok(HARNESS_VALUES.includes('claude'));
|
|
36
|
+
});
|
|
37
|
+
test('HARNESS_SKILL_TARGETS covers every harness value', () => {
|
|
38
|
+
for (const harness of HARNESS_VALUES) {
|
|
39
|
+
const target = HARNESS_SKILL_TARGETS[harness];
|
|
40
|
+
assert.ok(target, `missing target for harness ${harness}`);
|
|
41
|
+
assert.ok(target.asFlag.length > 0);
|
|
42
|
+
assert.ok(target.dir.length > 0);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
test('materializeSkills emits a codex-scoped prpm install for a prpm.dev URL', () => {
|
|
46
|
+
const plan = materializeSkills([
|
|
47
|
+
{
|
|
48
|
+
...prpmSkill,
|
|
49
|
+
source: 'https://prpm.dev/packages/@prpm/npm-trusted-publishing'
|
|
50
|
+
}
|
|
51
|
+
], 'codex');
|
|
52
|
+
assert.equal(plan.harness, 'codex');
|
|
53
|
+
assert.equal(plan.installs.length, 1);
|
|
54
|
+
const [install] = plan.installs;
|
|
55
|
+
assert.equal(install.sourceKind, 'prpm');
|
|
56
|
+
assert.equal(install.packageRef, '@prpm/npm-trusted-publishing');
|
|
57
|
+
assert.deepEqual([...install.installCommand], ['npx', '-y', 'prpm', 'install', '@prpm/npm-trusted-publishing', '--as', 'codex']);
|
|
58
|
+
assert.equal(install.installedDir, '.agents/skills/npm-trusted-publishing');
|
|
59
|
+
assert.equal(install.installedManifest, '.agents/skills/npm-trusted-publishing/SKILL.md');
|
|
60
|
+
});
|
|
61
|
+
test('materializeSkills routes claude skills to .claude/skills via --as claude', () => {
|
|
62
|
+
const plan = materializeSkills([prpmSkill], 'claude');
|
|
63
|
+
const [install] = plan.installs;
|
|
64
|
+
assert.deepEqual([...install.installCommand], ['npx', '-y', 'prpm', 'install', '@prpm/npm-trusted-publishing', '--as', 'claude']);
|
|
65
|
+
assert.equal(install.installedDir, '.claude/skills/npm-trusted-publishing');
|
|
66
|
+
});
|
|
67
|
+
test('materializeSkills emits a skill.sh install for a github#skill source', () => {
|
|
68
|
+
const plan = materializeSkills([skillShSkill], 'claude');
|
|
69
|
+
assert.equal(plan.installs.length, 1);
|
|
70
|
+
const [install] = plan.installs;
|
|
71
|
+
assert.equal(install.sourceKind, 'skill.sh');
|
|
72
|
+
assert.equal(install.packageRef, 'https://github.com/vercel-labs/skills#find-skills');
|
|
73
|
+
assert.deepEqual([...install.installCommand], [
|
|
74
|
+
'npx',
|
|
75
|
+
'-y',
|
|
76
|
+
'skills',
|
|
77
|
+
'add',
|
|
78
|
+
'https://github.com/vercel-labs/skills',
|
|
79
|
+
'--skill',
|
|
80
|
+
'find-skills',
|
|
81
|
+
'-y'
|
|
82
|
+
]);
|
|
83
|
+
assert.equal(install.installedDir, '.agents/skills/find-skills');
|
|
84
|
+
assert.equal(install.installedManifest, '.agents/skills/find-skills/SKILL.md');
|
|
85
|
+
assert.deepEqual([...install.cleanupPaths], [
|
|
86
|
+
'.agents/skills/find-skills',
|
|
87
|
+
'.claude/skills/find-skills',
|
|
88
|
+
'.factory/skills/find-skills',
|
|
89
|
+
'.kiro/skills/find-skills',
|
|
90
|
+
'skills/find-skills'
|
|
91
|
+
]);
|
|
92
|
+
assert.ok(!install.cleanupPaths.includes('skills-lock.json'));
|
|
93
|
+
});
|
|
94
|
+
test('materializeSkills accepts GitHub tree URLs for skill.sh skill directories', () => {
|
|
95
|
+
const plan = materializeSkills([
|
|
96
|
+
{
|
|
97
|
+
id: 'nextjs-anti-patterns',
|
|
98
|
+
source: 'https://github.com/wsimmonds/claude-nextjs-skills/tree/main/nextjs-anti-patterns',
|
|
99
|
+
description: 'Next.js anti-pattern guidance'
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'lighthouse-ci-integrator',
|
|
103
|
+
source: 'https://github.com/Dexploarer/hyper-forge/tree/main/.claude/skills/lighthouse-ci-integrator',
|
|
104
|
+
description: 'Lighthouse CI guidance'
|
|
105
|
+
}
|
|
106
|
+
], 'opencode');
|
|
107
|
+
assert.deepEqual(plan.installs.map((install) => ({
|
|
108
|
+
packageRef: install.packageRef,
|
|
109
|
+
installedDir: install.installedDir,
|
|
110
|
+
command: [...install.installCommand]
|
|
111
|
+
})), [
|
|
112
|
+
{
|
|
113
|
+
packageRef: 'https://github.com/wsimmonds/claude-nextjs-skills/tree/main#nextjs-anti-patterns',
|
|
114
|
+
installedDir: '.agents/skills/nextjs-anti-patterns',
|
|
115
|
+
command: [
|
|
116
|
+
'npx',
|
|
117
|
+
'-y',
|
|
118
|
+
'skills',
|
|
119
|
+
'add',
|
|
120
|
+
'https://github.com/wsimmonds/claude-nextjs-skills/tree/main',
|
|
121
|
+
'--skill',
|
|
122
|
+
'nextjs-anti-patterns',
|
|
123
|
+
'-y'
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
packageRef: 'https://github.com/Dexploarer/hyper-forge/tree/main#lighthouse-ci-integrator',
|
|
128
|
+
installedDir: '.agents/skills/lighthouse-ci-integrator',
|
|
129
|
+
command: [
|
|
130
|
+
'npx',
|
|
131
|
+
'-y',
|
|
132
|
+
'skills',
|
|
133
|
+
'add',
|
|
134
|
+
'https://github.com/Dexploarer/hyper-forge/tree/main',
|
|
135
|
+
'--skill',
|
|
136
|
+
'lighthouse-ci-integrator',
|
|
137
|
+
'-y'
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
test('materializeSkills rejects unsafe skill.sh skill names', () => {
|
|
143
|
+
assert.throws(() => materializeSkills([
|
|
144
|
+
{
|
|
145
|
+
id: 'unsafe',
|
|
146
|
+
source: 'https://github.com/example/skills#../unsafe',
|
|
147
|
+
description: 'unsafe fragment'
|
|
148
|
+
}
|
|
149
|
+
], 'opencode'), /Unsupported skill source/);
|
|
150
|
+
assert.throws(() => materializeSkills([
|
|
151
|
+
{
|
|
152
|
+
id: 'unsafe',
|
|
153
|
+
source: 'https://github.com/example/skills/tree/main/.hidden',
|
|
154
|
+
description: 'unsafe tree leaf'
|
|
155
|
+
}
|
|
156
|
+
], 'opencode'), /Unsupported skill source/);
|
|
157
|
+
});
|
|
158
|
+
test('prpm installs carry a harness-scoped cleanup path, not the lockfile', () => {
|
|
159
|
+
const plan = materializeSkills([prpmSkill], 'codex');
|
|
160
|
+
const [install] = plan.installs;
|
|
161
|
+
assert.deepEqual([...install.cleanupPaths], ['.agents/skills/npm-trusted-publishing']);
|
|
162
|
+
assert.ok(!install.cleanupPaths.includes('prpm.lock'));
|
|
163
|
+
});
|
|
164
|
+
test('materializeSkills with installRoot stages claude skills under the stage dir', () => {
|
|
165
|
+
const installRoot = '/tmp/agent-workforce/sessions/test-run/claude/plugin';
|
|
166
|
+
const plan = materializeSkills([prpmSkill], 'claude', { installRoot });
|
|
167
|
+
assert.equal(plan.sessionInstallRoot, installRoot);
|
|
168
|
+
const [install] = plan.installs;
|
|
169
|
+
assert.equal(install.installedDir, `${installRoot}/.claude/skills/npm-trusted-publishing`);
|
|
170
|
+
assert.equal(install.installedManifest, `${installRoot}/.claude/skills/npm-trusted-publishing/SKILL.md`);
|
|
171
|
+
assert.equal(install.installCommand[0], 'sh');
|
|
172
|
+
assert.equal(install.installCommand[1], '-c');
|
|
173
|
+
const script = install.installCommand[2];
|
|
174
|
+
assert.match(script, /^cd /);
|
|
175
|
+
assert.match(script, /agent-workforce\/sessions\/test-run\/claude\/plugin/);
|
|
176
|
+
assert.match(script, /npx -y prpm install @prpm\/npm-trusted-publishing --as claude/);
|
|
177
|
+
assert.deepEqual([...install.cleanupPaths], []);
|
|
178
|
+
});
|
|
179
|
+
test('materializeSkills rejects installRoot for non-claude harnesses', () => {
|
|
180
|
+
assert.throws(() => materializeSkills([prpmSkill], 'codex', {
|
|
181
|
+
installRoot: '/tmp/agent-workforce/sessions/abc/claude/plugin'
|
|
182
|
+
}), /installRoot is only supported for the claude harness/);
|
|
183
|
+
});
|
|
184
|
+
test('materializeSkills with installRoot and no skills still reports the sessionInstallRoot', () => {
|
|
185
|
+
const installRoot = '/tmp/agent-workforce/sessions/empty/claude/plugin';
|
|
186
|
+
const plan = materializeSkills([], 'claude', { installRoot });
|
|
187
|
+
assert.equal(plan.sessionInstallRoot, installRoot);
|
|
188
|
+
assert.equal(plan.installs.length, 0);
|
|
189
|
+
});
|
|
190
|
+
test('materializeSkills rejects unknown skill sources', () => {
|
|
191
|
+
assert.throws(() => materializeSkills([
|
|
192
|
+
{
|
|
193
|
+
id: 'x',
|
|
194
|
+
source: 'https://example.com/random',
|
|
195
|
+
description: 'not a supported source'
|
|
196
|
+
}
|
|
197
|
+
], 'claude'), /Unsupported skill source/);
|
|
198
|
+
});
|
|
199
|
+
test('materializeSkills handles personas with no skills', () => {
|
|
200
|
+
const plan = materializeSkills([], 'claude');
|
|
201
|
+
assert.equal(plan.installs.length, 0);
|
|
202
|
+
});
|
|
203
|
+
test('resolveSidecar: tier path override drops top-level inlined content for the same channel', () => {
|
|
204
|
+
const spec = syntheticSpec({
|
|
205
|
+
claudeMdContent: '# top-level inlined\n',
|
|
206
|
+
claudeMdMode: 'overwrite',
|
|
207
|
+
tiers: {
|
|
208
|
+
best: {
|
|
209
|
+
...syntheticSpec().tiers.best,
|
|
210
|
+
claudeMd: '/abs/persona.md'
|
|
211
|
+
},
|
|
212
|
+
'best-value': syntheticSpec().tiers['best-value'],
|
|
213
|
+
minimum: syntheticSpec().tiers.minimum
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const resolved = resolveSidecar(spec, 'best');
|
|
217
|
+
assert.equal(resolved.claudeMd, '/abs/persona.md');
|
|
218
|
+
assert.equal(resolved.claudeMdContent, undefined);
|
|
219
|
+
assert.equal(resolved.claudeMdMode, 'overwrite');
|
|
220
|
+
});
|
|
221
|
+
test('resolveSidecar: mode cascades independently of path', () => {
|
|
222
|
+
const spec = syntheticSpec({
|
|
223
|
+
claudeMd: '/abs/top.md',
|
|
224
|
+
claudeMdMode: 'extend'
|
|
225
|
+
});
|
|
226
|
+
const resolved = resolveSidecar(spec, 'best');
|
|
227
|
+
assert.equal(resolved.claudeMd, '/abs/top.md');
|
|
228
|
+
assert.equal(resolved.claudeMdMode, 'extend');
|
|
229
|
+
});
|
|
230
|
+
test('PersonaSpec accepts an optional defaultTier', () => {
|
|
231
|
+
const spec = syntheticSpec({ defaultTier: 'best' });
|
|
232
|
+
assert.equal(spec.defaultTier, 'best');
|
|
233
|
+
});
|
|
234
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
package/dist/inputs.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PersonaInputSpec } from './types.js';
|
|
2
|
+
export type PersonaInputValues = Record<string, string | number | boolean | null | undefined>;
|
|
3
|
+
export interface PersonaInputResolution {
|
|
4
|
+
values: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export declare class MissingPersonaInputError extends Error {
|
|
7
|
+
readonly input: string;
|
|
8
|
+
readonly env: string;
|
|
9
|
+
constructor(input: string, env: string);
|
|
10
|
+
}
|
|
11
|
+
export declare function resolvePersonaInputs(inputs: Record<string, PersonaInputSpec> | undefined, provided: PersonaInputValues | undefined, processEnv: NodeJS.ProcessEnv): PersonaInputResolution;
|
|
12
|
+
export declare function renderPersonaInputs(systemPrompt: string, values: Record<string, string>): string;
|
|
13
|
+
//# sourceMappingURL=inputs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAE9F,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBACT,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAQvC;AAQD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,EACpD,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,UAAU,EAAE,MAAM,CAAC,UAAU,GAC5B,sBAAsB,CAsBxB;AAMD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAeR"}
|
package/dist/inputs.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export class MissingPersonaInputError extends Error {
|
|
2
|
+
input;
|
|
3
|
+
env;
|
|
4
|
+
constructor(input, env) {
|
|
5
|
+
super(`Persona input ${input} is required but no explicit value, env var ${env}, or default was provided.`);
|
|
6
|
+
this.name = 'MissingPersonaInputError';
|
|
7
|
+
this.input = input;
|
|
8
|
+
this.env = env;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function stringifyProvidedValue(value) {
|
|
12
|
+
if (value === undefined || value === null)
|
|
13
|
+
return undefined;
|
|
14
|
+
const text = String(value);
|
|
15
|
+
return text === '' ? undefined : text;
|
|
16
|
+
}
|
|
17
|
+
export function resolvePersonaInputs(inputs, provided, processEnv) {
|
|
18
|
+
if (!inputs)
|
|
19
|
+
return { values: {} };
|
|
20
|
+
const values = {};
|
|
21
|
+
for (const [name, spec] of Object.entries(inputs)) {
|
|
22
|
+
const envName = spec.env ?? name;
|
|
23
|
+
const resolved = stringifyProvidedValue(provided?.[name]) ??
|
|
24
|
+
stringifyProvidedValue(processEnv[envName]) ??
|
|
25
|
+
spec.default;
|
|
26
|
+
if (resolved === undefined || resolved === '') {
|
|
27
|
+
// Optional inputs substitute as empty so personas can write
|
|
28
|
+
// sentinel-driven prompts (e.g. systemPrompt: "$TASK_DESCRIPTION")
|
|
29
|
+
// that produce an empty rendered output when nothing is supplied.
|
|
30
|
+
if (spec.optional) {
|
|
31
|
+
values[name] = '';
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
throw new MissingPersonaInputError(name, envName);
|
|
35
|
+
}
|
|
36
|
+
values[name] = resolved;
|
|
37
|
+
}
|
|
38
|
+
return { values };
|
|
39
|
+
}
|
|
40
|
+
function escapeRegExp(input) {
|
|
41
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
42
|
+
}
|
|
43
|
+
export function renderPersonaInputs(systemPrompt, values) {
|
|
44
|
+
const names = Object.keys(values);
|
|
45
|
+
if (names.length === 0)
|
|
46
|
+
return systemPrompt;
|
|
47
|
+
const alternatives = names
|
|
48
|
+
.map(escapeRegExp)
|
|
49
|
+
.sort((a, b) => b.length - a.length)
|
|
50
|
+
.join('|');
|
|
51
|
+
const inputRef = new RegExp(`\\$\\{(${alternatives})\\}|\\$(${alternatives})(?![A-Z0-9_])`, 'g');
|
|
52
|
+
return systemPrompt.replace(inputRef, (_match, bracedName, bareName) => {
|
|
53
|
+
const name = (bracedName ?? bareName);
|
|
54
|
+
return values[name];
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=inputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.js","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,KAAK,CAAS;IACd,GAAG,CAAS;IACrB,YAAY,KAAa,EAAE,GAAW;QACpC,KAAK,CACH,iBAAiB,KAAK,+CAA+C,GAAG,4BAA4B,CACrG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED,SAAS,sBAAsB,CAAC,KAAiC;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAoD,EACpD,QAAwC,EACxC,UAA6B;IAE7B,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACnC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC;QACjC,MAAM,QAAQ,GACZ,sBAAsB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;YACxC,sBAAsB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO,CAAC;QACf,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;YAC9C,4DAA4D;YAC5D,mEAAmE;YACnE,kEAAkE;YAClE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YACD,MAAM,IAAI,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,MAA8B;IAE9B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC;IAC5C,MAAM,YAAY,GAAG,KAAK;SACvB,GAAG,CAAC,YAAY,CAAC;SACjB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;SACnC,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,QAAQ,GAAG,IAAI,MAAM,CACzB,UAAU,YAAY,YAAY,YAAY,gBAAgB,EAC9D,GAAG,CACJ,CAAC;IACF,OAAO,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE;QACrE,MAAM,IAAI,GAAG,CAAC,UAAU,IAAI,QAAQ,CAAW,CAAC;QAChD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.test.d.ts","sourceRoot":"","sources":["../src/inputs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { MissingPersonaInputError, renderPersonaInputs, resolvePersonaInputs } from './inputs.js';
|
|
4
|
+
test('resolvePersonaInputs prefers explicit values over env and defaults', () => {
|
|
5
|
+
const resolved = resolvePersonaInputs({
|
|
6
|
+
TARGET_DIR: {
|
|
7
|
+
env: 'AW_TARGET_DIR',
|
|
8
|
+
default: '/default/personas'
|
|
9
|
+
}
|
|
10
|
+
}, { TARGET_DIR: '/explicit/personas' }, { AW_TARGET_DIR: '/env/personas' });
|
|
11
|
+
assert.deepEqual(resolved.values, { TARGET_DIR: '/explicit/personas' });
|
|
12
|
+
});
|
|
13
|
+
test('resolvePersonaInputs falls back to configured env var then default', () => {
|
|
14
|
+
assert.deepEqual(resolvePersonaInputs({
|
|
15
|
+
TARGET_DIR: { env: 'AW_TARGET_DIR', default: '/default/personas' },
|
|
16
|
+
CREATE_MODE: { default: 'local' }
|
|
17
|
+
}, undefined, { AW_TARGET_DIR: '/env/personas' }).values, {
|
|
18
|
+
TARGET_DIR: '/env/personas',
|
|
19
|
+
CREATE_MODE: 'local'
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
test('resolvePersonaInputs fails hard when a declared input is unset', () => {
|
|
23
|
+
assert.throws(() => resolvePersonaInputs({ TARGET_DIR: {} }, undefined, {}), (err) => err instanceof MissingPersonaInputError &&
|
|
24
|
+
err.input === 'TARGET_DIR' &&
|
|
25
|
+
err.env === 'TARGET_DIR');
|
|
26
|
+
});
|
|
27
|
+
test('resolvePersonaInputs substitutes optional inputs with empty when unset', () => {
|
|
28
|
+
// optional inputs are how a persona signals "this value may or may not
|
|
29
|
+
// be forwarded; render to empty when it isn't" — used by sentinel-style
|
|
30
|
+
// systemPrompts like "$TASK_DESCRIPTION" that should kick off the
|
|
31
|
+
// harness only when the launcher provided the value.
|
|
32
|
+
assert.deepEqual(resolvePersonaInputs({ TASK_DESCRIPTION: { optional: true } }, undefined, {}).values, { TASK_DESCRIPTION: '' });
|
|
33
|
+
});
|
|
34
|
+
test('resolvePersonaInputs uses provided value over optional empty fallback', () => {
|
|
35
|
+
assert.deepEqual(resolvePersonaInputs({ TASK_DESCRIPTION: { optional: true } }, { TASK_DESCRIPTION: 'build a thing' }, {}).values, { TASK_DESCRIPTION: 'build a thing' });
|
|
36
|
+
});
|
|
37
|
+
test('renderPersonaInputs substitutes $NAME and ${NAME} without touching longer names', () => {
|
|
38
|
+
const rendered = renderPersonaInputs('Write to $TARGET_DIR and ${CREATE_MODE}; leave $TARGET_DIR_SUFFIX alone.', {
|
|
39
|
+
TARGET_DIR: '/tmp/personas',
|
|
40
|
+
CREATE_MODE: 'local'
|
|
41
|
+
});
|
|
42
|
+
assert.equal(rendered, 'Write to /tmp/personas and local; leave $TARGET_DIR_SUFFIX alone.');
|
|
43
|
+
});
|
|
44
|
+
test('renderPersonaInputs treats replacement values literally', () => {
|
|
45
|
+
const rendered = renderPersonaInputs('Write to $TARGET_DIR in ${CREATE_MODE}.', {
|
|
46
|
+
TARGET_DIR: '/tmp/$&/$CREATE_MODE/personas',
|
|
47
|
+
CREATE_MODE: 'local'
|
|
48
|
+
});
|
|
49
|
+
assert.equal(rendered, 'Write to /tmp/$&/$CREATE_MODE/personas in local.');
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=inputs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.test.js","sourceRoot":"","sources":["../src/inputs.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Harness, HarnessSettings, McpServerSpec, PersonaPermissions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A config file the caller should materialize before launching the harness.
|
|
4
|
+
* Paths are relative to the harness's cwd — typically the mount dir when a
|
|
5
|
+
* sandbox is in use, otherwise process.cwd(). Pure data, no I/O here.
|
|
6
|
+
*/
|
|
7
|
+
export interface InteractiveConfigFile {
|
|
8
|
+
/** Relative path (from cwd) where the file should be written. */
|
|
9
|
+
path: string;
|
|
10
|
+
/** Exact file contents, already serialized. */
|
|
11
|
+
contents: string;
|
|
12
|
+
}
|
|
13
|
+
/** Result of translating a persona's runtime into a spawnable command. */
|
|
14
|
+
export interface InteractiveSpec {
|
|
15
|
+
/** Binary to exec (e.g. `claude`, `codex`, `opencode`). */
|
|
16
|
+
bin: string;
|
|
17
|
+
/** Argv for the binary, in order. Callers should `spawn(bin, args)`. */
|
|
18
|
+
args: readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* If set, the caller should append this as the final positional argument
|
|
21
|
+
* — used by harnesses that don't support a separate system-prompt flag
|
|
22
|
+
* to carry the persona's system prompt as the initial user prompt.
|
|
23
|
+
* Currently only codex takes this path; claude uses `--append-system-prompt`
|
|
24
|
+
* and opencode writes the prompt into `opencode.json` (see `configFiles`),
|
|
25
|
+
* so both return `null` here.
|
|
26
|
+
*/
|
|
27
|
+
initialPrompt: string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Non-fatal warnings produced during translation — e.g. "codex doesn't
|
|
30
|
+
* support MCP yet, ignoring". Callers decide whether to print them.
|
|
31
|
+
*/
|
|
32
|
+
warnings: string[];
|
|
33
|
+
/**
|
|
34
|
+
* Config files the caller must write (relative to the harness cwd) before
|
|
35
|
+
* launch. Opencode uses this to materialize an `opencode.json` carrying
|
|
36
|
+
* the persona's agent definition (model + system prompt) so `--agent` can
|
|
37
|
+
* resolve it; claude and codex return an empty array.
|
|
38
|
+
*/
|
|
39
|
+
configFiles: InteractiveConfigFile[];
|
|
40
|
+
}
|
|
41
|
+
export interface BuildInteractiveSpecInput {
|
|
42
|
+
harness: Harness;
|
|
43
|
+
/**
|
|
44
|
+
* Persona id — used as the opencode agent name. Claude and codex ignore
|
|
45
|
+
* this field today; keeping it required here keeps call sites honest and
|
|
46
|
+
* lets future harnesses consume it without another type change.
|
|
47
|
+
*/
|
|
48
|
+
personaId: string;
|
|
49
|
+
model: string;
|
|
50
|
+
systemPrompt: string;
|
|
51
|
+
/** Env-resolved MCP servers (pass the output of `resolveMcpServersLenient().servers`). */
|
|
52
|
+
mcpServers?: Record<string, McpServerSpec>;
|
|
53
|
+
permissions?: PersonaPermissions;
|
|
54
|
+
harnessSettings?: HarnessSettings;
|
|
55
|
+
/**
|
|
56
|
+
* Absolute paths of directories to load as Claude Code plugins for this
|
|
57
|
+
* session (`--plugin-dir <path>` per entry). Used to wire in out-of-repo
|
|
58
|
+
* skill stages produced by
|
|
59
|
+
* {@link import('@agentworkforce/workload-router').SkillMaterializationOptions.installRoot}.
|
|
60
|
+
* Claude-only: other harnesses emit a warning and ignore the field.
|
|
61
|
+
*/
|
|
62
|
+
pluginDirs?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Translate a persona's runtime fields into a concrete `{bin, args}` for
|
|
66
|
+
* spawning an interactive harness session. Pure — no I/O, no side effects.
|
|
67
|
+
*
|
|
68
|
+
* The claude branch always emits `--mcp-config` + `--strict-mcp-config`
|
|
69
|
+
* (with an empty `mcpServers: {}` payload if the persona declares none),
|
|
70
|
+
* so the spawned session only sees the persona's declared MCP servers,
|
|
71
|
+
* never the user's or project's Claude Code config.
|
|
72
|
+
*
|
|
73
|
+
* The codex branch carries the system prompt via `initialPrompt` because
|
|
74
|
+
* codex has no dedicated system-prompt flag today — callers append it as
|
|
75
|
+
* the final positional `[PROMPT]`.
|
|
76
|
+
*
|
|
77
|
+
* The opencode branch routes model + system prompt through opencode's
|
|
78
|
+
* agent abstraction (see https://opencode.ai/config.json: `agent.<id>.{
|
|
79
|
+
* model, prompt, mode }`). It emits an `opencode.json` via `configFiles`
|
|
80
|
+
* for the caller to materialize at cwd, and selects it with `--agent
|
|
81
|
+
* <personaId>`. It deliberately does NOT use `--prompt` (that flag
|
|
82
|
+
* pre-fills the TUI input with a user message) or bare `-m` (opencode
|
|
83
|
+
* expects full `provider/model` form and silently falls back to its
|
|
84
|
+
* default when given a stripped model name). `initialPrompt` is `null`
|
|
85
|
+
* so callers do not append a trailing positional, which opencode would
|
|
86
|
+
* otherwise interpret as a project directory.
|
|
87
|
+
*
|
|
88
|
+
* Both codex and opencode emit a warning if the persona declares
|
|
89
|
+
* `mcpServers` or `permissions` — those features aren't wired for those
|
|
90
|
+
* harnesses yet.
|
|
91
|
+
*/
|
|
92
|
+
export declare function buildInteractiveSpec(input: BuildInteractiveSpecInput): InteractiveSpec;
|
|
93
|
+
/** Result of translating a persona's runtime into a one-shot, non-interactive
|
|
94
|
+
* spawnable command. Caller writes `configFiles` before spawning. */
|
|
95
|
+
export interface NonInteractiveSpec {
|
|
96
|
+
bin: string;
|
|
97
|
+
args: readonly string[];
|
|
98
|
+
configFiles: readonly InteractiveConfigFile[];
|
|
99
|
+
warnings: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Translate a persona's runtime into a non-interactive, one-shot command.
|
|
103
|
+
* Layers harness-specific non-interactive flags on top of {@link buildInteractiveSpec},
|
|
104
|
+
* then appends the user task. Pure — no I/O.
|
|
105
|
+
*
|
|
106
|
+
* - `claude`: appends `--print --output-format text [--name <n>] <task>`.
|
|
107
|
+
* - `codex`: prefixes `exec`, appends `--skip-git-repo-check`, then a prompt
|
|
108
|
+
* built from any `initialPrompt` joined with the user task.
|
|
109
|
+
* - `opencode`: prefixes `run`, appends `--model <m> --format default
|
|
110
|
+
* [--dir <cwd>] [--title <n>] <task>`.
|
|
111
|
+
*/
|
|
112
|
+
export declare function buildNonInteractiveSpec(input: BuildInteractiveSpecInput & {
|
|
113
|
+
task: string;
|
|
114
|
+
name?: string;
|
|
115
|
+
workingDirectory?: string;
|
|
116
|
+
}): NonInteractiveSpec;
|
|
117
|
+
//# sourceMappingURL=interactive-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-spec.d.ts","sourceRoot":"","sources":["../src/interactive-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,aAAa,EACb,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,WAAW,EAAE,qBAAqB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,eAAe,CA2LtF;AAED;qEACqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC9C,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,yBAAyB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GACA,kBAAkB,CA0CpB"}
|