model-orchestrator 1.0.7 → 1.0.9

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/AGENTS.md CHANGED
@@ -25,14 +25,20 @@ When using the Claude Code plugin, follow [plugin/README.md](plugin/README.md).
25
25
 
26
26
  ## Change this repository
27
27
 
28
- - **Read first:** `CONTRIBUTING.md`, `src/README.md` and `docs/security-review-history.md`.
28
+ - **Read first:** `CONTRIBUTING.md`, `src/README.md`, `SECURITY.md` (security scope) and `docs/security-review-history.md`.
29
29
  - **Catalog:** when adding an AI or companion, edit `src/catalog.js`; keep templates free of logic.
30
30
  - **Templates:** when changing installed instructions, edit `templates/`. Use public terms: task brief, context file, acceptance checks, definition of done and result.
31
- - **Generated files:** run `npm run gen:catalog` after catalog changes and `npm run gen:plugin` after plugin-template changes. `test/plugin.test.js` checks the committed bundle.
31
+ - **Generated files:** run `npm run gen:catalog` after catalog changes and `npm run gen:plugin` after plugin-template changes. `plugin/` is generated from `templates/`; only `plugin/README.md` and `plugin/hooks/hooks.json` are hand-owned. `test/plugin.test.js` fails on drift. Before a release, `claude plugin validate --strict plugin` must pass.
32
+ Run `npm run gen:agensi` after template changes; `agensi/` is generated, only `templates/agensi/` is hand-owned.
32
33
  - **Plugin safety:** hooks may only read and emit context. No network, file writes, subprocesses or credential access.
33
- - **Installer safety:** writes remain inside `--dir` and `--project`; preserve user edits according to manifest hashes and explicit flags. Run no third-party installer.
34
- - **Runner safety:** preserve exit codes and the log schema. Before changing an output judge, add a failing case in `test/judges.test.js`.
34
+ - **Installer safety:** `bin/cli.js` writes only inside `--dir` and `--project`, refuses home-level agent configuration and runs no third-party installer or vendor script.
35
+ - **Installer ownership:** existing documents stay unless `--force` replaces them or `--update-docs` verifies their recorded hash. Machine-owned configuration refreshes, unchanged managed runtime files upgrade, and `--upgrade-runtime` explicitly replaces runtime files. Project activation merges supported entries with backups. Preserve these rules; `test/install.test.js` and `test/cli.test.js` check them.
36
+ - **Runner safety:** preserve exit codes and the log schema. `bin/cli-run.mjs` exits non-zero when a lane produced nothing. Every judge has a red case in `test/judges.test.js`; add one before changing a judge.
37
+ - **Systemd:** when touching `templates/advanced/vm/jobs/`, run `test/systemd/run-on-ubuntu.sh` by hand on a Linux host with systemd to check `TimeoutStartSec` and `KillMode`. This check sits outside `npm test`; follow `test/systemd/README.md`.
38
+ - **Fixtures:** `test/fixtures/` is real vendor output. When a vendor upgrade changes a shape, capture again at the new version and update `manifest.json` and the README compatibility table together.
35
39
  - **Secrets:** use environment-variable names only. Never add a credential value to code, examples or tests.
36
40
  - **Proof:** measure through `proof/scripts/`, store results in `proof/results.json` and regenerate the proof page. An expired entry warns and is re-measured; it never blocks tests or releases.
37
- - **Verify:** run `npm test` and report tests, pass, fail, skipped and exit code. The suite prints current counts. Use `npm pack --dry-run` to inspect publication contents.
41
+ - **Verify:** before proposing a change, run `npm test` and report tests, pass, fail, skipped and exit code. The suite prints current counts. Use `npm pack --dry-run` to inspect publication contents.
38
42
  - **Style:** use short condition-to-action instructions and no em dashes. `test/prose.test.js` checks public vocabulary and examples.
