@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.
Files changed (114) hide show
  1. package/README.md +213 -20
  2. package/contracts/conversation-contract.md +41 -0
  3. package/dist/apply-plan-cli.d.ts +7 -0
  4. package/dist/apply-plan-cli.d.ts.map +1 -0
  5. package/dist/apply-plan-cli.js +96 -0
  6. package/dist/apply-plan-cli.js.map +1 -0
  7. package/dist/apply-plan.d.ts +79 -0
  8. package/dist/apply-plan.d.ts.map +1 -0
  9. package/dist/apply-plan.js +129 -0
  10. package/dist/apply-plan.js.map +1 -0
  11. package/dist/check-cli.d.ts.map +1 -1
  12. package/dist/check-cli.js +3 -0
  13. package/dist/check-cli.js.map +1 -1
  14. package/dist/cli.d.ts +2 -1
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +37 -11
  17. package/dist/cli.js.map +1 -1
  18. package/dist/contract.d.ts +28 -0
  19. package/dist/contract.d.ts.map +1 -0
  20. package/dist/contract.js +78 -0
  21. package/dist/contract.js.map +1 -0
  22. package/dist/core.d.ts +38 -6
  23. package/dist/core.d.ts.map +1 -1
  24. package/dist/core.js +289 -42
  25. package/dist/core.js.map +1 -1
  26. package/dist/doctor-cli.d.ts +4 -0
  27. package/dist/doctor-cli.d.ts.map +1 -0
  28. package/dist/doctor-cli.js +32 -0
  29. package/dist/doctor-cli.js.map +1 -0
  30. package/dist/doctor.d.ts +28 -0
  31. package/dist/doctor.d.ts.map +1 -0
  32. package/dist/doctor.js +68 -0
  33. package/dist/doctor.js.map +1 -0
  34. package/dist/host.d.ts.map +1 -1
  35. package/dist/host.js +3 -0
  36. package/dist/host.js.map +1 -1
  37. package/dist/hosts.d.ts +14 -0
  38. package/dist/hosts.d.ts.map +1 -0
  39. package/dist/hosts.js +61 -0
  40. package/dist/hosts.js.map +1 -0
  41. package/dist/index.d.ts +15 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +7 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/inventory-adoption.d.ts +20 -0
  46. package/dist/inventory-adoption.d.ts.map +1 -0
  47. package/dist/inventory-adoption.js +67 -0
  48. package/dist/inventory-adoption.js.map +1 -0
  49. package/dist/manifest.d.ts +20 -0
  50. package/dist/manifest.d.ts.map +1 -0
  51. package/dist/manifest.js +106 -0
  52. package/dist/manifest.js.map +1 -0
  53. package/dist/model-profile.d.ts +46 -0
  54. package/dist/model-profile.d.ts.map +1 -0
  55. package/dist/model-profile.js +98 -0
  56. package/dist/model-profile.js.map +1 -0
  57. package/dist/product-repository.d.ts +26 -0
  58. package/dist/product-repository.d.ts.map +1 -0
  59. package/dist/product-repository.js +49 -0
  60. package/dist/product-repository.js.map +1 -0
  61. package/dist/skills.d.ts +20 -1
  62. package/dist/skills.d.ts.map +1 -1
  63. package/dist/skills.js +98 -7
  64. package/dist/skills.js.map +1 -1
  65. package/dist/types.d.ts +57 -1
  66. package/dist/types.d.ts.map +1 -1
  67. package/model-profiles/claude-code.json +10 -0
  68. package/model-profiles/codex.json +10 -0
  69. package/model-profiles/cursor.json +10 -0
  70. package/package.json +9 -5
  71. package/skeleton/README.md +5 -0
  72. package/skeleton/package.json +1 -1
  73. package/skill/SKILL.md +41 -0
  74. package/skill-catalogue/advisor/SKILL.md +46 -8
  75. package/skill-catalogue/architect/SKILL.md +0 -11
  76. package/skill-catalogue/bouncer/SKILL.md +0 -11
  77. package/skill-catalogue/builder/SKILL.md +0 -11
  78. package/skill-catalogue/butler/SKILL.md +0 -11
  79. package/skill-catalogue/controller/SKILL.md +6 -9
  80. package/skill-catalogue/customer/SKILL.md +83 -0
  81. package/skill-catalogue/designer/SKILL.md +18 -9
  82. package/skill-catalogue/giver/SKILL.md +0 -11
  83. package/skill-catalogue/influencer/SKILL.md +0 -11
  84. package/skill-catalogue/inspector/SKILL.md +1 -12
  85. package/skill-catalogue/integrator/SKILL.md +0 -11
  86. package/skill-catalogue/keeper/SKILL.md +0 -11
  87. package/skill-catalogue/launcher/SKILL.md +0 -12
  88. package/skill-catalogue/locksmith/SKILL.md +0 -11
  89. package/skill-catalogue/messenger/SKILL.md +0 -11
  90. package/skill-catalogue/observer/SKILL.md +0 -11
  91. package/skill-catalogue/publisher/SKILL.md +18 -10
  92. package/skill-catalogue/starter/SKILL.md +0 -11
  93. package/skill-catalogue/strategist/SKILL.md +35 -12
  94. package/skill-catalogue/writer/SKILL.md +7 -9
  95. package/src/apply-plan-cli.ts +94 -0
  96. package/src/apply-plan.ts +172 -0
  97. package/src/check-cli.ts +3 -0
  98. package/src/cli.ts +45 -10
  99. package/src/contract.ts +81 -0
  100. package/src/core.ts +337 -37
  101. package/src/doctor-cli.ts +33 -0
  102. package/src/doctor.ts +145 -0
  103. package/src/host.ts +3 -0
  104. package/src/hosts.ts +79 -0
  105. package/src/index.ts +33 -0
  106. package/src/inventory-adoption.ts +85 -0
  107. package/src/manifest.ts +103 -0
  108. package/src/model-profile.ts +148 -0
  109. package/src/product-repository.ts +73 -0
  110. package/src/skills.ts +113 -8
  111. package/src/types.ts +58 -1
  112. package/CHANGELOG.md +0 -64
  113. /package/skeleton/{.clossys → clossys/.state}/inventory.json +0 -0
  114. /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 type { WorkspaceHost } from "./types.js";
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 readSkillBody(host: WorkspaceHost, packageDir: string, options: ComposeSkillsOptions): string | null {
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. Missing sources are skipped with notes; the hub apply continues.
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 body = readSkillBody(host, packageDir, options);
111
- if (body === null) {
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
- return { composed, skipped };
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/.clossys/workspace.json. */
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.