@clossys/launcher 0.1.5 → 0.3.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/README.md +213 -20
- package/contracts/conversation-contract.md +41 -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 -5
- package/skeleton/README.md +5 -0
- package/skeleton/package.json +1 -1
- package/skill/SKILL.md +41 -0
- package/skill-catalogue/advisor/SKILL.md +46 -8
- package/skill-catalogue/architect/SKILL.md +0 -11
- package/skill-catalogue/bouncer/SKILL.md +0 -11
- package/skill-catalogue/builder/SKILL.md +0 -11
- package/skill-catalogue/butler/SKILL.md +0 -11
- package/skill-catalogue/controller/SKILL.md +6 -9
- package/skill-catalogue/customer/SKILL.md +83 -0
- package/skill-catalogue/designer/SKILL.md +18 -9
- package/skill-catalogue/giver/SKILL.md +0 -11
- package/skill-catalogue/influencer/SKILL.md +0 -11
- package/skill-catalogue/inspector/SKILL.md +1 -12
- package/skill-catalogue/integrator/SKILL.md +0 -11
- package/skill-catalogue/keeper/SKILL.md +0 -11
- package/skill-catalogue/launcher/SKILL.md +0 -12
- package/skill-catalogue/locksmith/SKILL.md +0 -11
- package/skill-catalogue/messenger/SKILL.md +0 -11
- package/skill-catalogue/observer/SKILL.md +0 -11
- package/skill-catalogue/publisher/SKILL.md +18 -10
- package/skill-catalogue/starter/SKILL.md +0 -11
- package/skill-catalogue/strategist/SKILL.md +35 -12
- package/skill-catalogue/writer/SKILL.md +7 -9
- 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/CHANGELOG.md +0 -64
- /package/skeleton/{.clossys → clossys/.state}/inventory.json +0 -0
- /package/skeleton/{.clossys → clossys/.state}/workspace.json +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { WorkspaceHost } from "./types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* One check from this repository's own docs/contracts/product-repository-layout.json `cloudSessionBootstrap` list (that contract file does not ship in the published package).
|
|
6
|
+
* Read-only: verifies a product repository has what a cloud agent session
|
|
7
|
+
* (browser plus GitHub only, no local setup) needs to install and run the
|
|
8
|
+
* team, without foundry's own heavy governance gates.
|
|
9
|
+
*/
|
|
10
|
+
export interface CloudBootstrapCheck {
|
|
11
|
+
readonly id: "package-manifest" | "agents-pointer" | "hub-marker";
|
|
12
|
+
readonly label: string;
|
|
13
|
+
readonly satisfied: boolean;
|
|
14
|
+
readonly note?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CloudBootstrapReport {
|
|
18
|
+
readonly schemaVersion: 1;
|
|
19
|
+
readonly checks: readonly CloudBootstrapCheck[];
|
|
20
|
+
readonly ready: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const PACKAGE_JSON_REL = "package.json";
|
|
24
|
+
const PACKAGE_LOCK_REL = "package-lock.json";
|
|
25
|
+
const AGENTS_MD_REL = "AGENTS.md";
|
|
26
|
+
const HUB_MARKER_REL = join("clossys", ".state", "workspace.json");
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Runs the three product-repository-layout.json cloudSessionBootstrap checks
|
|
30
|
+
* against `directory`. Never mutates anything, never runs `npm ci` itself
|
|
31
|
+
* -- it checks that the manifest and lockfile are BOTH present, which is
|
|
32
|
+
* the precondition a real `npm ci` needs, not a substitute for running it.
|
|
33
|
+
*/
|
|
34
|
+
export function checkCloudSessionBootstrap(host: WorkspaceHost, directory: string): CloudBootstrapReport {
|
|
35
|
+
const hasManifest = host.exists(join(directory, PACKAGE_JSON_REL));
|
|
36
|
+
const hasLock = host.exists(join(directory, PACKAGE_LOCK_REL));
|
|
37
|
+
const manifestCheck: CloudBootstrapCheck = {
|
|
38
|
+
id: "package-manifest",
|
|
39
|
+
label: "package.json and package-lock.json are both present",
|
|
40
|
+
satisfied: hasManifest && hasLock,
|
|
41
|
+
...(hasManifest && hasLock
|
|
42
|
+
? {}
|
|
43
|
+
: {
|
|
44
|
+
note: !hasManifest && !hasLock
|
|
45
|
+
? "Neither package.json nor package-lock.json exists yet."
|
|
46
|
+
: !hasManifest
|
|
47
|
+
? "package-lock.json exists but package.json does not."
|
|
48
|
+
: "package.json exists but package-lock.json does not -- npm ci needs both.",
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const agentsRaw = host.readText(join(directory, AGENTS_MD_REL));
|
|
53
|
+
const agentsPointsAtClossys = agentsRaw !== null && agentsRaw.includes("clossys/");
|
|
54
|
+
const agentsCheck: CloudBootstrapCheck = {
|
|
55
|
+
id: "agents-pointer",
|
|
56
|
+
label: "AGENTS.md exists at the repository root and points at clossys/",
|
|
57
|
+
satisfied: agentsPointsAtClossys,
|
|
58
|
+
...(agentsPointsAtClossys
|
|
59
|
+
? {}
|
|
60
|
+
: { note: agentsRaw === null ? "AGENTS.md does not exist at the repository root." : "AGENTS.md exists but does not mention clossys/." }),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const hasHubMarker = host.exists(join(directory, HUB_MARKER_REL));
|
|
64
|
+
const markerCheck: CloudBootstrapCheck = {
|
|
65
|
+
id: "hub-marker",
|
|
66
|
+
label: "clossys/.state/workspace.json (the hub marker) is present",
|
|
67
|
+
satisfied: hasHubMarker,
|
|
68
|
+
...(hasHubMarker ? {} : { note: "clossys/.state/workspace.json does not exist yet." }),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const checks = [manifestCheck, agentsCheck, markerCheck];
|
|
72
|
+
return { schemaVersion: 1, checks, ready: checks.every((check) => check.satisfied) };
|
|
73
|
+
}
|
package/src/skills.ts
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { dirname, join, resolve, sep } from "node:path";
|
|
2
|
-
import
|
|
2
|
+
import { extractContractBlock, injectContract } from "./contract.js";
|
|
3
|
+
import { parseSkillManifest, readInstalledVersion, serializeSkillManifest, sha256Hex } from "./manifest.js";
|
|
4
|
+
import type { SkillManifestEntry, WorkspaceHost } from "./types.js";
|
|
3
5
|
|
|
4
6
|
export interface SkillCompositionResult {
|
|
5
7
|
readonly composed: readonly string[];
|
|
6
8
|
readonly skipped: readonly { readonly packageDir: string; readonly note: string }[];
|
|
9
|
+
readonly rosterTargets?: readonly string[];
|
|
10
|
+
readonly rosterSkipped?: readonly { readonly inventoryId: string; readonly note: string }[];
|
|
11
|
+
/** Skills pruned this run: present in the directory's previous manifest, absent from this run's composed set. */
|
|
12
|
+
readonly retired: readonly string[];
|
|
7
13
|
}
|
|
8
14
|
|
|
9
15
|
export interface ComposeSkillsOptions {
|
|
10
16
|
readonly skillCatalogueRoot?: string;
|
|
11
17
|
readonly launcherPackageRoot: string;
|
|
18
|
+
/** Overrides where the packed conversation contract is read from (tests). */
|
|
19
|
+
readonly contractPath?: string;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
|
-
const DISCOVERY_PREFIXES = [".cursor/skills", ".claude/skills"] as const;
|
|
22
|
+
export const DISCOVERY_PREFIXES = [".cursor/skills", ".claude/skills"] as const;
|
|
15
23
|
const AGENTS_SKILLS_REL = join(".agents", "skills");
|
|
24
|
+
export const SKILLS_MANIFEST_REL = join("clossys", ".state", "skills.json");
|
|
16
25
|
|
|
17
26
|
function containedPath(root: string, relativePath: string): string {
|
|
18
27
|
const resolved = resolve(root, relativePath);
|
|
@@ -33,14 +42,63 @@ function skillSourceCandidates(packageDir: string, options: ComposeSkillsOptions
|
|
|
33
42
|
return paths;
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
function
|
|
45
|
+
function installedSkillPath(composeTargetDirectory: string, packageDir: string): string {
|
|
46
|
+
return join(composeTargetDirectory, "node_modules", "@clossys", packageDir, "skill", "SKILL.md");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readSkillBody(
|
|
50
|
+
host: WorkspaceHost,
|
|
51
|
+
packageDir: string,
|
|
52
|
+
options: ComposeSkillsOptions,
|
|
53
|
+
composeTargetDirectory: string,
|
|
54
|
+
): { body: string; source: "installed" | "catalogue" } | null {
|
|
55
|
+
const installed = host.readText(installedSkillPath(composeTargetDirectory, packageDir));
|
|
56
|
+
if (installed !== null) return { body: installed, source: "installed" };
|
|
37
57
|
for (const path of skillSourceCandidates(packageDir, options)) {
|
|
38
58
|
const body = host.readText(path);
|
|
39
|
-
if (body !== null) return body;
|
|
59
|
+
if (body !== null) return { body, source: "catalogue" };
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function contractSourceCandidates(options: ComposeSkillsOptions): string[] {
|
|
65
|
+
const paths: string[] = [];
|
|
66
|
+
if (options.contractPath) paths.push(options.contractPath);
|
|
67
|
+
paths.push(join(options.launcherPackageRoot, "contracts", "conversation-contract.md"));
|
|
68
|
+
// Monorepo fallback so tests and dev runs work without a prior `npm run build` pack step.
|
|
69
|
+
paths.push(join(options.launcherPackageRoot, "..", "..", "docs", "contracts", "conversation-contract.md"));
|
|
70
|
+
return paths;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Reads and extracts the shared conversation contract block. Returns null when no source resolves. */
|
|
74
|
+
function readContractBlock(host: WorkspaceHost, options: ComposeSkillsOptions): string | null {
|
|
75
|
+
for (const path of contractSourceCandidates(options)) {
|
|
76
|
+
const raw = host.readText(path);
|
|
77
|
+
if (raw === null) continue;
|
|
78
|
+
try {
|
|
79
|
+
return extractContractBlock(raw);
|
|
80
|
+
} catch {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
40
83
|
}
|
|
41
84
|
return null;
|
|
42
85
|
}
|
|
43
86
|
|
|
87
|
+
function readLauncherVersion(host: WorkspaceHost, options: ComposeSkillsOptions): string | undefined {
|
|
88
|
+
const raw = host.readText(join(options.launcherPackageRoot, "package.json"));
|
|
89
|
+
if (raw === null) return undefined;
|
|
90
|
+
try {
|
|
91
|
+
const parsed: unknown = JSON.parse(raw);
|
|
92
|
+
if (typeof parsed === "object" && parsed !== null && "version" in parsed) {
|
|
93
|
+
const version = (parsed as { version?: unknown }).version;
|
|
94
|
+
if (typeof version === "string" && version.trim() !== "") return version;
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
/* unreadable manifest; no version */
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
44
102
|
/** Package directory names that have a resolvable skill source in the catalogue or monorepo. */
|
|
45
103
|
export function listSkillPackageCandidates(host: WorkspaceHost, options: ComposeSkillsOptions): string[] {
|
|
46
104
|
const names = new Set<string>();
|
|
@@ -95,9 +153,27 @@ function writeDiscoveryLink(host: WorkspaceHost, directory: string, packageDir:
|
|
|
95
153
|
}
|
|
96
154
|
}
|
|
97
155
|
|
|
156
|
+
/** Removes a composed skill's `.agents/skills/` directory and its host discovery links. Missing paths are no-ops. */
|
|
157
|
+
function removeComposedSkill(host: WorkspaceHost, directory: string, packageDir: string): void {
|
|
158
|
+
host.remove(containedPath(directory, join(AGENTS_SKILLS_REL, `clossys-${packageDir}`)));
|
|
159
|
+
for (const prefix of DISCOVERY_PREFIXES) {
|
|
160
|
+
const prefixPath = containedPath(directory, prefix);
|
|
161
|
+
if (host.isSymlink(prefixPath)) continue; // shared view onto .agents/skills; already handled above
|
|
162
|
+
host.remove(containedPath(directory, join(prefix, `clossys-${packageDir}`)));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
98
166
|
/**
|
|
99
167
|
* Writes `.agents/skills/clossys-<pkg>/SKILL.md` and host discovery links for every
|
|
100
|
-
* catalogue package
|
|
168
|
+
* catalogue package, with the shared conversation contract (#1182) injected in place
|
|
169
|
+
* of each skill's own `## How we work together` / `## One question at a time`
|
|
170
|
+
* sections. Missing sources are skipped with notes; the hub apply continues.
|
|
171
|
+
*
|
|
172
|
+
* Also writes `clossys/.state/skills.json` (#1183): source, version, and content
|
|
173
|
+
* digest per composed skill. A skill named in this directory's *previous* manifest
|
|
174
|
+
* but not composed this run is retired — its composed output is pruned and it is
|
|
175
|
+
* dropped from the new manifest. Never touches a skill this directory's manifest
|
|
176
|
+
* did not itself write.
|
|
101
177
|
*/
|
|
102
178
|
export function composeSkills(
|
|
103
179
|
host: WorkspaceHost,
|
|
@@ -106,15 +182,44 @@ export function composeSkills(
|
|
|
106
182
|
): SkillCompositionResult {
|
|
107
183
|
const composed: string[] = [];
|
|
108
184
|
const skipped: { packageDir: string; note: string }[] = [];
|
|
185
|
+
const manifestEntries: SkillManifestEntry[] = [];
|
|
186
|
+
const contractBlock = readContractBlock(host, options);
|
|
187
|
+
const launcherVersion = readLauncherVersion(host, options);
|
|
188
|
+
|
|
109
189
|
for (const packageDir of listSkillPackageCandidates(host, options)) {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
190
|
+
const found = readSkillBody(host, packageDir, options, directory);
|
|
191
|
+
if (found === null) {
|
|
112
192
|
skipped.push({ packageDir, note: "skill source missing at apply time" });
|
|
113
193
|
continue;
|
|
114
194
|
}
|
|
195
|
+
const body = contractBlock === null ? found.body : injectContract(found.body, contractBlock);
|
|
115
196
|
writeAgentsSkill(host, directory, packageDir, body);
|
|
116
197
|
writeDiscoveryLink(host, directory, packageDir, body);
|
|
117
198
|
composed.push(packageDir);
|
|
199
|
+
const version = found.source === "installed" ? readInstalledVersion(host, directory, packageDir) : launcherVersion;
|
|
200
|
+
manifestEntries.push({
|
|
201
|
+
name: packageDir,
|
|
202
|
+
source: found.source,
|
|
203
|
+
sha256: sha256Hex(body.endsWith("\n") ? body : `${body}\n`),
|
|
204
|
+
...(version === undefined ? {} : { version }),
|
|
205
|
+
});
|
|
118
206
|
}
|
|
119
|
-
|
|
207
|
+
|
|
208
|
+
const previousManifest = parseSkillManifest(host.readText(join(directory, SKILLS_MANIFEST_REL)));
|
|
209
|
+
const composedSet = new Set(composed);
|
|
210
|
+
const retired: string[] = [];
|
|
211
|
+
for (const entry of previousManifest?.skills ?? []) {
|
|
212
|
+
if (composedSet.has(entry.name)) continue;
|
|
213
|
+
removeComposedSkill(host, directory, entry.name);
|
|
214
|
+
retired.push(entry.name);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const manifestPath = containedPath(directory, SKILLS_MANIFEST_REL);
|
|
218
|
+
host.mkdirp(dirname(manifestPath));
|
|
219
|
+
host.writeText(
|
|
220
|
+
manifestPath,
|
|
221
|
+
serializeSkillManifest({ schemaVersion: 1, generatedAt: host.now(), skills: manifestEntries }),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
return { composed, skipped, retired };
|
|
120
225
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { DiscoveredHost } from "./hosts.js";
|
|
2
|
+
import type { ExternalInventoryDeclaration, InventoryDriftReport } from "./inventory-adoption.js";
|
|
3
|
+
|
|
1
4
|
/** Ternary retained by the installed CLI. */
|
|
2
5
|
export type WorkspaceState = "satisfied" | "violated" | "indeterminate";
|
|
3
6
|
|
|
@@ -23,17 +26,52 @@ export interface WorkspaceHost {
|
|
|
23
26
|
mkdirp(path: string): void;
|
|
24
27
|
/** Creates a relative symlink at linkPath pointing at relativeTarget (directory link). */
|
|
25
28
|
symlink(relativeTarget: string, linkPath: string): void;
|
|
29
|
+
/** Recursively removes path. A missing path is a no-op, never a throw. */
|
|
30
|
+
remove(path: string): void;
|
|
26
31
|
readDir(path: string): string[];
|
|
27
32
|
run(command: string, args: readonly string[], options?: { cwd?: string }): CommandResult;
|
|
28
33
|
prompt(message: string, choices: readonly string[]): string | null;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
/** On-disk hub marker generated on the consumer hub. Packed template: skeleton/.
|
|
36
|
+
/** On-disk hub marker generated on the consumer hub. Packed template: skeleton/clossys/.state/workspace.json. */
|
|
32
37
|
export interface HubDocument {
|
|
33
38
|
readonly schemaVersion: 1;
|
|
34
39
|
readonly kind: "account-hub";
|
|
35
40
|
readonly owner: string;
|
|
36
41
|
readonly repository: string;
|
|
42
|
+
/** Declares an existing external repository inventory as the source of truth (#1216). Hand-edited by the client; launcher never writes this field. */
|
|
43
|
+
readonly externalInventory?: ExternalInventoryDeclaration;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Where the hub marker was found relative to the `.clossys/` -> `clossys/.state/`
|
|
48
|
+
* migration (#1171): `clean` — only the current path. `legacy` — only the old
|
|
49
|
+
* `.clossys/` path; resume migrates it. `indeterminate` — both paths carry a
|
|
50
|
+
* parseable marker; launcher never merges them silently and refuses instead.
|
|
51
|
+
*/
|
|
52
|
+
export type HubMigrationState = "clean" | "legacy" | "indeterminate";
|
|
53
|
+
|
|
54
|
+
/** One skill recorded in `clossys/.state/skills.json` (#1183). */
|
|
55
|
+
export interface SkillManifestEntry {
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly source: "installed" | "catalogue";
|
|
58
|
+
readonly version?: string;
|
|
59
|
+
readonly sha256: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The `clossys/.state/skills.json` document itself. */
|
|
63
|
+
export interface SkillManifestDocument {
|
|
64
|
+
readonly schemaVersion: 1;
|
|
65
|
+
readonly generatedAt: string;
|
|
66
|
+
readonly skills: readonly SkillManifestEntry[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Read-only freshness summary derived from the skills manifest for the health report. */
|
|
70
|
+
export interface SkillsManifestSummary {
|
|
71
|
+
readonly status: "present" | "missing";
|
|
72
|
+
readonly total: number;
|
|
73
|
+
readonly stale: number;
|
|
74
|
+
readonly retired: number;
|
|
37
75
|
}
|
|
38
76
|
|
|
39
77
|
export interface InventoryObservation {
|
|
@@ -84,18 +122,31 @@ export interface HubHealthReport {
|
|
|
84
122
|
readonly extraClossys: readonly string[];
|
|
85
123
|
readonly pinFindings: readonly PinFinding[];
|
|
86
124
|
readonly degraded: boolean;
|
|
125
|
+
/** Coding-agent hosts this apply found already linked for skill discovery here, recorded before compose ran (#1180). Always present after apply. */
|
|
126
|
+
readonly linkedHosts?: readonly DiscoveredHost[];
|
|
127
|
+
/** Present only when the hub marker declares an external inventory (#1216) and there is something to say about it (i.e. not "no-external-source"). */
|
|
128
|
+
readonly inventoryDrift?: InventoryDriftReport;
|
|
87
129
|
readonly skillComposition?: {
|
|
88
130
|
readonly composed: readonly string[];
|
|
89
131
|
readonly skipped: readonly { readonly packageDir: string; readonly note: string }[];
|
|
90
132
|
readonly rosterTargets?: readonly string[];
|
|
91
133
|
readonly rosterSkipped?: readonly { readonly inventoryId: string; readonly note: string }[];
|
|
134
|
+
readonly retired?: readonly string[];
|
|
92
135
|
};
|
|
136
|
+
/** Present only on the run that performed the `.clossys/` -> `clossys/.state/` migration. */
|
|
137
|
+
readonly migration?: { readonly status: "migrated"; readonly from: string; readonly to: string };
|
|
138
|
+
/** Freshness summary derived from `clossys/.state/skills.json`, when present. */
|
|
139
|
+
readonly skillsManifest?: SkillsManifestSummary;
|
|
93
140
|
}
|
|
94
141
|
|
|
95
142
|
/** Optional paths for skill composition during apply. */
|
|
96
143
|
export interface ApplyWorkspaceOptions {
|
|
97
144
|
readonly skillCatalogueRoot?: string;
|
|
98
145
|
readonly launcherPackageRoot?: string;
|
|
146
|
+
/** Overrides where the packed conversation contract is read from (tests). */
|
|
147
|
+
readonly contractPath?: string;
|
|
148
|
+
/** Live registry `@clossys/launcher` version, used only to grade catalogue-sourced skill staleness. */
|
|
149
|
+
readonly liveLauncherVersion?: string;
|
|
99
150
|
}
|
|
100
151
|
|
|
101
152
|
export interface CwdObservation {
|
|
@@ -107,6 +158,8 @@ export interface CwdObservation {
|
|
|
107
158
|
readonly hub?: HubDocument;
|
|
108
159
|
readonly looksLikeFoundry: boolean;
|
|
109
160
|
readonly inventory?: InventoryObservation;
|
|
161
|
+
/** Present only when a hub marker was found; absent means neither path has one. */
|
|
162
|
+
readonly hubMigration?: HubMigrationState;
|
|
110
163
|
}
|
|
111
164
|
|
|
112
165
|
export interface WorkspaceObservation {
|
|
@@ -133,6 +186,10 @@ export interface WorkspacePlanResume {
|
|
|
133
186
|
readonly repository: string;
|
|
134
187
|
readonly directory: string;
|
|
135
188
|
readonly clone: boolean;
|
|
189
|
+
/** Live registry Advisor version, when observeWorkspace could read one. Used only to grade health. */
|
|
190
|
+
readonly advisorVersion?: string;
|
|
191
|
+
/** Set when the hub marker was found only at the legacy `.clossys/` path; apply migrates it. */
|
|
192
|
+
readonly migrateFrom?: "legacy";
|
|
136
193
|
}
|
|
137
194
|
|
|
138
195
|
export interface WorkspacePlanAdopt {
|
package/CHANGELOG.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
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.5] - 2026-09-20
|
|
9
|
-
|
|
10
|
-
### Fixed
|
|
11
|
-
|
|
12
|
-
- Discovery compose skips a `.claude/skills` or `.cursor/skills` path that is already a symlink so it cannot replace composed `SKILL.md`.
|
|
13
|
-
|
|
14
|
-
## [0.1.4] - 2026-09-19
|
|
15
|
-
|
|
16
|
-
### Added
|
|
17
|
-
|
|
18
|
-
- Hub apply composes the full `clossys-*` skill tree under `.agents/skills/` on create, appoint, and resume, reading bodies from the packed skill catalogue (built at `npm run build` from each package's skill source) or from a sibling checkout. Missing sources are skipped with a health note; apply continues.
|
|
19
|
-
- The same roster is composed into every inventoried repository clone beside the hub (resolved from the generated hub inventory and confirmed with `git remote get-url origin`); the health report lists targets and skipped ids. Sister checkouts get optional canned `AGENTS.md` only when missing or still the generated sister text.
|
|
20
|
-
- Apply writes host discovery links under `.cursor/skills/` and `.claude/skills/` pointing at the composed skills in the hub and each resolved clone.
|
|
21
|
-
- Packed Agent Skill `clossys-launcher` so a coding agent can be invoked as `@clossys-launcher`.
|
|
22
|
-
|
|
23
|
-
### Changed
|
|
24
|
-
|
|
25
|
-
- Resume refreshes composed skills and replaces stale generated `AGENTS.md` when it still tells founders to use `npx` to continue the conversation; customized `AGENTS.md` files are left alone.
|
|
26
|
-
- Founder-facing hub guidance (`CONSUMER_AGENTS_MD`, skeleton README) now states the same `@clossys-*` team is available in every inventoried checkout; `@clossys-advisor` is the hiring check; `npx @clossys/launcher` refreshes voices on clones beside the hub.
|
|
27
|
-
|
|
28
|
-
## [0.1.2] - 2026-09-19
|
|
29
|
-
|
|
30
|
-
### Fixed
|
|
31
|
-
|
|
32
|
-
- 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.
|
|
33
|
-
- 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".
|
|
34
|
-
- 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.
|
|
35
|
-
- 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.
|
|
36
|
-
- 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.
|
|
37
|
-
|
|
38
|
-
### Added
|
|
39
|
-
|
|
40
|
-
- 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.
|
|
41
|
-
- Pin and extra-`@clossys/*` scans now cover `optionalDependencies` and `peerDependencies` in addition to `dependencies` and `devDependencies`.
|
|
42
|
-
- `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.
|
|
43
|
-
- `launcher-check` forwards `cwd.hub`, so a captured existing-hub observation grades as resume instead of mis-grading as adopt.
|
|
44
|
-
|
|
45
|
-
## [0.1.1] - 2026-09-19
|
|
46
|
-
|
|
47
|
-
### Fixed
|
|
48
|
-
|
|
49
|
-
- 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.
|
|
50
|
-
- 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.
|
|
51
|
-
|
|
52
|
-
### Added
|
|
53
|
-
|
|
54
|
-
- 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.
|
|
55
|
-
|
|
56
|
-
## [0.1.0] - 2026-09-18
|
|
57
|
-
|
|
58
|
-
### Added
|
|
59
|
-
|
|
60
|
-
- `npx @clossys/launcher` as the single get-started command.
|
|
61
|
-
- In-package hub skeleton (not a Foundry fork) copied into a GitHub repository.
|
|
62
|
-
- Create a new `{owner}/workspace` hub, resume an existing hub, or adopt the current GitHub repository as the account hub.
|
|
63
|
-
- Owner inference from `gh` and git remotes, with an interactive picker only when more than one GitHub owner is visible.
|
|
64
|
-
- `launcher-check --input` grades a captured observation without creating a hub, so qualification can prove the 0/1/2 ternary.
|
|
File without changes
|
|
File without changes
|