@clossys/launcher 0.1.2 → 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.
Files changed (114) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +231 -19
  3. package/contracts/conversation-contract.md +40 -0
  4. package/dist/apply-plan-cli.d.ts +7 -0
  5. package/dist/apply-plan-cli.d.ts.map +1 -0
  6. package/dist/apply-plan-cli.js +96 -0
  7. package/dist/apply-plan-cli.js.map +1 -0
  8. package/dist/apply-plan.d.ts +79 -0
  9. package/dist/apply-plan.d.ts.map +1 -0
  10. package/dist/apply-plan.js +129 -0
  11. package/dist/apply-plan.js.map +1 -0
  12. package/dist/check-cli.d.ts.map +1 -1
  13. package/dist/check-cli.js +7 -0
  14. package/dist/check-cli.js.map +1 -1
  15. package/dist/cli.d.ts +2 -1
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +43 -14
  18. package/dist/cli.js.map +1 -1
  19. package/dist/contract.d.ts +28 -0
  20. package/dist/contract.d.ts.map +1 -0
  21. package/dist/contract.js +78 -0
  22. package/dist/contract.js.map +1 -0
  23. package/dist/core.d.ts +50 -8
  24. package/dist/core.d.ts.map +1 -1
  25. package/dist/core.js +458 -40
  26. package/dist/core.js.map +1 -1
  27. package/dist/doctor-cli.d.ts +4 -0
  28. package/dist/doctor-cli.d.ts.map +1 -0
  29. package/dist/doctor-cli.js +32 -0
  30. package/dist/doctor-cli.js.map +1 -0
  31. package/dist/doctor.d.ts +28 -0
  32. package/dist/doctor.d.ts.map +1 -0
  33. package/dist/doctor.js +68 -0
  34. package/dist/doctor.js.map +1 -0
  35. package/dist/host.d.ts.map +1 -1
  36. package/dist/host.js +19 -1
  37. package/dist/host.js.map +1 -1
  38. package/dist/hosts.d.ts +14 -0
  39. package/dist/hosts.d.ts.map +1 -0
  40. package/dist/hosts.js +61 -0
  41. package/dist/hosts.js.map +1 -0
  42. package/dist/index.d.ts +15 -2
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +7 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/inventory-adoption.d.ts +20 -0
  47. package/dist/inventory-adoption.d.ts.map +1 -0
  48. package/dist/inventory-adoption.js +67 -0
  49. package/dist/inventory-adoption.js.map +1 -0
  50. package/dist/manifest.d.ts +20 -0
  51. package/dist/manifest.d.ts.map +1 -0
  52. package/dist/manifest.js +106 -0
  53. package/dist/manifest.js.map +1 -0
  54. package/dist/model-profile.d.ts +46 -0
  55. package/dist/model-profile.d.ts.map +1 -0
  56. package/dist/model-profile.js +98 -0
  57. package/dist/model-profile.js.map +1 -0
  58. package/dist/product-repository.d.ts +26 -0
  59. package/dist/product-repository.d.ts.map +1 -0
  60. package/dist/product-repository.js +49 -0
  61. package/dist/product-repository.js.map +1 -0
  62. package/dist/skills.d.ts +39 -0
  63. package/dist/skills.d.ts.map +1 -0
  64. package/dist/skills.js +197 -0
  65. package/dist/skills.js.map +1 -0
  66. package/dist/types.d.ts +78 -1
  67. package/dist/types.d.ts.map +1 -1
  68. package/model-profiles/claude-code.json +10 -0
  69. package/model-profiles/codex.json +10 -0
  70. package/model-profiles/cursor.json +10 -0
  71. package/package.json +11 -5
  72. package/skeleton/README.md +15 -20
  73. package/skeleton/package.json +1 -1
  74. package/skill/SKILL.md +53 -0
  75. package/skill-catalogue/advisor/SKILL.md +52 -0
  76. package/skill-catalogue/architect/SKILL.md +42 -0
  77. package/skill-catalogue/bouncer/SKILL.md +43 -0
  78. package/skill-catalogue/builder/SKILL.md +42 -0
  79. package/skill-catalogue/butler/SKILL.md +43 -0
  80. package/skill-catalogue/controller/SKILL.md +50 -0
  81. package/skill-catalogue/customer/SKILL.md +92 -0
  82. package/skill-catalogue/designer/SKILL.md +66 -0
  83. package/skill-catalogue/giver/SKILL.md +43 -0
  84. package/skill-catalogue/influencer/SKILL.md +43 -0
  85. package/skill-catalogue/inspector/SKILL.md +42 -0
  86. package/skill-catalogue/integrator/SKILL.md +42 -0
  87. package/skill-catalogue/keeper/SKILL.md +43 -0
  88. package/skill-catalogue/launcher/SKILL.md +53 -0
  89. package/skill-catalogue/locksmith/SKILL.md +42 -0
  90. package/skill-catalogue/messenger/SKILL.md +43 -0
  91. package/skill-catalogue/observer/SKILL.md +42 -0
  92. package/skill-catalogue/publisher/SKILL.md +64 -0
  93. package/skill-catalogue/starter/SKILL.md +48 -0
  94. package/skill-catalogue/strategist/SKILL.md +85 -0
  95. package/skill-catalogue/writer/SKILL.md +56 -0
  96. package/src/apply-plan-cli.ts +94 -0
  97. package/src/apply-plan.ts +172 -0
  98. package/src/check-cli.ts +7 -0
  99. package/src/cli.ts +51 -13
  100. package/src/contract.ts +81 -0
  101. package/src/core.ts +555 -38
  102. package/src/doctor-cli.ts +33 -0
  103. package/src/doctor.ts +145 -0
  104. package/src/host.ts +17 -1
  105. package/src/hosts.ts +79 -0
  106. package/src/index.ts +36 -0
  107. package/src/inventory-adoption.ts +85 -0
  108. package/src/manifest.ts +103 -0
  109. package/src/model-profile.ts +148 -0
  110. package/src/product-repository.ts +73 -0
  111. package/src/skills.ts +225 -0
  112. package/src/types.ts +74 -1
  113. /package/skeleton/{.clossys → clossys/.state}/inventory.json +0 -0
  114. /package/skeleton/{.clossys → clossys/.state}/workspace.json +0 -0
