@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
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# @agentworkforce/persona-kit
|
|
2
|
+
|
|
3
|
+
Persona-kit owns the AgentWorkforce persona instantiation lifecycle. See tracking issue [#64](https://github.com/AgentWorkforce/workforce/issues/64).
|
|
4
|
+
|
|
5
|
+
## Top-level orchestration API
|
|
6
|
+
|
|
7
|
+
The package exposes a two-phase API: a **pure plan builder** that composes a
|
|
8
|
+
persona's runtime data into a single inspectable value, and a **side-effecting
|
|
9
|
+
executor** that runs the plan and returns a handle that reverses every side
|
|
10
|
+
effect.
|
|
11
|
+
|
|
12
|
+
### Persona JSON → running agent (end-to-end)
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {
|
|
16
|
+
buildPersonaSpawnPlan,
|
|
17
|
+
executePersonaSpawnPlan,
|
|
18
|
+
type ResolvedPersona
|
|
19
|
+
} from '@agentworkforce/persona-kit';
|
|
20
|
+
import { spawn } from 'node:child_process';
|
|
21
|
+
|
|
22
|
+
declare const persona: ResolvedPersona; // from loadPersonas() / personaCatalog
|
|
23
|
+
|
|
24
|
+
// 1. Compose a plan. Pure — no I/O, no subprocesses.
|
|
25
|
+
// PlanOptions: inputValues, envOverrides, processEnv, installRoot.
|
|
26
|
+
// cwd belongs to ExecuteOptions, not the plan builder.
|
|
27
|
+
const plan = buildPersonaSpawnPlan(persona, {
|
|
28
|
+
inputValues: { TASK: 'tidy up the README' }
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// 2. Inspect or stamp the plan if you like — it's JSON-serializable.
|
|
32
|
+
console.log(plan.cli, plan.args, plan.env);
|
|
33
|
+
|
|
34
|
+
// 3. Run the side effects. Returns a handle whose dispose() reverses them.
|
|
35
|
+
const handle = await executePersonaSpawnPlan(plan, { cwd: process.cwd() });
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// 4. Spawn the harness at handle.cwd with plan.cli + plan.args + plan.env.
|
|
39
|
+
await new Promise<void>((resolve, reject) => {
|
|
40
|
+
const child = spawn(plan.cli, plan.args, {
|
|
41
|
+
cwd: handle.cwd,
|
|
42
|
+
env: plan.env,
|
|
43
|
+
stdio: 'inherit'
|
|
44
|
+
});
|
|
45
|
+
child.on('error', reject);
|
|
46
|
+
child.on('close', () => resolve());
|
|
47
|
+
});
|
|
48
|
+
} finally {
|
|
49
|
+
// 5. Tear down: removes installed skills, restores sidecar files,
|
|
50
|
+
// cleans up materialized config files, releases the mount.
|
|
51
|
+
await handle.dispose();
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Plan structure
|
|
56
|
+
|
|
57
|
+
`PersonaSpawnPlan` carries everything a caller needs:
|
|
58
|
+
|
|
59
|
+
- `persona` — the resolved persona (model, harness, skills, env, …).
|
|
60
|
+
- `cli`, `args`, `initialPrompt` — what to spawn.
|
|
61
|
+
- `env` — final environment with input bindings + persona env merged in.
|
|
62
|
+
- `skills` — pure `SkillMaterializationPlan` produced by `materializeSkills`.
|
|
63
|
+
- `mount`, `sidecars`, `configFiles`, `inputs` — resolved pieces ready for
|
|
64
|
+
the executor.
|
|
65
|
+
|
|
66
|
+
The plan is **JSON-serializable** — useful for stamping into launch metadata
|
|
67
|
+
or sending across a wire (e.g. relay's `getPersonaSpawnPlan`).
|
|
68
|
+
|
|
69
|
+
### Piecewise helpers
|
|
70
|
+
|
|
71
|
+
For callers who want their own orchestration:
|
|
72
|
+
|
|
73
|
+
- `applyPersonaMount(mount, options)` — opens an `@relayfile/local-mount`
|
|
74
|
+
sandbox when a mount policy is supplied, no-op otherwise. Returns a handle
|
|
75
|
+
exposing the harness `cwd`.
|
|
76
|
+
- `runSkillInstalls(plan, options)` — spawns the install commands produced
|
|
77
|
+
by `buildInstallArtifacts`. Aborts on the first non-zero exit and attaches
|
|
78
|
+
the buffered subprocess output to `SkillInstallError`.
|
|
79
|
+
- `writePersonaSidecars(sidecars, options)` — writes `CLAUDE.md` /
|
|
80
|
+
`AGENTS.md` with restore-on-dispose semantics.
|
|
81
|
+
- `materializePersonaConfigFiles(configFiles, options)` — writes the harness
|
|
82
|
+
config files (e.g. `opencode.json`) with restore-on-dispose semantics.
|
|
83
|
+
|
|
84
|
+
Each helper returns a handle of shape `{ dispose(): Promise<void> }`.
|
|
85
|
+
`executePersonaSpawnPlan` composes them in order: mount → skills → sidecars
|
|
86
|
+
→ config files. If any step throws, prior handles are disposed in LIFO
|
|
87
|
+
order before the original error propagates.
|
|
88
|
+
|
|
89
|
+
### Pure lower-level helpers
|
|
90
|
+
|
|
91
|
+
`buildInteractiveSpec`, `materializeSkills`, `parsePersonaFile`,
|
|
92
|
+
`resolvePersonaInputs`, etc. remain available for advanced callers who want
|
|
93
|
+
finer control than the plan builder offers.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { InteractiveConfigFile } from './interactive-spec.js';
|
|
2
|
+
export interface PersonaConfigFilesHandle {
|
|
3
|
+
/** Reverse every config-file write. Idempotent. */
|
|
4
|
+
dispose(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Reject paths that would escape the cwd or hit absolute targets — same
|
|
8
|
+
* policy as the CLI's existing `assertSafeRelativePath` so persona-kit's
|
|
9
|
+
* exec helpers can be plugged into the CLI later without weakening the
|
|
10
|
+
* sandbox guarantees.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertSafeRelativePath(relPath: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Materialize each {@link InteractiveConfigFile} under `options.cwd`,
|
|
15
|
+
* creating any missing parent directories. The returned handle restores
|
|
16
|
+
* each touched path to its prior state on `dispose()`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function materializePersonaConfigFiles(configFiles: readonly InteractiveConfigFile[], options: {
|
|
19
|
+
cwd: string;
|
|
20
|
+
}): Promise<PersonaConfigFilesHandle>;
|
|
21
|
+
//# sourceMappingURL=config-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-files.d.ts","sourceRoot":"","sources":["../src/config-files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE,MAAM,WAAW,wBAAwB;IACvC,mDAAmD;IACnD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAe5D;AAWD;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,SAAS,qBAAqB,EAAE,EAC7C,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACvB,OAAO,CAAC,wBAAwB,CAAC,CAuBnC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Reject paths that would escape the cwd or hit absolute targets — same
|
|
5
|
+
* policy as the CLI's existing `assertSafeRelativePath` so persona-kit's
|
|
6
|
+
* exec helpers can be plugged into the CLI later without weakening the
|
|
7
|
+
* sandbox guarantees.
|
|
8
|
+
*/
|
|
9
|
+
export function assertSafeRelativePath(relPath) {
|
|
10
|
+
if (!relPath) {
|
|
11
|
+
throw new Error('configFile path must be a non-empty relative path');
|
|
12
|
+
}
|
|
13
|
+
if (isAbsolute(relPath)) {
|
|
14
|
+
throw new Error(`configFile path must be relative; got absolute path ${JSON.stringify(relPath)}`);
|
|
15
|
+
}
|
|
16
|
+
const segments = relPath.split(/[\\/]+/);
|
|
17
|
+
if (segments.some((s) => s === '..')) {
|
|
18
|
+
throw new Error(`configFile path must not contain ".." segments; got ${JSON.stringify(relPath)}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function readIfExists(path) {
|
|
22
|
+
try {
|
|
23
|
+
return await readFile(path, 'utf8');
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err.code === 'ENOENT')
|
|
27
|
+
return null;
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Materialize each {@link InteractiveConfigFile} under `options.cwd`,
|
|
33
|
+
* creating any missing parent directories. The returned handle restores
|
|
34
|
+
* each touched path to its prior state on `dispose()`.
|
|
35
|
+
*/
|
|
36
|
+
export async function materializePersonaConfigFiles(configFiles, options) {
|
|
37
|
+
const restored = [];
|
|
38
|
+
let disposed = false;
|
|
39
|
+
try {
|
|
40
|
+
for (const file of configFiles) {
|
|
41
|
+
assertSafeRelativePath(file.path);
|
|
42
|
+
const target = join(options.cwd, file.path);
|
|
43
|
+
const prior = await readIfExists(target);
|
|
44
|
+
restored.push({ path: target, prior });
|
|
45
|
+
await mkdir(dirname(target), { recursive: true });
|
|
46
|
+
await writeFile(target, file.contents, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
await disposeRestored(restored);
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
async dispose() {
|
|
55
|
+
if (disposed)
|
|
56
|
+
return;
|
|
57
|
+
disposed = true;
|
|
58
|
+
await disposeRestored(restored);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async function disposeRestored(restored) {
|
|
63
|
+
for (let i = restored.length - 1; i >= 0; i -= 1) {
|
|
64
|
+
const entry = restored[i];
|
|
65
|
+
try {
|
|
66
|
+
if (entry.prior === null) {
|
|
67
|
+
await unlink(entry.path).catch((err) => {
|
|
68
|
+
if (err.code !== 'ENOENT')
|
|
69
|
+
throw err;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
await writeFile(entry.path, entry.prior, 'utf8');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Best-effort.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=config-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-files.js","sourceRoot":"","sources":["../src/config-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Harness, HarnessSkillTarget } from './types.js';
|
|
2
|
+
export declare const HARNESS_VALUES: readonly ["opencode", "codex", "claude"];
|
|
3
|
+
export declare const PERSONA_TIERS: readonly ["best", "best-value", "minimum"];
|
|
4
|
+
export declare const PERSONA_TAGS: readonly ["planning", "implementation", "review", "testing", "debugging", "documentation", "release", "discovery", "analytics"];
|
|
5
|
+
export declare const PERSONA_INTENTS: readonly ["implement-frontend", "review", "architecture-plan", "requirements-analysis", "debugging", "security-review", "documentation", "verification", "test-strategy", "tdd-enforcement", "flake-investigation", "opencode-workflow-correctness", "npm-provenance", "cloud-sandbox-infra", "sage-slack-egress-migration", "sage-proactive-rewire", "cloud-slack-proxy-guard", "sage-cloud-e2e-conduction", "capability-discovery", "npm-package-compat", "posthog", "persona-authoring", "persona-improvement", "agent-relay-workflow", "slop-audit", "api-contract-review", "local-stack-orchestration", "e2e-validation", "write-integration-tests", "relay-orchestrator"];
|
|
6
|
+
export declare const BUILT_IN_PERSONA_INTENTS: readonly ["persona-authoring", "persona-improvement"];
|
|
7
|
+
export declare const CODEX_SANDBOX_MODES: readonly ["read-only", "workspace-write", "danger-full-access"];
|
|
8
|
+
export declare const CODEX_APPROVAL_POLICIES: readonly ["untrusted", "on-failure", "on-request", "never"];
|
|
9
|
+
/**
|
|
10
|
+
* Sidecar markdown delivery mode. `overwrite` writes only the persona's
|
|
11
|
+
* resolved markdown into the harness's mount file. `extend` reads the
|
|
12
|
+
* caller's real-cwd file (if any) and prepends it to the persona content,
|
|
13
|
+
* separated by `\n\n---\n\n`. With no real-cwd file `extend` degrades to
|
|
14
|
+
* `overwrite` semantics — the persona content lands alone.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SIDECAR_MD_MODES: readonly ["overwrite", "extend"];
|
|
17
|
+
export declare const PERMISSION_MODES: readonly ["default", "acceptEdits", "bypassPermissions", "plan"];
|
|
18
|
+
export declare const SKILL_SOURCE_KINDS: readonly ["prpm", "skill.sh"];
|
|
19
|
+
export declare const HARNESS_SKILL_TARGETS: Record<Harness, HarnessSkillTarget>;
|
|
20
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE9D,eAAO,MAAM,cAAc,0CAA2C,CAAC;AACvE,eAAO,MAAM,aAAa,4CAA6C,CAAC;AACxE,eAAO,MAAM,YAAY,iIAUf,CAAC;AACX,eAAO,MAAM,eAAe,ipBA+BlB,CAAC;AAEX,eAAO,MAAM,wBAAwB,uDAAwD,CAAC;AAE9F,eAAO,MAAM,mBAAmB,iEAItB,CAAC;AAEX,eAAO,MAAM,uBAAuB,6DAK1B,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,kCAAmC,CAAC;AAEjE,eAAO,MAAM,gBAAgB,kEAKnB,CAAC;AAEX,eAAO,MAAM,kBAAkB,+BAAgC,CAAC;AAEhE,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAIrE,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const HARNESS_VALUES = ['opencode', 'codex', 'claude'];
|
|
2
|
+
export const PERSONA_TIERS = ['best', 'best-value', 'minimum'];
|
|
3
|
+
export const PERSONA_TAGS = [
|
|
4
|
+
'planning',
|
|
5
|
+
'implementation',
|
|
6
|
+
'review',
|
|
7
|
+
'testing',
|
|
8
|
+
'debugging',
|
|
9
|
+
'documentation',
|
|
10
|
+
'release',
|
|
11
|
+
'discovery',
|
|
12
|
+
'analytics'
|
|
13
|
+
];
|
|
14
|
+
export const PERSONA_INTENTS = [
|
|
15
|
+
'implement-frontend',
|
|
16
|
+
'review',
|
|
17
|
+
'architecture-plan',
|
|
18
|
+
'requirements-analysis',
|
|
19
|
+
'debugging',
|
|
20
|
+
'security-review',
|
|
21
|
+
'documentation',
|
|
22
|
+
'verification',
|
|
23
|
+
'test-strategy',
|
|
24
|
+
'tdd-enforcement',
|
|
25
|
+
'flake-investigation',
|
|
26
|
+
'opencode-workflow-correctness',
|
|
27
|
+
'npm-provenance',
|
|
28
|
+
'cloud-sandbox-infra',
|
|
29
|
+
'sage-slack-egress-migration',
|
|
30
|
+
'sage-proactive-rewire',
|
|
31
|
+
'cloud-slack-proxy-guard',
|
|
32
|
+
'sage-cloud-e2e-conduction',
|
|
33
|
+
'capability-discovery',
|
|
34
|
+
'npm-package-compat',
|
|
35
|
+
'posthog',
|
|
36
|
+
'persona-authoring',
|
|
37
|
+
'persona-improvement',
|
|
38
|
+
'agent-relay-workflow',
|
|
39
|
+
'slop-audit',
|
|
40
|
+
'api-contract-review',
|
|
41
|
+
'local-stack-orchestration',
|
|
42
|
+
'e2e-validation',
|
|
43
|
+
'write-integration-tests',
|
|
44
|
+
'relay-orchestrator'
|
|
45
|
+
];
|
|
46
|
+
export const BUILT_IN_PERSONA_INTENTS = ['persona-authoring', 'persona-improvement'];
|
|
47
|
+
export const CODEX_SANDBOX_MODES = [
|
|
48
|
+
'read-only',
|
|
49
|
+
'workspace-write',
|
|
50
|
+
'danger-full-access'
|
|
51
|
+
];
|
|
52
|
+
export const CODEX_APPROVAL_POLICIES = [
|
|
53
|
+
'untrusted',
|
|
54
|
+
'on-failure',
|
|
55
|
+
'on-request',
|
|
56
|
+
'never'
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Sidecar markdown delivery mode. `overwrite` writes only the persona's
|
|
60
|
+
* resolved markdown into the harness's mount file. `extend` reads the
|
|
61
|
+
* caller's real-cwd file (if any) and prepends it to the persona content,
|
|
62
|
+
* separated by `\n\n---\n\n`. With no real-cwd file `extend` degrades to
|
|
63
|
+
* `overwrite` semantics — the persona content lands alone.
|
|
64
|
+
*/
|
|
65
|
+
export const SIDECAR_MD_MODES = ['overwrite', 'extend'];
|
|
66
|
+
export const PERMISSION_MODES = [
|
|
67
|
+
'default',
|
|
68
|
+
'acceptEdits',
|
|
69
|
+
'bypassPermissions',
|
|
70
|
+
'plan'
|
|
71
|
+
];
|
|
72
|
+
export const SKILL_SOURCE_KINDS = ['prpm', 'skill.sh'];
|
|
73
|
+
export const HARNESS_SKILL_TARGETS = {
|
|
74
|
+
claude: { asFlag: 'claude', dir: '.claude/skills' },
|
|
75
|
+
codex: { asFlag: 'codex', dir: '.agents/skills' },
|
|
76
|
+
opencode: { asFlag: 'opencode', dir: '.skills' }
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AACvE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,CAAU,CAAC;AACxE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU;IACV,gBAAgB;IAChB,QAAQ;IACR,SAAS;IACT,WAAW;IACX,eAAe;IACf,SAAS;IACT,WAAW;IACX,WAAW;CACH,CAAC;AACX,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,oBAAoB;IACpB,QAAQ;IACR,mBAAmB;IACnB,uBAAuB;IACvB,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,cAAc;IACd,eAAe;IACf,iBAAiB;IACjB,qBAAqB;IACrB,+BAA+B;IAC/B,gBAAgB;IAChB,qBAAqB;IACrB,6BAA6B;IAC7B,uBAAuB;IACvB,yBAAyB;IACzB,2BAA2B;IAC3B,sBAAsB;IACtB,oBAAoB;IACpB,SAAS;IACT,mBAAmB;IACnB,qBAAqB;IACrB,sBAAsB;IACtB,YAAY;IACZ,qBAAqB;IACrB,2BAA2B;IAC3B,gBAAgB;IAChB,yBAAyB;IACzB,oBAAoB;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,mBAAmB,EAAE,qBAAqB,CAAU,CAAC;AAE9F,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,WAAW;IACX,iBAAiB;IACjB,oBAAoB;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,OAAO;CACC,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAU,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,SAAS;IACT,aAAa;IACb,mBAAmB;IACnB,MAAM;CACE,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,UAAU,CAAU,CAAC;AAEhE,MAAM,CAAC,MAAM,qBAAqB,GAAwC;IACxE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,gBAAgB,EAAE;IACnD,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE;IACjD,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE;CACjD,CAAC"}
|
package/dist/detect.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Harness } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Result of probing a harness binary on the caller's machine.
|
|
4
|
+
*
|
|
5
|
+
* `available` is true iff the binary was found on PATH *and* responded to
|
|
6
|
+
* `--version` with exit code 0. `path` is populated whenever we located the
|
|
7
|
+
* binary, even if it failed to run — useful for diagnosing a broken install
|
|
8
|
+
* vs. a missing one.
|
|
9
|
+
*/
|
|
10
|
+
export interface HarnessAvailability {
|
|
11
|
+
harness: Harness;
|
|
12
|
+
available: boolean;
|
|
13
|
+
version?: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Probe a single harness binary: locate it on PATH and run `<bin> --version`.
|
|
19
|
+
* Returns a typed availability record — never throws.
|
|
20
|
+
*/
|
|
21
|
+
export declare function detectHarness(harness: Harness, options?: {
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
}): HarnessAvailability;
|
|
24
|
+
/** Probe every known harness in `HARNESS_VALUES`. */
|
|
25
|
+
export declare function detectHarnesses(options?: {
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
}): HarnessAvailability[];
|
|
28
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsBD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,mBAAmB,CA6BrB;AAED,qDAAqD;AACrD,wBAAgB,eAAe,CAC7B,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,mBAAmB,EAAE,CAEvB"}
|
package/dist/detect.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { delimiter, join } from 'node:path';
|
|
4
|
+
import { HARNESS_VALUES } from './constants.js';
|
|
5
|
+
function findOnPath(bin) {
|
|
6
|
+
const pathEnv = process.env.PATH ?? '';
|
|
7
|
+
const pathExt = process.platform === 'win32'
|
|
8
|
+
? (process.env.PATHEXT ?? '.EXE;.CMD;.BAT').split(';')
|
|
9
|
+
: [''];
|
|
10
|
+
for (const dir of pathEnv.split(delimiter)) {
|
|
11
|
+
if (!dir)
|
|
12
|
+
continue;
|
|
13
|
+
for (const ext of pathExt) {
|
|
14
|
+
const candidate = join(dir, bin + ext);
|
|
15
|
+
try {
|
|
16
|
+
if (statSync(candidate).isFile())
|
|
17
|
+
return candidate;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Not found or unreadable; keep scanning.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Probe a single harness binary: locate it on PATH and run `<bin> --version`.
|
|
28
|
+
* Returns a typed availability record — never throws.
|
|
29
|
+
*/
|
|
30
|
+
export function detectHarness(harness, options = {}) {
|
|
31
|
+
const timeoutMs = options.timeoutMs ?? 3000;
|
|
32
|
+
const path = findOnPath(harness);
|
|
33
|
+
if (!path) {
|
|
34
|
+
return { harness, available: false, error: 'not found on PATH' };
|
|
35
|
+
}
|
|
36
|
+
const res = spawnSync(harness, ['--version'], {
|
|
37
|
+
timeout: timeoutMs,
|
|
38
|
+
encoding: 'utf8',
|
|
39
|
+
shell: false
|
|
40
|
+
});
|
|
41
|
+
if (res.error) {
|
|
42
|
+
return { harness, available: false, path, error: res.error.message };
|
|
43
|
+
}
|
|
44
|
+
if (res.status !== 0) {
|
|
45
|
+
const combined = `${res.stdout ?? ''}${res.stderr ?? ''}`.trim();
|
|
46
|
+
const firstLine = combined.split('\n')[0];
|
|
47
|
+
return {
|
|
48
|
+
harness,
|
|
49
|
+
available: false,
|
|
50
|
+
path,
|
|
51
|
+
error: `--version exited ${res.status}${firstLine ? `: ${firstLine}` : ''}`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const version = (res.stdout ?? '').trim().split('\n')[0] ||
|
|
55
|
+
(res.stderr ?? '').trim().split('\n')[0] ||
|
|
56
|
+
undefined;
|
|
57
|
+
return { harness, available: true, path, version };
|
|
58
|
+
}
|
|
59
|
+
/** Probe every known harness in `HARNESS_VALUES`. */
|
|
60
|
+
export function detectHarnesses(options = {}) {
|
|
61
|
+
return HARNESS_VALUES.map((h) => detectHarness(h, options));
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve env references in persona `env` / `mcpServers` values against the
|
|
3
|
+
* caller's process environment. Two reference forms are supported:
|
|
4
|
+
*
|
|
5
|
+
* "$VAR" whole-string reference; replaced by the env var value.
|
|
6
|
+
* "Bearer ${VAR}" braced reference(s), interpolated anywhere in the
|
|
7
|
+
* string. Useful for header prefixes like `Bearer …`.
|
|
8
|
+
*
|
|
9
|
+
* Bare `$VAR` that appears *inside* a longer string (without braces) is kept
|
|
10
|
+
* as a literal — we only interpolate when the intent is unambiguous, so a
|
|
11
|
+
* literal `$` in a JSON string doesn't accidentally get eaten.
|
|
12
|
+
*
|
|
13
|
+
* A missing env var is a hard error naming both the referenced variable and
|
|
14
|
+
* the persona field that asked for it.
|
|
15
|
+
*/
|
|
16
|
+
export type EnvRefResolver = (value: string) => string;
|
|
17
|
+
export declare class MissingEnvRefError extends Error {
|
|
18
|
+
readonly ref: string;
|
|
19
|
+
readonly referencedBy: string;
|
|
20
|
+
constructor(ref: string, referencedBy: string);
|
|
21
|
+
}
|
|
22
|
+
export declare function makeEnvRefResolver(processEnv: NodeJS.ProcessEnv): (value: string, field: string) => string;
|
|
23
|
+
export declare function resolveStringMap(map: Record<string, string> | undefined, processEnv: NodeJS.ProcessEnv, fieldPrefix: string): Record<string, string> | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Like {@link makeEnvRefResolver} but never throws on missing refs. Returns
|
|
26
|
+
* a result object the caller can inspect to decide whether a missing ref is
|
|
27
|
+
* fatal (e.g. a `url` / `command`) or droppable (e.g. a specific header).
|
|
28
|
+
*/
|
|
29
|
+
export type LenientResult = {
|
|
30
|
+
ok: true;
|
|
31
|
+
value: string;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
field: string;
|
|
35
|
+
ref: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function makeLenientResolver(processEnv: NodeJS.ProcessEnv): (value: string, field: string) => LenientResult;
|
|
38
|
+
export interface DroppedRef {
|
|
39
|
+
field: string;
|
|
40
|
+
ref: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Walk a `Record<string,string>`, resolving each value leniently. Entries
|
|
44
|
+
* whose value referenced an unset env var are dropped from the result and
|
|
45
|
+
* reported via `dropped`. Literal strings and successfully-resolved refs
|
|
46
|
+
* pass through to `value`.
|
|
47
|
+
*
|
|
48
|
+
* Returns `value: undefined` when every entry was either dropped or the map
|
|
49
|
+
* itself was undefined — callers can use that to decide whether to emit a
|
|
50
|
+
* flag at all.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveStringMapLenient(map: Record<string, string> | undefined, processEnv: NodeJS.ProcessEnv, fieldPrefix: string): {
|
|
53
|
+
value: Record<string, string> | undefined;
|
|
54
|
+
dropped: DroppedRef[];
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=env-refs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-refs.d.ts","sourceRoot":"","sources":["../src/env-refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;AAKvD,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAClB,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAQ9C;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,GAAG,CACjE,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,MAAM,CAsBV;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACvC,UAAU,EAAE,MAAM,CAAC,UAAU,EAC7B,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAQpC;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,UAAU,GAC5B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,aAAa,CAYjD;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACvC,UAAU,EAAE,MAAM,CAAC,UAAU,EAC7B,WAAW,EAAE,MAAM,GAClB;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAkBtE"}
|
package/dist/env-refs.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve env references in persona `env` / `mcpServers` values against the
|
|
3
|
+
* caller's process environment. Two reference forms are supported:
|
|
4
|
+
*
|
|
5
|
+
* "$VAR" whole-string reference; replaced by the env var value.
|
|
6
|
+
* "Bearer ${VAR}" braced reference(s), interpolated anywhere in the
|
|
7
|
+
* string. Useful for header prefixes like `Bearer …`.
|
|
8
|
+
*
|
|
9
|
+
* Bare `$VAR` that appears *inside* a longer string (without braces) is kept
|
|
10
|
+
* as a literal — we only interpolate when the intent is unambiguous, so a
|
|
11
|
+
* literal `$` in a JSON string doesn't accidentally get eaten.
|
|
12
|
+
*
|
|
13
|
+
* A missing env var is a hard error naming both the referenced variable and
|
|
14
|
+
* the persona field that asked for it.
|
|
15
|
+
*/
|
|
16
|
+
const WHOLE_REF = /^\$([A-Z_][A-Z0-9_]*)$/;
|
|
17
|
+
const BRACED_REF = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
18
|
+
export class MissingEnvRefError extends Error {
|
|
19
|
+
ref;
|
|
20
|
+
referencedBy;
|
|
21
|
+
constructor(ref, referencedBy) {
|
|
22
|
+
super(`Environment variable ${ref} is required by persona field \`${referencedBy}\` but is not set in the current shell. Export it and retry.`);
|
|
23
|
+
this.name = 'MissingEnvRefError';
|
|
24
|
+
this.ref = ref;
|
|
25
|
+
this.referencedBy = referencedBy;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function makeEnvRefResolver(processEnv) {
|
|
29
|
+
return (value, field) => {
|
|
30
|
+
const whole = WHOLE_REF.exec(value);
|
|
31
|
+
if (whole) {
|
|
32
|
+
const name = whole[1];
|
|
33
|
+
const resolved = processEnv[name];
|
|
34
|
+
if (resolved === undefined || resolved === '') {
|
|
35
|
+
throw new MissingEnvRefError(name, field);
|
|
36
|
+
}
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
if (!value.includes('${'))
|
|
40
|
+
return value;
|
|
41
|
+
return value.replace(BRACED_REF, (_, name) => {
|
|
42
|
+
const resolved = processEnv[name];
|
|
43
|
+
if (resolved === undefined || resolved === '') {
|
|
44
|
+
throw new MissingEnvRefError(name, field);
|
|
45
|
+
}
|
|
46
|
+
return resolved;
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function resolveStringMap(map, processEnv, fieldPrefix) {
|
|
51
|
+
if (!map)
|
|
52
|
+
return undefined;
|
|
53
|
+
const resolve = makeEnvRefResolver(processEnv);
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [key, value] of Object.entries(map)) {
|
|
56
|
+
out[key] = resolve(value, `${fieldPrefix}.${key}`);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
export function makeLenientResolver(processEnv) {
|
|
61
|
+
const strict = makeEnvRefResolver(processEnv);
|
|
62
|
+
return (value, field) => {
|
|
63
|
+
try {
|
|
64
|
+
return { ok: true, value: strict(value, field) };
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (err instanceof MissingEnvRefError) {
|
|
68
|
+
return { ok: false, field, ref: err.ref };
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Walk a `Record<string,string>`, resolving each value leniently. Entries
|
|
76
|
+
* whose value referenced an unset env var are dropped from the result and
|
|
77
|
+
* reported via `dropped`. Literal strings and successfully-resolved refs
|
|
78
|
+
* pass through to `value`.
|
|
79
|
+
*
|
|
80
|
+
* Returns `value: undefined` when every entry was either dropped or the map
|
|
81
|
+
* itself was undefined — callers can use that to decide whether to emit a
|
|
82
|
+
* flag at all.
|
|
83
|
+
*/
|
|
84
|
+
export function resolveStringMapLenient(map, processEnv, fieldPrefix) {
|
|
85
|
+
if (!map)
|
|
86
|
+
return { value: undefined, dropped: [] };
|
|
87
|
+
const resolve = makeLenientResolver(processEnv);
|
|
88
|
+
const out = {};
|
|
89
|
+
const dropped = [];
|
|
90
|
+
for (const [key, raw] of Object.entries(map)) {
|
|
91
|
+
const field = `${fieldPrefix}.${key}`;
|
|
92
|
+
const result = resolve(raw, field);
|
|
93
|
+
if (result.ok) {
|
|
94
|
+
out[key] = result.value;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
dropped.push({ field: result.field, ref: result.ref });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
value: Object.keys(out).length > 0 ? out : undefined,
|
|
102
|
+
dropped
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=env-refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-refs.js","sourceRoot":"","sources":["../src/env-refs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-refs.test.d.ts","sourceRoot":"","sources":["../src/env-refs.test.ts"],"names":[],"mappings":""}
|