@tacuchi/agent-workflow-cli 21.0.0 → 21.1.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 (153) hide show
  1. package/README.md +1 -0
  2. package/dist/application/capability/compose.js +161 -0
  3. package/dist/application/capability/compose.js.map +1 -0
  4. package/dist/application/capability/descriptor-loader.js +109 -0
  5. package/dist/application/capability/descriptor-loader.js.map +1 -0
  6. package/dist/application/capability/design-handler.js +299 -0
  7. package/dist/application/capability/design-handler.js.map +1 -0
  8. package/dist/application/capability/dispatcher.js +312 -0
  9. package/dist/application/capability/dispatcher.js.map +1 -0
  10. package/dist/application/capability/durable-effect.js +220 -0
  11. package/dist/application/capability/durable-effect.js.map +1 -0
  12. package/dist/application/capability/installed-inventory.js +168 -0
  13. package/dist/application/capability/installed-inventory.js.map +1 -0
  14. package/dist/application/capability/readiness.js +204 -0
  15. package/dist/application/capability/readiness.js.map +1 -0
  16. package/dist/application/capability/resolution.js +264 -0
  17. package/dist/application/capability/resolution.js.map +1 -0
  18. package/dist/application/capability/wrapper.js +187 -0
  19. package/dist/application/capability/wrapper.js.map +1 -0
  20. package/dist/application/context/manifest.js +11 -5
  21. package/dist/application/context/manifest.js.map +1 -1
  22. package/dist/application/context/measure.js +5 -2
  23. package/dist/application/context/measure.js.map +1 -1
  24. package/dist/application/context/plan-service.js +6 -6
  25. package/dist/application/context/plan-service.js.map +1 -1
  26. package/dist/application/design/design-bundle-service.js +148 -0
  27. package/dist/application/design/design-bundle-service.js.map +1 -0
  28. package/dist/application/design/design-proposal-service.js +69 -0
  29. package/dist/application/design/design-proposal-service.js.map +1 -0
  30. package/dist/application/design/design-publish-service.js +275 -7
  31. package/dist/application/design/design-publish-service.js.map +1 -1
  32. package/dist/application/design/design-record-service.js +100 -0
  33. package/dist/application/design/design-record-service.js.map +1 -0
  34. package/dist/application/flow/advance.js +533 -0
  35. package/dist/application/flow/advance.js.map +1 -0
  36. package/dist/application/flow/flow-service.js +65 -0
  37. package/dist/application/flow/flow-service.js.map +1 -0
  38. package/dist/application/flow/run-projection.js +80 -0
  39. package/dist/application/flow/run-projection.js.map +1 -0
  40. package/dist/application/flow/run-state-service.js +107 -0
  41. package/dist/application/flow/run-state-service.js.map +1 -0
  42. package/dist/application/flow/submit.js +423 -0
  43. package/dist/application/flow/submit.js.map +1 -0
  44. package/dist/application/resume-service.js +23 -10
  45. package/dist/application/resume-service.js.map +1 -1
  46. package/dist/application/self/install-skill.js +11 -0
  47. package/dist/application/self/install-skill.js.map +1 -1
  48. package/dist/application/self/uninstall.js +21 -0
  49. package/dist/application/self/uninstall.js.map +1 -1
  50. package/dist/application/skills-resolver-service.js +8 -2
  51. package/dist/application/skills-resolver-service.js.map +1 -1
  52. package/dist/application/status-service.js +4 -1
  53. package/dist/application/status-service.js.map +1 -1
  54. package/dist/application/workspace-init-service.js +13 -1
  55. package/dist/application/workspace-init-service.js.map +1 -1
  56. package/dist/cli/commands/capability.js +182 -0
  57. package/dist/cli/commands/capability.js.map +1 -0
  58. package/dist/cli/commands/flow.js +71 -0
  59. package/dist/cli/commands/flow.js.map +1 -0
  60. package/dist/cli/commands/index.js +4 -0
  61. package/dist/cli/commands/index.js.map +1 -1
  62. package/dist/cli/commands/skills.js +55 -2
  63. package/dist/cli/commands/skills.js.map +1 -1
  64. package/dist/cli/commands/status.js +5 -0
  65. package/dist/cli/commands/status.js.map +1 -1
  66. package/dist/cli/help-groups.js +6 -0
  67. package/dist/cli/help-groups.js.map +1 -1
  68. package/dist/cli/parser.js +6 -0
  69. package/dist/cli/parser.js.map +1 -1
  70. package/dist/cli/tui/data/workflow-content.js +5 -0
  71. package/dist/cli/tui/data/workflow-content.js.map +1 -1
  72. package/dist/cli/tui/tabs/workflow-tab.js +5 -1
  73. package/dist/cli/tui/tabs/workflow-tab.js.map +1 -1
  74. package/dist/domain/capability/descriptor.js +553 -0
  75. package/dist/domain/capability/descriptor.js.map +1 -0
  76. package/dist/domain/capability/effects.js +90 -0
  77. package/dist/domain/capability/effects.js.map +1 -0
  78. package/dist/domain/capability/protocol.js +494 -0
  79. package/dist/domain/capability/protocol.js.map +1 -0
  80. package/dist/domain/contract-reader.js +84 -0
  81. package/dist/domain/contract-reader.js.map +1 -0
  82. package/dist/domain/design/adapter.js +161 -0
  83. package/dist/domain/design/adapter.js.map +1 -0
  84. package/dist/domain/design/artifact.js +148 -4
  85. package/dist/domain/design/artifact.js.map +1 -1
  86. package/dist/domain/design/capability.js +263 -4
  87. package/dist/domain/design/capability.js.map +1 -1
  88. package/dist/domain/design/direct.js +108 -0
  89. package/dist/domain/design/direct.js.map +1 -0
  90. package/dist/domain/design/external-send.js +65 -0
  91. package/dist/domain/design/external-send.js.map +1 -0
  92. package/dist/domain/design/maturity.js +71 -0
  93. package/dist/domain/design/maturity.js.map +1 -1
  94. package/dist/domain/design/offline.js +92 -0
  95. package/dist/domain/design/offline.js.map +1 -0
  96. package/dist/domain/design/profiles.js +212 -0
  97. package/dist/domain/design/profiles.js.map +1 -0
  98. package/dist/domain/design/proposal.js +234 -0
  99. package/dist/domain/design/proposal.js.map +1 -0
  100. package/dist/domain/design/render-bundle.js +0 -0
  101. package/dist/domain/design/render-bundle.js.map +1 -0
  102. package/dist/domain/design/rendition.js +472 -0
  103. package/dist/domain/design/rendition.js.map +1 -0
  104. package/dist/domain/design/sources.js +180 -0
  105. package/dist/domain/design/sources.js.map +1 -0
  106. package/dist/domain/design/validation.js +12 -68
  107. package/dist/domain/design/validation.js.map +1 -1
  108. package/dist/domain/design/visual-evidence.js +155 -0
  109. package/dist/domain/design/visual-evidence.js.map +1 -0
  110. package/dist/domain/flow/answer.js +459 -0
  111. package/dist/domain/flow/answer.js.map +1 -0
  112. package/dist/domain/flow/authority.js +2276 -0
  113. package/dist/domain/flow/authority.js.map +1 -0
  114. package/dist/domain/flow/authorization.js +62 -0
  115. package/dist/domain/flow/authorization.js.map +1 -0
  116. package/dist/domain/flow/directive.js +421 -0
  117. package/dist/domain/flow/directive.js.map +1 -0
  118. package/dist/domain/flow/rules.js +140 -0
  119. package/dist/domain/flow/rules.js.map +1 -0
  120. package/dist/domain/flow/run-state.js +317 -0
  121. package/dist/domain/flow/run-state.js.map +1 -0
  122. package/dist/domain/harnesses.js +21 -0
  123. package/dist/domain/harnesses.js.map +1 -1
  124. package/dist/domain/skills.js +13 -14
  125. package/dist/domain/skills.js.map +1 -1
  126. package/package.json +1 -1
  127. package/skills/w/SKILL.md +5 -5
  128. package/skills/w/context/MANIFEST.json +38 -1
  129. package/skills/w/harness/HARNESS.md +20 -0
  130. package/skills/w/loops/CHASSIS.md +11 -20
  131. package/skills/w/loops/CODE-POLICIES.md +9 -15
  132. package/skills/w/loops/plan-exec-loop/LOOP.md +11 -13
  133. package/skills/w/loops/plan-new-loop/LOOP.md +6 -4
  134. package/skills/w/loops/plan-refine-loop/LOOP.md +5 -3
  135. package/skills/w/loops/quick-loop/LOOP.md +18 -26
  136. package/skills/w/loops/spec-refine-loop/LOOP.md +14 -18
  137. package/skills/w/modules/COMPACTION.md +2 -6
  138. package/skills/w/modules/DB-SCRIPTS-ONLY.md +2 -0
  139. package/skills/w/modules/DESIGN-REFERENCES.md +15 -11
  140. package/skills/w/modules/IDEATION-GATE.md +3 -3
  141. package/skills/w/modules/PLAN-EXECUTION-BATCHES.md +17 -36
  142. package/skills/w/modules/PLAN-INPUT.md +5 -3
  143. package/skills/w/modules/PLAN-REFINE-SPLIT.md +3 -1
  144. package/skills/w/modules/PLAN-SPLIT-GATE.md +7 -5
  145. package/skills/w/modules/PROMPT-CONTINUITY.md +3 -1
  146. package/skills/w/modules/SPEC-CHANGE-SHAPE.md +4 -4
  147. package/skills/w/roles/README.md +2 -0
  148. package/skills/w/roles/design/CONTRACT.md +80 -0
  149. package/skills/w/roles/design/ROLE.md +7 -0
  150. package/skills/w/schemas/capability-descriptor.schema.json +260 -0
  151. package/skills/w/schemas/design/design-render-bundle.v1.schema.json +191 -0
  152. package/skills/w/schemas/design/design-rendition.v1.schema.json +232 -0
  153. package/skills/w/schemas/design/ui-screen.v1.schema.json +29 -1