@@ -0,0 +1,67 @@
1
+ // Adopt an existing repository inventory instead of creating a second one
2
+ // (#1216). An account that already keeps a repository inventory in its own
3
+ // control plane becomes the source of truth when the hub marker declares
4
+ // it. Launcher writes only what that inventory lacks (a later apply step,
5
+ // not this module) and reports drift instead of silently merging.
6
+ function isRecord(value) {
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8
+ }
9
+ /** Reads a foundry-shaped inventory document's repository ids. Malformed or missing is null, never []. */
10
+ function readForeignIds(host, path) {
11
+ const raw = host.readText(path);
12
+ if (raw === null)
13
+ return null;
14
+ let parsed;
15
+ try {
16
+ parsed = JSON.parse(raw);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ if (!isRecord(parsed) || parsed.schemaVersion !== 1 || !Array.isArray(parsed.repositories))
22
+ return null;
23
+ const ids = [];
24
+ for (const entry of parsed.repositories) {
25
+ if (isRecord(entry) && typeof entry.id === "string" && entry.id.trim() !== "")
26
+ ids.push(entry.id);
27
+ }
28
+ return ids;
29
+ }
30
+ /**
31
+ * Compares the declared external inventory against the launcher-written
32
+ * inventory at `directory/launcherInventoryRelPath`. Read-only -- callers
33
+ * decide whether and how to write the reconciled set, as an explicit,
34
+ * approved apply step (same #1045 pattern as clone-on-approval).
35
+ */
36
+ export function reportInventoryDrift(host, directory, declaration, launcherInventoryRelPath) {
37
+ if (declaration === undefined) {
38
+ return { status: "no-external-source", externalOnly: [], launcherOnly: [], agreeing: [] };
39
+ }
40
+ if (declaration.shape === "custom") {
41
+ return {
42
+ status: "indeterminate",
43
+ externalOnly: [],
44
+ launcherOnly: [],
45
+ agreeing: [],
46
+ note: `externalInventory at ${declaration.path} declares shape "custom"; launcher has no mapping for a non-foundry inventory shape yet and will not guess one. Reconcile by hand or file the mapping gap.`,
47
+ };
48
+ }
49
+ const externalIds = readForeignIds(host, declaration.path);
50
+ if (externalIds === null) {
51
+ return {
52
+ status: "indeterminate",
53
+ externalOnly: [],
54
+ launcherOnly: [],
55
+ agreeing: [],
56
+ note: `externalInventory at ${declaration.path} could not be read as a populated schemaVersion:1 inventory document.`,
57
+ };
58
+ }
59
+ const launcherIds = readForeignIds(host, `${directory}/${launcherInventoryRelPath}`) ?? [];
60
+ const externalSet = new Set(externalIds);
61
+ const launcherSet = new Set(launcherIds);
62
+ const externalOnly = externalIds.filter((id) => !launcherSet.has(id));
63
+ const launcherOnly = launcherIds.filter((id) => !externalSet.has(id));
64
+ const agreeing = externalIds.filter((id) => launcherSet.has(id));
65
+ return { status: "reconciled", externalOnly, launcherOnly, agreeing };
66
+ }
67
+ //# sourceMappingURL=inventory-adoption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory-adoption.js","sourceRoot":"","sources":["../src/inventory-adoption.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,kEAAkE;AAiBlE,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,0GAA0G;AAC1G,SAAS,cAAc,CAAC,IAAmB,EAAE,IAAY;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IACxG,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpG,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAmB,EACnB,SAAiB,EACjB,WAAqD,EACrD,wBAAgC;IAEhC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC5F,CAAC;IACD,IAAI,WAAW,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACnC,OAAO;YACL,MAAM,EAAE,eAAe;YACvB,YAAY,EAAE,EAAE;YAChB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,wBAAwB,WAAW,CAAC,IAAI,4JAA4J;SAC3M,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO;YACL,MAAM,EAAE,eAAe;YACvB,YAAY,EAAE,EAAE;YAChB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,wBAAwB,WAAW,CAAC,IAAI,uEAAuE;SACtH,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,SAAS,IAAI,wBAAwB,EAAE,CAAC,IAAI,EAAE,CAAC;IAC3F,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AACxE,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { SkillManifestDocument, SkillsManifestSummary, WorkspaceHost } from "./types.js";
2
+ /** sha256 hex digest of a skill's final composed content (post contract injection). */
3
+ export declare function sha256Hex(content: string): string;
4
+ /** Parses `clossys/.state/skills.json`. An unreadable or malformed document is treated as absent. */
5
+ export declare function parseSkillManifest(raw: string | null): SkillManifestDocument | undefined;
6
+ export declare function serializeSkillManifest(document: SkillManifestDocument): string;
7
+ /**
8
+ * Freshness summary for the health report: "N skills out of date, M
9
+ * retired". `stale` counts catalogue-sourced entries whose recorded version
10
+ * is older than `liveLauncherVersion` (a client running an old launcher
11
+ * carries a catalogue only as fresh as that release, #1033) — unknown or
12
+ * unparseable versions are never counted stale. `retiredThisRun` is supplied
13
+ * by the composition step that just ran; a read-only inspection (no
14
+ * composition) reports 0 retired, which is correct — retirement is a
15
+ * this-run event, not a property of the manifest at rest.
16
+ */
17
+ export declare function summarizeSkillsManifest(manifest: SkillManifestDocument | undefined, liveLauncherVersion: string | undefined, retiredThisRun: readonly string[]): SkillsManifestSummary;
18
+ /** Reads `installed` version from `<composeTargetDirectory>/node_modules/@clossys/<pkg>/package.json`. */
19
+ export declare function readInstalledVersion(host: WorkspaceHost, composeTargetDirectory: string, packageDir: string): string | undefined;
20
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAsB,qBAAqB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMlH,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAoBD,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,GAAG,SAAS,CA4BxF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CAE9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,EAC3C,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,qBAAqB,CASvB;AAED,0GAA0G;AAC1G,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUhI"}
@@ -0,0 +1,106 @@
1
+ import { createHash } from "node:crypto";
2
+ import { join } from "node:path";
3
+ function isRecord(value) {
4
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5
+ }
6
+ /** sha256 hex digest of a skill's final composed content (post contract injection). */
7
+ export function sha256Hex(content) {
8
+ return createHash("sha256").update(content, "utf8").digest("hex");
9
+ }
10
+ /** Tiny semver-ish compare, duplicated from core.ts to keep this module dependency-free within the package. */
11
+ function compareVersions(a, b) {
12
+ const parse = (version) => {
13
+ const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)$/);
14
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
15
+ };
16
+ const left = parse(a);
17
+ const right = parse(b);
18
+ if (!left || !right)
19
+ return null;
20
+ for (let index = 0; index < 3; index += 1) {
21
+ const l = left[index] ?? 0;
22
+ const r = right[index] ?? 0;
23
+ if (l < r)
24
+ return -1;
25
+ if (l > r)
26
+ return 1;
27
+ }
28
+ return 0;
29
+ }
30
+ /** Parses `clossys/.state/skills.json`. An unreadable or malformed document is treated as absent. */
31
+ export function parseSkillManifest(raw) {
32
+ if (raw === null)
33
+ return undefined;
34
+ let parsed;
35
+ try {
36
+ parsed = JSON.parse(raw);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ if (!isRecord(parsed) || parsed.schemaVersion !== 1 || !Array.isArray(parsed.skills))
42
+ return undefined;
43
+ const skills = [];
44
+ for (const entry of parsed.skills) {
45
+ if (!isRecord(entry))
46
+ continue;
47
+ const { name, source, sha256 } = entry;
48
+ if (typeof name !== "string" || name.trim() === "")
49
+ continue;
50
+ if (source !== "installed" && source !== "catalogue")
51
+ continue;
52
+ if (typeof sha256 !== "string" || sha256.trim() === "")
53
+ continue;
54
+ skills.push({
55
+ name,
56
+ source,
57
+ sha256,
58
+ ...(typeof entry.version === "string" && entry.version.trim() !== "" ? { version: entry.version } : {}),
59
+ });
60
+ }
61
+ return {
62
+ schemaVersion: 1,
63
+ generatedAt: typeof parsed.generatedAt === "string" ? parsed.generatedAt : "",
64
+ skills,
65
+ };
66
+ }
67
+ export function serializeSkillManifest(document) {
68
+ return `${JSON.stringify(document, null, 2)}\n`;
69
+ }
70
+ /**
71
+ * Freshness summary for the health report: "N skills out of date, M
72
+ * retired". `stale` counts catalogue-sourced entries whose recorded version
73
+ * is older than `liveLauncherVersion` (a client running an old launcher
74
+ * carries a catalogue only as fresh as that release, #1033) — unknown or
75
+ * unparseable versions are never counted stale. `retiredThisRun` is supplied
76
+ * by the composition step that just ran; a read-only inspection (no
77
+ * composition) reports 0 retired, which is correct — retirement is a
78
+ * this-run event, not a property of the manifest at rest.
79
+ */
80
+ export function summarizeSkillsManifest(manifest, liveLauncherVersion, retiredThisRun) {
81
+ if (manifest === undefined) {
82
+ return { status: "missing", total: 0, stale: 0, retired: retiredThisRun.length };
83
+ }
84
+ const stale = manifest.skills.filter((entry) => {
85
+ if (entry.source !== "catalogue" || liveLauncherVersion === undefined || entry.version === undefined)
86
+ return false;
87
+ return compareVersions(entry.version, liveLauncherVersion) === -1;
88
+ }).length;
89
+ return { status: "present", total: manifest.skills.length, stale, retired: retiredThisRun.length };
90
+ }
91
+ /** Reads `installed` version from `<composeTargetDirectory>/node_modules/@clossys/<pkg>/package.json`. */
92
+ export function readInstalledVersion(host, composeTargetDirectory, packageDir) {
93
+ const raw = host.readText(join(composeTargetDirectory, "node_modules", "@clossys", packageDir, "package.json"));
94
+ if (raw === null)
95
+ return undefined;
96
+ try {
97
+ const parsed = JSON.parse(raw);
98
+ if (isRecord(parsed) && typeof parsed.version === "string" && parsed.version.trim() !== "")
99
+ return parsed.version;
100
+ }
101
+ catch {
102
+ /* unreadable manifest; no version */
103
+ }
104
+ return undefined;
105
+ }
106
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ export type ReasoningTier = "light" | "standard" | "deep";
2
+ export type BudgetPreference = "cost-conscious" | "balanced" | "max-quality";
3
+ export type SupportedHost = "claude-code" | "codex" | "cursor";
4
+ export interface HostTierMapping {
5
+ /** The model this host runs for this tier under a "balanced" preference. */
6
+ readonly balanced: string;
7
+ /** Cheaper substitute under "cost-conscious", when one exists for this tier. Absent means "balanced" is already the floor. */
8
+ readonly costConscious?: string;
9
+ /** Stronger substitute under "max-quality", when one exists for this tier. */
10
+ readonly maxQuality?: string;
11
+ }
12
+ export interface HostModelProfile {
13
+ readonly schemaVersion: 1;
14
+ readonly host: SupportedHost;
15
+ /** ISO date this mapping was last verified against that host's real current models. */
16
+ readonly verifiedAt: string;
17
+ readonly tiers: Readonly<Record<ReasoningTier, HostTierMapping>>;
18
+ }
19
+ export interface PreferencesDocument {
20
+ readonly schemaVersion: 1;
21
+ readonly budget: BudgetPreference;
22
+ }
23
+ export interface ModelResolution {
24
+ readonly tier: ReasoningTier;
25
+ readonly host: SupportedHost;
26
+ readonly model: string;
27
+ /** True when a hard floor tier was requested but this host/preference combination could not clear it -- reported, never silently substituted. */
28
+ readonly belowFloor: boolean;
29
+ }
30
+ /** Parses clossys/preferences.json. Absent or malformed defaults to "balanced" -- a missing preference is not a floor violation. */
31
+ export declare function parsePreferences(raw: string | null): PreferencesDocument;
32
+ /**
33
+ * Resolves a step's demanded tier to a real model name for one host, under
34
+ * one budget preference, respecting an optional hard floor tier.
35
+ */
36
+ export declare function resolveModelForTier(profile: HostModelProfile, tier: ReasoningTier, budget: BudgetPreference, floorTier?: ReasoningTier): ModelResolution;
37
+ /**
38
+ * Reads a packed `model-profiles/<host>.json` file from the launcher
39
+ * package root. Returns undefined -- never throws, never guesses a
40
+ * fallback profile -- when the file is absent or malformed, matching this
41
+ * package's read-only, fail-closed pattern for every other packed
42
+ * artifact (manifest.ts's parseSkillManifest is the sibling to model this
43
+ * on).
44
+ */
45
+ export declare function readHostModelProfile(readText: (path: string) => string | null, launcherPackageRoot: string, host: SupportedHost): HostModelProfile | undefined;
46
+ //# sourceMappingURL=model-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-profile.d.ts","sourceRoot":"","sources":["../src/model-profile.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAC1D,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,UAAU,GAAG,aAAa,CAAC;AAC7E,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8HAA8H;IAC9H,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iJAAiJ;IACjJ,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAQD,oIAAoI;AACpI,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,mBAAmB,CAgBxE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,gBAAgB,EACxB,SAAS,CAAC,EAAE,aAAa,GACxB,eAAe,CAUjB;AAYD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,EACzC,mBAAmB,EAAE,MAAM,EAC3B,IAAI,EAAE,aAAa,GAClB,gBAAgB,GAAG,SAAS,CA6B9B"}
@@ -0,0 +1,98 @@
1
+ // Model guidance (#1219, Launcher side). Owner decision: packages declare
2
+ // WHAT a step demands (a reasoning tier), never model names. Three layers:
3
+ // 1. Step demands -- each package's own loop matrix (#1197, not built here).
4
+ // 2. Tier-to-model profile -- PER HOST, shipped by Launcher, dated and
5
+ // re-verified, so a model change reaches clients in one launcher
6
+ // release rather than a bump of every package.
7
+ // 3. User preference -- cost-conscious / balanced / max-quality, asked
8
+ // once by Advisor, stored in clossys/preferences.json (Advisor's file
9
+ // to write; this module only reads it to resolve a tier to a model).
10
+ //
11
+ // Floors are hard where the verdict depends on it (Customer's keep):
12
+ // resolveModelForTier never silently drops below a caller-supplied floor;
13
+ // it reports belowFloor so the composed skill can say so plainly.
14
+ import { join } from "node:path";
15
+ function isRecord(value) {
16
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17
+ }
18
+ const TIER_ORDER = ["light", "standard", "deep"];
19
+ /** Parses clossys/preferences.json. Absent or malformed defaults to "balanced" -- a missing preference is not a floor violation. */
20
+ export function parsePreferences(raw) {
21
+ if (raw !== null) {
22
+ try {
23
+ const parsed = JSON.parse(raw);
24
+ if (isRecord(parsed) &&
25
+ parsed.schemaVersion === 1 &&
26
+ (parsed.budget === "cost-conscious" || parsed.budget === "balanced" || parsed.budget === "max-quality")) {
27
+ return { schemaVersion: 1, budget: parsed.budget };
28
+ }
29
+ }
30
+ catch {
31
+ /* falls through to the default below */
32
+ }
33
+ }
34
+ return { schemaVersion: 1, budget: "balanced" };
35
+ }
36
+ /**
37
+ * Resolves a step's demanded tier to a real model name for one host, under
38
+ * one budget preference, respecting an optional hard floor tier.
39
+ */
40
+ export function resolveModelForTier(profile, tier, budget, floorTier) {
41
+ const mapping = profile.tiers[tier];
42
+ const model = budget === "cost-conscious"
43
+ ? (mapping.costConscious ?? mapping.balanced)
44
+ : budget === "max-quality"
45
+ ? (mapping.maxQuality ?? mapping.balanced)
46
+ : mapping.balanced;
47
+ const belowFloor = floorTier !== undefined && TIER_ORDER.indexOf(tier) < TIER_ORDER.indexOf(floorTier);
48
+ return { tier, host: profile.host, model, belowFloor };
49
+ }
50
+ function isTierMapping(value) {
51
+ if (typeof value !== "object" || value === null || Array.isArray(value))
52
+ return false;
53
+ const record = value;
54
+ return (typeof record.balanced === "string" &&
55
+ (record.costConscious === undefined || typeof record.costConscious === "string") &&
56
+ (record.maxQuality === undefined || typeof record.maxQuality === "string"));
57
+ }
58
+ /**
59
+ * Reads a packed `model-profiles/<host>.json` file from the launcher
60
+ * package root. Returns undefined -- never throws, never guesses a
61
+ * fallback profile -- when the file is absent or malformed, matching this
62
+ * package's read-only, fail-closed pattern for every other packed
63
+ * artifact (manifest.ts's parseSkillManifest is the sibling to model this
64
+ * on).
65
+ */
66
+ export function readHostModelProfile(readText, launcherPackageRoot, host) {
67
+ const raw = readText(join(launcherPackageRoot, "model-profiles", `${host}.json`));
68
+ if (raw === null)
69
+ return undefined;
70
+ let parsed;
71
+ try {
72
+ parsed = JSON.parse(raw);
73
+ }
74
+ catch {
75
+ return undefined;
76
+ }
77
+ if (typeof parsed !== "object" ||
78
+ parsed === null ||
79
+ Array.isArray(parsed) ||
80
+ parsed.schemaVersion !== 1 ||
81
+ parsed.host !== host ||
82
+ typeof parsed.verifiedAt !== "string") {
83
+ return undefined;
84
+ }
85
+ const tiersRaw = parsed.tiers;
86
+ if (typeof tiersRaw !== "object" || tiersRaw === null || Array.isArray(tiersRaw))
87
+ return undefined;
88
+ const tiers = tiersRaw;
89
+ if (!isTierMapping(tiers.light) || !isTierMapping(tiers.standard) || !isTierMapping(tiers.deep))
90
+ return undefined;
91
+ return {
92
+ schemaVersion: 1,
93
+ host,
94
+ verifiedAt: parsed.verifiedAt,
95
+ tiers: { light: tiers.light, standard: tiers.standard, deep: tiers.deep },
96
+ };
97
+ }
98
+ //# sourceMappingURL=model-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-profile.js","sourceRoot":"","sources":["../src/model-profile.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,+EAA+E;AAC/E,yEAAyE;AACzE,sEAAsE;AACtE,oDAAoD;AACpD,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAC1E,EAAE;AACF,qEAAqE;AACrE,0EAA0E;AAC1E,kEAAkE;AAElE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoCjC,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,GAA6B,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAE3E,oIAAoI;AACpI,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,IACE,QAAQ,CAAC,MAAM,CAAC;gBAChB,MAAM,CAAC,aAAa,KAAK,CAAC;gBAC1B,CAAC,MAAM,CAAC,MAAM,KAAK,gBAAgB,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,CAAC,EACvG,CAAC;gBACD,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;YACrD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAyB,EACzB,IAAmB,EACnB,MAAwB,EACxB,SAAyB;IAEzB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,KAAK,GACT,MAAM,KAAK,gBAAgB;QACzB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC;QAC7C,CAAC,CAAC,MAAM,KAAK,aAAa;YACxB,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC;YAC1C,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,MAAM,UAAU,GAAG,SAAS,KAAK,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,OAAO,CACL,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACnC,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC;QAChF,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAyC,EACzC,mBAA2B,EAC3B,IAAmB;IAEnB,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;IAClF,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACnC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QACpB,MAAkC,CAAC,aAAa,KAAK,CAAC;QACtD,MAAkC,CAAC,IAAI,KAAK,IAAI;QACjD,OAAQ,MAAkC,CAAC,UAAU,KAAK,QAAQ,EAClE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,QAAQ,GAAI,MAAkC,CAAC,KAAK,CAAC;IAC3D,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACnG,MAAM,KAAK,GAAG,QAAmC,CAAC;IAClD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAClH,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,IAAI;QACJ,UAAU,EAAG,MAAiC,CAAC,UAAU;QACzD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;KAC1E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { WorkspaceHost } from "./types.js";
2
+ /**
3
+ * 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).
4
+ * Read-only: verifies a product repository has what a cloud agent session
5
+ * (browser plus GitHub only, no local setup) needs to install and run the
6
+ * team, without foundry's own heavy governance gates.
7
+ */
8
+ export interface CloudBootstrapCheck {
9
+ readonly id: "package-manifest" | "agents-pointer" | "hub-marker";
10
+ readonly label: string;
11
+ readonly satisfied: boolean;
12
+ readonly note?: string;
13
+ }
14
+ export interface CloudBootstrapReport {
15
+ readonly schemaVersion: 1;
16
+ readonly checks: readonly CloudBootstrapCheck[];
17
+ readonly ready: boolean;
18
+ }
19
+ /**
20
+ * Runs the three product-repository-layout.json cloudSessionBootstrap checks
21
+ * against `directory`. Never mutates anything, never runs `npm ci` itself
22
+ * -- it checks that the manifest and lockfile are BOTH present, which is
23
+ * the precondition a real `npm ci` needs, not a substitute for running it.
24
+ */
25
+ export declare function checkCloudSessionBootstrap(host: WorkspaceHost, directory: string): CloudBootstrapReport;
26
+ //# sourceMappingURL=product-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-repository.d.ts","sourceRoot":"","sources":["../src/product-repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,kBAAkB,GAAG,gBAAgB,GAAG,YAAY,CAAC;IAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAOD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAuCvG"}
@@ -0,0 +1,49 @@
1
+ import { join } from "node:path";
2
+ const PACKAGE_JSON_REL = "package.json";
3
+ const PACKAGE_LOCK_REL = "package-lock.json";
4
+ const AGENTS_MD_REL = "AGENTS.md";
5
+ const HUB_MARKER_REL = join("clossys", ".state", "workspace.json");
6
+ /**
7
+ * Runs the three product-repository-layout.json cloudSessionBootstrap checks
8
+ * against `directory`. Never mutates anything, never runs `npm ci` itself
9
+ * -- it checks that the manifest and lockfile are BOTH present, which is
10
+ * the precondition a real `npm ci` needs, not a substitute for running it.
11
+ */
12
+ export function checkCloudSessionBootstrap(host, directory) {
13
+ const hasManifest = host.exists(join(directory, PACKAGE_JSON_REL));
14
+ const hasLock = host.exists(join(directory, PACKAGE_LOCK_REL));
15
+ const manifestCheck = {
16
+ id: "package-manifest",
17
+ label: "package.json and package-lock.json are both present",
18
+ satisfied: hasManifest && hasLock,
19
+ ...(hasManifest && hasLock
20
+ ? {}
21
+ : {
22
+ note: !hasManifest && !hasLock
23
+ ? "Neither package.json nor package-lock.json exists yet."
24
+ : !hasManifest
25
+ ? "package-lock.json exists but package.json does not."
26
+ : "package.json exists but package-lock.json does not -- npm ci needs both.",
27
+ }),
28
+ };
29
+ const agentsRaw = host.readText(join(directory, AGENTS_MD_REL));
30
+ const agentsPointsAtClossys = agentsRaw !== null && agentsRaw.includes("clossys/");
31
+ const agentsCheck = {
32
+ id: "agents-pointer",
33
+ label: "AGENTS.md exists at the repository root and points at clossys/",
34
+ satisfied: agentsPointsAtClossys,
35
+ ...(agentsPointsAtClossys
36
+ ? {}
37
+ : { note: agentsRaw === null ? "AGENTS.md does not exist at the repository root." : "AGENTS.md exists but does not mention clossys/." }),
38
+ };
39
+ const hasHubMarker = host.exists(join(directory, HUB_MARKER_REL));
40
+ const markerCheck = {
41
+ id: "hub-marker",
42
+ label: "clossys/.state/workspace.json (the hub marker) is present",
43
+ satisfied: hasHubMarker,
44
+ ...(hasHubMarker ? {} : { note: "clossys/.state/workspace.json does not exist yet." }),
45
+ };
46
+ const checks = [manifestCheck, agentsCheck, markerCheck];
47
+ return { schemaVersion: 1, checks, ready: checks.every((check) => check.satisfied) };
48
+ }
49
+ //# sourceMappingURL=product-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-repository.js","sourceRoot":"","sources":["../src/product-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AACxC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAC7C,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAmB,EAAE,SAAiB;IAC/E,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAwB;QACzC,EAAE,EAAE,kBAAkB;QACtB,KAAK,EAAE,qDAAqD;QAC5D,SAAS,EAAE,WAAW,IAAI,OAAO;QACjC,GAAG,CAAC,WAAW,IAAI,OAAO;YACxB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,IAAI,EAAE,CAAC,WAAW,IAAI,CAAC,OAAO;oBAC5B,CAAC,CAAC,wDAAwD;oBAC1D,CAAC,CAAC,CAAC,WAAW;wBACZ,CAAC,CAAC,qDAAqD;wBACvD,CAAC,CAAC,0EAA0E;aACjF,CAAC;KACP,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IAChE,MAAM,qBAAqB,GAAG,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnF,MAAM,WAAW,GAAwB;QACvC,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,gEAAgE;QACvE,SAAS,EAAE,qBAAqB;QAChC,GAAG,CAAC,qBAAqB;YACvB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,kDAAkD,CAAC,CAAC,CAAC,iDAAiD,EAAE,CAAC;KAC3I,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;IAClE,MAAM,WAAW,GAAwB;QACvC,EAAE,EAAE,YAAY;QAChB,KAAK,EAAE,2DAA2D;QAClE,SAAS,EAAE,YAAY;QACvB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,mDAAmD,EAAE,CAAC;KACvF,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,aAAa,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IACzD,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AACvF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { WorkspaceHost } from "./types.js";
2
+ export interface SkillCompositionResult {
3
+ readonly composed: readonly string[];
4
+ readonly skipped: readonly {
5
+ readonly packageDir: string;
6
+ readonly note: string;
7
+ }[];
8
+ readonly rosterTargets?: readonly string[];
9
+ readonly rosterSkipped?: readonly {
10
+ readonly inventoryId: string;
11
+ readonly note: string;
12
+ }[];
13
+ /** Skills pruned this run: present in the directory's previous manifest, absent from this run's composed set. */
14
+ readonly retired: readonly string[];
15
+ }
16
+ export interface ComposeSkillsOptions {
17
+ readonly skillCatalogueRoot?: string;
18
+ readonly launcherPackageRoot: string;
19
+ /** Overrides where the packed conversation contract is read from (tests). */
20
+ readonly contractPath?: string;
21
+ }
22
+ export declare const DISCOVERY_PREFIXES: readonly [".cursor/skills", ".claude/skills"];
23
+ export declare const SKILLS_MANIFEST_REL: string;
24
+ /** Package directory names that have a resolvable skill source in the catalogue or monorepo. */
25
+ export declare function listSkillPackageCandidates(host: WorkspaceHost, options: ComposeSkillsOptions): string[];
26
+ /**
27
+ * Writes `.agents/skills/clossys-<pkg>/SKILL.md` and host discovery links for every
28
+ * catalogue package, with the shared conversation contract (#1182) injected in place
29
+ * of each skill's own `## How we work together` / `## One question at a time`
30
+ * sections. Missing sources are skipped with notes; the hub apply continues.
31
+ *
32
+ * Also writes `clossys/.state/skills.json` (#1183): source, version, and content
33
+ * digest per composed skill. A skill named in this directory's *previous* manifest
34
+ * but not composed this run is retired — its composed output is pruned and it is
35
+ * dropped from the new manifest. Never touches a skill this directory's manifest
36
+ * did not itself write.
37
+ */
38
+ export declare function composeSkills(host: WorkspaceHost, directory: string, options: ComposeSkillsOptions): SkillCompositionResult;
39
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpF,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5F,iHAAiH;IACjH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,eAAO,MAAM,kBAAkB,+CAAgD,CAAC;AAEhF,eAAO,MAAM,mBAAmB,QAA2C,CAAC;AA8E5E,gGAAgG;AAChG,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAqBvG;AA0CD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,oBAAoB,GAC5B,sBAAsB,CA2CxB"}