@clossys/launcher 0.1.1
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 +27 -0
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/check-cli.d.ts +14 -0
- package/dist/check-cli.d.ts.map +1 -0
- package/dist/check-cli.js +161 -0
- package/dist/check-cli.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +90 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.d.ts +29 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +500 -0
- package/dist/core.js.map +1 -0
- package/dist/host.d.ts +4 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +65 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -0
- package/skeleton/.clossys/inventory.json +4 -0
- package/skeleton/.clossys/workspace.json +6 -0
- package/skeleton/README.md +29 -0
- package/skeleton/package.json +13 -0
- package/src/check-cli.ts +179 -0
- package/src/cli.ts +92 -0
- package/src/core.ts +570 -0
- package/src/host.ts +63 -0
- package/src/index.ts +28 -0
- package/src/types.ts +114 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.1] - 2026-09-19
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Appoint leaves an existing `@clossys/advisor` pin in whichever bucket it already occupies. It no longer dual-pins or overwrites a frozen version with the live registry version.
|
|
13
|
+
- Appoint refuses when 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. Create may still write an empty inventory. Resume does not invent one.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Read-only health report after create, resume, and appoint: hub marker, inventory classification, Advisor pin location and version versus live, dual pin, extra `@clossys/*` names. Does not uninstall.
|
|
18
|
+
|
|
19
|
+
## [0.1.0] - 2026-09-18
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `npx @clossys/launcher` as the single get-started command.
|
|
24
|
+
- In-package hub skeleton (not a Foundry fork) copied into a GitHub repository.
|
|
25
|
+
- Create a new `{owner}/workspace` hub, resume an existing hub, or adopt the current GitHub repository as the account hub.
|
|
26
|
+
- Owner inference from `gh` and git remotes, with an interactive picker only when more than one GitHub owner is visible.
|
|
27
|
+
- `launcher-check --input` grades a captured observation without creating a hub, so qualification can prove the 0/1/2 ternary.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Clossys
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Foundry Launcher
|
|
2
|
+
|
|
3
|
+
Foundry Launcher (`@clossys/launcher`) is executable tooling
|
|
4
|
+
that makes one GitHub repository the account workspace hub. It is not a role
|
|
5
|
+
and does not claim adoption, grounding, or closure.
|
|
6
|
+
|
|
7
|
+
The hub inventories where Foundry packages are installed and coordinates
|
|
8
|
+
engagement. It is not a product application and does not receive a dump of
|
|
9
|
+
the catalogue.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
The get-started command is the package name:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx @clossys/launcher
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Public npm reads are credentialless. Packages publish to
|
|
20
|
+
`https://registry.npmjs.org`. Do not add a token or private registry
|
|
21
|
+
mapping for `@clossys`. Pin an exact version once you depend on the library
|
|
22
|
+
API:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install --save-dev --save-exact @clossys/launcher@0.1.1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## How to run it
|
|
29
|
+
|
|
30
|
+
There is no `--org` flag. Owner is inferred from authenticated `gh` and from
|
|
31
|
+
the current git remote. If more than one GitHub owner is visible, the
|
|
32
|
+
command asks which one should hold the hub. Non-interactive runs may set
|
|
33
|
+
`CLOSSYS_OWNER`.
|
|
34
|
+
|
|
35
|
+
GitHub-only. A GitLab, self-hosted, or other remote is a refusal, not a
|
|
36
|
+
silent fallback.
|
|
37
|
+
|
|
38
|
+
| Current directory | What happens |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| 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. |
|
|
43
|
+
|
|
44
|
+
It does not have to be a brand-new exclusive repository, and it does not
|
|
45
|
+
have to already match a Foundry layout. Informal "workspace-looking" trees
|
|
46
|
+
are appointed by writing the hub contract, not assumed to be hubs already.
|
|
47
|
+
Product applications may be appointed: they become the hub **and** remain
|
|
48
|
+
the product. Sister repositories still pin their own roles. Appoint does
|
|
49
|
+
not install packages.
|
|
50
|
+
|
|
51
|
+
Do not run this inside the Foundry supplier tree.
|
|
52
|
+
|
|
53
|
+
Open the resulting folder in your coding agent. Advisor stays read-only
|
|
54
|
+
until you approve a next action. The same command resumes later.
|
|
55
|
+
|
|
56
|
+
## CLI
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
launcher
|
|
60
|
+
launcher --inventory path/to/inventory.json
|
|
61
|
+
launcher --help
|
|
62
|
+
launcher-check --help
|
|
63
|
+
launcher-check --input observation.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Exit codes preserve the ternary:
|
|
67
|
+
|
|
68
|
+
| Exit | State | Meaning |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| `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 supplier tree. |
|
|
72
|
+
| `2` | `indeterminate` | Missing `gh`, unreadable registry pin, or an owner that could not be inferred. |
|
|
73
|
+
|
|
74
|
+
`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.
|
|
75
|
+
|
|
76
|
+
## API
|
|
77
|
+
|
|
78
|
+
| Export | Description |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `planWorkspace()` | Decides create, resume, or adopt from a cwd observation. Optional `{ inventoryPath }` is the only way to appoint without a populated on-disk inventory. |
|
|
81
|
+
| `applyWorkspacePlan()` | Copies the in-package skeleton or hub marker through a host port and returns a `WorkspaceApplyResult` with health. Resume does not write. |
|
|
82
|
+
| `observeWorkspace()` | Reads `gh`, git remotes, cwd, inventory classification, and the public Advisor version. |
|
|
83
|
+
| `parseGitHubRemote()` | Parses a github.com remote and rejects any other host. |
|
|
84
|
+
| `isHubDocument()` | Type guard for the generated hub marker (packed template: `skeleton/.clossys/workspace.json`). |
|
|
85
|
+
| `inspectInventory()` | Classifies inventory JSON as missing, empty, or populated. |
|
|
86
|
+
| `reportHubHealth()` | Read-only pin and inventory report. Does not install or uninstall. |
|
|
87
|
+
| `formatHubHealth()` | Human lines plus a `health:` JSON line for the same report. |
|
|
88
|
+
| `DEFAULT_REPOSITORY_NAME` | Default new-hub repository name (`workspace`). Used only when creating, never when appointing. |
|
|
89
|
+
| `WORKSPACE_MARKER_REL` | Relative path of the hub marker. |
|
|
90
|
+
| `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. |
|
|
92
|
+
|
|
93
|
+
## Why this is not Advisor, Starter, Builder, installer, creator, or a connector
|
|
94
|
+
|
|
95
|
+
Advisor is the engagement engine: it grades evidence and names a next
|
|
96
|
+
action. It has no GitHub I/O, and must not grow any. A remote chat
|
|
97
|
+
connector is a separately deployed product surface for that engine, not a
|
|
98
|
+
repo scaffolder.
|
|
99
|
+
|
|
100
|
+
Starter (`@clossys/starter`) is the protected-base **activation** gate.
|
|
101
|
+
Its only v1 subcommand is `decide`. It joins a pull-request snapshot to
|
|
102
|
+
fixed install evidence, Advisor readiness, and one target CLI. It refuses
|
|
103
|
+
commands, shell, and caller-selected paths. That is why get-started is not
|
|
104
|
+
`npx @clossys/starter`: a no-argument Starter invocation that created a
|
|
105
|
+
GitHub repository would be a contract break, and stuffing `gh repo create`
|
|
106
|
+
into `foundry-starter decide` would be the same defect. Starter starts the
|
|
107
|
+
trusted-base **loop in CI**, after a hub and a workflow already exist. It
|
|
108
|
+
does not start the human.
|
|
109
|
+
|
|
110
|
+
Builder realizes declared live state later in operating control. A new
|
|
111
|
+
hub has no declared topology yet.
|
|
112
|
+
|
|
113
|
+
This package is not named installer: an install is not adoption, Starter
|
|
114
|
+
already owns install-evidence joins, and the hub must not dump the
|
|
115
|
+
catalogue. It is not named creator: that reads as a role. Launcher is the
|
|
116
|
+
get-started bin that puts a hub on disk so a coding agent can open it.
|
|
117
|
+
|
|
118
|
+
This package exists because `npx` runs a **package name**. Step 0 is a
|
|
119
|
+
bin and a skeleton, not a role. It stays executable tooling so Starter's
|
|
120
|
+
`decide` contract, Advisor's engine boundary, and Builder's loop stay
|
|
121
|
+
intact.
|
|
122
|
+
|
|
123
|
+
## Requirements
|
|
124
|
+
|
|
125
|
+
Node.js 20+, ESM, GitHub `gh`, and no runtime dependencies. Creating a new
|
|
126
|
+
hub needs permission to create a private repository under the inferred
|
|
127
|
+
owner. Appointing uses the current checkout and does not create a second
|
|
128
|
+
repository.
|
|
129
|
+
|
|
130
|
+
## Licence
|
|
131
|
+
|
|
132
|
+
MIT.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import type { WorkspaceHost, WorkspaceObservation } from "./types.js";
|
|
3
|
+
export declare const CHECK_USAGE = "Usage: launcher-check --input <observation.json>\n\nGrade a captured workspace observation through planWorkspace. This bin does\nnot create, resume, or appoint a hub.\n\nExit codes: 0 = a create, resume, or adopt plan, 1 = a known refusal,\n2 = indeterminate or the input could not be read.";
|
|
4
|
+
export declare class LauncherCheckInputError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export declare function parseObservation(value: unknown): WorkspaceObservation;
|
|
7
|
+
/** Host used only for owner prompting. Grading never creates a hub. */
|
|
8
|
+
export declare function planningHost(): WorkspaceHost;
|
|
9
|
+
export declare function parseCheckArgs(argv: readonly string[]): {
|
|
10
|
+
help: boolean;
|
|
11
|
+
inputPath?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function checkMain(argv: readonly string[], readText: (path: string) => string, writeOut: (text: string) => void, writeErr: (text: string) => void): number;
|
|
14
|
+
//# sourceMappingURL=check-cli.d.ts.map
|
|
@@ -0,0 +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;AAiDrD,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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { isDirectInvocation } from "./cli.js";
|
|
5
|
+
import { planWorkspace } from "./core.js";
|
|
6
|
+
export const CHECK_USAGE = `Usage: launcher-check --input <observation.json>
|
|
7
|
+
|
|
8
|
+
Grade a captured workspace observation through planWorkspace. This bin does
|
|
9
|
+
not create, resume, or appoint a hub.
|
|
10
|
+
|
|
11
|
+
Exit codes: 0 = a create, resume, or adopt plan, 1 = a known refusal,
|
|
12
|
+
2 = indeterminate or the input could not be read.`;
|
|
13
|
+
export class LauncherCheckInputError extends Error {
|
|
14
|
+
}
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function isText(value) {
|
|
19
|
+
return typeof value === "string" && value.trim() !== "";
|
|
20
|
+
}
|
|
21
|
+
function parseInventoryObservation(value) {
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (!isRecord(value)) {
|
|
25
|
+
throw new LauncherCheckInputError("observation.cwd.inventory must be an object");
|
|
26
|
+
}
|
|
27
|
+
if (value.status !== "missing" && value.status !== "empty" && value.status !== "populated") {
|
|
28
|
+
throw new LauncherCheckInputError("observation.cwd.inventory.status must be missing, empty, or populated");
|
|
29
|
+
}
|
|
30
|
+
if (typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0) {
|
|
31
|
+
throw new LauncherCheckInputError("observation.cwd.inventory.count must be a nonnegative integer");
|
|
32
|
+
}
|
|
33
|
+
return { status: value.status, count: value.count };
|
|
34
|
+
}
|
|
35
|
+
function parseCwd(value) {
|
|
36
|
+
if (!isRecord(value) || !isText(value.absolutePath)) {
|
|
37
|
+
throw new LauncherCheckInputError("observation.cwd.absolutePath must be a nonempty string");
|
|
38
|
+
}
|
|
39
|
+
if (typeof value.empty !== "boolean" || typeof value.git !== "boolean" || typeof value.looksLikeFoundry !== "boolean") {
|
|
40
|
+
throw new LauncherCheckInputError("observation.cwd must declare empty, git, and looksLikeFoundry booleans");
|
|
41
|
+
}
|
|
42
|
+
if (value.githubOwner !== undefined && !isText(value.githubOwner)) {
|
|
43
|
+
throw new LauncherCheckInputError("observation.cwd.githubOwner must be a string");
|
|
44
|
+
}
|
|
45
|
+
if (value.githubRepository !== undefined && !isText(value.githubRepository)) {
|
|
46
|
+
throw new LauncherCheckInputError("observation.cwd.githubRepository must be a string");
|
|
47
|
+
}
|
|
48
|
+
const inventory = parseInventoryObservation(value.inventory);
|
|
49
|
+
return {
|
|
50
|
+
absolutePath: value.absolutePath,
|
|
51
|
+
empty: value.empty,
|
|
52
|
+
git: value.git,
|
|
53
|
+
looksLikeFoundry: value.looksLikeFoundry,
|
|
54
|
+
...(isText(value.githubOwner) ? { githubOwner: value.githubOwner } : {}),
|
|
55
|
+
...(isText(value.githubRepository) ? { githubRepository: value.githubRepository } : {}),
|
|
56
|
+
...(inventory === undefined ? {} : { inventory }),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function parseObservation(value) {
|
|
60
|
+
if (!isRecord(value))
|
|
61
|
+
throw new LauncherCheckInputError("observation must be a JSON object");
|
|
62
|
+
if (!Array.isArray(value.ownerCandidates) || value.ownerCandidates.some((item) => typeof item !== "string")) {
|
|
63
|
+
throw new LauncherCheckInputError("observation.ownerCandidates must be an array of strings");
|
|
64
|
+
}
|
|
65
|
+
if (typeof value.ghAvailable !== "boolean" || typeof value.gitAvailable !== "boolean") {
|
|
66
|
+
throw new LauncherCheckInputError("observation must declare ghAvailable and gitAvailable booleans");
|
|
67
|
+
}
|
|
68
|
+
if (value.envOwner !== undefined && !isText(value.envOwner)) {
|
|
69
|
+
throw new LauncherCheckInputError("observation.envOwner must be a string");
|
|
70
|
+
}
|
|
71
|
+
if (value.advisorVersion !== undefined && !isText(value.advisorVersion)) {
|
|
72
|
+
throw new LauncherCheckInputError("observation.advisorVersion must be a string");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
cwd: parseCwd(value.cwd),
|
|
76
|
+
ownerCandidates: value.ownerCandidates,
|
|
77
|
+
ghAvailable: value.ghAvailable,
|
|
78
|
+
gitAvailable: value.gitAvailable,
|
|
79
|
+
...(isText(value.envOwner) ? { envOwner: value.envOwner } : {}),
|
|
80
|
+
...(isText(value.advisorVersion) ? { advisorVersion: value.advisorVersion } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function unused() {
|
|
84
|
+
return { status: 1, stdout: "", stderr: "launcher-check does not run host commands" };
|
|
85
|
+
}
|
|
86
|
+
/** Host used only for owner prompting. Grading never creates a hub. */
|
|
87
|
+
export function planningHost() {
|
|
88
|
+
return {
|
|
89
|
+
cwd: "/",
|
|
90
|
+
env: {},
|
|
91
|
+
isTTY: false,
|
|
92
|
+
now: () => "1970-01-01T00:00:00.000Z",
|
|
93
|
+
exists: () => false,
|
|
94
|
+
isDirectory: () => false,
|
|
95
|
+
readText: () => null,
|
|
96
|
+
writeText: () => {
|
|
97
|
+
throw new Error("launcher-check does not write");
|
|
98
|
+
},
|
|
99
|
+
mkdirp: () => {
|
|
100
|
+
throw new Error("launcher-check does not write");
|
|
101
|
+
},
|
|
102
|
+
readDir: () => [],
|
|
103
|
+
run: () => unused(),
|
|
104
|
+
prompt: () => null,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function parseCheckArgs(argv) {
|
|
108
|
+
if (argv.length === 0)
|
|
109
|
+
return { help: true };
|
|
110
|
+
if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h"))
|
|
111
|
+
return { help: true };
|
|
112
|
+
if (argv.length === 2 && argv[0] === "--input" && argv[1])
|
|
113
|
+
return { help: false, inputPath: argv[1] };
|
|
114
|
+
throw new LauncherCheckInputError("expected --input <observation.json>, or --help");
|
|
115
|
+
}
|
|
116
|
+
export function checkMain(argv, readText, writeOut, writeErr) {
|
|
117
|
+
const parsed = parseCheckArgs(argv);
|
|
118
|
+
if (parsed.help) {
|
|
119
|
+
writeOut(`${CHECK_USAGE}\n`);
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
const inputPath = parsed.inputPath;
|
|
123
|
+
if (inputPath === undefined)
|
|
124
|
+
throw new LauncherCheckInputError("expected --input <observation.json>");
|
|
125
|
+
let raw;
|
|
126
|
+
try {
|
|
127
|
+
raw = readText(resolve(inputPath));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new LauncherCheckInputError(`cannot read ${inputPath}`);
|
|
131
|
+
}
|
|
132
|
+
let parsedJson;
|
|
133
|
+
try {
|
|
134
|
+
parsedJson = JSON.parse(raw);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
throw new LauncherCheckInputError(`${inputPath} is not JSON`);
|
|
138
|
+
}
|
|
139
|
+
const observation = parseObservation(parsedJson);
|
|
140
|
+
const decision = planWorkspace(observation, planningHost());
|
|
141
|
+
if (decision.action === "refuse") {
|
|
142
|
+
writeErr(`launcher-check: ${decision.message}\n`);
|
|
143
|
+
return decision.state === "violated" ? 1 : 2;
|
|
144
|
+
}
|
|
145
|
+
writeOut(`${JSON.stringify({ action: decision.action, owner: decision.owner, repository: decision.repository })}\n`);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
if (isDirectInvocation(import.meta.url, process.argv[1])) {
|
|
149
|
+
try {
|
|
150
|
+
process.exitCode = checkMain(process.argv.slice(2), (path) => readFileSync(path, "utf8"), (text) => {
|
|
151
|
+
process.stdout.write(text);
|
|
152
|
+
}, (text) => {
|
|
153
|
+
process.stderr.write(text);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (cause) {
|
|
157
|
+
process.stderr.write(`launcher-check: ${cause instanceof Error ? cause.message : String(cause)}\n`);
|
|
158
|
+
process.exitCode = 2;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=check-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-cli.js","sourceRoot":"","sources":["../src/check-cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import type { WorkspaceHost } from "./types.js";
|
|
3
|
+
export declare const USAGE = "Usage: launcher [--inventory <path>]\n\nCreate, resume, or appoint a GitHub repository as the account workspace hub.\n\nRun from an empty directory to create {owner}/workspace. Run from an existing\nhub to resume. Run from any GitHub repository you want to own the account-level\nhub to appoint it \u2014 it does not have to be a new exclusive repo, and it keeps\nits current name and files.\n\nAppointing requires a populated generated hub inventory (packed template\nskeleton/.clossys/inventory.json; the generated path does not ship), or\n--inventory <path> pointing at one. Resume does not write. Create may write\nan empty inventory.\n\nGitHub-only. Owner is inferred from `gh` and git remotes. Public npm reads\nneed no token.\n\nExit codes: 0 = satisfied, 1 = a known refusal, 2 = indeterminate.";
|
|
4
|
+
export declare class LauncherInputError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export declare function parseLauncherArgs(argv: readonly string[]): {
|
|
7
|
+
help: boolean;
|
|
8
|
+
inventoryPath?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Testable CLI dispatcher. Unknown arguments throw; the executable maps them to exit 2. */
|
|
11
|
+
export declare function main(argv: readonly string[], host: WorkspaceHost, skeletonRoot: string): number;
|
|
12
|
+
/** Resolves an npm/POSIX bin symlink before deciding whether this module is the entrypoint. */
|
|
13
|
+
export declare function isDirectInvocation(moduleUrl: string, argvPath: string | undefined): boolean;
|
|
14
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +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,CA4B/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
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { applyWorkspacePlan, observeWorkspace, planWorkspace, skeletonRootFromModule } from "./core.js";
|
|
6
|
+
import { createNodeHost } from "./host.js";
|
|
7
|
+
export const USAGE = `Usage: launcher [--inventory <path>]
|
|
8
|
+
|
|
9
|
+
Create, resume, or appoint a GitHub repository as the account workspace hub.
|
|
10
|
+
|
|
11
|
+
Run from an empty directory to create {owner}/workspace. Run from an existing
|
|
12
|
+
hub to resume. Run from any GitHub repository you want to own the account-level
|
|
13
|
+
hub to appoint it — it does not have to be a new exclusive repo, and it keeps
|
|
14
|
+
its current name and files.
|
|
15
|
+
|
|
16
|
+
Appointing requires a populated generated hub inventory (packed template
|
|
17
|
+
skeleton/.clossys/inventory.json; the generated path does not ship), or
|
|
18
|
+
--inventory <path> pointing at one. Resume does not write. Create may write
|
|
19
|
+
an empty inventory.
|
|
20
|
+
|
|
21
|
+
GitHub-only. Owner is inferred from \`gh\` and git remotes. Public npm reads
|
|
22
|
+
need no token.
|
|
23
|
+
|
|
24
|
+
Exit codes: 0 = satisfied, 1 = a known refusal, 2 = indeterminate.`;
|
|
25
|
+
export class LauncherInputError extends Error {
|
|
26
|
+
}
|
|
27
|
+
function exitCodeFor(state) {
|
|
28
|
+
return state === "satisfied" ? 0 : state === "violated" ? 1 : 2;
|
|
29
|
+
}
|
|
30
|
+
export function parseLauncherArgs(argv) {
|
|
31
|
+
if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h"))
|
|
32
|
+
return { help: true };
|
|
33
|
+
if (argv.length === 0)
|
|
34
|
+
return { help: false };
|
|
35
|
+
if (argv.length === 2 && argv[0] === "--inventory" && argv[1])
|
|
36
|
+
return { help: false, inventoryPath: argv[1] };
|
|
37
|
+
throw new LauncherInputError("launcher takes no arguments except optional --inventory <path>; run it from the directory to create or appoint");
|
|
38
|
+
}
|
|
39
|
+
/** Testable CLI dispatcher. Unknown arguments throw; the executable maps them to exit 2. */
|
|
40
|
+
export function main(argv, host, skeletonRoot) {
|
|
41
|
+
const parsed = parseLauncherArgs(argv);
|
|
42
|
+
if (parsed.help) {
|
|
43
|
+
console.log(USAGE);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
const observation = observeWorkspace(host);
|
|
47
|
+
if (!observation.cwd.empty &&
|
|
48
|
+
!observation.cwd.git &&
|
|
49
|
+
observation.cwd.hub === undefined &&
|
|
50
|
+
!observation.cwd.looksLikeFoundry) {
|
|
51
|
+
console.log(USAGE);
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
const decision = planWorkspace(observation, host, { inventoryPath: parsed.inventoryPath });
|
|
55
|
+
if (decision.action === "refuse") {
|
|
56
|
+
console.error(`launcher: ${decision.message}`);
|
|
57
|
+
return exitCodeFor(decision.state);
|
|
58
|
+
}
|
|
59
|
+
if (parsed.inventoryPath !== undefined && decision.action !== "adopt") {
|
|
60
|
+
console.error("launcher: --inventory is only valid when appointing a GitHub repository");
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
const result = applyWorkspacePlan(host, decision, skeletonRoot);
|
|
64
|
+
console.log(result.message);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
function run() {
|
|
68
|
+
try {
|
|
69
|
+
const host = createNodeHost();
|
|
70
|
+
process.exitCode = main(process.argv.slice(2), host, skeletonRootFromModule(import.meta.url));
|
|
71
|
+
}
|
|
72
|
+
catch (cause) {
|
|
73
|
+
console.error(`launcher: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
74
|
+
process.exitCode = 2;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Resolves an npm/POSIX bin symlink before deciding whether this module is the entrypoint. */
|
|
78
|
+
export function isDirectInvocation(moduleUrl, argvPath) {
|
|
79
|
+
if (argvPath === undefined)
|
|
80
|
+
return false;
|
|
81
|
+
try {
|
|
82
|
+
return realpathSync(fileURLToPath(moduleUrl)) === realpathSync(resolve(argvPath));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (isDirectInvocation(import.meta.url, process.argv[1]))
|
|
89
|
+
run();
|
|
90
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { HubDocument, HubHealthReport, InventoryObservation, WorkspaceApplyResult, WorkspaceDecision, WorkspaceHost, WorkspaceObservation, WorkspacePlan } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_REPOSITORY_NAME = "workspace";
|
|
3
|
+
export declare const WORKSPACE_MARKER_REL = ".clossys/workspace.json";
|
|
4
|
+
export declare const WORKSPACE_INVENTORY_REL = ".clossys/inventory.json";
|
|
5
|
+
export declare const ADVISOR_PACKAGE = "@clossys/advisor";
|
|
6
|
+
/** Written at generate time so this package never ships a nested AGENTS.md. */
|
|
7
|
+
export declare const CONSUMER_AGENTS_MD = "# Account workspace\n\nThis repository is the account hub for Foundry packages. It inventories\nwhere packages are installed and coordinates engagement. It is not a\nproduct application and does not need the whole catalogue installed here.\n\nOpen this folder in your coding agent. Advisor is read-only until you\napprove a next action.\n\nRun `npx @clossys/launcher` again to resume. Public npm reads\nneed no token.\n";
|
|
8
|
+
export declare const CONSUMER_CLAUDE_MD = "@AGENTS.md\n";
|
|
9
|
+
/** Parses a GitHub git remote. Any other host is rejected. */
|
|
10
|
+
export declare function parseGitHubRemote(url: string): {
|
|
11
|
+
owner: string;
|
|
12
|
+
repository: string;
|
|
13
|
+
} | null;
|
|
14
|
+
/** True when the marker is a v1 account-hub document. */
|
|
15
|
+
export declare function isHubDocument(value: unknown): value is HubDocument;
|
|
16
|
+
/** Classifies a generated hub inventory (packed template skeleton/.clossys/inventory.json; the generated path does not ship) without inventing repositories. */
|
|
17
|
+
export declare function inspectInventory(raw: string | null): InventoryObservation;
|
|
18
|
+
/** Collects GitHub owner, cwd shape, default-hub presence, and the public Advisor pin. */
|
|
19
|
+
export declare function observeWorkspace(host: WorkspaceHost): WorkspaceObservation;
|
|
20
|
+
export declare function planWorkspace(observation: WorkspaceObservation, host: WorkspaceHost, options?: {
|
|
21
|
+
inventoryPath?: string;
|
|
22
|
+
}): WorkspaceDecision;
|
|
23
|
+
/** Read-only pin and inventory report. Does not install or uninstall. */
|
|
24
|
+
export declare function reportHubHealth(host: WorkspaceHost, directory: string, liveAdvisorVersion?: string): HubHealthReport;
|
|
25
|
+
export declare function formatHubHealth(report: HubHealthReport): string;
|
|
26
|
+
/** Applies a create, resume, or adopt plan through the host. Resume does not write. */
|
|
27
|
+
export declare function applyWorkspacePlan(host: WorkspaceHost, plan: WorkspacePlan, skeletonRoot: string): WorkspaceApplyResult;
|
|
28
|
+
export declare function skeletonRootFromModule(moduleUrl: string): string;
|
|
29
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,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;AAYlD,+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;AAED,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,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,oBAAoB,CA4D1E;AAiDD,wBAAgB,aAAa,CAC3B,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,iBAAiB,CAiEnB;AA2HD,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,eAAe,CA2BpH;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAiB/D;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"}
|