43
+
44
+ Each rule is the fix for a failure that reached an audit or CI. `CHANGELOG.md` names the issue behind each.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ All notable changes to this project are documented here. The format follows [Kee
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.0.9] - 2026-10-04
8
+
9
+ ### Added
10
+
11
+ - Generate standalone beginner and intermediate Agensi skill packs from shared templates, with setup guidance, the bundled intermediate runner, zip packaging and drift checks.
12
+
13
+ ### Changed
14
+
15
+ - LICENSE names Auny LLC as copyright holder; outside contributions now require the CLA in CLA.md.
16
+
17
+ ## [1.0.8] - 2026-09-30
18
+
19
+ ### Changed
20
+
21
+ - AGENTS.md is the single source of agent instructions. CLAUDE.md imports it so Claude Code loads the same rules as every other agent.
22
+ - Merge the contributor rules that had diverged between AGENTS.md and CLAUDE.md.
23
+ - The feature request form asks for an observable success check.
24
+
7
25
  ## [1.0.7] - 2026-09-30
8
26
 
9
27
  ### Fixed
@@ -587,7 +605,9 @@ First release.
587
605
  - Tests: a case per fix, judges proven to go red, mutation checks; `npm test` prints the current count.
588
606
  - Adversarial audit: two Codex rounds plus a two-engine review (Codex, Antigravity); findings and fixes in `docs/audit-brief.md`. After the review: subagents go to the project root (`--project`), snippet paths computed from `--dir`, lane sections rendered from the selection, a primary agent required, level 3 asks for API keys separately from CLIs, images and CLI installs pinned, an activation summary at the end of every install.
589
607
 
590
- [Unreleased]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.7...HEAD
608
+ [Unreleased]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.9...HEAD
609
+ [1.0.9]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.8...v1.0.9
610
+ [1.0.8]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.7...v1.0.8
591
611
  [1.0.7]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.6...v1.0.7
592
612
  [1.0.6]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.5...v1.0.6
593
613
  [1.0.5]: https://github.com/aunysillyme/model-orchestrator/compare/v1.0.4...v1.0.5
package/CLA.md ADDED
@@ -0,0 +1,37 @@
1
+ # Contributor License Agreement
2
+
3
+ This agreement lets Auny LLC accept your contribution and keep the project's licensing options open, while you keep the copyright in what you wrote. It is adapted from the Apache Software Foundation's Individual Contributor License Agreement v2.2.
4
+
5
+ To agree, tick the Contributor License Agreement box in your pull request description. The box is the record of your agreement for that pull request and every later change you push to it.
6
+
7
+ ## 1. Definitions
8
+
9
+ - **"You"** means the person or legal entity submitting a Contribution.
10
+ - **"Contribution"** means any original work of authorship, including any changes or additions to existing work, that You intentionally submit to Auny LLC for inclusion in this project, through a pull request, an issue, a comment or any other channel Auny LLC uses to discuss or manage the project.
11
+ - **"Auny LLC"** means Auny LLC, a New York limited liability company, the owner and maintainer of this project.
12
+
13
+ ## 2. Copyright license
14
+
15
+ You grant Auny LLC, and recipients of software distributed by Auny LLC, a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute Your Contributions and such derivative works, under any license terms, including open source and commercial terms.
16
+
17
+ ## 3. Patent license
18
+
19
+ You grant Auny LLC, and recipients of software distributed by Auny LLC, a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the work, where the license applies only to patent claims licensable by You that are necessarily infringed by Your Contribution alone or by its combination with the work to which it was submitted. If any entity starts patent litigation alleging that Your Contribution, or the work it was submitted to, infringes a patent, the patent licenses granted to that entity under this agreement for that Contribution or work end on the date the litigation is filed.
20
+
21
+ ## 4. Your rights
22
+
23
+ You keep the copyright in Your Contributions. Apart from the licenses granted above, You reserve all rights, and You may use Your Contributions for any other purpose.
24
+
25
+ ## 5. Your promises
26
+
27
+ - You are legally entitled to grant these licenses. If your employer has rights to intellectual property you create, You have permission to make the Contribution on its behalf, or your employer has waived those rights.
28
+ - Each Contribution is Your original creation. When it includes third-party material, You identify that material and its license in the pull request.
29
+ - You will tell Auny LLC if any of these promises stops being accurate.
30
+
31
+ ## 6. No warranty
32
+
33
+ You provide Your Contributions "as is", without warranties or conditions of any kind, including warranties of title, non-infringement, merchantability or fitness for a particular purpose. You are not expected to provide support for Your Contributions.
34
+
35
+ ## 7. Trademarks
36
+
37
+ This agreement grants no rights in the names, logos or trademarks of Auny LLC, including "Auny", "AunySillyMe" and the project's name.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 model-orchestrator contributors
3
+ Copyright (c) 2026 Auny LLC and contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "model-orchestrator",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Model router for AI coding agents: installs routing rules, 8 subagents, hooks and a CLI runner so your AI picks model and effort per task and saves tokens",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,10 +11,12 @@
11
11
  "bin",
