@clossys/launcher 0.1.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +209 -20
- package/contracts/conversation-contract.md +40 -0
- package/dist/apply-plan-cli.d.ts +7 -0
- package/dist/apply-plan-cli.d.ts.map +1 -0
- package/dist/apply-plan-cli.js +96 -0
- package/dist/apply-plan-cli.js.map +1 -0
- package/dist/apply-plan.d.ts +79 -0
- package/dist/apply-plan.d.ts.map +1 -0
- package/dist/apply-plan.js +129 -0
- package/dist/apply-plan.js.map +1 -0
- package/dist/check-cli.d.ts.map +1 -1
- package/dist/check-cli.js +3 -0
- package/dist/check-cli.js.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +37 -11
- package/dist/cli.js.map +1 -1
- package/dist/contract.d.ts +28 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +78 -0
- package/dist/contract.js.map +1 -0
- package/dist/core.d.ts +38 -6
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +289 -42
- package/dist/core.js.map +1 -1
- package/dist/doctor-cli.d.ts +4 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +32 -0
- package/dist/doctor-cli.js.map +1 -0
- package/dist/doctor.d.ts +28 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +68 -0
- package/dist/doctor.js.map +1 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +3 -0
- package/dist/host.js.map +1 -1
- package/dist/hosts.d.ts +14 -0
- package/dist/hosts.d.ts.map +1 -0
- package/dist/hosts.js +61 -0
- package/dist/hosts.js.map +1 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/inventory-adoption.d.ts +20 -0
- package/dist/inventory-adoption.d.ts.map +1 -0
- package/dist/inventory-adoption.js +67 -0
- package/dist/inventory-adoption.js.map +1 -0
- package/dist/manifest.d.ts +20 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +106 -0
- package/dist/manifest.js.map +1 -0
- package/dist/model-profile.d.ts +46 -0
- package/dist/model-profile.d.ts.map +1 -0
- package/dist/model-profile.js +98 -0
- package/dist/model-profile.js.map +1 -0
- package/dist/product-repository.d.ts +26 -0
- package/dist/product-repository.d.ts.map +1 -0
- package/dist/product-repository.js +49 -0
- package/dist/product-repository.js.map +1 -0
- package/dist/skills.d.ts +20 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +98 -7
- package/dist/skills.js.map +1 -1
- package/dist/types.d.ts +57 -1
- package/dist/types.d.ts.map +1 -1
- package/model-profiles/claude-code.json +10 -0
- package/model-profiles/codex.json +10 -0
- package/model-profiles/cursor.json +10 -0
- package/package.json +9 -4
- package/skeleton/README.md +5 -0
- package/skeleton/package.json +1 -1
- package/skill/SKILL.md +53 -0
- package/skill-catalogue/advisor/SKILL.md +3 -1
- package/skill-catalogue/controller/SKILL.md +8 -0
- package/skill-catalogue/customer/SKILL.md +92 -0
- package/skill-catalogue/designer/SKILL.md +18 -2
- package/skill-catalogue/inspector/SKILL.md +1 -1
- package/skill-catalogue/publisher/SKILL.md +17 -3
- package/skill-catalogue/strategist/SKILL.md +37 -3
- package/skill-catalogue/writer/SKILL.md +7 -2
- package/src/apply-plan-cli.ts +94 -0
- package/src/apply-plan.ts +172 -0
- package/src/check-cli.ts +3 -0
- package/src/cli.ts +45 -10
- package/src/contract.ts +81 -0
- package/src/core.ts +337 -37
- package/src/doctor-cli.ts +33 -0
- package/src/doctor.ts +145 -0
- package/src/host.ts +3 -0
- package/src/hosts.ts +79 -0
- package/src/index.ts +33 -0
- package/src/inventory-adoption.ts +85 -0
- package/src/manifest.ts +103 -0
- package/src/model-profile.ts +148 -0
- package/src/product-repository.ts +73 -0
- package/src/skills.ts +113 -8
- package/src/types.ts +58 -1
- /package/skeleton/{.clossys → clossys/.state}/inventory.json +0 -0
- /package/skeleton/{.clossys → clossys/.state}/workspace.json +0 -0
|
@@ -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 {
|
|
File without changes
|
|
File without changes
|