@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,260 @@
|
|
|
1
|
+
function stripProviderPrefix(model) {
|
|
2
|
+
const idx = model.indexOf('/');
|
|
3
|
+
return idx >= 0 ? model.slice(idx + 1) : model;
|
|
4
|
+
}
|
|
5
|
+
function hasAnyPermission(p) {
|
|
6
|
+
if (!p)
|
|
7
|
+
return false;
|
|
8
|
+
return Boolean(p.allow?.length || p.deny?.length || p.mode);
|
|
9
|
+
}
|
|
10
|
+
function hasCodexLaunchSettings(settings) {
|
|
11
|
+
if (!settings)
|
|
12
|
+
return false;
|
|
13
|
+
return Boolean(settings.sandboxMode ||
|
|
14
|
+
settings.approvalPolicy ||
|
|
15
|
+
settings.workspaceWriteNetworkAccess !== undefined ||
|
|
16
|
+
settings.webSearch);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Translate a persona's runtime fields into a concrete `{bin, args}` for
|
|
20
|
+
* spawning an interactive harness session. Pure — no I/O, no side effects.
|
|
21
|
+
*
|
|
22
|
+
* The claude branch always emits `--mcp-config` + `--strict-mcp-config`
|
|
23
|
+
* (with an empty `mcpServers: {}` payload if the persona declares none),
|
|
24
|
+
* so the spawned session only sees the persona's declared MCP servers,
|
|
25
|
+
* never the user's or project's Claude Code config.
|
|
26
|
+
*
|
|
27
|
+
* The codex branch carries the system prompt via `initialPrompt` because
|
|
28
|
+
* codex has no dedicated system-prompt flag today — callers append it as
|
|
29
|
+
* the final positional `[PROMPT]`.
|
|
30
|
+
*
|
|
31
|
+
* The opencode branch routes model + system prompt through opencode's
|
|
32
|
+
* agent abstraction (see https://opencode.ai/config.json: `agent.<id>.{
|
|
33
|
+
* model, prompt, mode }`). It emits an `opencode.json` via `configFiles`
|
|
34
|
+
* for the caller to materialize at cwd, and selects it with `--agent
|
|
35
|
+
* <personaId>`. It deliberately does NOT use `--prompt` (that flag
|
|
36
|
+
* pre-fills the TUI input with a user message) or bare `-m` (opencode
|
|
37
|
+
* expects full `provider/model` form and silently falls back to its
|
|
38
|
+
* default when given a stripped model name). `initialPrompt` is `null`
|
|
39
|
+
* so callers do not append a trailing positional, which opencode would
|
|
40
|
+
* otherwise interpret as a project directory.
|
|
41
|
+
*
|
|
42
|
+
* Both codex and opencode emit a warning if the persona declares
|
|
43
|
+
* `mcpServers` or `permissions` — those features aren't wired for those
|
|
44
|
+
* harnesses yet.
|
|
45
|
+
*/
|
|
46
|
+
export function buildInteractiveSpec(input) {
|
|
47
|
+
const { harness, personaId, model, systemPrompt, mcpServers, permissions, harnessSettings, pluginDirs } = input;
|
|
48
|
+
const warnings = [];
|
|
49
|
+
const hasPluginDirs = pluginDirs !== undefined && pluginDirs.length > 0;
|
|
50
|
+
switch (harness) {
|
|
51
|
+
case 'claude': {
|
|
52
|
+
const mcpPayload = JSON.stringify({ mcpServers: mcpServers ?? {} });
|
|
53
|
+
// Skip --append-system-prompt entirely when the persona's prompt is
|
|
54
|
+
// empty (e.g. an optional task-description input that wasn't
|
|
55
|
+
// forwarded). Personas should keep systemPrompt sparse — the harness
|
|
56
|
+
// already auto-loads CLAUDE.md / AGENTS.md from cwd, so the heavy
|
|
57
|
+
// operating spec lives in the sidecar and the systemPrompt is only
|
|
58
|
+
// worth setting when there's a concrete task to kick off with.
|
|
59
|
+
const args = [
|
|
60
|
+
'--model',
|
|
61
|
+
model,
|
|
62
|
+
...(systemPrompt ? ['--append-system-prompt', systemPrompt] : []),
|
|
63
|
+
'--mcp-config',
|
|
64
|
+
mcpPayload,
|
|
65
|
+
'--strict-mcp-config'
|
|
66
|
+
];
|
|
67
|
+
if (hasPluginDirs) {
|
|
68
|
+
for (const dir of pluginDirs) {
|
|
69
|
+
args.push('--plugin-dir', dir);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (permissions?.allow && permissions.allow.length > 0) {
|
|
73
|
+
args.push('--allowedTools', ...permissions.allow);
|
|
74
|
+
}
|
|
75
|
+
if (permissions?.deny && permissions.deny.length > 0) {
|
|
76
|
+
args.push('--disallowedTools', ...permissions.deny);
|
|
77
|
+
}
|
|
78
|
+
if (permissions?.mode) {
|
|
79
|
+
args.push('--permission-mode', permissions.mode);
|
|
80
|
+
}
|
|
81
|
+
if (hasCodexLaunchSettings(harnessSettings)) {
|
|
82
|
+
warnings.push('persona declares codex-only harnessSettings but the claude harness ignores sandboxMode, approvalPolicy, workspaceWriteNetworkAccess, and webSearch.');
|
|
83
|
+
}
|
|
84
|
+
return { bin: 'claude', args, initialPrompt: null, warnings, configFiles: [] };
|
|
85
|
+
}
|
|
86
|
+
case 'codex': {
|
|
87
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
88
|
+
warnings.push('persona declares mcpServers but the codex harness is not yet wired for runtime MCP injection; proceeding without MCP.');
|
|
89
|
+
}
|
|
90
|
+
if (hasAnyPermission(permissions)) {
|
|
91
|
+
warnings.push('persona declares permissions but the codex harness is not yet wired for runtime permission injection; proceeding with codex defaults.');
|
|
92
|
+
}
|
|
93
|
+
if (hasPluginDirs) {
|
|
94
|
+
warnings.push('pluginDirs is currently claude-only; ignoring under the codex harness. Skills must be staged via codex conventions.');
|
|
95
|
+
}
|
|
96
|
+
const args = ['-m', stripProviderPrefix(model)];
|
|
97
|
+
if (harnessSettings?.sandboxMode) {
|
|
98
|
+
args.push('--sandbox', harnessSettings.sandboxMode);
|
|
99
|
+
}
|
|
100
|
+
if (harnessSettings?.approvalPolicy) {
|
|
101
|
+
args.push('--ask-for-approval', harnessSettings.approvalPolicy);
|
|
102
|
+
}
|
|
103
|
+
if (harnessSettings?.workspaceWriteNetworkAccess !== undefined) {
|
|
104
|
+
args.push('-c', `sandbox_workspace_write.network_access=${String(harnessSettings.workspaceWriteNetworkAccess)}`);
|
|
105
|
+
}
|
|
106
|
+
if (harnessSettings?.webSearch) {
|
|
107
|
+
args.push('--search');
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
bin: 'codex',
|
|
111
|
+
args,
|
|
112
|
+
initialPrompt: systemPrompt,
|
|
113
|
+
warnings,
|
|
114
|
+
configFiles: []
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
case 'opencode': {
|
|
118
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
119
|
+
warnings.push('persona declares mcpServers but the opencode harness is not yet wired for runtime MCP injection; proceeding without MCP.');
|
|
120
|
+
}
|
|
121
|
+
if (hasAnyPermission(permissions)) {
|
|
122
|
+
warnings.push('persona declares permissions but the opencode harness is not yet wired for runtime permission injection; proceeding with opencode defaults.');
|
|
123
|
+
}
|
|
124
|
+
if (hasPluginDirs) {
|
|
125
|
+
warnings.push('pluginDirs is currently claude-only; ignoring under the opencode harness. Skills must be staged via opencode conventions.');
|
|
126
|
+
}
|
|
127
|
+
if (hasCodexLaunchSettings(harnessSettings)) {
|
|
128
|
+
warnings.push('persona declares codex-only harnessSettings but the opencode harness ignores sandboxMode, approvalPolicy, workspaceWriteNetworkAccess, and webSearch.');
|
|
129
|
+
}
|
|
130
|
+
// opencode resolves a persona's system prompt + model through its own
|
|
131
|
+
// "agent" abstraction (see https://opencode.ai/config.json: `agent.<id>.{
|
|
132
|
+
// model, prompt, mode }`). Earlier revisions tried to use `--prompt` for
|
|
133
|
+
// the system prompt and `-m` for the model directly, but that was wrong
|
|
134
|
+
// on two counts:
|
|
135
|
+
// (a) `--prompt` pre-fills the TUI input buffer with a *user* message,
|
|
136
|
+
// not the agent's instructions — the persona's systemPrompt ended
|
|
137
|
+
// up sitting unsent in the chat field.
|
|
138
|
+
// (b) `-m` expects `provider/model` (opencode's own docs); stripping
|
|
139
|
+
// the `opencode/` prefix left just `gpt-5-nano`, which opencode
|
|
140
|
+
// could not resolve and silently fell back to its default model.
|
|
141
|
+
// The correct shape is an `opencode.json` under cwd defining an agent
|
|
142
|
+
// with the persona's prompt + full-provider-form model, selected via
|
|
143
|
+
// `--agent <personaId>` at launch. We emit that file via configFiles
|
|
144
|
+
// so the CLI can drop it into the mount dir before exec.
|
|
145
|
+
// `permission: { '*': 'allow' }` is wildcard-allow across every
|
|
146
|
+
// opencode tool (read / edit / bash / webfetch / etc.), matching the
|
|
147
|
+
// built-in `build` agent's effective permissions. Without this,
|
|
148
|
+
// opencode applies its restrictive default and agent-side edits never
|
|
149
|
+
// reach the mount (the user-visible symptom: "I asked the agent to
|
|
150
|
+
// change files and nothing synced"). The mount already sandboxes
|
|
151
|
+
// writes so wildcard-allow does not escape to the real repo outside
|
|
152
|
+
// of autosync, and callers who want a read-only persona (e.g. a code
|
|
153
|
+
// reviewer) can override this in a follow-up PR that threads a
|
|
154
|
+
// richer permission spec through the persona config — the current
|
|
155
|
+
// harness-kit PersonaPermissions shape is claude-specific and
|
|
156
|
+
// already warned about for opencode.
|
|
157
|
+
//
|
|
158
|
+
// The bare-string form `permission: 'allow'` was valid in older
|
|
159
|
+
// opencode versions but is rejected by 1.14.x: the agent decoder
|
|
160
|
+
// runs `Object.assign({}, $.permission)` before the schema's own
|
|
161
|
+
// string→`{'*': str}` normalizer fires, which spreads the string's
|
|
162
|
+
// indexed chars and then fails validation against
|
|
163
|
+
// `'ask' | 'allow' | 'deny'` ("Expected PermissionActionConfig, got
|
|
164
|
+
// 'a' / 'l' / 'l' / 'o' / 'w'"). Emitting the object form directly
|
|
165
|
+
// avoids that pre-decode step.
|
|
166
|
+
// Omit `prompt` when the persona's systemPrompt is empty so opencode
|
|
167
|
+
// falls back to the AGENTS.md that the harness auto-loads from cwd.
|
|
168
|
+
// Personas should keep systemPrompt sparse — see the claude branch
|
|
169
|
+
// above for the rationale.
|
|
170
|
+
const agentConfig = {
|
|
171
|
+
agent: {
|
|
172
|
+
[personaId]: {
|
|
173
|
+
model,
|
|
174
|
+
...(systemPrompt ? { prompt: systemPrompt } : {}),
|
|
175
|
+
mode: 'primary',
|
|
176
|
+
permission: { '*': 'allow' }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
return {
|
|
181
|
+
bin: 'opencode',
|
|
182
|
+
args: ['--agent', personaId],
|
|
183
|
+
initialPrompt: null,
|
|
184
|
+
warnings,
|
|
185
|
+
configFiles: [
|
|
186
|
+
{
|
|
187
|
+
path: 'opencode.json',
|
|
188
|
+
contents: JSON.stringify(agentConfig, null, 2) + '\n'
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
default: {
|
|
194
|
+
// Exhaustiveness guard: if `Harness` gains a new variant, this
|
|
195
|
+
// assertion will fail to compile and force the maintainer to handle
|
|
196
|
+
// the new case above rather than silently dropping into an untyped
|
|
197
|
+
// fallthrough at runtime.
|
|
198
|
+
const _exhaustive = harness;
|
|
199
|
+
throw new Error(`Unhandled harness: ${String(_exhaustive)}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Translate a persona's runtime into a non-interactive, one-shot command.
|
|
205
|
+
* Layers harness-specific non-interactive flags on top of {@link buildInteractiveSpec},
|
|
206
|
+
* then appends the user task. Pure — no I/O.
|
|
207
|
+
*
|
|
208
|
+
* - `claude`: appends `--print --output-format text [--name <n>] <task>`.
|
|
209
|
+
* - `codex`: prefixes `exec`, appends `--skip-git-repo-check`, then a prompt
|
|
210
|
+
* built from any `initialPrompt` joined with the user task.
|
|
211
|
+
* - `opencode`: prefixes `run`, appends `--model <m> --format default
|
|
212
|
+
* [--dir <cwd>] [--title <n>] <task>`.
|
|
213
|
+
*/
|
|
214
|
+
export function buildNonInteractiveSpec(input) {
|
|
215
|
+
const interactive = buildInteractiveSpec(input);
|
|
216
|
+
switch (input.harness) {
|
|
217
|
+
case 'claude': {
|
|
218
|
+
const args = [...interactive.args, '--print', '--output-format', 'text'];
|
|
219
|
+
if (input.name)
|
|
220
|
+
args.push('--name', input.name);
|
|
221
|
+
args.push(input.task);
|
|
222
|
+
return {
|
|
223
|
+
bin: interactive.bin,
|
|
224
|
+
args,
|
|
225
|
+
configFiles: interactive.configFiles,
|
|
226
|
+
warnings: interactive.warnings
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
case 'codex': {
|
|
230
|
+
const prompt = interactive.initialPrompt
|
|
231
|
+
? `${interactive.initialPrompt}\n\nUser task:\n${input.task}`
|
|
232
|
+
: input.task;
|
|
233
|
+
return {
|
|
234
|
+
bin: interactive.bin,
|
|
235
|
+
args: ['exec', ...interactive.args, '--skip-git-repo-check', prompt],
|
|
236
|
+
configFiles: interactive.configFiles,
|
|
237
|
+
warnings: interactive.warnings
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
case 'opencode': {
|
|
241
|
+
const args = ['run', ...interactive.args, '--model', input.model, '--format', 'default'];
|
|
242
|
+
if (input.workingDirectory)
|
|
243
|
+
args.push('--dir', input.workingDirectory);
|
|
244
|
+
if (input.name)
|
|
245
|
+
args.push('--title', input.name);
|
|
246
|
+
args.push(input.task);
|
|
247
|
+
return {
|
|
248
|
+
bin: interactive.bin,
|
|
249
|
+
args,
|
|
250
|
+
configFiles: interactive.configFiles,
|
|
251
|
+
warnings: interactive.warnings
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
default: {
|
|
255
|
+
const _exhaustive = input.harness;
|
|
256
|
+
throw new Error(`Unhandled harness: ${String(_exhaustive)}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=interactive-spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-spec.js","sourceRoot":"","sources":["../src/interactive-spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-spec.test.d.ts","sourceRoot":"","sources":["../src/interactive-spec.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { buildInteractiveSpec } from './interactive-spec.js';
|
|
4
|
+
test('claude branch always emits --mcp-config + --strict-mcp-config', () => {
|
|
5
|
+
const result = buildInteractiveSpec({
|
|
6
|
+
harness: 'claude',
|
|
7
|
+
personaId: 'test-persona',
|
|
8
|
+
model: 'claude-opus-4-6',
|
|
9
|
+
systemPrompt: 'you are a test'
|
|
10
|
+
});
|
|
11
|
+
assert.equal(result.bin, 'claude');
|
|
12
|
+
assert.equal(result.initialPrompt, null);
|
|
13
|
+
assert.deepEqual(result.warnings, []);
|
|
14
|
+
// Both flags present even with no mcpServers — forces isolation from
|
|
15
|
+
// user/project Claude Code config.
|
|
16
|
+
const args = result.args;
|
|
17
|
+
const mcpIdx = args.indexOf('--mcp-config');
|
|
18
|
+
assert.ok(mcpIdx >= 0, 'expected --mcp-config');
|
|
19
|
+
assert.equal(args[mcpIdx + 1], '{"mcpServers":{}}');
|
|
20
|
+
assert.ok(args.includes('--strict-mcp-config'));
|
|
21
|
+
assert.ok(args.includes('--model'));
|
|
22
|
+
assert.ok(args.includes('--append-system-prompt'));
|
|
23
|
+
});
|
|
24
|
+
test('claude branch serializes resolved mcpServers into the --mcp-config payload', () => {
|
|
25
|
+
const result = buildInteractiveSpec({
|
|
26
|
+
harness: 'claude',
|
|
27
|
+
personaId: 'test-persona',
|
|
28
|
+
model: 'claude-sonnet-4-6',
|
|
29
|
+
systemPrompt: 'x',
|
|
30
|
+
mcpServers: {
|
|
31
|
+
posthog: {
|
|
32
|
+
type: 'http',
|
|
33
|
+
url: 'https://mcp.posthog.com/mcp',
|
|
34
|
+
headers: { Authorization: 'Bearer phx_real' }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const mcpIdx = result.args.indexOf('--mcp-config');
|
|
39
|
+
const payload = JSON.parse(result.args[mcpIdx + 1]);
|
|
40
|
+
assert.deepEqual(payload, {
|
|
41
|
+
mcpServers: {
|
|
42
|
+
posthog: {
|
|
43
|
+
type: 'http',
|
|
44
|
+
url: 'https://mcp.posthog.com/mcp',
|
|
45
|
+
headers: { Authorization: 'Bearer phx_real' }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
test('claude branch translates permissions to flags', () => {
|
|
51
|
+
const result = buildInteractiveSpec({
|
|
52
|
+
harness: 'claude',
|
|
53
|
+
personaId: 'test-persona',
|
|
54
|
+
model: 'claude-opus-4-6',
|
|
55
|
+
systemPrompt: 'x',
|
|
56
|
+
permissions: {
|
|
57
|
+
allow: ['mcp__posthog', 'Bash(git *)'],
|
|
58
|
+
deny: ['Bash(rm -rf *)'],
|
|
59
|
+
mode: 'acceptEdits'
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const args = result.args;
|
|
63
|
+
const allowIdx = args.indexOf('--allowedTools');
|
|
64
|
+
const denyIdx = args.indexOf('--disallowedTools');
|
|
65
|
+
const modeIdx = args.indexOf('--permission-mode');
|
|
66
|
+
assert.ok(allowIdx >= 0 && denyIdx >= 0 && modeIdx >= 0);
|
|
67
|
+
assert.equal(args[allowIdx + 1], 'mcp__posthog');
|
|
68
|
+
assert.equal(args[allowIdx + 2], 'Bash(git *)');
|
|
69
|
+
assert.equal(args[denyIdx + 1], 'Bash(rm -rf *)');
|
|
70
|
+
assert.equal(args[modeIdx + 1], 'acceptEdits');
|
|
71
|
+
});
|
|
72
|
+
test('claude branch omits permission flags when unset or empty', () => {
|
|
73
|
+
const result = buildInteractiveSpec({
|
|
74
|
+
harness: 'claude',
|
|
75
|
+
personaId: 'test-persona',
|
|
76
|
+
model: 'claude-opus-4-6',
|
|
77
|
+
systemPrompt: 'x',
|
|
78
|
+
permissions: { allow: [], deny: [] }
|
|
79
|
+
});
|
|
80
|
+
assert.ok(!result.args.includes('--allowedTools'));
|
|
81
|
+
assert.ok(!result.args.includes('--disallowedTools'));
|
|
82
|
+
assert.ok(!result.args.includes('--permission-mode'));
|
|
83
|
+
});
|
|
84
|
+
test('codex carries system prompt as initial positional; strips provider prefix from model', () => {
|
|
85
|
+
const result = buildInteractiveSpec({
|
|
86
|
+
harness: 'codex',
|
|
87
|
+
personaId: 'test-persona',
|
|
88
|
+
model: 'openai-codex/gpt-5.3-codex',
|
|
89
|
+
systemPrompt: 'system-directive'
|
|
90
|
+
});
|
|
91
|
+
assert.equal(result.bin, 'codex');
|
|
92
|
+
assert.deepEqual(result.args, ['-m', 'gpt-5.3-codex']);
|
|
93
|
+
assert.equal(result.initialPrompt, 'system-directive');
|
|
94
|
+
});
|
|
95
|
+
test('codex translates sandbox harness settings to launch flags', () => {
|
|
96
|
+
const result = buildInteractiveSpec({
|
|
97
|
+
harness: 'codex',
|
|
98
|
+
personaId: 'test-persona',
|
|
99
|
+
model: 'openai-codex/gpt-5.3-codex',
|
|
100
|
+
systemPrompt: 'x',
|
|
101
|
+
harnessSettings: {
|
|
102
|
+
reasoning: 'high',
|
|
103
|
+
timeoutSeconds: 1200,
|
|
104
|
+
sandboxMode: 'workspace-write',
|
|
105
|
+
approvalPolicy: 'on-request',
|
|
106
|
+
workspaceWriteNetworkAccess: true,
|
|
107
|
+
webSearch: true
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
assert.deepEqual(result.args, [
|
|
111
|
+
'-m',
|
|
112
|
+
'gpt-5.3-codex',
|
|
113
|
+
'--sandbox',
|
|
114
|
+
'workspace-write',
|
|
115
|
+
'--ask-for-approval',
|
|
116
|
+
'on-request',
|
|
117
|
+
'-c',
|
|
118
|
+
'sandbox_workspace_write.network_access=true',
|
|
119
|
+
'--search'
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
test('codex warns when mcpServers / permissions are declared', () => {
|
|
123
|
+
const result = buildInteractiveSpec({
|
|
124
|
+
harness: 'codex',
|
|
125
|
+
personaId: 'test-persona',
|
|
126
|
+
model: 'openai-codex/gpt-5.3-codex',
|
|
127
|
+
systemPrompt: 'x',
|
|
128
|
+
mcpServers: { foo: { type: 'http', url: 'https://example.com' } },
|
|
129
|
+
permissions: { allow: ['mcp__foo'] }
|
|
130
|
+
});
|
|
131
|
+
assert.equal(result.warnings.length, 2);
|
|
132
|
+
assert.match(result.warnings[0], /codex harness is not yet wired for runtime MCP/);
|
|
133
|
+
assert.match(result.warnings[1], /codex harness is not yet wired for runtime permission/);
|
|
134
|
+
});
|
|
135
|
+
test('opencode defines a per-persona agent in opencode.json and selects it with --agent', () => {
|
|
136
|
+
const result = buildInteractiveSpec({
|
|
137
|
+
harness: 'opencode',
|
|
138
|
+
personaId: 'test-persona',
|
|
139
|
+
model: 'opencode/minimax-m2.5',
|
|
140
|
+
systemPrompt: 'you are a test'
|
|
141
|
+
});
|
|
142
|
+
assert.equal(result.bin, 'opencode');
|
|
143
|
+
// No --prompt (that flag pre-fills the TUI input with the system prompt as
|
|
144
|
+
// a *user* message) and no bare -m (opencode's -m expects provider/model;
|
|
145
|
+
// earlier code stripped the provider and silently fell back to the default
|
|
146
|
+
// model). Model + system prompt now live in the emitted opencode.json,
|
|
147
|
+
// selected by persona id via --agent.
|
|
148
|
+
assert.deepEqual(result.args, ['--agent', 'test-persona']);
|
|
149
|
+
assert.ok(!result.args.includes('--prompt'));
|
|
150
|
+
assert.ok(!result.args.includes('--model'));
|
|
151
|
+
assert.ok(!result.args.includes('-m'));
|
|
152
|
+
assert.equal(result.initialPrompt, null);
|
|
153
|
+
});
|
|
154
|
+
test('opencode configFiles carries a well-formed opencode.json with the agent definition', () => {
|
|
155
|
+
const result = buildInteractiveSpec({
|
|
156
|
+
harness: 'opencode',
|
|
157
|
+
personaId: 'test-persona',
|
|
158
|
+
model: 'opencode/minimax-m2.5',
|
|
159
|
+
systemPrompt: 'you are a test'
|
|
160
|
+
});
|
|
161
|
+
assert.equal(result.configFiles.length, 1);
|
|
162
|
+
const [file] = result.configFiles;
|
|
163
|
+
assert.equal(file.path, 'opencode.json');
|
|
164
|
+
const parsed = JSON.parse(file.contents);
|
|
165
|
+
assert.deepEqual(parsed, {
|
|
166
|
+
agent: {
|
|
167
|
+
'test-persona': {
|
|
168
|
+
model: 'opencode/minimax-m2.5',
|
|
169
|
+
prompt: 'you are a test',
|
|
170
|
+
mode: 'primary',
|
|
171
|
+
// Wildcard-allow across opencode's tool set — matches the built-in
|
|
172
|
+
// `build` agent. Without this, opencode's restrictive default kept
|
|
173
|
+
// agents from making any edits and autosync had nothing to
|
|
174
|
+
// propagate on exit. Object form (not bare 'allow' string) because
|
|
175
|
+
// opencode 1.14.x's agent-config decoder Object.assigns the value
|
|
176
|
+
// before its string-normalizer runs, which mangles strings into
|
|
177
|
+
// their indexed chars.
|
|
178
|
+
permission: { '*': 'allow' }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
test('claude and codex emit an empty configFiles array', () => {
|
|
184
|
+
const claude = buildInteractiveSpec({
|
|
185
|
+
harness: 'claude',
|
|
186
|
+
personaId: 'test-persona',
|
|
187
|
+
model: 'claude-opus-4-6',
|
|
188
|
+
systemPrompt: 'x'
|
|
189
|
+
});
|
|
190
|
+
assert.deepEqual(claude.configFiles, []);
|
|
191
|
+
const codex = buildInteractiveSpec({
|
|
192
|
+
harness: 'codex',
|
|
193
|
+
personaId: 'test-persona',
|
|
194
|
+
model: 'openai-codex/gpt-5.3-codex',
|
|
195
|
+
systemPrompt: 'x'
|
|
196
|
+
});
|
|
197
|
+
assert.deepEqual(codex.configFiles, []);
|
|
198
|
+
});
|
|
199
|
+
test('claude branch omits --append-system-prompt when systemPrompt is empty', () => {
|
|
200
|
+
// Empty systemPrompt is the persona's signal that no kickoff message is
|
|
201
|
+
// intended (e.g. an optional task input that wasn't forwarded). The
|
|
202
|
+
// harness still auto-loads CLAUDE.md from cwd, so the agent has its
|
|
203
|
+
// operating spec; we just don't want a stray `--append-system-prompt ''`
|
|
204
|
+
// flag steering behavior on every turn.
|
|
205
|
+
const result = buildInteractiveSpec({
|
|
206
|
+
harness: 'claude',
|
|
207
|
+
personaId: 'test-persona',
|
|
208
|
+
model: 'claude-opus-4-6',
|
|
209
|
+
systemPrompt: ''
|
|
210
|
+
});
|
|
211
|
+
assert.ok(!result.args.includes('--append-system-prompt'));
|
|
212
|
+
// strict-mcp still emitted — that's about isolation, not the prompt.
|
|
213
|
+
assert.ok(result.args.includes('--strict-mcp-config'));
|
|
214
|
+
});
|
|
215
|
+
test('opencode omits agent.prompt when systemPrompt is empty', () => {
|
|
216
|
+
const result = buildInteractiveSpec({
|
|
217
|
+
harness: 'opencode',
|
|
218
|
+
personaId: 'test-persona',
|
|
219
|
+
model: 'opencode/minimax-m2.5',
|
|
220
|
+
systemPrompt: ''
|
|
221
|
+
});
|
|
222
|
+
const [file] = result.configFiles;
|
|
223
|
+
const parsed = JSON.parse(file.contents);
|
|
224
|
+
assert.equal(parsed.agent['test-persona'].prompt, undefined);
|
|
225
|
+
assert.equal(parsed.agent['test-persona'].model, 'opencode/minimax-m2.5');
|
|
226
|
+
assert.equal(parsed.agent['test-persona'].mode, 'primary');
|
|
227
|
+
});
|
|
228
|
+
test('codex passes empty systemPrompt through as a falsy initialPrompt', () => {
|
|
229
|
+
// Caller appends initialPrompt only when truthy, so an empty
|
|
230
|
+
// systemPrompt produces a TUI-only launch with no kickoff message.
|
|
231
|
+
const result = buildInteractiveSpec({
|
|
232
|
+
harness: 'codex',
|
|
233
|
+
personaId: 'test-persona',
|
|
234
|
+
model: 'openai-codex/gpt-5.3-codex',
|
|
235
|
+
systemPrompt: ''
|
|
236
|
+
});
|
|
237
|
+
assert.equal(result.initialPrompt, '');
|
|
238
|
+
});
|
|
239
|
+
test('claude branch appends --plugin-dir per entry in pluginDirs', () => {
|
|
240
|
+
const result = buildInteractiveSpec({
|
|
241
|
+
harness: 'claude',
|
|
242
|
+
personaId: 'test-persona',
|
|
243
|
+
model: 'claude-opus-4-6',
|
|
244
|
+
systemPrompt: 'x',
|
|
245
|
+
pluginDirs: ['/tmp/session-a/claude/plugin', '/tmp/session-b/claude/plugin']
|
|
246
|
+
});
|
|
247
|
+
const args = result.args;
|
|
248
|
+
const indices = [];
|
|
249
|
+
args.forEach((a, i) => {
|
|
250
|
+
if (a === '--plugin-dir')
|
|
251
|
+
indices.push(i);
|
|
252
|
+
});
|
|
253
|
+
assert.equal(indices.length, 2);
|
|
254
|
+
assert.equal(args[indices[0] + 1], '/tmp/session-a/claude/plugin');
|
|
255
|
+
assert.equal(args[indices[1] + 1], '/tmp/session-b/claude/plugin');
|
|
256
|
+
assert.deepEqual(result.warnings, []);
|
|
257
|
+
});
|
|
258
|
+
test('claude branch omits --plugin-dir when pluginDirs is empty or absent', () => {
|
|
259
|
+
const withEmpty = buildInteractiveSpec({
|
|
260
|
+
harness: 'claude',
|
|
261
|
+
personaId: 'test-persona',
|
|
262
|
+
model: 'claude-opus-4-6',
|
|
263
|
+
systemPrompt: 'x',
|
|
264
|
+
pluginDirs: []
|
|
265
|
+
});
|
|
266
|
+
const without = buildInteractiveSpec({
|
|
267
|
+
harness: 'claude',
|
|
268
|
+
personaId: 'test-persona',
|
|
269
|
+
model: 'claude-opus-4-6',
|
|
270
|
+
systemPrompt: 'x'
|
|
271
|
+
});
|
|
272
|
+
assert.ok(!withEmpty.args.includes('--plugin-dir'));
|
|
273
|
+
assert.ok(!without.args.includes('--plugin-dir'));
|
|
274
|
+
});
|
|
275
|
+
test('non-claude harnesses warn and ignore pluginDirs', () => {
|
|
276
|
+
const codex = buildInteractiveSpec({
|
|
277
|
+
harness: 'codex',
|
|
278
|
+
personaId: 'test-persona',
|
|
279
|
+
model: 'x',
|
|
280
|
+
systemPrompt: 'x',
|
|
281
|
+
pluginDirs: ['/tmp/session/plugin']
|
|
282
|
+
});
|
|
283
|
+
assert.ok(!codex.args.includes('--plugin-dir'));
|
|
284
|
+
assert.ok(codex.warnings.some((w) => /pluginDirs is currently claude-only/.test(w)));
|
|
285
|
+
const opencode = buildInteractiveSpec({
|
|
286
|
+
harness: 'opencode',
|
|
287
|
+
personaId: 'test-persona',
|
|
288
|
+
model: 'x',
|
|
289
|
+
systemPrompt: 'x',
|
|
290
|
+
pluginDirs: ['/tmp/session/plugin']
|
|
291
|
+
});
|
|
292
|
+
assert.ok(!opencode.args.includes('--plugin-dir'));
|
|
293
|
+
assert.ok(opencode.warnings.some((w) => /pluginDirs is currently claude-only/.test(w)));
|
|
294
|
+
});
|
|
295
|
+
test('warnings are returned, not printed — library consumers route I/O themselves', () => {
|
|
296
|
+
// Ensure no side effects on stderr: if the function wrote to stderr, this
|
|
297
|
+
// test would leak output into the test runner. We just assert the shape.
|
|
298
|
+
const result = buildInteractiveSpec({
|
|
299
|
+
harness: 'codex',
|
|
300
|
+
personaId: 'test-persona',
|
|
301
|
+
model: 'x',
|
|
302
|
+
systemPrompt: 'x',
|
|
303
|
+
mcpServers: { a: { type: 'http', url: 'https://x' } }
|
|
304
|
+
});
|
|
305
|
+
assert.ok(Array.isArray(result.warnings));
|
|
306
|
+
assert.equal(result.warnings.length, 1);
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=interactive-spec.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-spec.test.js","sourceRoot":"","sources":["../src/interactive-spec.test.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { McpServerSpec } from './types.js';
|
|
2
|
+
import { type DroppedRef } from './env-refs.js';
|
|
3
|
+
export interface DroppedMcpServer {
|
|
4
|
+
name: string;
|
|
5
|
+
/** Env var names that couldn't be resolved on the server's structural fields. */
|
|
6
|
+
refs: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface McpResolution {
|
|
9
|
+
/** Servers that resolved cleanly (or with only droppable-field losses). */
|
|
10
|
+
servers: Record<string, McpServerSpec> | undefined;
|
|
11
|
+
/** Non-fatal drops — specific headers / env / args entries whose ref was unset. */
|
|
12
|
+
dropped: DroppedRef[];
|
|
13
|
+
/** Whole servers dropped because a structural field (url, command, any arg) had an unset ref. */
|
|
14
|
+
droppedServers: DroppedMcpServer[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve env-var references inside an `mcpServers` block, policy: lenient.
|
|
18
|
+
*
|
|
19
|
+
* - Headers / env / args entries with an unresolved ref are **dropped** from
|
|
20
|
+
* the result; they surface in `dropped`.
|
|
21
|
+
* - A server whose `url`, `command`, or any `arg` references an unresolved
|
|
22
|
+
* ref is dropped **entirely**; it surfaces in `droppedServers`. Structural
|
|
23
|
+
* fields can't be silently skipped — the server wouldn't launch without
|
|
24
|
+
* them.
|
|
25
|
+
*
|
|
26
|
+
* Literal strings pass through untouched.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveMcpServersLenient(servers: Record<string, McpServerSpec> | undefined, processEnv: NodeJS.ProcessEnv): McpResolution;
|
|
29
|
+
/**
|
|
30
|
+
* Format the dropped-ref tracking from env + MCP resolution into flat,
|
|
31
|
+
* human-readable lines. Callers print them wherever they want — stderr,
|
|
32
|
+
* a logger, a UI toast — the helper itself has no I/O.
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatDropWarnings(envDrops: DroppedRef[], mcpDrops: DroppedRef[], mcpServerDrops: DroppedMcpServer[]): string[];
|
|
35
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,KAAK,UAAU,EAAgD,MAAM,eAAe,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,SAAS,CAAC;IACnD,mFAAmF;IACnF,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,iGAAiG;IACjG,cAAc,EAAE,gBAAgB,EAAE,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,SAAS,EAClD,UAAU,EAAE,MAAM,CAAC,UAAU,GAC5B,aAAa,CA0Df;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,UAAU,EAAE,EACtB,QAAQ,EAAE,UAAU,EAAE,EACtB,cAAc,EAAE,gBAAgB,EAAE,GACjC,MAAM,EAAE,CAcV"}
|