@clossys/launcher 0.1.5 → 0.3.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/CHANGELOG.md +67 -0
- package/README.md +209 -20
- package/contracts/conversation-contract.md +40 -0
- package/dist/apply-plan-cli.d.ts +7 -0
- package/dist/apply-plan-cli.d.ts.map +1 -0
- package/dist/apply-plan-cli.js +96 -0
- package/dist/apply-plan-cli.js.map +1 -0
- package/dist/apply-plan.d.ts +79 -0
- package/dist/apply-plan.d.ts.map +1 -0
- package/dist/apply-plan.js +129 -0
- package/dist/apply-plan.js.map +1 -0
- package/dist/check-cli.d.ts.map +1 -1
- package/dist/check-cli.js +3 -0
- package/dist/check-cli.js.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +37 -11
- package/dist/cli.js.map +1 -1
- package/dist/contract.d.ts +28 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +78 -0
- package/dist/contract.js.map +1 -0
- package/dist/core.d.ts +38 -6
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +289 -42
- package/dist/core.js.map +1 -1
- package/dist/doctor-cli.d.ts +4 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +32 -0
- package/dist/doctor-cli.js.map +1 -0
- package/dist/doctor.d.ts +28 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +68 -0
- package/dist/doctor.js.map +1 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +3 -0
- package/dist/host.js.map +1 -1
- package/dist/hosts.d.ts +14 -0
- package/dist/hosts.d.ts.map +1 -0
- package/dist/hosts.js +61 -0
- package/dist/hosts.js.map +1 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/inventory-adoption.d.ts +20 -0
- package/dist/inventory-adoption.d.ts.map +1 -0
- package/dist/inventory-adoption.js +67 -0
- package/dist/inventory-adoption.js.map +1 -0
- package/dist/manifest.d.ts +20 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +106 -0
- package/dist/manifest.js.map +1 -0
- package/dist/model-profile.d.ts +46 -0
- package/dist/model-profile.d.ts.map +1 -0
- package/dist/model-profile.js +98 -0
- package/dist/model-profile.js.map +1 -0
- package/dist/product-repository.d.ts +26 -0
- package/dist/product-repository.d.ts.map +1 -0
- package/dist/product-repository.js +49 -0
- package/dist/product-repository.js.map +1 -0
- package/dist/skills.d.ts +20 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +98 -7
- package/dist/skills.js.map +1 -1
- package/dist/types.d.ts +57 -1
- package/dist/types.d.ts.map +1 -1
- package/model-profiles/claude-code.json +10 -0
- package/model-profiles/codex.json +10 -0
- package/model-profiles/cursor.json +10 -0
- package/package.json +9 -4
- package/skeleton/README.md +5 -0
- package/skeleton/package.json +1 -1
- package/skill/SKILL.md +53 -0
- package/skill-catalogue/advisor/SKILL.md +3 -1
- package/skill-catalogue/controller/SKILL.md +8 -0
- package/skill-catalogue/customer/SKILL.md +92 -0
- package/skill-catalogue/designer/SKILL.md +18 -2
- package/skill-catalogue/inspector/SKILL.md +1 -1
- package/skill-catalogue/publisher/SKILL.md +17 -3
- package/skill-catalogue/strategist/SKILL.md +37 -3
- package/skill-catalogue/writer/SKILL.md +7 -2
- package/src/apply-plan-cli.ts +94 -0
- package/src/apply-plan.ts +172 -0
- package/src/check-cli.ts +3 -0
- package/src/cli.ts +45 -10
- package/src/contract.ts +81 -0
- package/src/core.ts +337 -37
- package/src/doctor-cli.ts +33 -0
- package/src/doctor.ts +145 -0
- package/src/host.ts +3 -0
- package/src/hosts.ts +79 -0
- package/src/index.ts +33 -0
- package/src/inventory-adoption.ts +85 -0
- package/src/manifest.ts +103 -0
- package/src/model-profile.ts +148 -0
- package/src/product-repository.ts +73 -0
- package/src/skills.ts +113 -8
- package/src/types.ts +58 -1
- /package/skeleton/{.clossys → clossys/.state}/inventory.json +0 -0
- /package/skeleton/{.clossys → clossys/.state}/workspace.json +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,73 @@ All notable changes to this package are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-09-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- The product repository standard (#1215), recorded in this repository's own docs/contracts/product-repository-layout.json (not shipped in the published package) -- `apps/*`, workspace wiring, agent pointers, and CI, extending the consumer layout. `checkCloudSessionBootstrap()` verifies the three checks a cloud agent session (browser plus GitHub only, no local setup) needs before it can install and run the team in a product repository.
|
|
13
|
+
- `launcher-doctor`: a read-only command that checks git, the GitHub command-line tool, sign-in, Node.js, and npm, and names the first missing prerequisite in plain language with the one next action to take -- never a dump of everything at once (#1220).
|
|
14
|
+
- Adopts an existing repository inventory instead of writing a second, diverging one, when the hub marker declares an `externalInventory`. `reportInventoryDrift()` runs automatically on every `launcher` create, resume, or appoint and prints the result in hub health output -- external-only, launcher-only, and agreeing repository ids, all three even when one is empty -- instead of silently merging them (#1216).
|
|
15
|
+
- `--clone-missing`, an explicit, non-default flag on `launcher` that clones inventoried repositories not yet sitting beside the hub (#1179), reversing the previous no-clone default for exactly this one approved action. Plain invocation is unchanged: still report-only by default.
|
|
16
|
+
- Every `launcher` create, resume, or appoint records which coding-agent hosts a directory could already discover skills through -- read before that same run composes skills and stamps every host's discovery path -- into `clossys/.state/hosts.json`, for the hub and every sibling clone (#1180). Codex is detected by the presence of `.agents/skills` itself -- verified against Codex's own documentation, which reads repository skills from that path directly and needs no separate discovery symlink the way Claude Code and Cursor do.
|
|
17
|
+
- Ships a per-host model profile (`model-profiles/<host>.json`) mapping the fixed reasoning tiers (`light` / `standard` / `deep`) to that host's current models, and reads `clossys/preferences.json`'s budget stance to resolve within it (#1219). Packages never name a model; only this profile does.
|
|
18
|
+
- `launcher-apply-plan`: validates an approved `clossys/advisor/plan.json` and an `EngagementBrief`-shaped `clossys/brief.json` against the "Plan file contract" recorded on issue #1175, then writes the brief into a staffed repository byte-identically (#1178, #1176). Multi-repository orchestration (branch creation, exact package installs, Starter's caller workflow, opening one pull request per repository) is deferred -- see the package README's "Applying an approved plan" section for why.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `README.md`: documents the new commands and exports, and updates the "does not clone" line to describe the new explicit `--clone-missing` exception.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `detectLinkedHosts()` (#1180) and `reportInventoryDrift()` (#1216) are now called from the real `launcher` command path (`applyWorkspacePlan`, via `composeSkillRoster` / `finishHubApply`) on every create, resume, and appoint, instead of existing only as library functions nothing called. Per independent review at f2a50de707f8682c6885592f2910425c2e5a0b5f: neither had a reachable call site, so no client-run command actually recorded a linked host or reported inventory drift despite the PR body and this changelog describing both as delivered behavior.
|
|
27
|
+
|
|
28
|
+
## [0.2.0] - 2026-09-22
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Scaffolds one visible `clossys/` folder per repository: a generated `README.md` index of active roles at the root of `clossys/`, and `clossys/.state/` for machine files (hub marker, inventory, and the new skills manifest).
|
|
33
|
+
- Writes `clossys/.state/skills.json` on every apply: each composed skill's source (`installed` or `catalogue`), version, and a content digest. The health report states how many composed skills are out of date against the live `@clossys/launcher` version and how many were retired this run; retirement removes only a skill this directory's own previous manifest listed, never one launcher did not write.
|
|
34
|
+
- Packs the shared conversation contract at build time and injects it into every composed skill in place of that skill's own "how we work together" and "one question at a time" sections, at the same position. No package edit is needed for this to take effect.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- Moves its own hub marker and inventory from the hidden `.clossys/` to the visible `clossys/.state/`; the packed skeleton template moves with it. Resume detects a hub still on the legacy path and migrates it automatically, reporting the move in the health report. A hub with a marker at both paths is graded `indeterminate` and launcher refuses rather than merging them silently.
|
|
39
|
+
- Adds a `.gitignore` entry for generated run output under `clossys/**/.generated/`. Approved records, proof, and machine state are still committed, never ignored.
|
|
40
|
+
|
|
41
|
+
## [0.1.8] - 2026-09-21
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- Ships the packed Agent Skill in the tarball (`files` includes `skill`).
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Skill compose prefers each checkout's installed `@clossys/<package>/skill/SKILL.md` when present, then falls back to the packed catalogue or sibling source.
|
|
50
|
+
- Apply marks hub health degraded when the skill roster skips inventoried targets; missing per-package catalogue sources remain notes only.
|
|
51
|
+
|
|
52
|
+
## [0.1.7] - 2026-09-20
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- Packed skill catalogue now carries pre-auth fold gates, the exceptional-keep brief that ships with `@clossys/designer` (synthetic user, not the doer, the sealer, or a QA contractor), and expression-wave skills that treat 3 as the floor not done.
|
|
57
|
+
|
|
58
|
+
## [0.1.6] - 2026-09-20
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Appoint now pins live `@clossys/advisor` in `devDependencies` only. It relocates a pin left in another bucket and overwrites a frozen version. A dedicated `{owner}/workspace` hub is named `@owner/workspace`; an appointed product keeps its package name.
|
|
63
|
+
- Observe always reads the public Advisor version, including when a pin already exists, so appoint can write the live pin and resume can grade it.
|
|
64
|
+
- Health is degraded when Advisor is missing, dual-pinned, or present outside `devDependencies`, not only when the pin is older than live.
|
|
65
|
+
- New-hub skeleton package name is `@owner/workspace`.
|
|
66
|
+
- New-hub `AGENTS.md` tells the coding agent to speak to a founder in
|
|
67
|
+
ordinary sentences: where we are, what to do next, what we will not
|
|
68
|
+
do, and whether anything is saved to git. Machine identifiers stay
|
|
69
|
+
out of the default voice.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- Resume health now receives the live Advisor version from observe, so a stale or misplaced pin is visible on every resume instead of only after a fresh appoint.
|
|
74
|
+
|
|
8
75
|
## [0.1.5] - 2026-09-20
|
|
9
76
|
|
|
10
77
|
### Fixed
|
package/README.md
CHANGED
|
@@ -8,6 +8,46 @@ The hub inventories where Foundry packages are installed and coordinates
|
|
|
8
8
|
engagement. It is not a product application and does not receive a dump of
|
|
9
9
|
the catalogue.
|
|
10
10
|
|
|
11
|
+
## Layout: the `clossys/` folder
|
|
12
|
+
|
|
13
|
+
Every apply writes to one visible `clossys/` folder in the target repository —
|
|
14
|
+
never a hidden dot-folder for anything a person might want to see. A generated
|
|
15
|
+
`README.md` at the root of `clossys/` is an index of which `clossys/<role>/` folders are active and what
|
|
16
|
+
each holds; it is rewritten on every run, never hand-edited. `clossys/.state/`
|
|
17
|
+
holds machine files only — the hub marker, the inventory, and the skills
|
|
18
|
+
manifest (below) — visible so it is easy to find, but still not a place to
|
|
19
|
+
edit by hand. Other roles' folders (`clossys/strategist/`, `clossys/writer/`,
|
|
20
|
+
and so on) are written by their own packages, not by launcher.
|
|
21
|
+
|
|
22
|
+
A hub created before this layout existed kept its marker and inventory under
|
|
23
|
+
a hidden `.clossys/`. Resume detects that automatically and migrates both
|
|
24
|
+
files to `clossys/.state/`, removing the old directory, and reports the move
|
|
25
|
+
in the health report. If somehow both a `.clossys/` and a `clossys/.state/`
|
|
26
|
+
hub state exist at once, launcher refuses rather than guessing which one is
|
|
27
|
+
current — remove one and resume again.
|
|
28
|
+
|
|
29
|
+
## Conversation contract
|
|
30
|
+
|
|
31
|
+
Every composed skill carries one shared conversation contract: lead with a
|
|
32
|
+
plain-language status, always state a recommendation, ask exactly one
|
|
33
|
+
question with the recommended option labelled first, and say what happens
|
|
34
|
+
next. Launcher packs this contract at build time and injects it into each
|
|
35
|
+
composed skill in place of that skill's own "how we work together" and "one
|
|
36
|
+
question at a time" sections, at the same position — so an installed or
|
|
37
|
+
catalogue skill's own wording never has to drift from it.
|
|
38
|
+
|
|
39
|
+
## Skills manifest and freshness
|
|
40
|
+
|
|
41
|
+
Every apply writes a skills manifest recording each composed skill's source
|
|
42
|
+
(`installed` or `catalogue`), version, and a content digest. The health
|
|
43
|
+
report states how many composed skills are out of date against the live
|
|
44
|
+
`@clossys/launcher` version (catalogue-sourced skills are only ever as fresh
|
|
45
|
+
as the launcher release that packed them) and how many were retired this
|
|
46
|
+
run. Retirement means: a skill this directory's own manifest previously
|
|
47
|
+
listed is no longer composed (its source disappeared), so launcher removes
|
|
48
|
+
its composed output and host discovery links — and only that. It never
|
|
49
|
+
touches a skill it did not itself write.
|
|
50
|
+
|
|
11
51
|
## Health report and staleness
|
|
12
52
|
|
|
13
53
|
After create, resume, or appoint — and on every resume — the command prints
|
|
@@ -16,11 +56,17 @@ a read-only health report. It scans all four dependency buckets
|
|
|
16
56
|
`peerDependencies`) for the Advisor pin and for extra `@clossys/*` names.
|
|
17
57
|
When the live registry version is known, each pin is graded against it: a
|
|
18
58
|
pin older than live is a `stale pin` finding and marks the report
|
|
19
|
-
**degraded**.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
59
|
+
**degraded**. The report is also degraded when Advisor is missing, dual-pinned,
|
|
60
|
+
or present in any bucket other than `devDependencies`, and when apply skipped
|
|
61
|
+
one or more inventoried roster targets (missing sibling clone, origin mismatch,
|
|
62
|
+
and similar — the same `skill roster skipped` lines in the report). Per-package
|
|
63
|
+
skill sources missing from the catalogue are noted but do not by themselves mark
|
|
64
|
+
degraded. Exit stays 0 on resume
|
|
65
|
+
(the report is advisory); adopt prints the same report and an unparseable
|
|
66
|
+
pin-versus-live comparison is noted as indeterminate rather than stale.
|
|
67
|
+
`checkInventoryEntries()` additionally validates hub inventory ids read-only,
|
|
68
|
+
marking ids whose repository no longer resolves (skipped with a note when
|
|
69
|
+
`gh` is unavailable).
|
|
24
70
|
|
|
25
71
|
|
|
26
72
|
## Install
|
|
@@ -31,13 +77,25 @@ The get-started command is the package name:
|
|
|
31
77
|
npx @clossys/launcher
|
|
32
78
|
```
|
|
33
79
|
|
|
80
|
+
`npx` caches the resolved version, so a plain `npx @clossys/launcher` can
|
|
81
|
+
keep running an old one. Because a catalogue-sourced skill is only ever as
|
|
82
|
+
fresh as the launcher release that packed it (see "Skills manifest and
|
|
83
|
+
freshness" above), run:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx @clossys/launcher@latest
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
when the health report says a skill is out of date, or whenever you want to
|
|
90
|
+
be sure you are on the current release.
|
|
91
|
+
|
|
34
92
|
Public npm reads are credentialless. Packages publish to
|
|
35
93
|
`https://registry.npmjs.org`. Do not add a token or private registry
|
|
36
94
|
mapping for `@clossys`. Pin an exact version once you depend on the library
|
|
37
95
|
API:
|
|
38
96
|
|
|
39
97
|
```bash
|
|
40
|
-
npm install --save-dev --save-exact @clossys/launcher@0.
|
|
98
|
+
npm install --save-dev --save-exact @clossys/launcher@0.2.0
|
|
41
99
|
```
|
|
42
100
|
|
|
43
101
|
## Talking to the team
|
|
@@ -54,11 +112,20 @@ Voices are how you talk in a coding agent; they are not engagement engines. The
|
|
|
54
112
|
`@clossys-advisor` in chat is its hiring and compatibility voice. Use
|
|
55
113
|
`@clossys-advisor` and `@clossys-<package>` in the hub or in any inventoried
|
|
56
114
|
product repository. Each voice can talk even when that npm package is not pinned
|
|
57
|
-
in that repo.
|
|
115
|
+
in that repo. When composing into a checkout, the launcher reads each skill body
|
|
116
|
+
from that checkout's installed `@clossys/<package>/skill/SKILL.md` when present,
|
|
117
|
+
then from the packed catalogue or a sibling monorepo source. Launcher health
|
|
118
|
+
notes missing catalogue sources but apply continues.
|
|
58
119
|
|
|
59
120
|
Run `npx @clossys/launcher` again from the hub for a health report and to
|
|
60
|
-
refresh composed voices on sibling inventoried clones.
|
|
61
|
-
`gh repo clone` missing inventory entries
|
|
121
|
+
refresh composed voices on sibling inventoried clones. By default it does
|
|
122
|
+
not `gh repo clone` missing inventory entries -- that is not how you talk to
|
|
123
|
+
the team. `launcher --clone-missing` is the one explicit, approved
|
|
124
|
+
exception (#1179): on resume only, it clones every inventoried repository
|
|
125
|
+
not yet sitting beside the hub, using `cloneMissingInventoryRepositories()`,
|
|
126
|
+
and only those -- an id skipped for any other reason (wrong account, the
|
|
127
|
+
Foundry supplier tree, a mismatched git origin) is left exactly as skipped,
|
|
128
|
+
never attempted.
|
|
62
129
|
|
|
63
130
|
## How to run it
|
|
64
131
|
|
|
@@ -72,9 +139,9 @@ silent fallback.
|
|
|
72
139
|
|
|
73
140
|
| Current directory | What happens |
|
|
74
141
|
| --- | --- |
|
|
75
|
-
| Empty | Creates `{owner}/workspace` from the in-package skeleton, or clones that hub if it already exists. |
|
|
76
|
-
| Already a hub (generated marker; packed template `skeleton/.
|
|
77
|
-
| Any other GitHub repository you control | Appoints it as the account hub. Keeps
|
|
142
|
+
| Empty | Creates `{owner}/workspace` from the in-package skeleton (package name `@owner/workspace`), or clones that hub if it already exists. |
|
|
143
|
+
| Already a hub (generated marker; packed template `skeleton/clossys/.state/workspace.json`) | Resumes. No new repository. `--inventory` here is refused with a pointer to the appointed hub's own `clossys/.state/inventory.json`. A legacy `.clossys/` hub state is migrated automatically; see "Layout" above. |
|
|
144
|
+
| Any other GitHub repository you control | Appoints it as the account hub. Keeps existing product files. Refuses when the working tree has uncommitted changes (`git status --porcelain` non-empty) — the refusal names the offending remote host when the origin is not on github.com. Refuses when `CLOSSYS_OWNER` names a different account than the repository's github.com origin owner. Writes the hub marker. Pins live `@clossys/advisor` in `devDependencies`, relocating and upgrading any pin left in another bucket. A dedicated `{owner}/workspace` checkout is named `@owner/workspace`; a product repository keeps its package name. Always reads the public Advisor version (needed to pin live and to grade resume health). Refuses if the generated hub inventory is missing or empty (packed template `skeleton/clossys/.state/inventory.json`; that generated path does not ship) unless `--inventory <path>` supplies a populated document — or, when the on-disk inventory is already populated and `--inventory` is also supplied, merges the two by repository id (on-disk order first, new ids appended, first occurrence of an id wins). Does not rewrite the lockfile or dump the catalogue. Prints a read-only health report. |
|
|
78
145
|
|
|
79
146
|
It does not have to be a brand-new exclusive repository, and it does not
|
|
80
147
|
have to already match a Foundry layout. Informal "workspace-looking" trees
|
|
@@ -85,17 +152,23 @@ not install packages.
|
|
|
85
152
|
|
|
86
153
|
Do not run this inside the Foundry supplier tree.
|
|
87
154
|
|
|
88
|
-
Open the resulting folder in your coding agent.
|
|
89
|
-
until you approve a next action.
|
|
155
|
+
Open the resulting folder in your coding agent. Talk in ordinary
|
|
156
|
+
sentences. Advisor stays read-only until you approve a next action. A
|
|
157
|
+
yes in chat is permission for that one step only; it is not a lasting
|
|
158
|
+
grant and it does not write git unless a file is saved later. The same
|
|
159
|
+
command resumes later.
|
|
90
160
|
|
|
91
161
|
## CLI
|
|
92
162
|
|
|
93
163
|
```bash
|
|
94
164
|
launcher
|
|
95
165
|
launcher --inventory path/to/inventory.json
|
|
166
|
+
launcher --clone-missing
|
|
96
167
|
launcher --help
|
|
97
168
|
launcher-check --help
|
|
98
169
|
launcher-check --input observation.json
|
|
170
|
+
launcher-doctor
|
|
171
|
+
launcher-apply-plan --plan plan.json --brief brief.json --repo ./product-checkout
|
|
99
172
|
```
|
|
100
173
|
|
|
101
174
|
Exit codes preserve the ternary:
|
|
@@ -113,21 +186,137 @@ Exit codes preserve the ternary:
|
|
|
113
186
|
| Export | Description |
|
|
114
187
|
| --- | --- |
|
|
115
188
|
| `planWorkspace()` | Decides create, resume, or adopt from a cwd observation. Optional `{ inventoryPath }` is the only way to appoint without a populated on-disk inventory. |
|
|
116
|
-
| `applyWorkspacePlan()` | Copies the in-package skeleton or hub marker through a host port and returns a `WorkspaceApplyResult` with health. Composes the same skill voices on the hub and on inventoried sibling checkouts beside it; refreshes stale hub guidance on every path, including resume. Optional `{ skillCatalogueRoot, launcherPackageRoot }` selects where skill bodies are read. |
|
|
117
|
-
| `observeWorkspace()` | Reads `gh`, git remotes, cwd, inventory classification, and the public Advisor version. |
|
|
189
|
+
| `applyWorkspacePlan()` | Copies the in-package skeleton or hub marker through a host port and returns a `WorkspaceApplyResult` with health. Composes the same skill voices (with the shared conversation contract injected) on the hub and on inventoried sibling checkouts beside it; refreshes stale hub guidance and the generated `clossys/` README on every path, including resume; migrates a legacy `.clossys/` hub state automatically. Optional `{ skillCatalogueRoot, launcherPackageRoot, contractPath, liveLauncherVersion }` selects where skill and contract bodies are read and grades skill-manifest staleness. |
|
|
190
|
+
| `observeWorkspace()` | Reads `gh`, git remotes, cwd, inventory classification, hub-state migration status, and the public Advisor version. |
|
|
118
191
|
| `readInventoryRepositories()` | Reads repository ids from a `schemaVersion: 1` inventory document. |
|
|
119
|
-
| `
|
|
192
|
+
| `readLiveLauncherVersion()` | Reads the public `@clossys/launcher` registry version, used only to grade catalogue-sourced skill staleness. |
|
|
193
|
+
| `launcherPackageRootFromModule()` | Resolves this package's root from `import.meta.url` so apply can find the packed skill catalogue and contract. |
|
|
120
194
|
| `parseGitHubRemote()` | Parses a github.com remote and rejects any other host. |
|
|
121
|
-
| `isHubDocument()` | Type guard for the generated hub marker (packed template: `skeleton/.
|
|
195
|
+
| `isHubDocument()` | Type guard for the generated hub marker (packed template: `skeleton/clossys/.state/workspace.json`). |
|
|
122
196
|
| `inspectInventory()` | Classifies inventory JSON as missing, empty, or populated. |
|
|
123
|
-
| `reportHubHealth()` | Read-only pin and
|
|
197
|
+
| `reportHubHealth()` | Read-only pin, inventory, migration, and skills-manifest report. Does not install or uninstall. |
|
|
124
198
|
| `formatHubHealth()` | Human lines plus a `health:` JSON line for the same report. |
|
|
125
199
|
| `hasAdvisorPin()` | True when a manifest already pins Advisor in any dependency bucket. |
|
|
126
200
|
| `checkInventoryEntries()` | Read-only inventory id validation through `gh repo view` (batched; skips with a note when `gh` is unavailable). |
|
|
127
201
|
| `DEFAULT_REPOSITORY_NAME` | Default new-hub repository name (`workspace`). Used only when creating, never when appointing. |
|
|
202
|
+
| `CLOSSYS_DIR_REL` | Relative path of the one visible per-repository Clossys folder (`clossys`). |
|
|
203
|
+
| `STATE_DIR_REL` | Relative path of the machine-state folder (`clossys/.state`). |
|
|
128
204
|
| `WORKSPACE_MARKER_REL` | Relative path of the hub marker. |
|
|
129
205
|
| `WORKSPACE_INVENTORY_REL` | Relative path of the hub inventory. |
|
|
130
|
-
| `
|
|
206
|
+
| `CLOSSYS_README_REL` | Relative path of the generated index README at the root of `clossys/`. |
|
|
207
|
+
| `LEGACY_STATE_DIR_REL` / `LEGACY_WORKSPACE_MARKER_REL` / `LEGACY_WORKSPACE_INVENTORY_REL` | Pre-#1171 `.clossys/` paths, kept only so resume can detect and migrate them. |
|
|
208
|
+
| `CommandResult` / `CwdObservation` / `DependencyBucket` / `HubDocument` / `HubHealthReport` / `HubMigrationState` / `InventoryObservation` / `InventoryValidationEntry` / `InventoryValidationReport` / `PinFinding` / `PinGrade` / `SkillManifestDocument` / `SkillManifestEntry` / `SkillsManifestSummary` / `ApplyWorkspaceOptions` / `WorkspaceApplyResult` / `WorkspaceDecision` / `WorkspaceHost` / `WorkspaceObservation` / `WorkspacePlan` / `WorkspaceRefusal` / `WorkspaceState` | Typed host, observation, plan, health, and outcome contracts. |
|
|
209
|
+
| `cloneMissingInventoryRepositories()` | Explicit, approved action (#1179): clones every inventoried repository `resolveSisterCloneTargets` skipped for "not beside the hub", and only those. Returns a `CloneMissingOutcome[]`. |
|
|
210
|
+
| `runDoctorChecks()` | Read-only prerequisite checks in fix-in-this-order sequence: git, `gh`, signed in, Node.js, npm, then the advisory coding-agent step. Returns a `DoctorReport`. |
|
|
211
|
+
| `renderDoctorReport()` | Renders a `DoctorReport` one step at a time, the way `launcher-doctor` prints it. |
|
|
212
|
+
| `checkCloudSessionBootstrap()` | Read-only: the three product-repository-layout.json cloud-session-bootstrap checks against a directory. Returns a `CloudBootstrapReport`. |
|
|
213
|
+
| `reportInventoryDrift()` | Compares a declared external inventory against the launcher-written one; reports external-only, launcher-only, and agreeing repository ids. Returns an `InventoryDriftReport`. |
|
|
214
|
+
| `detectLinkedHosts()` | Read-only: which of `claude-code`, `cursor`, `codex` can currently discover skills in a directory. |
|
|
215
|
+
| `serializeHostRecord()` / `parseHostRecord()` | Round-trip `clossys/.state/hosts.json` (`HOSTS_REL`). |
|
|
216
|
+
| `parsePreferences()` | Reads `clossys/preferences.json`'s budget stance; defaults to `"balanced"` on absence or malformed input. |
|
|
217
|
+
| `readHostModelProfile()` | Reads a packed `model-profiles/<host>.json`; returns `undefined`, never throws, on a missing or malformed file. |
|
|
218
|
+
| `resolveModelForTier()` | Resolves a tier and budget preference to one model name for a host, reporting `belowFloor` rather than silently substituting a weaker tier's model. |
|
|
219
|
+
| `validateAdvisorPlan()` / `validateEngagementBrief()` | Shape validation against the #1175 "Plan file contract" for `clossys/advisor/plan.json` and `clossys/brief.json`. |
|
|
220
|
+
| `isPlanApproved()` | True only when a plan's most recent decision (by timestamp) has `chosen === "approved"`. |
|
|
221
|
+
| `applyEngagementBrief()` | Writes `clossys/brief.json` into a repository directory once both the plan and the brief validate; refuses and writes nothing otherwise. |
|
|
222
|
+
| `CloneMissingOutcome` / `DoctorCheckHost` / `DoctorReport` / `DoctorStepId` / `DoctorStepResult` / `CloudBootstrapCheck` / `CloudBootstrapReport` / `ExternalInventoryDeclaration` / `InventoryDriftReport` / `DiscoveredHost` / `HostRecord` / `BudgetPreference` / `HostModelProfile` / `HostTierMapping` / `ModelResolution` / `PreferencesDocument` / `ReasoningTier` / `SupportedHost` / `AdvisorPlan` / `ApplyBriefResult` / `BlockerKind` / `EngagementBrief` / `EngagementBriefRole` / `PlanBlocker` / `PlanDecision` / `ValidationResult` | Typed contracts for the sections above. |
|
|
223
|
+
|
|
224
|
+
## Doctor
|
|
225
|
+
|
|
226
|
+
`launcher-doctor` (installed alongside `@clossys/launcher`) is read-only and
|
|
227
|
+
never writes anything (#1220). It checks the prerequisites a client needs
|
|
228
|
+
before the hub even exists -- git, the GitHub command-line tool, whether
|
|
229
|
+
you are signed in, Node.js, and npm -- and reports the first thing that is
|
|
230
|
+
missing, in plain language, with the one next action to take. Run it again
|
|
231
|
+
after fixing that one thing; it always reports the next thing, never a dump
|
|
232
|
+
of everything at once. A missing coding agent is reported but never blocks
|
|
233
|
+
the verdict: `runDoctorChecks()` marks it advisory, since Launcher cannot
|
|
234
|
+
detect every host and it is a one-time choice, not a step to fix in
|
|
235
|
+
sequence. `renderDoctorReport()` renders the report the way the CLI prints
|
|
236
|
+
it.
|
|
237
|
+
|
|
238
|
+
## Product repositories
|
|
239
|
+
|
|
240
|
+
`docs/contracts/product-repository-layout.json` (this repository's own contract; it does not ship in the published package) extends the account hub's
|
|
241
|
+
`clossys/` layout to a product repository: `apps/*`, workspace wiring so
|
|
242
|
+
`@clossys/*` packages install as exact pinned versions, `AGENTS.md` /
|
|
243
|
+
`CLAUDE.md` pointers, and the CI Starter proof (#1215). A cloud agent
|
|
244
|
+
session (browser plus GitHub, no local setup) can pick up a product
|
|
245
|
+
repository too -- `checkCloudSessionBootstrap()` verifies exactly what that
|
|
246
|
+
session needs: a resolvable `package.json` plus `package-lock.json` pair,
|
|
247
|
+
an `AGENTS.md` that mentions `clossys/`, and a hub marker at the same
|
|
248
|
+
relative path as the packed template `skeleton/clossys/.state/workspace.json`.
|
|
249
|
+
It never runs `npm ci` itself and never mutates anything; it only reports
|
|
250
|
+
which of the three is missing.
|
|
251
|
+
|
|
252
|
+
## Inventory: adopting an existing source
|
|
253
|
+
|
|
254
|
+
When an account already keeps a repository inventory in its own control
|
|
255
|
+
plane, launcher reads it as the source of truth instead of writing a
|
|
256
|
+
second, diverging one (#1216). Declare it by hand-editing the hub marker (the packed template
|
|
257
|
+
`skeleton/clossys/.state/workspace.json`; the generated path does not
|
|
258
|
+
ship) to add an `externalInventory: { path, shape }` field (a `"foundry"`
|
|
259
|
+
or `"custom"` shape). Every `launcher` run
|
|
260
|
+
(create, resume, or appoint) then calls `reportInventoryDrift()`
|
|
261
|
+
automatically and prints the result in hub health output when the marker
|
|
262
|
+
declares one: three sets, all three even when one is empty -- ids only in
|
|
263
|
+
the external source, ids only in launcher's own inventory, and ids both
|
|
264
|
+
agree on. A `"custom"` shape is reported indeterminate rather than guessed
|
|
265
|
+
at -- launcher has no mapping for a non-foundry inventory shape yet. It
|
|
266
|
+
never merges the two silently; writing the reconciled set is left as a
|
|
267
|
+
separate, explicit apply step for a follow-up.
|
|
268
|
+
|
|
269
|
+
## Hosts
|
|
270
|
+
|
|
271
|
+
Every `launcher` run (create, resume, or appoint) records which
|
|
272
|
+
coding-agent hosts a directory could already discover skills through,
|
|
273
|
+
*before* that run composes skills and stamps every host's discovery path
|
|
274
|
+
(#1180): `claude-code` and `cursor` are detected by their own discovery
|
|
275
|
+
symlink (`.claude/skills`, `.cursor/skills`); `codex` is detected by the
|
|
276
|
+
presence of `.agents/skills` itself, since Codex reads repository skills
|
|
277
|
+
from that path directly and needs no separate discovery link (verified
|
|
278
|
+
against developers.openai.com/codex/skills, 2026-09-22). The snapshot is
|
|
279
|
+
written to `clossys/.state/hosts.json` (`HOSTS_REL`, via
|
|
280
|
+
`serializeHostRecord()` / `parseHostRecord()`) for the hub and for every
|
|
281
|
+
sibling clone launcher composes skills into -- so a consumer such as
|
|
282
|
+
Advisor's next-action phrasing can name the client's actual tool instead
|
|
283
|
+
of guessing.
|
|
284
|
+
|
|
285
|
+
## Model guidance
|
|
286
|
+
|
|
287
|
+
Packages declare what a step demands -- a reasoning tier (`light` /
|
|
288
|
+
`standard` / `deep`) -- never a model name (#1219). Launcher ships the
|
|
289
|
+
tier-to-model mapping per host in `model-profiles/<host>.json`, dated and
|
|
290
|
+
re-verified against that host's real current models;
|
|
291
|
+
`readHostModelProfile()` reads one. `parsePreferences()` reads
|
|
292
|
+
`clossys/preferences.json`'s budget stance (`cost-conscious` / `balanced` /
|
|
293
|
+
`max-quality`, defaulting to `balanced` when absent or malformed) --
|
|
294
|
+
Advisor asks the question and writes the file; this package only resolves
|
|
295
|
+
against it. `resolveModelForTier()` combines a profile, a tier, and a
|
|
296
|
+
preference into one `ModelResolution`, and reports `belowFloor` rather than
|
|
297
|
+
silently substituting a weaker model when a caller-supplied hard floor
|
|
298
|
+
tier cannot be met.
|
|
299
|
+
|
|
300
|
+
## Applying an approved plan
|
|
301
|
+
|
|
302
|
+
`launcher-apply-plan --plan <plan.json> --brief <brief.json> --repo <dir>`
|
|
303
|
+
writes `clossys/brief.json` into a staffed repository once the plan is
|
|
304
|
+
approved (#1178). `validateAdvisorPlan()` and `validateEngagementBrief()`
|
|
305
|
+
check both files against the exact shapes recorded on issue #1175's "Plan
|
|
306
|
+
file contract"; `isPlanApproved()` reads a plan's most recent decision (by
|
|
307
|
+
timestamp, not array position) and requires it to be `"approved"` --
|
|
308
|
+
absence of any decision is never treated as approval.
|
|
309
|
+
`applyEngagementBrief()` refuses, and writes nothing, unless both checks
|
|
310
|
+
pass, then writes the brief byte-identically -- it never re-authors its
|
|
311
|
+
prose. This package does not compute a brief's content (that is
|
|
312
|
+
`@clossys/advisor`'s `EngagementBrief`, landing in #1193) and does not
|
|
313
|
+
decide whether a plan should be approved (that is Advisor's job); it only
|
|
314
|
+
validates the two landed shapes and writes the one file. Multi-repository
|
|
315
|
+
orchestration -- branch creation, exact package installs, adding Starter's
|
|
316
|
+
caller workflow, and opening one pull request per repository -- is
|
|
317
|
+
deferred: the landed contract does not yet specify how a plan's approved
|
|
318
|
+
roles map to inventory repository ids or to install/remove/relocate work
|
|
319
|
+
items.
|
|
131
320
|
|
|
132
321
|
## Why this is not Advisor, Starter, Builder, installer, creator, or a connector
|
|
133
322
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Conversation contract
|
|
2
|
+
|
|
3
|
+
One conversation contract for every Foundry role (#1182). Every `packages/*/skill/SKILL.md`
|
|
4
|
+
carried a byte-identical `## How we work together` / `## One question at a time`
|
|
5
|
+
pair with no gate enforcing it; this file is the single source those sections
|
|
6
|
+
now come from. `@clossys/launcher` packs this file at build time and, when it
|
|
7
|
+
composes a skill, replaces that skill's own `## How we work together` and
|
|
8
|
+
`## One question at a time` sections (if present) with the block below, at
|
|
9
|
+
the same position. Packages keep their own role content; only this shared
|
|
10
|
+
block is owned here. A later, separate migration removes the duplicated
|
|
11
|
+
block from each package's own `skill/SKILL.md` on its next natural version
|
|
12
|
+
bump — no package edit is needed for the contract to take effect, because
|
|
13
|
+
composition already replaces it.
|
|
14
|
+
|
|
15
|
+
Everything from the heading below to the end of this file is the injected
|
|
16
|
+
block, verbatim.
|
|
17
|
+
|
|
18
|
+
## How we work together
|
|
19
|
+
|
|
20
|
+
Before anything else, a role reads `clossys/brief.json` to learn why it is
|
|
21
|
+
staffed here and what its goals are. If the brief is absent, or does not
|
|
22
|
+
staff this role, it says so in plain language and routes the client to
|
|
23
|
+
`@clossys-advisor`, rather than improvising a mandate.
|
|
24
|
+
|
|
25
|
+
Every reply has four parts:
|
|
26
|
+
|
|
27
|
+
1. **Where we are** — one or two plain sentences, grounded in the brief and this role's status probe.
|
|
28
|
+
2. **My recommendation** — what we would do, with a one-line reason. Always stated.
|
|
29
|
+
3. **Your call** — one question with 2-4 options, the recommended option listed first and labelled, "something else" as the only free-text path. Use the host's multiple-choice control when one exists; otherwise numbered picks.
|
|
30
|
+
4. **What happens next** — what happens if the client takes the recommendation.
|
|
31
|
+
|
|
32
|
+
Rules:
|
|
33
|
+
|
|
34
|
+
- Ask only what only the client can know: business facts, audience, taste, authority, risk appetite.
|
|
35
|
+
- Decide craft yourself and state it (for example, "I'm using a four-step type scale; say if you want otherwise").
|
|
36
|
+
- Never ask for ids, slugs, paths, versions, commands, or tool choices.
|
|
37
|
+
- Translate machine states into plain language; no exit codes or check names in the default reply.
|
|
38
|
+
- One decision per turn; no forms.
|
|
39
|
+
- Push back once, plainly, when a choice goes against the recommendation. Refuse, with the reason, when a choice breaks a hard rule.
|
|
40
|
+
- Read-only until approval, one approved step at a time; chat agreement by itself is never authorization.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createNodeHost } from "./host.js";
|
|
3
|
+
export declare const APPLY_PLAN_USAGE = "Usage: launcher-apply-plan --plan <plan.json> --brief <brief.json> --repo <directory>\n\nWrites clossys/brief.json into <directory> from the given brief, once the\ngiven plan's most recent decision is \"approved\". Refuses, and writes\nnothing, otherwise.\n\nDeterministic mechanics only: this does not decide whether a plan should be\napproved (that is Advisor's job) and does not compute the brief's content\n(that is @clossys/advisor's EngagementBrief, #1193) -- it validates the\nexact shapes recorded on issue #1175 and writes the one file.\n\nExit codes: 0 = applied, 1 = refused (not approved, or a shape does not\nvalidate), 2 = a given file could not be read as JSON.";
|
|
4
|
+
export declare class ApplyPlanInputError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export declare function main(argv: readonly string[], host: ReturnType<typeof createNodeHost>): number;
|
|
7
|
+
//# sourceMappingURL=apply-plan-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-plan-cli.d.ts","sourceRoot":"","sources":["../src/apply-plan-cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,eAAO,MAAM,gBAAgB,yqBAY0B,CAAC;AAExD,qBAAa,mBAAoB,SAAQ,KAAK;CAAG;AAgCjD,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,GAAG,MAAM,CAgC7F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { isDirectInvocation } from "./cli.js";
|
|
3
|
+
import { createNodeHost } from "./host.js";
|
|
4
|
+
import { applyEngagementBrief, validateAdvisorPlan, validateEngagementBrief } from "./apply-plan.js";
|
|
5
|
+
export const APPLY_PLAN_USAGE = `Usage: launcher-apply-plan --plan <plan.json> --brief <brief.json> --repo <directory>
|
|
6
|
+
|
|
7
|
+
Writes clossys/brief.json into <directory> from the given brief, once the
|
|
8
|
+
given plan's most recent decision is "approved". Refuses, and writes
|
|
9
|
+
nothing, otherwise.
|
|
10
|
+
|
|
11
|
+
Deterministic mechanics only: this does not decide whether a plan should be
|
|
12
|
+
approved (that is Advisor's job) and does not compute the brief's content
|
|
13
|
+
(that is @clossys/advisor's EngagementBrief, #1193) -- it validates the
|
|
14
|
+
exact shapes recorded on issue #1175 and writes the one file.
|
|
15
|
+
|
|
16
|
+
Exit codes: 0 = applied, 1 = refused (not approved, or a shape does not
|
|
17
|
+
validate), 2 = a given file could not be read as JSON.`;
|
|
18
|
+
export class ApplyPlanInputError extends Error {
|
|
19
|
+
}
|
|
20
|
+
function parseArgs(argv) {
|
|
21
|
+
if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h"))
|
|
22
|
+
return { help: true };
|
|
23
|
+
const flags = new Map();
|
|
24
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
25
|
+
const name = argv[index];
|
|
26
|
+
const value = argv[index + 1];
|
|
27
|
+
if ((name !== "--plan" && name !== "--brief" && name !== "--repo") || value === undefined) {
|
|
28
|
+
throw new ApplyPlanInputError("usage: launcher-apply-plan --plan <path> --brief <path> --repo <directory>");
|
|
29
|
+
}
|
|
30
|
+
flags.set(name, value);
|
|
31
|
+
}
|
|
32
|
+
const planPath = flags.get("--plan");
|
|
33
|
+
const briefPath = flags.get("--brief");
|
|
34
|
+
const repoDirectory = flags.get("--repo");
|
|
35
|
+
if (planPath === undefined || briefPath === undefined || repoDirectory === undefined) {
|
|
36
|
+
throw new ApplyPlanInputError("--plan, --brief, and --repo are all required");
|
|
37
|
+
}
|
|
38
|
+
return { help: false, planPath, briefPath, repoDirectory };
|
|
39
|
+
}
|
|
40
|
+
function readJson(readText, path, label) {
|
|
41
|
+
const raw = readText(path);
|
|
42
|
+
if (raw === null)
|
|
43
|
+
throw new ApplyPlanInputError(`${label} could not be read: ${path}`);
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new ApplyPlanInputError(`${label} is not valid JSON: ${path}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function main(argv, host) {
|
|
52
|
+
const parsed = parseArgs(argv);
|
|
53
|
+
if (parsed.help) {
|
|
54
|
+
console.log(APPLY_PLAN_USAGE);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
let planRaw;
|
|
58
|
+
let briefRaw;
|
|
59
|
+
try {
|
|
60
|
+
planRaw = readJson(host.readText, parsed.planPath, "--plan");
|
|
61
|
+
briefRaw = readJson(host.readText, parsed.briefPath, "--brief");
|
|
62
|
+
}
|
|
63
|
+
catch (cause) {
|
|
64
|
+
console.error(`launcher-apply-plan: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
const planValidation = validateAdvisorPlan(planRaw);
|
|
68
|
+
if (!planValidation.valid) {
|
|
69
|
+
console.error(`launcher-apply-plan: --plan does not validate: ${planValidation.reason}`);
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
const briefValidation = validateEngagementBrief(briefRaw);
|
|
73
|
+
if (!briefValidation.valid) {
|
|
74
|
+
console.error(`launcher-apply-plan: --brief does not validate: ${briefValidation.reason}`);
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
const result = applyEngagementBrief(host, parsed.repoDirectory, planRaw, briefRaw, "clossys/brief.json");
|
|
78
|
+
if (result.state === "refused") {
|
|
79
|
+
console.error(`launcher-apply-plan: refused -- ${result.reason}`);
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
console.log(`wrote ${result.path}`);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
function run() {
|
|
86
|
+
try {
|
|
87
|
+
process.exitCode = main(process.argv.slice(2), createNodeHost());
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
console.error(`launcher-apply-plan: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
91
|
+
process.exitCode = 2;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (isDirectInvocation(import.meta.url, process.argv[1]))
|
|
95
|
+
run();
|
|
96
|
+
//# sourceMappingURL=apply-plan-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-plan-cli.js","sourceRoot":"","sources":["../src/apply-plan-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { WorkspaceHost } from "./types.js";
|
|
2
|
+
export interface EngagementBriefRole {
|
|
3
|
+
readonly role: string;
|
|
4
|
+
readonly why: string;
|
|
5
|
+
readonly goal: {
|
|
6
|
+
readonly metric: string;
|
|
7
|
+
readonly direction: "increase" | "decrease";
|
|
8
|
+
};
|
|
9
|
+
readonly inputsFrom: readonly string[];
|
|
10
|
+
readonly outputsTo: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
export interface EngagementBrief {
|
|
13
|
+
readonly schemaVersion: 1;
|
|
14
|
+
readonly problem: string;
|
|
15
|
+
readonly roles: readonly EngagementBriefRole[];
|
|
16
|
+
readonly sequence: readonly string[];
|
|
17
|
+
readonly deliverables: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export type BlockerKind = "missing-input" | "missing-authority" | "failing-evidence" | "unavailable-environment" | "contradiction";
|
|
20
|
+
export interface PlanBlocker {
|
|
21
|
+
readonly kind: BlockerKind;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly owner: string;
|
|
24
|
+
readonly dueDate?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface PlanDecision {
|
|
27
|
+
readonly at: string;
|
|
28
|
+
readonly recommended: string;
|
|
29
|
+
readonly chosen: string;
|
|
30
|
+
readonly by: string;
|
|
31
|
+
}
|
|
32
|
+
export interface AdvisorPlan {
|
|
33
|
+
readonly schemaVersion: 1;
|
|
34
|
+
readonly asOf: string;
|
|
35
|
+
readonly mandate: {
|
|
36
|
+
readonly problem: string;
|
|
37
|
+
readonly primaryProblemId: string;
|
|
38
|
+
readonly roles: readonly string[];
|
|
39
|
+
};
|
|
40
|
+
readonly whereWeAre: readonly string[];
|
|
41
|
+
readonly recommendedNext: {
|
|
42
|
+
readonly action: string;
|
|
43
|
+
readonly owner: string;
|
|
44
|
+
readonly due: string;
|
|
45
|
+
} | null;
|
|
46
|
+
readonly decisions: readonly PlanDecision[];
|
|
47
|
+
readonly blockers: readonly PlanBlocker[];
|
|
48
|
+
}
|
|
49
|
+
export type ValidationResult = {
|
|
50
|
+
readonly valid: true;
|
|
51
|
+
} | {
|
|
52
|
+
readonly valid: false;
|
|
53
|
+
readonly reason: string;
|
|
54
|
+
};
|
|
55
|
+
/** Validates an EngagementBrief's shape exactly against the #1175 contract. Never mutates, never re-derives content. */
|
|
56
|
+
export declare function validateEngagementBrief(value: unknown): ValidationResult;
|
|
57
|
+
/** Validates an AdvisorPlan's shape exactly against the #1175 contract. */
|
|
58
|
+
export declare function validateAdvisorPlan(value: unknown): ValidationResult;
|
|
59
|
+
/**
|
|
60
|
+
* The plan is approved when its most recent decision (by `at`) records
|
|
61
|
+
* chosen === "approved". No decisions, or a most-recent decision that
|
|
62
|
+
* isn't "approved", is not approved -- this never assumes approval from
|
|
63
|
+
* absence.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isPlanApproved(plan: AdvisorPlan): boolean;
|
|
66
|
+
export type ApplyBriefResult = {
|
|
67
|
+
readonly state: "applied";
|
|
68
|
+
readonly path: string;
|
|
69
|
+
} | {
|
|
70
|
+
readonly state: "refused";
|
|
71
|
+
readonly reason: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Writes clossys/brief.json into `repositoryDirectory`, byte-identically
|
|
75
|
+
* from the validated brief -- never re-authors its prose. Refuses (does
|
|
76
|
+
* not write) unless both the plan is approved and the brief validates.
|
|
77
|
+
*/
|
|
78
|
+
export declare function applyEngagementBrief(host: WorkspaceHost, repositoryDirectory: string, plan: AdvisorPlan, brief: EngagementBrief, briefRelPath: string): ApplyBriefResult;
|
|
79
|
+
//# sourceMappingURL=apply-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-plan.d.ts","sourceRoot":"","sources":["../src/apply-plan.ts"],"names":[],"mappings":"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"}
|