@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.
Files changed (90) hide show
  1. package/README.md +93 -0
  2. package/dist/config-files.d.ts +21 -0
  3. package/dist/config-files.d.ts.map +1 -0
  4. package/dist/config-files.js +81 -0
  5. package/dist/config-files.js.map +1 -0
  6. package/dist/constants.d.ts +20 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +78 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/detect.d.ts +28 -0
  11. package/dist/detect.d.ts.map +1 -0
  12. package/dist/detect.js +63 -0
  13. package/dist/detect.js.map +1 -0
  14. package/dist/env-refs.d.ts +56 -0
  15. package/dist/env-refs.d.ts.map +1 -0
  16. package/dist/env-refs.js +105 -0
  17. package/dist/env-refs.js.map +1 -0
  18. package/dist/env-refs.test.d.ts +2 -0
  19. package/dist/env-refs.test.d.ts.map +1 -0
  20. package/dist/env-refs.test.js +84 -0
  21. package/dist/env-refs.test.js.map +1 -0
  22. package/dist/execute.d.ts +47 -0
  23. package/dist/execute.d.ts.map +1 -0
  24. package/dist/execute.js +68 -0
  25. package/dist/execute.js.map +1 -0
  26. package/dist/execute.test.d.ts +2 -0
  27. package/dist/execute.test.d.ts.map +1 -0
  28. package/dist/execute.test.js +255 -0
  29. package/dist/execute.test.js.map +1 -0
  30. package/dist/index.d.ts +16 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +26 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/index.test.d.ts +2 -0
  35. package/dist/index.test.d.ts.map +1 -0
  36. package/dist/index.test.js +234 -0
  37. package/dist/index.test.js.map +1 -0
  38. package/dist/inputs.d.ts +13 -0
  39. package/dist/inputs.d.ts.map +1 -0
  40. package/dist/inputs.js +57 -0
  41. package/dist/inputs.js.map +1 -0
  42. package/dist/inputs.test.d.ts +2 -0
  43. package/dist/inputs.test.d.ts.map +1 -0
  44. package/dist/inputs.test.js +51 -0
  45. package/dist/inputs.test.js.map +1 -0
  46. package/dist/interactive-spec.d.ts +117 -0
  47. package/dist/interactive-spec.d.ts.map +1 -0
  48. package/dist/interactive-spec.js +260 -0
  49. package/dist/interactive-spec.js.map +1 -0
  50. package/dist/interactive-spec.test.d.ts +2 -0
  51. package/dist/interactive-spec.test.d.ts.map +1 -0
  52. package/dist/interactive-spec.test.js +308 -0
  53. package/dist/interactive-spec.test.js.map +1 -0
  54. package/dist/mcp.d.ts +35 -0
  55. package/dist/mcp.d.ts.map +1 -0
  56. package/dist/mcp.js +86 -0
  57. package/dist/mcp.js.map +1 -0
  58. package/dist/mount.d.ts +44 -0
  59. package/dist/mount.d.ts.map +1 -0
  60. package/dist/mount.js +51 -0
  61. package/dist/mount.js.map +1 -0
  62. package/dist/parse.d.ts +47 -0
  63. package/dist/parse.d.ts.map +1 -0
  64. package/dist/parse.js +475 -0
  65. package/dist/parse.js.map +1 -0
  66. package/dist/plan.d.ts +118 -0
  67. package/dist/plan.d.ts.map +1 -0
  68. package/dist/plan.js +150 -0
  69. package/dist/plan.js.map +1 -0
  70. package/dist/plan.test.d.ts +2 -0
  71. package/dist/plan.test.d.ts.map +1 -0
  72. package/dist/plan.test.js +191 -0
  73. package/dist/plan.test.js.map +1 -0
  74. package/dist/sidecars.d.ts +17 -0
  75. package/dist/sidecars.d.ts.map +1 -0
  76. package/dist/sidecars.js +101 -0
  77. package/dist/sidecars.js.map +1 -0
  78. package/dist/skill-runner.d.ts +30 -0
  79. package/dist/skill-runner.d.ts.map +1 -0
  80. package/dist/skill-runner.js +94 -0
  81. package/dist/skill-runner.js.map +1 -0
  82. package/dist/skills.d.ts +41 -0
  83. package/dist/skills.d.ts.map +1 -0
  84. package/dist/skills.js +322 -0
  85. package/dist/skills.js.map +1 -0
  86. package/dist/types.d.ts +321 -0
  87. package/dist/types.d.ts.map +1 -0
  88. package/dist/types.js +2 -0
  89. package/dist/types.js.map +1 -0
  90. 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"}
@@ -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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=env-refs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-refs.test.d.ts","sourceRoot":"","sources":["../src/env-refs.test.ts"],"names":[],"mappings":""}