@@ -0,0 +1,168 @@
1
+ /**
2
+ * What is ACTUALLY installed, as exact instances.
3
+ *
4
+ * The advisory check this replaces compared names. A name is not a thing that
5
+ * runs: two directories can both be called `design`, and picking one by scan
6
+ * order is a silent choice nobody made. So the unit here is an instance —
7
+ * name, scope, the locator of its `SKILL.md`, the locator of its descriptor, its
8
+ * version and a digest over its bytes — and the two failure modes are kept
9
+ * apart:
10
+ *
11
+ * - **Same name, same digest, several roots.** Equivalent replicas. Every
12
+ * locator is kept, because "which copy answered" is still a real question.
13
+ * - **Same name, different bytes.** `misconfigured`. Not a precedence puzzle to
14
+ * resolve — two different things are wearing one name, and no scan order makes
15
+ * that safe.
16
+ *
17
+ * Only skills that DECLARE a descriptor enter this inventory. An ambient skill —
18
+ * a linter, a writing convention — is installed and invisible here, which is the
19
+ * whole content of the opt-in.
20
+ */
21
+ import { createHash } from "node:crypto";
22
+ import { RETIRED_SKILL_IDENTITIES } from "../../domain/skills.js";
23
+ import { semanticDigest } from "../semantic-operation/protocol.js";
24
+ import { skillRoots } from "../skills-resolver-service.js";
25
+ import { loadDescriptor, readSkillHead } from "./descriptor-loader.js";
26
+ export async function buildCapabilityInventory(fs, env) {
27
+ const roots = skillRoots(env);
28
+ const candidates = [];
29
+ for (const root of roots) {
30
+ candidates.push(...(await scanRoot(fs, root)));
31
+ }
32
+ return { roots, capabilities: group(candidates) };
33
+ }
34
+ async function scanRoot(fs, root) {
35
+ if (!(await fs.exists(root)))
36
+ return [];
37
+ let entries;
38
+ try {
39
+ entries = await fs.list(root);
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ const found = [];
45
+ for (const entry of entries) {
46
+ if (entry.type !== "dir")
47
+ continue;
48
+ const head = await readSkillHead(fs, entry.path, entry.name);
49
+ // No readable head, or no claim at all: an ambient skill. It never becomes a
50
+ // capability by being installed, so it never enters the inventory.
51
+ if (head === null || head.locatorValue === null)
52
+ continue;
53
+ found.push(await candidateFor(fs, root, entry.path, head));
54
+ }
55
+ return found;
56
+ }
57
+ async function candidateFor(fs, root, skillDir, head) {
58
+ const location = {
59
+ scope: root,
60
+ skillDir,
61
+ skillMd: head.skillMd,
62
+ descriptorPath: null,
63
+ };
64
+ const base = { name: head.name, version: head.version, location, descriptor: null };
65
+ // A directory wearing a retired name is refused before its descriptor is even
66
+ // read: the name IS the identity, and honoring it would resurrect the alias
67
+ // the contract exists to close.
68
+ const retired = RETIRED_SKILL_IDENTITIES.get(head.name.toLowerCase());
69
+ if (retired !== undefined) {
70
+ return {
71
+ ...base,
72
+ digest: null,
73
+ failure: {
74
+ code: "CAPABILITY_NAME_RETIRED",
75
+ message: `'${head.name}' está retirado — ${retired}`,
76
+ action: "renombrá la skill al nombre vigente de la capacidad; no hay alias",
77
+ },
78
+ };
79
+ }
80
+ const load = await loadDescriptor(fs, skillDir, head);
81
+ if (load.state !== "loaded") {
82
+ return {
83
+ ...base,
84
+ digest: null,
85
+ failure: load.state === "invalid" ? load.failure : null,
86
+ };
87
+ }
88
+ return {
89
+ name: head.name,
90
+ version: head.version,
91
+ digest: await instanceDigest(fs, head.skillMd, load.loaded.digest),
92
+ location: { ...location, descriptorPath: load.loaded.path },
93
+ descriptor: load.loaded.descriptor,
94
+ failure: null,
95
+ };
96
+ }
97
+ /**
98
+ * The identity of the bytes that would run: the instruction file AND the
99
+ * contract it points at. Sealing only the descriptor would call two skills
100
+ * identical while their `SKILL.md` told the host to do different things.
101
+ */
102
+ async function instanceDigest(fs, skillMd, descriptorDigest) {
103
+ try {
104
+ const text = await fs.readText(skillMd);
105
+ return semanticDigest({
106
+ skill_md: createHash("sha256").update(text, "utf8").digest("hex"),
107
+ descriptor: descriptorDigest,
108
+ });
109
+ }
110
+ catch {
111
+ return null;
112
+ }
113
+ }
114
+ function group(candidates) {
115
+ const byName = new Map();
116
+ for (const candidate of candidates) {
117
+ byName.set(candidate.name, [...(byName.get(candidate.name) ?? []), candidate]);
118
+ }
119
+ const out = [];
120
+ for (const [name, copies] of byName) {
121
+ const locations = copies.map((c) => c.location);
122
+ const broken = copies.find((c) => c.failure !== null);
123
+ if (broken?.failure != null) {
124
+ out.push({
125
+ name,
126
+ version: broken.version,
127
+ digest: null,
128
+ locations,
129
+ descriptor: null,
130
+ state: "misconfigured",
131
+ failure: broken.failure,
132
+ });
133
+ continue;
134
+ }
135
+ const digests = [...new Set(copies.map((c) => c.digest))];
136
+ const first = copies[0];
137
+ if (digests.length > 1) {
138
+ out.push({
139
+ name,
140
+ version: first.version,
141
+ digest: null,
142
+ locations,
143
+ descriptor: null,
144
+ state: "misconfigured",
145
+ failure: {
146
+ code: "CAPABILITY_INSTANCE_COLLISION",
147
+ message: `hay ${copies.length} skills llamadas '${name}' con bytes distintos: ${locations.map((l) => l.skillDir).join(", ")}`,
148
+ action: "dejá una sola instalación de ese nombre, o renombrá la que no corresponde: no hay precedencia entre roots",
149
+ },
150
+ });
151
+ continue;
152
+ }
153
+ out.push({
154
+ name,
155
+ version: first.version,
156
+ digest: first.digest,
157
+ locations,
158
+ descriptor: first.descriptor,
159
+ state: "ready",
160
+ failure: null,
161
+ });
162
+ }
163
+ return out.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
164
+ }
165
+ export function findInstalled(inventory, name) {
166
+ return inventory.capabilities.find((c) => c.name === name) ?? null;
167
+ }
168
+ //# sourceMappingURL=installed-inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed-inventory.js","sourceRoot":"","sources":["../../../src/application/capability/installed-inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAGlE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAsCvE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,EAAkB,EAClB,GAAY;IAEZ,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,EAAkB,EAAE,IAAY;IACtD,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,OAAoD,CAAC;IACzD,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK;YAAE,SAAS;QACnC,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7D,6EAA6E;QAC7E,mEAAmE;QACnE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI;YAAE,SAAS;QAC1D,KAAK,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,EAAkB,EAClB,IAAY,EACZ,QAAgB,EAChB,IAAe;IAEf,MAAM,QAAQ,GAAqB;QACjC,KAAK,EAAE,IAAI;QACX,QAAQ;QACR,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,cAAc,EAAE,IAAI;KACrB,CAAC;IACF,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAW,CAAC;IAE7F,8EAA8E;IAC9E,4EAA4E;IAC5E,gCAAgC;IAChC,MAAM,OAAO,GAAG,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;gBACP,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,qBAAqB,OAAO,EAAE;gBACpD,MAAM,EAAE,mEAAmE;aAC5E;SACF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;SACxD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,MAAM,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAClE,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAC3D,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;QAClC,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAC3B,EAAkB,EAClB,OAAe,EACf,gBAAwB;IAExB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,cAAc,CAAC;YACpB,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YACjE,UAAU,EAAE,gBAAgB;SAC7B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,UAAuB;IACpC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,GAAG,GAA0B,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;QACtD,IAAI,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI;gBACJ,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM,EAAE,IAAI;gBACZ,SAAS;gBACT,UAAU,EAAE,IAAI;gBAChB,KAAK,EAAE,eAAe;gBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAc,CAAC;QACrC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI;gBACJ,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,MAAM,EAAE,IAAI;gBACZ,SAAS;gBACT,UAAU,EAAE,IAAI;gBAChB,KAAK,EAAE,eAAe;gBACtB,OAAO,EAAE;oBACP,IAAI,EAAE,+BAA+B;oBACrC,OAAO,EAAE,OAAO,MAAM,CAAC,MAAM,qBAAqB,IAAI,0BAA0B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAC7H,MAAM,EACJ,2GAA2G;iBAC9G;aACF,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI;YACJ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,SAAS;YACT,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,SAA8B,EAC9B,IAAY;IAEZ,OAAO,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;AACrE,CAAC"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * What can be invoked here, in what state, and what to do about it.
3
+ *
4
+ * The check this replaces compared names and emitted advice. Readiness answers
5
+ * the question a person actually has — "can I use this right now, and if not,
6
+ * why?" — and every state carries its evidence and one next action, because a
7
+ * status with neither is a puzzle rather than a diagnosis.
8
+ *
9
+ * Two things are deliberately kept apart:
10
+ *
11
+ * - **Per exposure.** The direct entrypoint and the composed route fail
12
+ * independently. A foreign skill squatting the wrapper's name breaks `direct`
13
+ * and leaves `compose` running on the floor; collapsing them into one state
14
+ * would hide half of that.
15
+ * - **Per operation.** `off` blocks four operations of `design` and keeps
16
+ * `validate` alive. One state for the capability cannot express that.
17
+ *
18
+ * The invocation form is read from `HARNESSES` and never inferred. A host with
19
+ * no verified form says so instead of borrowing another host's syntax.
20
+ */
21
+ import { join } from "node:path";
22
+ import { HARNESSES } from "../../domain/harnesses.js";
23
+ import { classifyCapabilityBinding } from "../../domain/skills.js";
24
+ import { resolveSkills } from "../skills-resolver-service.js";
25
+ import { capabilityHandler, registeredCapabilities } from "./dispatcher.js";
26
+ import { buildCapabilityInventory } from "./installed-inventory.js";
27
+ import { resolveCapability } from "./resolution.js";
28
+ import { inspectCapabilityDirVia } from "./wrapper.js";
29
+ export async function capabilityReadiness(input) {
30
+ const skills = await resolveSkills(input.fs, input.paths);
31
+ const inventory = await buildCapabilityInventory(input.fs, input.env);
32
+ const reports = [];
33
+ for (const name of registeredCapabilities()) {
34
+ const handler = capabilityHandler(name);
35
+ if (handler === null)
36
+ continue;
37
+ const slot = skills.skills[name];
38
+ const binding = slot === undefined
39
+ ? { state: "floor_and_improvements", reason: null, action: null }
40
+ : classifyCapabilityBinding(slot, name);
41
+ const resolution = resolveCapability({ descriptor: handler.descriptor, binding, inventory });
42
+ reports.push(await reportFor(input, handler.descriptor, resolution, inventory, {
43
+ state: resolution.state,
44
+ reason: resolution.reason,
45
+ action: resolution.action,
46
+ }));
47
+ }
48
+ return reports;
49
+ }
50
+ async function reportFor(input, descriptor, resolution, inventory, verdict) {
51
+ const direct = await directVerdict(input, descriptor, verdict);
52
+ return {
53
+ capability: descriptor.name,
54
+ contract_version: descriptor.contract_version,
55
+ purpose: descriptor.purpose,
56
+ exposure: descriptor.exposure,
57
+ ...verdict,
58
+ floor: {
59
+ builtin: descriptor.floor.builtin,
60
+ kind: descriptor.floor.kind,
61
+ running: resolution.floor,
62
+ },
63
+ instance: resolution.selection[0] === undefined
64
+ ? null
65
+ : {
66
+ name: resolution.selection[0].name,
67
+ scope: resolution.selection[0].scope,
68
+ locator: resolution.selection[0].locator,
69
+ version: resolution.selection[0].version,
70
+ digest: resolution.selection[0].digest,
71
+ },
72
+ invocation: invocationFor(input.host, descriptor.name),
73
+ exposures: {
74
+ direct: descriptor.exposure.includes("direct")
75
+ ? direct
76
+ : { state: "unavailable", reason: "la capacidad no expone la ruta directa", action: null },
77
+ compose: descriptor.exposure.includes("compose")
78
+ ? verdict
79
+ : {
80
+ state: "unavailable",
81
+ reason: "la capacidad no expone la ruta compuesta",
82
+ action: null,
83
+ },
84
+ },
85
+ operations: descriptor.operations.map((op) => {
86
+ const availability = resolution.operations.find((o) => o.operation === op.name);
87
+ const blocked = availability !== undefined && !availability.available;
88
+ return {
89
+ operation: op.name,
90
+ exposure: op.exposure,
91
+ workspace: op.workspace,
92
+ effects: op.effects.map((e) => e.class),
93
+ // The capability being `disabled` does NOT make the operation `off`
94
+ // spared disabled too: saying so would erase exactly the consumption
95
+ // `off` is required to preserve.
96
+ state: blocked ? "disabled" : availableState(verdict, resolution.floor),
97
+ reason: blocked ? availability.reason : verdict.reason,
98
+ action: blocked ? (resolution.action ?? null) : verdict.action,
99
+ };
100
+ }),
101
+ improvements: inventory.capabilities
102
+ .filter((c) => c.name !== descriptor.name)
103
+ .map((c) => eligibility(c, descriptor)),
104
+ };
105
+ }
106
+ /**
107
+ * The direct route lives or dies by a real directory on disk.
108
+ *
109
+ * A capability can be perfectly resolved and still be unreachable directly
110
+ * because nobody installed the wrapper — or because someone else's skill holds
111
+ * the name. Both are states of the ENTRYPOINT, not of the capability, so they
112
+ * are reported here and nowhere else.
113
+ */
114
+ async function directVerdict(input, descriptor, verdict) {
115
+ const harness = HARNESSES.find((h) => h.id === input.host);
116
+ if (harness === undefined || harness.invocation === null) {
117
+ return {
118
+ state: "unavailable",
119
+ reason: `no hay una forma de invocación verificada para el host '${input.host}'`,
120
+ action: "usá la ruta compuesta desde un flow, o instalá en un host soportado",
121
+ };
122
+ }
123
+ const root = join(input.env.homeDir(), ...(harness.skillsDirs[0]?.split("/") ?? []));
124
+ const ownership = await inspectCapabilityDirVia(input.fs, join(root, descriptor.name));
125
+ if (ownership.state === "foreign") {
126
+ return {
127
+ state: "misconfigured",
128
+ reason: ownership.why,
129
+ action: `renombrá o quitá esa skill y reinstalá con 'aw self install-skill'`,
130
+ };
131
+ }
132
+ if (ownership.state === "absent") {
133
+ return {
134
+ state: "unavailable",
135
+ reason: `no hay un wrapper '${descriptor.name}' instalado en ${root}`,
136
+ action: "instalalo con 'aw self install-skill'",
137
+ };
138
+ }
139
+ return verdict;
140
+ }
141
+ /** What an AVAILABLE operation's state is when the capability itself is off. */
142
+ function availableState(verdict, floorRunning) {
143
+ if (verdict.state !== "disabled")
144
+ return verdict.state;
145
+ return floorRunning ? "ready" : "unavailable";
146
+ }
147
+ function invocationFor(host, name) {
148
+ const harness = HARNESSES.find((h) => h.id === host);
149
+ const invocation = harness?.invocation ?? null;
150
+ if (invocation === null) {
151
+ return {
152
+ host,
153
+ kind: "unavailable",
154
+ form: null,
155
+ // Saying "unavailable" is the honest answer. Printing another host's
156
+ // syntax would send a person to type something that does nothing.
157
+ note: `no hay una forma de invocación verificada para '${host}'`,
158
+ };
159
+ }
160
+ return {
161
+ host,
162
+ kind: invocation.kind,
163
+ form: invocation.template.replace("<name>", name),
164
+ note: invocation.note,
165
+ };
166
+ }
167
+ function eligibility(installed, descriptor) {
168
+ const improves = installed.descriptor?.compatibility.improves ?? null;
169
+ if (installed.state === "misconfigured") {
170
+ return {
171
+ name: installed.name,
172
+ digest: null,
173
+ improves: null,
174
+ eligible: false,
175
+ why: installed.failure?.message ?? "instancia no identificable",
176
+ };
177
+ }
178
+ if (improves === null || improves.capability !== descriptor.name) {
179
+ return {
180
+ name: installed.name,
181
+ digest: installed.digest,
182
+ improves: improves?.capability ?? null,
183
+ eligible: false,
184
+ why: `no declara mejorar '${descriptor.name}'`,
185
+ };
186
+ }
187
+ if (improves.contract_version !== descriptor.contract_version) {
188
+ return {
189
+ name: installed.name,
190
+ digest: installed.digest,
191
+ improves: improves.capability,
192
+ eligible: false,
193
+ why: `habla la versión de contrato ${improves.contract_version}`,
194
+ };
195
+ }
196
+ return {
197
+ name: installed.name,
198
+ digest: installed.digest,
199
+ improves: improves.capability,
200
+ eligible: true,
201
+ why: null,
202
+ };
203
+ }
204
+ //# sourceMappingURL=readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.js","sourceRoot":"","sources":["../../../src/application/capability/readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,264 @@
1
+ /**
2
+ * What will actually run, and who gets credit for it.
3
+ *
4
+ * The resolution answers three questions that used to have no answer at all:
5
+ * whether the capability is available, whether an improvement contributes, and —
6
+ * when one does — WHICH exact instance, pinned so it cannot change mid-
7
+ * conversation. Everything here is built so that the honest answer is always
8
+ * reachable:
9
+ *
10
+ * - **No improvement is the ordinary case, not a degradation.** A machine with
11
+ * nothing extra installed runs the floor and reports `ready`. Calling that
12
+ * "degraded" would make the normal state look broken and hide the real one.
13
+ * - **A degradation names its cause and its loss, and attributes nothing.** When
14
+ * a selection cannot be identified, the run does not guess who helped; it says
15
+ * what it could not verify.
16
+ * - **A floor is what keeps a missing skill from blocking a flow.** A capability
17
+ * a core gate needs declares `floor.builtin`; one that does not may be
18
+ * `unavailable`, and then it blocks ITS operations and nothing else.
19
+ */
20
+ import { findInstalled } from "./installed-inventory.js";
21
+ export function resolveCapability(input) {
22
+ const { descriptor, binding } = input;
23
+ const operations = availability(descriptor, binding);
24
+ if (binding.state === "off") {
25
+ return {
26
+ capability: descriptor.name,
27
+ state: "disabled",
28
+ // The operations `off` leaves alive still run on the floor. Reporting
29
+ // `floor: false` here would say nothing implements `validate`, which is
30
+ // exactly the consumption `off` is required to preserve.
31
+ floor: descriptor.floor.builtin && operations.some((o) => o.available),
32
+ selection: [],
33
+ degradations: [],
34
+ operations,
35
+ reason: binding.reason,
36
+ action: `para reactivarla, quitá el binding o ponelo en '${descriptor.name}'`,
37
+ };
38
+ }
39
+ if (binding.state === "misconfigured") {
40
+ return degradeToFloor(input, operations, {
41
+ cause: "invalid_binding",
42
+ loss: binding.reason ?? "el binding no selecciona una instancia identificable",
43
+ action: binding.action,
44
+ });
45
+ }
46
+ const contributors = input.hostSelection?.contributors ?? [];
47
+ if (descriptor.floor.improvements === "none" || contributors.length === 0) {
48
+ // Nothing extra selected. Not a loss — there was nothing to lose.
49
+ return floorOnly(descriptor, operations);
50
+ }
51
+ const verified = verifyContributors(input, contributors);
52
+ if (verified.degradation !== null) {
53
+ return degradeToFloor(input, operations, {
54
+ cause: verified.degradation.cause,
55
+ loss: verified.degradation.loss,
56
+ action: verified.degradation.action,
57
+ });
58
+ }
59
+ return {
60
+ capability: descriptor.name,
61
+ state: "ready",
62
+ floor: false,
63
+ selection: verified.selection,
64
+ degradations: [],
65
+ operations,
66
+ reason: null,
67
+ action: null,
68
+ };
69
+ }
70
+ function availability(descriptor, binding) {
71
+ return descriptor.operations.map((op) => operationState(op, binding));
72
+ }
73
+ function operationState(op, binding) {
74
+ if (binding.state === "off" && op.off === "blocked") {
75
+ return {
76
+ operation: op.name,
77
+ available: false,
78
+ // `off` is not reverted by a host, a wrapper or a legacy name; the only
79
+ // way back is the binding itself.
80
+ reason: "la capacidad está en off y esta operación queda bloqueada",
81
+ };
82
+ }
83
+ return { operation: op.name, available: true, reason: null };
84
+ }
85
+ function floorOnly(descriptor, operations) {
86
+ if (descriptor.floor.builtin) {
87
+ return {
88
+ capability: descriptor.name,
89
+ state: "ready",
90
+ floor: true,
91
+ selection: [],
92
+ degradations: [],
93
+ operations,
94
+ reason: null,
95
+ action: null,
96
+ };
97
+ }
98
+ // Feature-only with nothing installed. It blocks ITS operations — the flows
99
+ // that never asked for it keep working, which is the whole isolation rule.
100
+ return {
101
+ capability: descriptor.name,
102
+ state: "unavailable",
103
+ floor: false,
104
+ selection: [],
105
+ degradations: [],
106
+ operations: operations.map((o) => ({
107
+ operation: o.operation,
108
+ available: false,
109
+ reason: `'${descriptor.name}' no tiene floor incorporado y no hay ninguna instancia conformante`,
110
+ })),
111
+ reason: `'${descriptor.name}' es una capacidad sin floor y no hay implementación instalada`,
112
+ action: `instalá una skill conformante con '${descriptor.name}' o dejá de invocar esa feature`,
113
+ };
114
+ }
115
+ /**
116
+ * Fall back — but only where falling back is safe.
117
+ *
118
+ * With a built-in floor the run continues and the receipt carries the cause and
119
+ * the loss. Without one there is nothing safe to fall to, so the resolution says
120
+ * `misconfigured` instead of quietly producing a lesser result under the same
121
+ * name.
122
+ */
123
+ function degradeToFloor(input, operations, seed) {
124
+ const { descriptor } = input;
125
+ const degradations = [{ cause: seed.cause, loss: seed.loss }];
126
+ const declared = descriptor.degradations.some((d) => d.cause === seed.cause);
127
+ if (!descriptor.floor.builtin || !declared) {
128
+ return {
129
+ capability: descriptor.name,
130
+ state: "misconfigured",
131
+ floor: false,
132
+ selection: [],
133
+ degradations,
134
+ operations: operations.map((o) => ({ ...o, available: false, reason: seed.loss })),
135
+ reason: seed.loss,
136
+ action: seed.action ?? `revisá la configuración de '${descriptor.name}'`,
137
+ };
138
+ }
139
+ return {
140
+ capability: descriptor.name,
141
+ state: "degraded",
142
+ floor: true,
143
+ // Empty on purpose: the whole point of the degradation is that nothing
144
+ // verifiable contributed, so nothing gets credit.
145
+ selection: [],
146
+ degradations,
147
+ operations,
148
+ reason: seed.loss,
149
+ action: seed.action ?? "corré la operación con el floor o corregí la selección",
150
+ };
151
+ }
152
+ function verifyContributors(input, contributors) {
153
+ const selection = [];
154
+ const ordered = [...contributors].sort((a, b) => a.order - b.order);
155
+ for (const contributor of ordered) {
156
+ const installed = findInstalled(input.inventory, contributor.name);
157
+ const problem = identify(input, contributor, installed);
158
+ if (problem !== null)
159
+ return { selection: [], degradation: problem };
160
+ const instance = installed;
161
+ const location = instance.locations.find((l) => l.skillDir === contributor.locator) ?? instance.locations[0];
162
+ selection.push({
163
+ name: instance.name,
164
+ scope: location?.scope ?? "",
165
+ locator: location?.skillDir ?? "",
166
+ version: instance.version,
167
+ digest: instance.digest,
168
+ order: contributor.order,
169
+ });
170
+ }
171
+ return { selection, degradation: null };
172
+ }
173
+ /** Everything that can stop a declared contributor from being a real one. */
174
+ function identify(input, contributor, installed) {
175
+ if (installed === null) {
176
+ return {
177
+ cause: "opaque_selection",
178
+ loss: `el host declaró '${contributor.name}' y no hay ninguna instancia instalada con ese nombre`,
179
+ action: "instalá la skill declarada, o quitala de la selección del host",
180
+ };
181
+ }
182
+ if (installed.state === "misconfigured" || installed.digest === null) {
183
+ return {
184
+ cause: "opaque_selection",
185
+ loss: installed.failure?.message ?? `'${contributor.name}' no identifica una instancia exacta`,
186
+ action: installed.failure?.action ?? "dejá una sola instalación de ese nombre",
187
+ };
188
+ }
189
+ // Equivalent replicas are the same BYTES, not the same install. A name-only
190
+ // selection among several roots still cannot say which copy answered, and
191
+ // picking the first would be exactly the silent precedence there must not be.
192
+ const locators = installed.locations.map((l) => l.skillDir);
193
+ if (locators.length > 1 && !locators.includes(contributor.locator ?? "")) {
194
+ return {
195
+ cause: "opaque_selection",
196
+ loss: `'${contributor.name}' está instalada en ${locators.length} raíces y la selección no dice cuál contribuyó`,
197
+ action: `declará el locator de la instancia (${locators.join(", ")}), o dejá una sola instalación`,
198
+ };
199
+ }
200
+ if (contributor.digest != null && contributor.digest !== installed.digest) {
201
+ return {
202
+ cause: "digest_changed",
203
+ loss: `'${contributor.name}' cambió de bytes entre la selección del host y el inventario`,
204
+ action: "volvé a resolver la capacidad: la instancia dejó de ser la que se fijó",
205
+ };
206
+ }
207
+ return compatible(input, contributor, installed);
208
+ }
209
+ /**
210
+ * Installed is not compatible. The claim has to come from the improvement's own
211
+ * descriptor and has to match the capability being resolved — the operation
212
+ * included, because improving `render` says nothing about `create`.
213
+ */
214
+ function compatible(input, contributor, installed) {
215
+ const improves = installed.descriptor?.compatibility.improves ?? null;
216
+ const reject = (why) => ({
217
+ cause: "incompatible_improvement",
218
+ loss: `'${contributor.name}' ${why}`,
219
+ action: `corregí 'compatibility.improves' de '${contributor.name}', o sacala de la selección`,
220
+ });
221
+ if (improves === null) {
222
+ return reject(`no declara mejorar a '${input.descriptor.name}'`);
223
+ }
224
+ if (improves.capability !== input.descriptor.name) {
225
+ return reject(`declara mejorar a '${improves.capability}', no a '${input.descriptor.name}'`);
226
+ }
227
+ if (improves.contract_version !== input.descriptor.contract_version) {
228
+ return reject(`habla la versión de contrato ${improves.contract_version} y esta capacidad es la ${input.descriptor.contract_version}`);
229
+ }
230
+ const operation = input.operation ?? null;
231
+ if (operation !== null && !improves.operations.includes(operation)) {
232
+ return reject(`no declara mejorar la operación '${operation}'`);
233
+ }
234
+ return null;
235
+ }
236
+ export function pinSelection(resolution, descriptor) {
237
+ return {
238
+ capability: resolution.capability,
239
+ contract_version: descriptor.contract_version,
240
+ floor: resolution.floor,
241
+ instances: resolution.selection.map((s) => ({
242
+ name: s.name,
243
+ digest: s.digest,
244
+ order: s.order,
245
+ })),
246
+ };
247
+ }
248
+ export function checkPin(pin, inventory) {
249
+ for (const instance of pin.instances) {
250
+ const installed = findInstalled(inventory, instance.name);
251
+ if (installed?.digest === instance.digest)
252
+ continue;
253
+ return {
254
+ ok: false,
255
+ degradation: {
256
+ cause: "digest_changed",
257
+ loss: `'${instance.name}' ya no son los bytes que se fijaron al empezar la invocación`,
258
+ },
259
+ action: "volvé a empezar la invocación: la selección fijada dejó de existir tal cual",
260
+ };
261
+ }
262
+ return { ok: true };
263
+ }
264
+ //# sourceMappingURL=resolution.js.map