12
12
  "src",
13
13
  "templates",
14
+ "!templates/agensi",
14
15
  "docs",
15
16
  "!docs/router-trailer.gif",
16
17
  "README.md",
17
18
  "LICENSE",
19
+ "CLA.md",
18
20
  "CHANGELOG.md",
19
21
  "SECURITY.md",
20
22
  "llms.txt",
@@ -30,7 +32,9 @@
30
32
  "gen:plugin": "node scripts/gen-plugin.js",
31
33
  "proof:measure": "node proof/scripts/measure.js",
32
34
  "proof:render": "node proof/scripts/render.js",
33
- "proof:demo": "node proof/scripts/record-gate.js"
35
+ "proof:demo": "node proof/scripts/record-gate.js",
36
+ "gen:agensi": "node scripts/gen-agensi.js",
37
+ "pack:agensi": "node scripts/pack-agensi.js"
34
38
  },
35
39
  "engines": {
36
40
  "node": ">=18"
package/src/agensi.js ADDED
@@ -0,0 +1,177 @@
1
+ // Standalone packs share installer templates, with explicit setup slots instead
2
+ // of an assumed stack. Pure planner: reads sources and writes nothing.
3
+ import { readFileSync, readdirSync } from 'node:fs';
4
+ import { dirname, join, posix } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { AIS } from './catalog.js';
7
+ import { render } from './render.js';
8
+
9
+ export const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
10
+ export const AGENSI_DIR = join(ROOT, 'agensi');
11
+ export const PACK_NAMES = ['model-router-beginner', 'model-router-intermediate'];
12
+ export const AGENSI_VERSION = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version;
13
+ const TEMPLATES = join(ROOT, 'templates');
14
+ const PUBLIC_SOURCE = 'https://github.com/aunysillyme/model-orchestrator/blob/main/';
15
+ const BRIEFS = ['TASK_BRIEF.md', 'CONTEXT.md', 'ACCEPTANCE_CHECKS.json', 'DECISIONS.md'];
16
+ const INTERMEDIATE_RULES = ['ROUTING.md', 'TIERS.md', 'DELEGATION_MATRIX.md', 'RESEARCH_TRIAGE.md', 'CLI-RUN.md'];
17
+
18
+ export function packLanes() {
19
+ return {
20
+ enabled: [],
21
+ defaults: {},
22
+ available: AIS.filter(ai => ai.facts.cliRun).map(ai => ai.bin),
23
+ note: 'Fill at setup: add only verified installed CLI names from available to enabled. Every lane starts disabled. An unlisted lane exits 13.',
24
+ defaultsNote: 'Unpinned: inherit each CLI configuration. Verify its current model and effort before a call. Flags override defaults. Qwen has no effort flag. Hermes provider selection requires a matching model. Doctor exits 13 until a lane is enabled.'
25
+ };
26
+ }
27
+
28
+ // Each slot names the fact to probe or the selection rule to apply. No vendor
29
+ // model IDs, selected tools, dates or project-specific assignments are invented.
30
+ export function unconfiguredVars(level) {
31
+ const role = job => `Fill at setup: ${job}`;
32
+ const stack = '| Role | Tool and model | Selection evidence |\n|---|---|---|\n| Fill at setup: plan, build, review, verify, research, bulk, read, private | Fill at setup: verified user tools and current models, or none selected | Fill at setup: reach, family, permissions, billing and capacity |';
33
+ const vars = {
34
+ STACK_TABLE: stack,
35
+ STACK_SUMMARY: '## Your stack: who does what\n\n' + stack + '\n\nUse SKILL.md first-run setup to fill this table from the user\'s real tools.',
36
+ STACK_FALLBACK_NOTE: 'When a separate eligible lane is absent, the main agent handles the job at the appropriate tier. A same-family fresh-context review is a self-check. Independent review needs a verified different family; private work needs a verified local runtime.',
37
+ STACK_GAPS: 'Fill at setup: name unavailable roles and access. Unknown capabilities remain UNVERIFIED; review and private roles remain none selected until verified.',
38
+ PRIMARY_NAME: role('the user\'s main agent'),
39
+ PRIMARY_DEEP: role('current planning model and supported effort'),
40
+ PRIMARY_STANDARD: role('current working model and supported effort'),
41
+ PRIMARY_FAST: role('current cheap model and supported effort'),
42
+ READER_ROLE: role('reader with enough context and source access'),
43
+ REVIEW_ROLE: role('reviewer from a known different model family, or report independent review pending'),
44
+ PLANNER_ROLE: role('planner, preferring the main agent then largest verified context'),
45
+ BUILDER_ROLE: role('builder with authorized writes and verified main-agent or headless access'),
46
+ FINDING_ROLE: role('finding verifier with reproduction access'),
47
+ DONE_ROLE: role('completion verifier with artifact access'),
48
+ LIVE_ROLE: role('researcher with verified live tools'),
49
+ BULK_ROLE: role('bounded worker, preferring eligible cheaper billing'),
50
+ CODECALC_STATUS: 'optional, verify availability at setup; otherwise use the local runtime, spreadsheet or tests',
51
+ OBSIDIAN_TC_STATUS: 'optional, verify availability at setup; otherwise use project files, search and version control',
52
+ CONTEXT7_STATUS: 'optional, verify availability at setup; otherwise read official docs or installed source',
53
+ DECISION_RULE5_L1: '8. **Build:** use the working model with high effort where supported; verify write reach and acceptance checks first.',
54
+ DECISION_RULE5: '5. **Build:** use the verified builder with high effort where supported; raise to xhigh for architecture, security or irreversible work.',
55
+ INLINE_THRESHOLD_NOTE: ' Keep small lookups local when dispatch adds no useful reach or capacity.',
56
+ DELEGATE_RULES_NOTE: 'Before delegating, probe whether the worker loads project rules; supply any missing instructions explicitly.',
57
+ ROUTE_GATE_SECTION: '## Loading the rules\n\nFill at setup: name the project instruction file or session-loading procedure that reads these rules. Verify it in a fresh session; this pack installs no hooks.',
58
+ BUILDER_HANDOFF_NOTE: 'When dispatching, verify the builder\'s actual tools and project-rule loading; pass missing context explicitly.',
59
+ ROLES_BUILDER_ROW: '| Fill at setup: authorized builder | Implement and verify its assigned section | Granted files and commands |',
60
+ RESEARCH_SELECTION_ADVICE: 'choose verified live tools by question fit; run independent bounded questions together where useful, and record missing coverage.',
61
+ GAP_ANALYSIS_LANE: role('independent coverage reviewer; do not claim independence without a different verified family'),
62
+ LANES_TABLE: '| Tool | Models and family | Reach and permissions | Billing and headroom |\n|---|---|---|---|\n| Fill at setup: actual available tool | Fill at setup: probe current roster | Fill at setup: verified access | Fill at setup: local, free, subscription or metered |',
63
+ PLAN_GUIDANCE: 'Fill at setup: verify the user\'s plans, quota and model availability. Unknown prices or capacity remain UNVERIFIED. Choose by job, complexity, stakes and reach; never assume a subscription permits unlimited work.',
64
+ DATE: '(Fill at setup: date of the live probes)',
65
+ AI_IDS: 'Fill at setup: user-selected tool identifiers',
66
+ TASK_LANES_TABLE: stack,
67
+ INSTALL_TABLE: 'Fill at setup: record verified CLI presence, sign-in and missing prerequisites. This pack runs no vendor installer or login flow; hand required account actions to the user.',
68
+ COST_PLAYBOOK: 'Prefer eligible local, free, subscription, then pay-per-token routes. Verify current prices and headroom; do not spend outside the approved budget. Unknown pricing remains UNVERIFIED.',
69
+ CLI_RUN_LANES: 'none enabled until setup; inspect bin/lanes.json available and enable only verified installed CLIs',
70
+ LANE_STEP0: '0a. **Availability:** read the user\'s filled stack table and verify tools, permissions and headroom before dispatch.',
71
+ BULK_LANE: '',
72
+ FAN_OUT_ADVICE: ' Use fan-out only when a selected tool\'s live capabilities verify it.',
73
+ LIVE_LANE: role('available research tool with verified live access'),
74
+ ATTACK_LANE: role('different-family reviewer with scope and suitable effort'),
75
+ WHO_BUILDS: 'When assigning a build, prefer the main agent with authorized writes, then an eligible headless CLI. Write the choice and evidence in briefs/DECISIONS.md.',
76
+ CLAUDE_WORKER_TRANSPORT: '',
77
+ METERED_CITATION_NOTE: ' Verify current provider rates before quoting costs.',
78
+ PLAN_BIG_LINE: 'Use planning capability for unresolved decisions and scoped working capability for execution. ',
79
+ ADD_ENDPOINT_ROW: '| Add an endpoint from an agreed specification | Fill at setup: verified builder, working model tier |',
80
+ LANE_EXAMPLES: '| Fill at setup: project-specific task | Fill at setup: eligible lane, model and selection reason |',
81
+ RESEARCH_ENGINES: 'Fill at setup: number of verified available',
82
+ RESEARCH_ROLES: '| Fill at setup: bounded research question | Fill at setup: verified live tool | Inspect primary sources and return cited evidence |',
83
+ RESEARCH_RUN: '# Fill at setup: replace <lane> with an enabled research CLI; repeat for independent questions.\nnode <skill-dir>/bin/cli-run.mjs <lane> --brief "$BRIEF"',
84
+ EXAMPLE_LANE: '<lane>',
85
+ EXAMPLE_EFFORT_FLAGS: ' --effort high',
86
+ EXAMPLE_AUDIT_BLOCK: 'When using Codex for an authorized read-only review, use `node <skill-dir>/bin/cli-run.mjs codex --audit --brief TASK_BRIEF.md`. Other lanes require their own verified review permissions.',
87
+ EXAMPLE_LANES_JSON: JSON.stringify(packLanes(), null, 2),
88
+ QWEN_SAFE_MODE_NOTE: 'For Qwen, omit --effort; when required use its --safe-mode flag. '
89
+ };
90
+ for (const [key, job] of Object.entries({ PLANNER: 'planning', REVIEW: 'code review', FINDING: 'finding verification', BUILDER: 'building', LIVE: 'live research', BULK: 'bulk work', DONE: 'completion verification', READER: 'reading' })) {
91
+ vars[`TIER_${key}_ROLE`] = role(`${job} tool and model`);
92
+ }
93
+ return vars;
94
+ }
95
+
96
+ // Rewrite only pack output. Installer templates retain their commands and paths.
97
+ function standalone(text) {
98
+ return text
99
+ .replace(/`aunx route "<task>"` prints a deterministic keyword suggestion; verify that suggestion against the task's scope, required tools and stakes before dispatching\./g, 'Apply the decision tree below to the task\'s scope, required tools and stakes before dispatching.')
100
+ .replace(/, optionally starting with `aunx route "<task>"`/g, '')
101
+ .replace(/When `aunx` runs,[^\n]+/g, 'Run `node <skill-dir>/bin/cli-run.mjs` from the user\'s project root, where `<skill-dir>` is the absolute path of the filled project copy; its lanes.json lives beside that script. Save the filled brief as TASK_BRIEF.md in the project root, or pass its absolute path.')
102
+ .replace(/The manifest's `preferredTransport: "mcp"`[^\n]+/g, 'Record the verified transport in your filled stack table. This pack supplies no manifest or worker service.')
103
+ .replace(/When using the installed script directly,[^\n]+/g, 'Run the bundled script from the filled project folder after enabling the chosen lane.')
104
+ .replace(/^aunx cli-run[^\n]*\n/gm, '') // direct Node examples follow these wrapper examples
105
+ .replace(/`aunx cli-run/g, '`node bin/cli-run.mjs')
106
+ .replace(/ \(`aunx brief`\)/g, '')
107
+ .replace(/`aunx brief`/g, 'the filled task brief')
108
+ .replace(/ \(`aunx checks`\)/g, '')
109
+ .replace(/scaffold the context file with `aunx context` and the acceptance checks with `aunx checks`/g, 'copy briefs/CONTEXT.md and briefs/ACCEPTANCE_CHECKS.json, fill their fields and run each approved verifier with the project runtime')
110
+ .replace(/scaffold `CONTEXT.md` with `aunx context`/g, 'copy briefs/CONTEXT.md')
111
+ .replace(/Scaffold a checks file with `aunx checks`/g, 'Copy briefs/ACCEPTANCE_CHECKS.json to the run\'s checks file')
112
+ .replace(/Run `aunx checks run ACCEPTANCE_CHECKS.json` against the final artifact\. A failed command gives the gate exit code 1\./g, 'Run each approved command from ACCEPTANCE_CHECKS.json with the local runtime against the final artifact, using its cwd relative to the checks file. Record each exit code; any failed or unverified check leaves acceptance pending.')
113
+ .replace(/Name the checks file when using `aunx checks run`/g, 'Name the checks file and run each approved verifier with the local runtime')
114
+ .replace(/blocks the automated gate until replaced by a verifiable result/g, 'leaves acceptance pending until verified')
115
+ .replace(/Replace the placeholder with a current vendor model ID before using this example\./g, "Before adding defaults, verify the lane's current vendor model and supported flags.")
116
+ .replace(/- Checks run sequentially[^\n]+/g, '- Run approved checks sequentially and record their exit codes. Bound long runs with the project\'s supported timeout or supervisor; stop descendants on timeout or interruption and verify cleanup. Manual execution provides no automatic process cleanup or sandbox.')
117
+ .replace(/rerun the installer with `--level 2`/g, 'use the intermediate pack and fill its stack table from verified tools')
118
+ .replace(/Select Claude Code with installer ID `claude-code`/g, 'Identify Claude Code as `claude-code` in your stack table')
119
+ .replace(/or re-run the installer with a supported CLI selected/g, 'or enable a verified installed CLI in the project copy of bin/lanes.json')
120
+ .replace(/choose a supported CLI or use level 1/g, 'enable a verified CLI in the project copy of bin/lanes.json, or follow rules/ORCHESTRATOR.md as a single agent')
121
+ .replace(/At level 2 and above, consider this selected lane:/g, 'When a second model family is available, consider this reviewer:');
122
+ }
123
+
124
+ function adaptPaths(text, rel, sources) {
125
+ // Entrypoints are authored against the finished pack layout already.
126
+ if (rel === 'SKILL.md') return text;
127
+ // Markdown destinations resolve by their template location before remapping.
128
+ text = text.replace(/(!?\[[^\]]*\]\()([^\s)]+)(\))/g, (all, start, target, end) => {
129
+ if (/^(?:[a-z][a-z0-9+.-]*:|#)/i.test(target)) return all;
130
+ const [path, anchor = ''] = target.split('#');
131
+ const source = posix.normalize(posix.join(posix.dirname(sources.get(rel)), path));
132
+ const destination = [...sources].find(([, value]) => value === source)?.[0];
133
+ return start + (destination ? posix.relative(posix.dirname(rel), destination) : PUBLIC_SOURCE + source) + (anchor ? '#' + anchor : '') + end;
134
+ });
135
+ // Templates use code spans for file pointers. Give those their new pack paths.
136
+ const prefix = posix.relative(posix.dirname(rel), '.') || '.';
137
+ const local = path => (prefix === '.' ? '' : prefix + '/') + path;
138
+ text = text.replace(/`((?:protocols\/)?[A-Z][A-Z_-]*\.(?:md|json)|protocols\/[a-z-]+\.md|bin\/(?:cli-run\.mjs|lanes\.json))`/g, (all, path) => {
139
+ let destination = path;
140
+ if (BRIEFS.includes(path)) destination = 'briefs/' + path;
141
+ else if (path === 'ORCHESTRATOR.md' || INTERMEDIATE_RULES.includes(path)) destination = 'rules/' + path;
142
+ return '`' + local(destination) + '`';
143
+ });
144
+ // Shell examples execute from the project-copy root, not from rules/.
145
+ // Worker CLIs inherit the cwd, so the runner is called from the user's project
146
+ // root by the absolute pack path and the filled brief sits in that root.
147
+ return text
148
+ .replace(/`node (?:<skill-dir>\/)?bin\/cli-run\.mjs` or the installed `(?:\.\.\/)?bin\/cli-run\.mjs`/g, '`node <skill-dir>/bin/cli-run.mjs` from the user\'s project root')
149
+ .replace(/node bin\/cli-run\.mjs/g, 'node <skill-dir>/bin/cli-run.mjs')
150
+ .replace(/--brief briefs\/TASK_BRIEF\.md/g, '--brief TASK_BRIEF.md');
151
+ }
152
+
153
+ export function planAgensiFiles() {
154
+ const files = [];
155
+ for (const [index, pack] of PACK_NAMES.entries()) {
156
+ const level = index + 1;
157
+ const sources = new Map([
158
+ ['SKILL.md', `templates/agensi/${level === 1 ? 'beginner' : 'intermediate'}/SKILL.md`],
159
+ ['rules/ORCHESTRATOR.md', 'templates/beginner/ORCHESTRATOR.md'],
160
+ ...BRIEFS.map(name => ['briefs/' + name, 'templates/common/' + name]),
161
+ ...readdirSync(join(TEMPLATES, 'common', 'protocols')).sort().map(name => ['protocols/' + name, 'templates/common/protocols/' + name]),
162
+ ...(level === 2 ? INTERMEDIATE_RULES.map(name => ['rules/' + name, 'templates/intermediate/' + name]) : [])
163
+ ]);
164
+ for (const [rel, source] of sources) {
165
+ const raw = readFileSync(join(ROOT, source), 'utf8');
166
+ const content = adaptPaths(standalone(render(raw, unconfiguredVars(level))), rel, sources);
167
+ if (content.includes('{{') || /\baunx\b/.test(content)) throw new Error(`unresolved pack instruction: ${pack}/${rel}`);
168
+ files.push({ rel: pack + '/' + rel, content });
169
+ }
170
+ files.push({ rel: pack + '/LICENSE', content: readFileSync(join(ROOT, 'LICENSE'), 'utf8') });
171
+ if (level === 2) {
172
+ files.push({ rel: pack + '/bin/cli-run.mjs', content: readFileSync(join(ROOT, 'bin/cli-run.mjs'), 'utf8') });
173
+ files.push({ rel: pack + '/bin/lanes.json', content: JSON.stringify(packLanes(), null, 2) + '\n' });
174
+ }
175
+ }
176
+ return files;
177
+ }