@clossys/launcher 0.1.1 → 0.1.2
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 +17 -0
- package/README.md +22 -5
- package/dist/check-cli.d.ts.map +1 -1
- package/dist/check-cli.js +5 -1
- package/dist/check-cli.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +15 -2
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +210 -24
- package/dist/core.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/check-cli.ts +5 -1
- package/src/cli.ts +5 -1
- package/src/core.ts +218 -21
- package/src/index.ts +7 -0
- package/src/types.ts +34 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ 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.1.2] - 2026-09-19
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Appoint merges `--inventory` into a populated on-disk hub inventory instead of silently discarding the supplied document: repositories are unioned by id (on-disk order first, new ids appended in supplied order, first occurrence of an id wins) and the merged document is written to `.clossys/inventory.json` (that on-disk path does not ship with this package). The both-empty refusal is unchanged.
|
|
13
|
+
- Resume with `--inventory` now refuses with "hub already appointed; edit `.clossys/inventory.json`" (that on-disk path does not ship with this package) instead of the misleading "--inventory is only valid when appointing".
|
|
14
|
+
- Appoint refuses as `violated` when `CLOSSYS_OWNER` names a different account than the repository's github.com origin owner, naming both values; the marker is no longer written for the wrong account.
|
|
15
|
+
- Appoint no longer requires a readable npm registry when the tree already pins `@clossys/advisor` in any dependency bucket (no new version would be needed); the indeterminate refusal only fires when a version is actually required.
|
|
16
|
+
- Appoint refuses as `violated` when `git status --porcelain` is non-empty, before writing anything; when the origin is not on github.com the refusal names the remote host.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Health report grades each Advisor pin against the live registry version (internal semver compare, no new dependencies): pin older than live is a `stale pin` finding and marks the report degraded; equal pins pass; unparseable comparisons are noted as indeterminate. Exit stays 0 on resume; adopt prints the same report.
|
|
21
|
+
- Pin and extra-`@clossys/*` scans now cover `optionalDependencies` and `peerDependencies` in addition to `dependencies` and `devDependencies`.
|
|
22
|
+
- `checkInventoryEntries()`: read-only validation of hub inventory repository ids through batched `gh repo view --json name`, marking unknown ids in the report and skipping with a note when `gh` is absent. Never mutates the inventory.
|
|
23
|
+
- `launcher-check` forwards `cwd.hub`, so a captured existing-hub observation grades as resume instead of mis-grading as adopt.
|
|
24
|
+
|
|
8
25
|
## [0.1.1] - 2026-09-19
|
|
9
26
|
|
|
10
27
|
### Fixed
|
package/README.md
CHANGED
|
@@ -8,6 +8,21 @@ 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
|
+
## Health report and staleness
|
|
12
|
+
|
|
13
|
+
After create, resume, or appoint — and on every resume — the command prints
|
|
14
|
+
a read-only health report. It scans all four dependency buckets
|
|
15
|
+
(`dependencies`, `devDependencies`, `optionalDependencies`,
|
|
16
|
+
`peerDependencies`) for the Advisor pin and for extra `@clossys/*` names.
|
|
17
|
+
When the live registry version is known, each pin is graded against it: a
|
|
18
|
+
pin older than live is a `stale pin` finding and marks the report
|
|
19
|
+
**degraded**. Exit stays 0 on resume (the report is advisory); adopt prints
|
|
20
|
+
the same report and an unparseable pin-versus-live comparison is noted as
|
|
21
|
+
indeterminate rather than stale. `checkInventoryEntries()` additionally
|
|
22
|
+
validates hub inventory ids read-only, marking ids whose repository no
|
|
23
|
+
longer resolves (skipped with a note when `gh` is unavailable).
|
|
24
|
+
|
|
25
|
+
|
|
11
26
|
## Install
|
|
12
27
|
|
|
13
28
|
The get-started command is the package name:
|
|
@@ -22,7 +37,7 @@ mapping for `@clossys`. Pin an exact version once you depend on the library
|
|
|
22
37
|
API:
|
|
23
38
|
|
|
24
39
|
```bash
|
|
25
|
-
npm install --save-dev --save-exact @clossys/launcher@0.1.
|
|
40
|
+
npm install --save-dev --save-exact @clossys/launcher@0.1.2
|
|
26
41
|
```
|
|
27
42
|
|
|
28
43
|
## How to run it
|
|
@@ -38,8 +53,8 @@ silent fallback.
|
|
|
38
53
|
| Current directory | What happens |
|
|
39
54
|
| --- | --- |
|
|
40
55
|
| Empty | Creates `{owner}/workspace` from the in-package skeleton, or clones that hub if it already exists. |
|
|
41
|
-
| Already a hub (generated marker; packed template `skeleton/.clossys/workspace.json`) | Resumes. No new repository. |
|
|
42
|
-
| Any other GitHub repository you control | Appoints it as the account hub. Keeps the existing name and files. Writes the hub marker. Leaves an existing `@clossys/advisor` pin in whichever bucket it already occupies; pins live Advisor in `devDependencies` only when missing. Refuses if the generated hub inventory is missing or empty (packed template `skeleton/.clossys/inventory.json`; that generated path does not ship) unless `--inventory <path>` supplies a populated document. Does not rewrite the lockfile or dump the catalogue. Prints a read-only health report. |
|
|
56
|
+
| Already a hub (generated marker; packed template `skeleton/.clossys/workspace.json`) | Resumes. No new repository. `--inventory` here is refused with a pointer to the appointed hub's own `.clossys/inventory.json`. |
|
|
57
|
+
| Any other GitHub repository you control | Appoints it as the account hub. Keeps the existing name and 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. Leaves an existing `@clossys/advisor` pin in whichever bucket it already occupies; pins live Advisor in `devDependencies` only when missing. Refuses if the generated hub inventory is missing or empty (packed template `skeleton/.clossys/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. |
|
|
43
58
|
|
|
44
59
|
It does not have to be a brand-new exclusive repository, and it does not
|
|
45
60
|
have to already match a Foundry layout. Informal "workspace-looking" trees
|
|
@@ -68,7 +83,7 @@ Exit codes preserve the ternary:
|
|
|
68
83
|
| Exit | State | Meaning |
|
|
69
84
|
| --- | --- | --- |
|
|
70
85
|
| `0` | `satisfied` | Created, resumed, or appointed the hub. The message includes a read-only health report. |
|
|
71
|
-
| `1` | `violated` | Known refusal: not GitHub, not empty, missing appoint inventory, or the
|
|
86
|
+
| `1` | `violated` | Known refusal: not GitHub, not empty, missing appoint inventory, the supplier tree, uncommitted changes in the appoint tree, or a `CLOSSYS_OWNER` that disagrees with the origin owner. |
|
|
72
87
|
| `2` | `indeterminate` | Missing `gh`, unreadable registry pin, or an owner that could not be inferred. |
|
|
73
88
|
|
|
74
89
|
`launcher-check` grades a captured observation JSON through `planWorkspace` and does not create a hub. Same ternary: 0 is a create/resume/adopt plan, 1 is a known refusal, 2 could not run or could not decide. Appoint grades as a plan only when the observation already records a populated inventory; `--inventory` is a live CLI flag, not a check-cli input.
|
|
@@ -85,10 +100,12 @@ Exit codes preserve the ternary:
|
|
|
85
100
|
| `inspectInventory()` | Classifies inventory JSON as missing, empty, or populated. |
|
|
86
101
|
| `reportHubHealth()` | Read-only pin and inventory report. Does not install or uninstall. |
|
|
87
102
|
| `formatHubHealth()` | Human lines plus a `health:` JSON line for the same report. |
|
|
103
|
+
| `hasAdvisorPin()` | True when a manifest already pins Advisor in any dependency bucket. |
|
|
104
|
+
| `checkInventoryEntries()` | Read-only inventory id validation through `gh repo view` (batched; skips with a note when `gh` is unavailable). |
|
|
88
105
|
| `DEFAULT_REPOSITORY_NAME` | Default new-hub repository name (`workspace`). Used only when creating, never when appointing. |
|
|
89
106
|
| `WORKSPACE_MARKER_REL` | Relative path of the hub marker. |
|
|
90
107
|
| `WORKSPACE_INVENTORY_REL` | Relative path of the hub inventory. |
|
|
91
|
-
| `CommandResult` / `CwdObservation` / `HubDocument` / `HubHealthReport` / `InventoryObservation` / `WorkspaceApplyResult` / `WorkspaceDecision` / `WorkspaceHost` / `WorkspaceObservation` / `WorkspacePlan` / `WorkspaceRefusal` / `WorkspaceState` | Typed host, observation, plan, health, and outcome contracts. |
|
|
108
|
+
| `CommandResult` / `CwdObservation` / `DependencyBucket` / `HubDocument` / `HubHealthReport` / `InventoryObservation` / `InventoryValidationEntry` / `InventoryValidationReport` / `PinFinding` / `PinGrade` / `WorkspaceApplyResult` / `WorkspaceDecision` / `WorkspaceHost` / `WorkspaceObservation` / `WorkspacePlan` / `WorkspaceRefusal` / `WorkspaceState` | Typed host, observation, plan, health, and outcome contracts. |
|
|
92
109
|
|
|
93
110
|
## Why this is not Advisor, Starter, Builder, installer, creator, or a connector
|
|
94
111
|
|
package/dist/check-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-cli.d.ts","sourceRoot":"","sources":["../src/check-cli.ts"],"names":[],"mappings":";AAKA,OAAO,KAAK,EAIV,aAAa,EACb,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,WAAW,uSAM0B,CAAC;AAEnD,qBAAa,uBAAwB,SAAQ,KAAK;CAAG;
|
|
1
|
+
{"version":3,"file":"check-cli.d.ts","sourceRoot":"","sources":["../src/check-cli.ts"],"names":[],"mappings":";AAKA,OAAO,KAAK,EAIV,aAAa,EACb,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,WAAW,uSAM0B,CAAC;AAEnD,qBAAa,uBAAwB,SAAQ,KAAK;CAAG;AAqDrD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAsBrE;AAMD,uEAAuE;AACvE,wBAAgB,YAAY,IAAI,aAAa,CAmB5C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAK7F;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC/B,MAAM,CA4BR"}
|
package/dist/check-cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { isDirectInvocation } from "./cli.js";
|
|
5
|
-
import { planWorkspace } from "./core.js";
|
|
5
|
+
import { isHubDocument, planWorkspace } from "./core.js";
|
|
6
6
|
export const CHECK_USAGE = `Usage: launcher-check --input <observation.json>
|
|
7
7
|
|
|
8
8
|
Grade a captured workspace observation through planWorkspace. This bin does
|
|
@@ -45,6 +45,9 @@ function parseCwd(value) {
|
|
|
45
45
|
if (value.githubRepository !== undefined && !isText(value.githubRepository)) {
|
|
46
46
|
throw new LauncherCheckInputError("observation.cwd.githubRepository must be a string");
|
|
47
47
|
}
|
|
48
|
+
if (value.hub !== undefined && !isHubDocument(value.hub)) {
|
|
49
|
+
throw new LauncherCheckInputError("observation.cwd.hub must be a v1 account-hub marker (schemaVersion, kind, owner, repository)");
|
|
50
|
+
}
|
|
48
51
|
const inventory = parseInventoryObservation(value.inventory);
|
|
49
52
|
return {
|
|
50
53
|
absolutePath: value.absolutePath,
|
|
@@ -53,6 +56,7 @@ function parseCwd(value) {
|
|
|
53
56
|
looksLikeFoundry: value.looksLikeFoundry,
|
|
54
57
|
...(isText(value.githubOwner) ? { githubOwner: value.githubOwner } : {}),
|
|
55
58
|
...(isText(value.githubRepository) ? { githubRepository: value.githubRepository } : {}),
|
|
59
|
+
...(isHubDocument(value.hub) ? { hub: value.hub } : {}),
|
|
56
60
|
...(inventory === undefined ? {} : { inventory }),
|
|
57
61
|
};
|
|
58
62
|
}
|
package/dist/check-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-cli.js","sourceRoot":"","sources":["../src/check-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"check-cli.js","sourceRoot":"","sources":["../src/check-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AASzD,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;kDAMuB,CAAC;AAEnD,MAAM,OAAO,uBAAwB,SAAQ,KAAK;CAAG;AAErD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAc;IAC/C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,uBAAuB,CAAC,6CAA6C,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3F,MAAM,IAAI,uBAAuB,CAAC,uEAAuE,CAAC,CAAC;IAC7G,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QACzF,MAAM,IAAI,uBAAuB,CAAC,+DAA+D,CAAC,CAAC;IACrG,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,uBAAuB,CAAC,wDAAwD,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACtH,MAAM,IAAI,uBAAuB,CAAC,wEAAwE,CAAC,CAAC;IAC9G,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,uBAAuB,CAAC,8CAA8C,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,uBAAuB,CAAC,mDAAmD,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,uBAAuB,CAAC,8FAA8F,CAAC,CAAC;IACpI,CAAC;IACD,MAAM,SAAS,GAAG,yBAAyB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7D,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,uBAAuB,CAAC,mCAAmC,CAAC,CAAC;IAC7F,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;QAC5G,MAAM,IAAI,uBAAuB,CAAC,yDAAyD,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACtF,MAAM,IAAI,uBAAuB,CAAC,gEAAgE,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,uBAAuB,CAAC,uCAAuC,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,uBAAuB,CAAC,6CAA6C,CAAC,CAAC;IACnF,CAAC;IACD,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;QACxB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClF,CAAC;AACJ,CAAC;AAED,SAAS,MAAM;IACb,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;AACxF,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,GAAG,EAAE,GAAG;QACR,GAAG,EAAE,EAAE;QACP,KAAK,EAAE,KAAK;QACZ,GAAG,EAAE,GAAG,EAAE,CAAC,0BAA0B;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK;QACnB,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK;QACxB,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI;QACpB,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,EAAE,GAAG,EAAE;YACX,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;QACjB,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE;QACnB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAuB;IACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3F,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACtG,MAAM,IAAI,uBAAuB,CAAC,gDAAgD,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,IAAuB,EACvB,QAAkC,EAClC,QAAgC,EAChC,QAAgC;IAEhC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,QAAQ,CAAC,GAAG,WAAW,IAAI,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACnC,IAAI,SAAS,KAAK,SAAS;QAAE,MAAM,IAAI,uBAAuB,CAAC,qCAAqC,CAAC,CAAC;IACtG,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,uBAAuB,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,uBAAuB,CAAC,GAAG,SAAS,cAAc,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,EAAE,YAAY,EAAE,CAAC,CAAC;IAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACjC,QAAQ,CAAC,mBAAmB,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;QAClD,OAAO,QAAQ,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;IACrH,OAAO,CAAC,CAAC;AACX,CAAC;AAED,IAAI,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,IAAI,CAAC;QACH,OAAO,CAAC,QAAQ,GAAG,SAAS,CAC1B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EACrB,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EACpC,CAAC,IAAI,EAAE,EAAE;YACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC,EACD,CAAC,IAAI,EAAE,EAAE;YACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,KAAK,uyBAiBiD,CAAC;AAEpE,qBAAa,kBAAmB,SAAQ,KAAK;CAAG;AAMhD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAKpG;AAED,4FAA4F;AAC5F,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,KAAK,uyBAiBiD,CAAC;AAEpE,qBAAa,kBAAmB,SAAQ,KAAK;CAAG;AAMhD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAKpG;AAED,4FAA4F;AAC5F,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAgC/F;AAYD,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAO3F"}
|
package/dist/cli.js
CHANGED
|
@@ -57,7 +57,12 @@ export function main(argv, host, skeletonRoot) {
|
|
|
57
57
|
return exitCodeFor(decision.state);
|
|
58
58
|
}
|
|
59
59
|
if (parsed.inventoryPath !== undefined && decision.action !== "adopt") {
|
|
60
|
-
|
|
60
|
+
if (decision.action === "resume") {
|
|
61
|
+
console.error("launcher: this hub is already appointed; edit .clossys/inventory.json to change its inventory");
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.error("launcher: --inventory is only valid when appointing a GitHub repository");
|
|
65
|
+
}
|
|
61
66
|
return 1;
|
|
62
67
|
}
|
|
63
68
|
const result = applyWorkspacePlan(host, decision, skeletonRoot);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACxG,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;mEAiB8C,CAAC;AAEpE,MAAM,OAAO,kBAAmB,SAAQ,KAAK;CAAG;AAEhD,SAAS,WAAW,CAAC,KAAiD;IACpE,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAuB;IACvD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3F,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9G,MAAM,IAAI,kBAAkB,CAAC,gHAAgH,CAAC,CAAC;AACjJ,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,IAAI,CAAC,IAAuB,EAAE,IAAmB,EAAE,YAAoB;IACrF,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3C,IACE,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK;QACtB,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG;QACpB,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS;QACjC,CAAC,WAAW,CAAC,GAAG,CAAC,gBAAgB,EACjC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IAC3F,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,aAAa,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/C,OAAO,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QACtE,OAAO,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HubDocument, HubHealthReport, InventoryObservation, WorkspaceApplyResult, WorkspaceDecision, WorkspaceHost, WorkspaceObservation, WorkspacePlan } from "./types.js";
|
|
1
|
+
import type { HubDocument, HubHealthReport, InventoryObservation, InventoryValidationReport, WorkspaceApplyResult, WorkspaceDecision, WorkspaceHost, WorkspaceObservation, WorkspacePlan } from "./types.js";
|
|
2
2
|
export declare const DEFAULT_REPOSITORY_NAME = "workspace";
|
|
3
3
|
export declare const WORKSPACE_MARKER_REL = ".clossys/workspace.json";
|
|
4
4
|
export declare const WORKSPACE_INVENTORY_REL = ".clossys/inventory.json";
|
|
@@ -15,14 +15,27 @@ export declare function parseGitHubRemote(url: string): {
|
|
|
15
15
|
export declare function isHubDocument(value: unknown): value is HubDocument;
|
|
16
16
|
/** Classifies a generated hub inventory (packed template skeleton/.clossys/inventory.json; the generated path does not ship) without inventing repositories. */
|
|
17
17
|
export declare function inspectInventory(raw: string | null): InventoryObservation;
|
|
18
|
+
/** True when the tree already pins Advisor in some bucket, so adopt would not need a new version. */
|
|
19
|
+
export declare function hasAdvisorPin(manifest: unknown): boolean;
|
|
18
20
|
/** Collects GitHub owner, cwd shape, default-hub presence, and the public Advisor pin. */
|
|
19
21
|
export declare function observeWorkspace(host: WorkspaceHost): WorkspaceObservation;
|
|
20
22
|
export declare function planWorkspace(observation: WorkspaceObservation, host: WorkspaceHost, options?: {
|
|
21
23
|
inventoryPath?: string;
|
|
22
24
|
}): WorkspaceDecision;
|
|
23
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Read-only pin and inventory report. Does not install or uninstall. Scans all
|
|
27
|
+
* four dependency buckets; grades each pinned advisor version against the live
|
|
28
|
+
* registry version, marking a pin older than live as a stale-pin finding and a
|
|
29
|
+
* degraded report.
|
|
30
|
+
*/
|
|
24
31
|
export declare function reportHubHealth(host: WorkspaceHost, directory: string, liveAdvisorVersion?: string): HubHealthReport;
|
|
25
32
|
export declare function formatHubHealth(report: HubHealthReport): string;
|
|
33
|
+
/**
|
|
34
|
+
* Read-only inventory validation: runs `gh repo view --json name` for each
|
|
35
|
+
* repository id, batched. Tolerates a missing or failing `gh` by skipping with
|
|
36
|
+
* a note; marks ids whose check fails as unknown. Never mutates the inventory.
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkInventoryEntries(host: WorkspaceHost, directory: string): InventoryValidationReport;
|
|
26
39
|
/** Applies a create, resume, or adopt plan through the host. Resume does not write. */
|
|
27
40
|
export declare function applyWorkspacePlan(host: WorkspaceHost, plan: WorkspacePlan, skeletonRoot: string): WorkspaceApplyResult;
|
|
28
41
|
export declare function skeletonRootFromModule(moduleUrl: string): string;
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,WAAW,EACX,eAAe,EACf,oBAAoB,EAEpB,yBAAyB,EAEzB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,aAAa,EAGd,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,uBAAuB,cAAc,CAAC;AACnD,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAC9D,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAmBlD,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,waAW9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,iBAC9B,CAAC;AAoBF,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB3F;AA8BD,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CASlE;AAaD,gKAAgK;AAChK,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,oBAAoB,CAYzE;AAkCD,qGAAqG;AACrG,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGxD;AAED,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,oBAAoB,CAiE1E;AAwFD,wBAAgB,aAAa,CAC3B,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,iBAAiB,CAgFnB;AAyJD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,eAAe,CA0CpH;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAyB/D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,yBAAyB,CA4BvG;AAgBD,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAsCvH;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE"}
|
package/dist/core.js
CHANGED
|
@@ -4,6 +4,12 @@ export const DEFAULT_REPOSITORY_NAME = "workspace";
|
|
|
4
4
|
export const WORKSPACE_MARKER_REL = ".clossys/workspace.json";
|
|
5
5
|
export const WORKSPACE_INVENTORY_REL = ".clossys/inventory.json";
|
|
6
6
|
export const ADVISOR_PACKAGE = "@clossys/advisor";
|
|
7
|
+
const DEPENDENCY_BUCKETS = [
|
|
8
|
+
"dependencies",
|
|
9
|
+
"devDependencies",
|
|
10
|
+
"optionalDependencies",
|
|
11
|
+
"peerDependencies",
|
|
12
|
+
];
|
|
7
13
|
const OWNER = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
|
|
8
14
|
const REPO = /^[A-Za-z0-9._-]+$/;
|
|
9
15
|
const SKELETON_FILES = [
|
|
@@ -70,6 +76,37 @@ export function parseGitHubRemote(url) {
|
|
|
70
76
|
return null;
|
|
71
77
|
}
|
|
72
78
|
}
|
|
79
|
+
function readJson(host, path) {
|
|
80
|
+
const raw = host.readText(path);
|
|
81
|
+
if (raw === null)
|
|
82
|
+
return undefined;
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(raw);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Tiny semver-ish compare of `a` versus `b`: -1 older, 0 equal, 1 newer. Unparseable versions are indeterminate (null). */
|
|
91
|
+
function compareVersions(a, b) {
|
|
92
|
+
const parse = (version) => {
|
|
93
|
+
const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)$/);
|
|
94
|
+
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
95
|
+
};
|
|
96
|
+
const left = parse(a);
|
|
97
|
+
const right = parse(b);
|
|
98
|
+
if (!left || !right)
|
|
99
|
+
return null;
|
|
100
|
+
for (let index = 0; index < 3; index += 1) {
|
|
101
|
+
const l = left[index] ?? 0;
|
|
102
|
+
const r = right[index] ?? 0;
|
|
103
|
+
if (l < r)
|
|
104
|
+
return -1;
|
|
105
|
+
if (l > r)
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
73
110
|
/** True when the marker is a v1 account-hub document. */
|
|
74
111
|
export function isHubDocument(value) {
|
|
75
112
|
if (!isRecord(value) || value.schemaVersion !== 1 || value.kind !== "account-hub")
|
|
@@ -144,6 +181,12 @@ function commandAvailable(host, command) {
|
|
|
144
181
|
const result = host.run(command, ["--version"]);
|
|
145
182
|
return result.status === 0;
|
|
146
183
|
}
|
|
184
|
+
/** True when the tree already pins Advisor in some bucket, so adopt would not need a new version. */
|
|
185
|
+
export function hasAdvisorPin(manifest) {
|
|
186
|
+
if (!isRecord(manifest))
|
|
187
|
+
return false;
|
|
188
|
+
return DEPENDENCY_BUCKETS.some((bucket) => clossysNames(manifest[bucket], new Set()) !== undefined);
|
|
189
|
+
}
|
|
147
190
|
/** Collects GitHub owner, cwd shape, default-hub presence, and the public Advisor pin. */
|
|
148
191
|
export function observeWorkspace(host) {
|
|
149
192
|
const cwd = host.cwd;
|
|
@@ -184,10 +227,15 @@ export function observeWorkspace(host) {
|
|
|
184
227
|
if (viewed.status === 0)
|
|
185
228
|
remoteDefaultHub = { owner: ownerGuess, repository: DEFAULT_REPOSITORY_NAME };
|
|
186
229
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
230
|
+
// Skip the registry read when the tree already pins Advisor in some bucket:
|
|
231
|
+
// adopt leaves an existing pin alone, so no live version is needed to plan it.
|
|
232
|
+
const manifestPinsAdvisor = hasAdvisorPin(readJson(host, join(cwd, "package.json")));
|
|
233
|
+
if (!manifestPinsAdvisor) {
|
|
234
|
+
const viewedAdvisor = host.run("npm", ["view", ADVISOR_PACKAGE, "version"]);
|
|
235
|
+
const version = viewedAdvisor.stdout.trim();
|
|
236
|
+
if (viewedAdvisor.status === 0 && /^\d+\.\d+\.\d+$/.test(version))
|
|
237
|
+
advisorVersion = version;
|
|
238
|
+
}
|
|
191
239
|
const cwdObservation = {
|
|
192
240
|
absolutePath: cwd,
|
|
193
241
|
empty: isEffectivelyEmpty(entries),
|
|
@@ -230,22 +278,74 @@ function resolveOwner(observation, host) {
|
|
|
230
278
|
* Decides create, resume, or adopt from a cwd observation.
|
|
231
279
|
* Appointing means: run this from the GitHub repository that should own the hub.
|
|
232
280
|
*/
|
|
281
|
+
function readInventoryRepositories(host, source, label) {
|
|
282
|
+
const raw = host.readText(source);
|
|
283
|
+
if (raw === null)
|
|
284
|
+
return [];
|
|
285
|
+
try {
|
|
286
|
+
const parsed = JSON.parse(raw);
|
|
287
|
+
if (!isRecord(parsed) || !Array.isArray(parsed.repositories))
|
|
288
|
+
return [];
|
|
289
|
+
return parsed.repositories.map((entry) => {
|
|
290
|
+
if (isRecord(entry) && isText(entry.id))
|
|
291
|
+
return entry.id.trim();
|
|
292
|
+
return "";
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
throw new Error(`${label} is not readable inventory JSON (schemaVersion 1, repositories array)`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Resolves which repositories the adopt plan inventories. When the on-disk hub
|
|
301
|
+
* inventory is populated AND --inventory is supplied, the two are merged by id:
|
|
302
|
+
* on-disk entries keep their order, ids not already on disk are appended in
|
|
303
|
+
* supplied-file order, and the first occurrence of an id wins; the plan carries
|
|
304
|
+
* the merged ids for applyWorkspacePlan to write. When both are empty or
|
|
305
|
+
* missing, adopt refuses rather than appointing an inventory-less hub.
|
|
306
|
+
*/
|
|
233
307
|
function resolveAdoptInventory(host, cwd, inventoryPath) {
|
|
234
|
-
if (cwd.inventory?.status === "populated")
|
|
235
|
-
return {};
|
|
236
308
|
const trimmed = inventoryPath?.trim();
|
|
237
|
-
|
|
309
|
+
const onDiskPopulated = cwd.inventory?.status === "populated";
|
|
310
|
+
if (!onDiskPopulated && !trimmed) {
|
|
238
311
|
return refuse("violated", "appointing requires a populated generated hub inventory (packed template skeleton/.clossys/inventory.json; the generated path does not ship), or --inventory <path> to a populated inventory document");
|
|
239
312
|
}
|
|
313
|
+
if (!trimmed)
|
|
314
|
+
return {};
|
|
240
315
|
const resolved = resolve(cwd.absolutePath, trimmed);
|
|
241
316
|
const imported = inspectInventory(host.readText(resolved));
|
|
242
317
|
if (imported.status !== "populated") {
|
|
243
318
|
return refuse("violated", "--inventory must point at a populated inventory document (schemaVersion 1, nonempty repositories)");
|
|
244
319
|
}
|
|
245
|
-
|
|
320
|
+
if (!onDiskPopulated)
|
|
321
|
+
return { inventorySource: resolved };
|
|
322
|
+
const merged = [];
|
|
323
|
+
const seen = new Set();
|
|
324
|
+
for (const id of readInventoryRepositories(host, join(cwd.absolutePath, WORKSPACE_INVENTORY_REL), "the on-disk hub inventory")) {
|
|
325
|
+
if (id !== "" && !seen.has(id)) {
|
|
326
|
+
seen.add(id);
|
|
327
|
+
merged.push(id);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
for (const id of readInventoryRepositories(host, resolved, "--inventory")) {
|
|
331
|
+
if (id !== "" && !seen.has(id)) {
|
|
332
|
+
seen.add(id);
|
|
333
|
+
merged.push(id);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return { mergedInventoryIds: merged };
|
|
246
337
|
}
|
|
247
338
|
export function planWorkspace(observation, host, options = {}) {
|
|
248
339
|
const { cwd } = observation;
|
|
340
|
+
const envOwner = observation.envOwner ?? (host.env.CLOSSYS_OWNER?.trim() || undefined);
|
|
341
|
+
if (envOwner !== undefined &&
|
|
342
|
+
!cwd.looksLikeFoundry &&
|
|
343
|
+
cwd.hub === undefined &&
|
|
344
|
+
cwd.git &&
|
|
345
|
+
cwd.githubOwner !== undefined &&
|
|
346
|
+
cwd.githubOwner !== envOwner) {
|
|
347
|
+
return refuse("violated", `CLOSSYS_OWNER is "${envOwner}" but the github.com origin here is owned by "${cwd.githubOwner}"; refusing to appoint a marker for the wrong account`);
|
|
348
|
+
}
|
|
249
349
|
if (cwd.looksLikeFoundry) {
|
|
250
350
|
return refuse("violated", "refusing to scaffold a hub inside the Foundry supplier tree; run from the GitHub repository you want to appoint, or from an empty directory");
|
|
251
351
|
}
|
|
@@ -272,6 +372,7 @@ export function planWorkspace(observation, host, options = {}) {
|
|
|
272
372
|
directory: cwd.absolutePath,
|
|
273
373
|
advisorVersion: observation.advisorVersion,
|
|
274
374
|
...(imported.inventorySource === undefined ? {} : { inventorySource: imported.inventorySource }),
|
|
375
|
+
...(imported.mergedInventoryIds === undefined ? {} : { mergedInventoryIds: imported.mergedInventoryIds }),
|
|
275
376
|
};
|
|
276
377
|
}
|
|
277
378
|
if (cwd.git) {
|
|
@@ -364,9 +465,8 @@ function mergeAdvisorPin(host, directory, skeletonRoot, advisorVersion, reposito
|
|
|
364
465
|
throw new Error("existing package.json is unreadable JSON");
|
|
365
466
|
}
|
|
366
467
|
const extra = new Set();
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
if (inDependencies !== undefined || inDevDependencies !== undefined)
|
|
468
|
+
const pinnedSomewhere = DEPENDENCY_BUCKETS.some((bucket) => clossysNames(manifest[bucket], extra) !== undefined);
|
|
469
|
+
if (pinnedSomewhere)
|
|
370
470
|
return;
|
|
371
471
|
const devDependencies = isRecord(manifest.devDependencies) ? { ...manifest.devDependencies } : {};
|
|
372
472
|
devDependencies[ADVISOR_PACKAGE] = advisorVersion;
|
|
@@ -383,7 +483,28 @@ function copySkeleton(host, skeletonRoot, plan) {
|
|
|
383
483
|
writeSkeletonFile(host, plan.directory, "AGENTS.md", CONSUMER_AGENTS_MD);
|
|
384
484
|
writeSkeletonFile(host, plan.directory, "CLAUDE.md", CONSUMER_CLAUDE_MD);
|
|
385
485
|
}
|
|
486
|
+
/** Refuses adopt when the working tree has uncommitted changes; names a non-github.com remote host. */
|
|
487
|
+
function assertCleanTree(host, directory) {
|
|
488
|
+
const status = host.run("git", ["status", "--porcelain"], { cwd: directory });
|
|
489
|
+
if (status.status === 0 && status.stdout.trim() !== "") {
|
|
490
|
+
const origin = host.run("git", ["remote", "get-url", "origin"], { cwd: directory }).stdout.trim();
|
|
491
|
+
let where = "this checkout";
|
|
492
|
+
if (origin !== "") {
|
|
493
|
+
try {
|
|
494
|
+
const parsed = new URL(origin);
|
|
495
|
+
if (parsed.protocol === "ssh:" || parsed.protocol === "https:" || parsed.protocol === "http:") {
|
|
496
|
+
where = `the repository on ${parsed.hostname}`;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
/* ssh form or unparsable; keep the generic host */
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
throw new Error(`${where} has uncommitted changes (git status --porcelain is nonempty); commit or stash them before appointing it as the account hub`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
386
506
|
function adoptHubFiles(host, skeletonRoot, plan) {
|
|
507
|
+
assertCleanTree(host, plan.directory);
|
|
387
508
|
const marker = {
|
|
388
509
|
schemaVersion: 1,
|
|
389
510
|
kind: "account-hub",
|
|
@@ -391,7 +512,11 @@ function adoptHubFiles(host, skeletonRoot, plan) {
|
|
|
391
512
|
repository: `${plan.owner}/${plan.repository}`,
|
|
392
513
|
};
|
|
393
514
|
writeSkeletonFile(host, plan.directory, WORKSPACE_MARKER_REL, `${JSON.stringify(marker, null, 2)}\n`);
|
|
394
|
-
if ("
|
|
515
|
+
if ("mergedInventoryIds" in plan && Array.isArray(plan.mergedInventoryIds)) {
|
|
516
|
+
const document = { schemaVersion: 1, repositories: plan.mergedInventoryIds.map((id) => ({ id })) };
|
|
517
|
+
writeSkeletonFile(host, plan.directory, WORKSPACE_INVENTORY_REL, `${JSON.stringify(document, null, 2)}\n`);
|
|
518
|
+
}
|
|
519
|
+
else if ("inventorySource" in plan && typeof plan.inventorySource === "string") {
|
|
395
520
|
const raw = host.readText(plan.inventorySource);
|
|
396
521
|
if (raw === null || inspectInventory(raw).status !== "populated") {
|
|
397
522
|
throw new Error("inventory source is not a populated inventory document");
|
|
@@ -421,55 +546,116 @@ function requireZero(result, label) {
|
|
|
421
546
|
throw new Error(`${label} failed (${result.status}): ${result.stderr.trim() || result.stdout.trim() || "no output"}`);
|
|
422
547
|
}
|
|
423
548
|
}
|
|
424
|
-
/**
|
|
549
|
+
/**
|
|
550
|
+
* Read-only pin and inventory report. Does not install or uninstall. Scans all
|
|
551
|
+
* four dependency buckets; grades each pinned advisor version against the live
|
|
552
|
+
* registry version, marking a pin older than live as a stale-pin finding and a
|
|
553
|
+
* degraded report.
|
|
554
|
+
*/
|
|
425
555
|
export function reportHubHealth(host, directory, liveAdvisorVersion) {
|
|
426
556
|
const extra = new Set();
|
|
427
|
-
|
|
428
|
-
let devDependencies;
|
|
557
|
+
const pins = {};
|
|
429
558
|
const manifestRaw = host.readText(join(directory, "package.json"));
|
|
430
559
|
if (manifestRaw !== null) {
|
|
431
560
|
try {
|
|
432
561
|
const parsed = JSON.parse(manifestRaw);
|
|
433
562
|
if (isRecord(parsed)) {
|
|
434
|
-
|
|
435
|
-
|
|
563
|
+
for (const bucket of DEPENDENCY_BUCKETS) {
|
|
564
|
+
const pin = clossysNames(parsed[bucket], extra);
|
|
565
|
+
if (pin !== undefined)
|
|
566
|
+
pins[bucket] = pin;
|
|
567
|
+
}
|
|
436
568
|
}
|
|
437
569
|
}
|
|
438
570
|
catch {
|
|
439
571
|
/* unreadable manifest is reported as missing pins */
|
|
440
572
|
}
|
|
441
573
|
}
|
|
574
|
+
const pinFindings = Object.entries(pins).flatMap(([bucket, pinned]) => {
|
|
575
|
+
if (liveAdvisorVersion === undefined)
|
|
576
|
+
return [];
|
|
577
|
+
const comparison = compareVersions(pinned, liveAdvisorVersion);
|
|
578
|
+
if (comparison === null) {
|
|
579
|
+
return [{ bucket: bucket, pinned, grade: "indeterminate", note: `cannot compare ${pinned} with live ${liveAdvisorVersion}` }];
|
|
580
|
+
}
|
|
581
|
+
return comparison < 0
|
|
582
|
+
? [{ bucket: bucket, pinned, grade: "stale", note: `pinned ${pinned} is older than live ${liveAdvisorVersion}` }]
|
|
583
|
+
: [];
|
|
584
|
+
});
|
|
442
585
|
return {
|
|
443
586
|
marker: readHub(host, directory) === undefined ? "missing" : "present",
|
|
444
587
|
inventory: inspectInventory(host.readText(join(directory, WORKSPACE_INVENTORY_REL))),
|
|
445
588
|
advisorPin: {
|
|
446
|
-
...(dependencies === undefined ? {} : { dependencies }),
|
|
447
|
-
...(devDependencies === undefined ? {} : { devDependencies }),
|
|
589
|
+
...(pins.dependencies === undefined ? {} : { dependencies: pins.dependencies }),
|
|
590
|
+
...(pins.devDependencies === undefined ? {} : { devDependencies: pins.devDependencies }),
|
|
591
|
+
...(pins.optionalDependencies === undefined ? {} : { optionalDependencies: pins.optionalDependencies }),
|
|
592
|
+
...(pins.peerDependencies === undefined ? {} : { peerDependencies: pins.peerDependencies }),
|
|
448
593
|
...(liveAdvisorVersion === undefined ? {} : { live: liveAdvisorVersion }),
|
|
449
594
|
},
|
|
450
|
-
dualPin:
|
|
595
|
+
dualPin: Object.values(pins).filter((value) => value !== undefined).length > 1,
|
|
451
596
|
extraClossys: [...extra].sort(),
|
|
597
|
+
pinFindings,
|
|
598
|
+
degraded: pinFindings.some((finding) => finding.grade === "stale"),
|
|
452
599
|
};
|
|
453
600
|
}
|
|
454
601
|
export function formatHubHealth(report) {
|
|
455
602
|
const pinParts = [];
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
603
|
+
for (const bucket of DEPENDENCY_BUCKETS) {
|
|
604
|
+
const pinned = report.advisorPin[bucket];
|
|
605
|
+
if (pinned !== undefined)
|
|
606
|
+
pinParts.push(`${bucket} ${pinned}`);
|
|
607
|
+
}
|
|
460
608
|
const pin = pinParts.length === 0 ? "missing" : pinParts.join(" and ");
|
|
461
609
|
const live = report.advisorPin.live === undefined ? "" : `; live ${report.advisorPin.live}`;
|
|
462
610
|
const extra = report.extraClossys.length === 0 ? "none" : report.extraClossys.join(", ");
|
|
463
611
|
const inventory = report.inventory.status === "populated" ? `populated (${report.inventory.count})` : report.inventory.status;
|
|
612
|
+
const findings = report.pinFindings.map((finding) => finding.note !== undefined ? `${finding.bucket} ${finding.note}` : `${finding.bucket} ${finding.grade}`);
|
|
613
|
+
const findingLine = findings.length === 0 ? "none" : findings.join("; ");
|
|
464
614
|
return [
|
|
465
615
|
`hub marker: ${report.marker}`,
|
|
466
616
|
`inventory: ${inventory}`,
|
|
467
617
|
`advisor pin: ${pin}${live}`,
|
|
468
618
|
`dual pin: ${report.dualPin ? "yes" : "no"}`,
|
|
469
619
|
`extra @clossys/*: ${extra}`,
|
|
620
|
+
`pin findings: ${findingLine}`,
|
|
621
|
+
`degraded: ${report.degraded ? "yes" : "no"}`,
|
|
470
622
|
`health: ${JSON.stringify(report)}`,
|
|
471
623
|
].join("\n");
|
|
472
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Read-only inventory validation: runs `gh repo view --json name` for each
|
|
627
|
+
* repository id, batched. Tolerates a missing or failing `gh` by skipping with
|
|
628
|
+
* a note; marks ids whose check fails as unknown. Never mutates the inventory.
|
|
629
|
+
*/
|
|
630
|
+
export function checkInventoryEntries(host, directory) {
|
|
631
|
+
const raw = host.readText(join(directory, WORKSPACE_INVENTORY_REL));
|
|
632
|
+
const observation = inspectInventory(raw);
|
|
633
|
+
if (observation.status !== "populated") {
|
|
634
|
+
return { entries: [], skipped: true, note: `inventory is ${observation.status}; nothing to validate` };
|
|
635
|
+
}
|
|
636
|
+
const available = commandAvailable(host, "gh");
|
|
637
|
+
if (!available) {
|
|
638
|
+
return { entries: [], skipped: true, note: "`gh` is unavailable; inventory ids were not validated" };
|
|
639
|
+
}
|
|
640
|
+
const ids = readInventoryRepositories(host, join(directory, WORKSPACE_INVENTORY_REL), "the hub inventory").filter((id) => id !== "");
|
|
641
|
+
const batch = 20;
|
|
642
|
+
const entries = [];
|
|
643
|
+
for (let index = 0; index < ids.length; index += batch) {
|
|
644
|
+
for (const id of ids.slice(index, index + batch)) {
|
|
645
|
+
const viewed = host.run("gh", ["repo", "view", id, "--json", "name"]);
|
|
646
|
+
if (viewed.status === 0) {
|
|
647
|
+
entries.push({ id, known: true });
|
|
648
|
+
}
|
|
649
|
+
else if (viewed.status === 127 || (viewed.status === null && viewed.stderr.includes("ENOENT"))) {
|
|
650
|
+
entries.push({ id, known: null, note: "`gh` unavailable; not checked" });
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
entries.push({ id, known: false, note: "`gh repo view` failed; the repository may not exist" });
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return { entries, skipped: false };
|
|
658
|
+
}
|
|
473
659
|
function withHealth(host, directory, headline, liveAdvisorVersion) {
|
|
474
660
|
const health = reportHubHealth(host, directory, liveAdvisorVersion);
|
|
475
661
|
return {
|