@open-agent-toolkit/cli 0.2.51 → 0.2.52

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 (213) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/bootstrap.md +6 -2
  3. package/assets/docs/cli-utilities/tool-packs.md +87 -33
  4. package/assets/docs/provider-sync/commands.md +30 -2
  5. package/assets/docs/provider-sync/config.md +19 -0
  6. package/assets/docs/provider-sync/manifest-and-drift.md +37 -0
  7. package/assets/docs/provider-sync/providers.md +69 -2
  8. package/assets/docs/provider-sync/scope-and-surface.md +44 -0
  9. package/assets/docs/reference/cli-reference.md +1 -0
  10. package/assets/docs/reference/oat-directory-structure.md +11 -4
  11. package/assets/docs/workflows/projects/evidence-layers.md +110 -1
  12. package/assets/docs/workflows/projects/implementation-execution.md +13 -0
  13. package/assets/docs/workflows/projects/orchestration-model.md +18 -0
  14. package/assets/public-package-versions.json +4 -4
  15. package/assets/skills/oat-dispatch-subagents/SKILL.md +57 -1
  16. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +77 -1
  17. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  18. package/assets/skills/oat-project-dispatch-subagents/SKILL.md +24 -1
  19. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  20. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +11 -0
  21. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  22. package/assets/skills/oat-project-plan-writing/SKILL.md +12 -1
  23. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  24. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  25. package/assets/skills/oat-project-review-provide/SKILL.md +12 -1
  26. package/assets/skills/oat-project-review-provide-remote/SKILL.md +12 -1
  27. package/dist/agents/canonical/index.d.ts +2 -0
  28. package/dist/agents/canonical/index.d.ts.map +1 -1
  29. package/dist/agents/canonical/index.js +1 -0
  30. package/dist/agents/canonical/resolve.d.ts +45 -0
  31. package/dist/agents/canonical/resolve.d.ts.map +1 -0
  32. package/dist/agents/canonical/resolve.js +175 -0
  33. package/dist/commands/decision/agents-guidance.d.ts +2 -2
  34. package/dist/commands/decision/agents-guidance.d.ts.map +1 -1
  35. package/dist/commands/decision/agents-guidance.js +1 -4
  36. package/dist/commands/decision/index.d.ts.map +1 -1
  37. package/dist/commands/decision/index.js +25 -6
  38. package/dist/commands/docs/init/index.d.ts +7 -1
  39. package/dist/commands/docs/init/index.d.ts.map +1 -1
  40. package/dist/commands/docs/init/index.js +53 -20
  41. package/dist/commands/doctor/index.d.ts +8 -2
  42. package/dist/commands/doctor/index.d.ts.map +1 -1
  43. package/dist/commands/doctor/index.js +157 -46
  44. package/dist/commands/init/index.d.ts +8 -3
  45. package/dist/commands/init/index.d.ts.map +1 -1
  46. package/dist/commands/init/index.js +64 -26
  47. package/dist/commands/init/tools/index.d.ts +12 -12
  48. package/dist/commands/init/tools/index.d.ts.map +1 -1
  49. package/dist/commands/init/tools/index.js +430 -99
  50. package/dist/commands/init/tools/install-state.d.ts +2 -0
  51. package/dist/commands/init/tools/install-state.d.ts.map +1 -1
  52. package/dist/commands/init/tools/install-state.js +11 -0
  53. package/dist/commands/init/tools/project-guidance.d.ts +49 -0
  54. package/dist/commands/init/tools/project-guidance.d.ts.map +1 -0
  55. package/dist/commands/init/tools/project-guidance.js +144 -0
  56. package/dist/commands/init/tools/workflows/index.d.ts +7 -0
  57. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  58. package/dist/commands/init/tools/workflows/index.js +160 -7
  59. package/dist/commands/pjm/index.d.ts.map +1 -1
  60. package/dist/commands/pjm/index.js +28 -3
  61. package/dist/commands/pjm/init.d.ts +5 -0
  62. package/dist/commands/pjm/init.d.ts.map +1 -1
  63. package/dist/commands/pjm/init.js +19 -3
  64. package/dist/commands/project/dispatch/index.d.ts +10 -0
  65. package/dist/commands/project/dispatch/index.d.ts.map +1 -0
  66. package/dist/commands/project/dispatch/index.js +137 -0
  67. package/dist/commands/project/dispatch/record.d.ts +91 -0
  68. package/dist/commands/project/dispatch/record.d.ts.map +1 -0
  69. package/dist/commands/project/dispatch/record.js +402 -0
  70. package/dist/commands/project/index.d.ts.map +1 -1
  71. package/dist/commands/project/index.js +2 -0
  72. package/dist/commands/providers/inspect/inspect.d.ts +8 -1
  73. package/dist/commands/providers/inspect/inspect.d.ts.map +1 -1
  74. package/dist/commands/providers/inspect/inspect.js +146 -26
  75. package/dist/commands/providers/list/list.d.ts +8 -1
  76. package/dist/commands/providers/list/list.d.ts.map +1 -1
  77. package/dist/commands/providers/list/list.js +139 -23
  78. package/dist/commands/providers/providers.types.d.ts +25 -1
  79. package/dist/commands/providers/providers.types.d.ts.map +1 -1
  80. package/dist/commands/providers/set/index.d.ts +9 -1
  81. package/dist/commands/providers/set/index.d.ts.map +1 -1
  82. package/dist/commands/providers/set/index.js +43 -33
  83. package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
  84. package/dist/commands/remove/skill/remove-skill.js +11 -0
  85. package/dist/commands/shared/agents-md.d.ts +42 -14
  86. package/dist/commands/shared/agents-md.d.ts.map +1 -1
  87. package/dist/commands/shared/agents-md.js +364 -70
  88. package/dist/commands/status/index.d.ts +8 -3
  89. package/dist/commands/status/index.d.ts.map +1 -1
  90. package/dist/commands/status/index.js +147 -32
  91. package/dist/commands/sync/apply.d.ts.map +1 -1
  92. package/dist/commands/sync/apply.js +220 -29
  93. package/dist/commands/sync/dry-run.d.ts.map +1 -1
  94. package/dist/commands/sync/dry-run.js +30 -6
  95. package/dist/commands/sync/index.d.ts +17 -2
  96. package/dist/commands/sync/index.d.ts.map +1 -1
  97. package/dist/commands/sync/index.js +106 -41
  98. package/dist/commands/sync/sync.types.d.ts +39 -2
  99. package/dist/commands/sync/sync.types.d.ts.map +1 -1
  100. package/dist/commands/sync/sync.utils.d.ts +5 -1
  101. package/dist/commands/sync/sync.utils.d.ts.map +1 -1
  102. package/dist/commands/sync/sync.utils.js +73 -0
  103. package/dist/commands/tools/info/info-tool.d.ts +2 -0
  104. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  105. package/dist/commands/tools/info/info-tool.js +34 -12
  106. package/dist/commands/tools/install/index.d.ts.map +1 -1
  107. package/dist/commands/tools/install/index.js +19 -3
  108. package/dist/commands/tools/list/list-tools.d.ts +2 -0
  109. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  110. package/dist/commands/tools/list/list-tools.js +36 -7
  111. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  112. package/dist/commands/tools/remove/index.js +150 -21
  113. package/dist/commands/tools/remove/remove-tools.d.ts +20 -0
  114. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  115. package/dist/commands/tools/remove/remove-tools.js +122 -1
  116. package/dist/commands/tools/shared/format-pack-inventory.d.ts +19 -0
  117. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
  118. package/dist/commands/tools/shared/format-pack-inventory.js +109 -0
  119. package/dist/commands/tools/shared/pack-evidence.d.ts +66 -0
  120. package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -0
  121. package/dist/commands/tools/shared/pack-evidence.js +132 -0
  122. package/dist/commands/tools/shared/pack-inventory.d.ts +1 -0
  123. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
  124. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +44 -0
  125. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -0
  126. package/dist/commands/tools/shared/pack-lifecycle-outcome.js +91 -0
  127. package/dist/commands/tools/update/index.d.ts.map +1 -1
  128. package/dist/commands/tools/update/index.js +74 -4
  129. package/dist/commands/tools/update/update-tools.d.ts +5 -0
  130. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  131. package/dist/commands/tools/update/update-tools.js +64 -2
  132. package/dist/config/oat-config.d.ts +5 -0
  133. package/dist/config/oat-config.d.ts.map +1 -1
  134. package/dist/config/oat-config.js +17 -5
  135. package/dist/config/user-sync-config.d.ts +1 -0
  136. package/dist/config/user-sync-config.d.ts.map +1 -1
  137. package/dist/config/user-sync-config.js +8 -0
  138. package/dist/drift/detector.d.ts +2 -2
  139. package/dist/drift/detector.d.ts.map +1 -1
  140. package/dist/drift/detector.js +18 -0
  141. package/dist/drift/strays.d.ts.map +1 -1
  142. package/dist/drift/strays.js +5 -0
  143. package/dist/engine/collection-sync.d.ts +14 -0
  144. package/dist/engine/collection-sync.d.ts.map +1 -0
  145. package/dist/engine/collection-sync.js +282 -0
  146. package/dist/engine/compute-plan.d.ts +8 -1
  147. package/dist/engine/compute-plan.d.ts.map +1 -1
  148. package/dist/engine/compute-plan.js +303 -12
  149. package/dist/engine/engine.types.d.ts +61 -0
  150. package/dist/engine/engine.types.d.ts.map +1 -1
  151. package/dist/engine/execute-plan.d.ts +22 -2
  152. package/dist/engine/execute-plan.d.ts.map +1 -1
  153. package/dist/engine/execute-plan.js +459 -27
  154. package/dist/engine/provider-path-safety.d.ts +1 -0
  155. package/dist/engine/provider-path-safety.d.ts.map +1 -1
  156. package/dist/engine/provider-path-safety.js +15 -0
  157. package/dist/engine/scanner.d.ts +2 -2
  158. package/dist/engine/scanner.d.ts.map +1 -1
  159. package/dist/engine/scanner.js +21 -4
  160. package/dist/fs/io.d.ts +67 -0
  161. package/dist/fs/io.d.ts.map +1 -1
  162. package/dist/fs/io.js +536 -3
  163. package/dist/manifest/index.d.ts +2 -2
  164. package/dist/manifest/index.d.ts.map +1 -1
  165. package/dist/manifest/index.js +1 -1
  166. package/dist/manifest/manager.d.ts +2 -2
  167. package/dist/manifest/manager.d.ts.map +1 -1
  168. package/dist/manifest/manager.js +20 -3
  169. package/dist/manifest/manifest.types.d.ts +704 -13
  170. package/dist/manifest/manifest.types.d.ts.map +1 -1
  171. package/dist/manifest/manifest.types.js +131 -15
  172. package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
  173. package/dist/providers/codex/codec/sync-extension.js +41 -10
  174. package/dist/providers/cursor/codec/sync-extension.d.ts.map +1 -1
  175. package/dist/providers/cursor/codec/sync-extension.js +41 -10
  176. package/dist/providers/identity/absolute-paths.d.ts +68 -0
  177. package/dist/providers/identity/absolute-paths.d.ts.map +1 -0
  178. package/dist/providers/identity/absolute-paths.js +144 -0
  179. package/dist/providers/identity/claude-runtime-observation.d.ts +105 -0
  180. package/dist/providers/identity/claude-runtime-observation.d.ts.map +1 -0
  181. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts +40 -0
  182. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts.map +1 -0
  183. package/dist/providers/identity/claude-runtime-observation.fixtures.js +146 -0
  184. package/dist/providers/identity/claude-runtime-observation.js +229 -0
  185. package/dist/providers/identity/codex-runtime-observation.d.ts +75 -0
  186. package/dist/providers/identity/codex-runtime-observation.d.ts.map +1 -0
  187. package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts +37 -0
  188. package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts.map +1 -0
  189. package/dist/providers/identity/codex-runtime-observation.fixtures.js +539 -0
  190. package/dist/providers/identity/codex-runtime-observation.js +255 -0
  191. package/dist/providers/identity/generic-dispatch-record.d.ts +313 -0
  192. package/dist/providers/identity/generic-dispatch-record.d.ts.map +1 -0
  193. package/dist/providers/identity/generic-dispatch-record.js +539 -0
  194. package/dist/providers/identity/oat-dispatch-record.d.ts +1964 -0
  195. package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -0
  196. package/dist/providers/identity/oat-dispatch-record.js +691 -0
  197. package/dist/providers/identity/runtime-observation.d.ts +100 -0
  198. package/dist/providers/identity/runtime-observation.d.ts.map +1 -0
  199. package/dist/providers/identity/runtime-observation.js +169 -0
  200. package/dist/providers/shared/index.d.ts +2 -0
  201. package/dist/providers/shared/index.d.ts.map +1 -1
  202. package/dist/providers/shared/index.js +1 -0
  203. package/dist/providers/shared/materialization-extension.d.ts +12 -0
  204. package/dist/providers/shared/materialization-extension.d.ts.map +1 -1
  205. package/dist/providers/shared/registry.d.ts +69 -0
  206. package/dist/providers/shared/registry.d.ts.map +1 -0
  207. package/dist/providers/shared/registry.js +252 -0
  208. package/dist/providers/shared/restart-adviser.d.ts +26 -0
  209. package/dist/providers/shared/restart-adviser.d.ts.map +1 -0
  210. package/dist/providers/shared/restart-adviser.js +96 -0
  211. package/dist/shared/types.d.ts +4 -0
  212. package/dist/shared/types.d.ts.map +1 -1
  213. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  import { execFile } from 'node:child_process';
2
2
  import { buildCommandContext } from '../../../app/command-context.js';
3
- import { consumeInitToolsRunMetadata, createInitToolsCommand, } from '../../init/tools/index.js';
3
+ import { consumeInitToolsRunMetadata, createInitToolsCommand, wasInstallSyncHandled, } from '../../init/tools/index.js';
4
+ import { withProjectGuidanceOptions } from '../../init/tools/project-guidance.js';
4
5
  import { withScopeOption } from '../../shared/scope-option.js';
5
6
  import { readGlobalOptions, resolveConcreteScopes, } from '../../shared/shared.utils.js';
6
7
  import { autoSync, } from '../../tools/shared/auto-sync.js';
@@ -28,22 +29,37 @@ const defaultSyncDependencies = {
28
29
  },
29
30
  };
30
31
  export function createToolsInstallCommand(syncDependencies = defaultSyncDependencies, initOverrides = {}, createBaseCommand) {
32
+ let syncEnabled = true;
33
+ const buildContext = initOverrides.buildCommandContext ?? buildCommandContext;
34
+ const effectiveOverrides = {
35
+ ...initOverrides,
36
+ syncAfterInstall: async (scopes, context, installedCanonicalPaths) => syncEnabled
37
+ ? autoSync(scopes, context.cwd, context.home, context.logger, syncDependencies, { installedCanonicalPaths })
38
+ : { synced: false, scopes: [], error: null },
39
+ };
31
40
  const cmd = createBaseCommand === undefined
32
- ? createInitToolsCommand(initOverrides)
41
+ ? createInitToolsCommand(effectiveOverrides)
33
42
  : createBaseCommand();
34
43
  cmd.name('install');
35
44
  withScopeOption(cmd);
45
+ withProjectGuidanceOptions(cmd);
36
46
  cmd.option('--no-sync', 'Skip auto-sync after install');
47
+ cmd.hook('preAction', (thisCommand) => {
48
+ syncEnabled = thisCommand.opts().sync !== false;
49
+ });
37
50
  cmd.hook('postAction', async (thisCommand, actionCommand) => {
38
51
  if (process.exitCode !== 0 && process.exitCode !== undefined)
39
52
  return;
53
+ if (wasInstallSyncHandled(actionCommand))
54
+ return;
40
55
  const opts = thisCommand.opts();
41
56
  if (opts.sync === false)
42
57
  return;
43
58
  const globalOptions = readGlobalOptions(actionCommand);
44
- const buildContext = initOverrides.buildCommandContext ?? buildCommandContext;
45
59
  const context = buildContext(globalOptions);
46
60
  const metadata = consumeInitToolsRunMetadata();
61
+ if (metadata?.syncHandled)
62
+ return;
47
63
  const scopes = metadata === null
48
64
  ? resolveConcreteScopes(context.scope)
49
65
  : metadata.affectedScopes;
@@ -1,4 +1,5 @@
1
1
  import type { CommandContext } from '../../../app/command-context.js';
2
+ import { type PackEvidenceBlockV1 } from '../../tools/shared/format-pack-inventory.js';
2
3
  import { type InventoryPackInput, type PackInventory } from '../../tools/shared/pack-inventory.js';
3
4
  import type { ScanToolsOptions } from '../../tools/shared/scan-tools.js';
4
5
  import type { ToolInfo } from '../../tools/shared/types.js';
@@ -11,6 +12,7 @@ export interface ListToolsDependencies {
11
12
  export interface ListToolsResult {
12
13
  tools: ToolInfo[];
13
14
  packs: PackInventory[];
15
+ packEvidence: PackEvidenceBlockV1;
14
16
  }
15
17
  export declare function runListTools(context: CommandContext, dependencies: ListToolsDependencies): Promise<ListToolsResult>;
16
18
  //# sourceMappingURL=list-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/list/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,gBAAgB,EAAE,CAChB,KAAK,EAAE,SAAS,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,qBAAqB,GAClC,OAAO,CAAC,eAAe,CAAC,CAiG1B"}
1
+ {"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/list/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAML,KAAK,mBAAmB,EACzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,gBAAgB,EAAE,CAChB,KAAK,EAAE,SAAS,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,EAAE,mBAAmB,CAAC;CACnC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,qBAAqB,GAClC,OAAO,CAAC,eAAe,CAAC,CAkI1B"}
@@ -1,5 +1,5 @@
1
1
  import { resolveConcreteScopes } from '../../shared/shared.utils.js';
2
- import { formatPackInventoryDetails } from '../../tools/shared/format-pack-inventory.js';
2
+ import { formatPackEvidenceDetails, formatPackInventoryDetails, packEvidenceBlock, projectRenderablePackEvidence, unavailablePackEvidence, } from '../../tools/shared/format-pack-inventory.js';
3
3
  import { inventoryPack, } from '../../tools/shared/pack-inventory.js';
4
4
  import { PACK_MANIFEST } from '../../tools/shared/pack-manifest.js';
5
5
  export async function runListTools(context, dependencies) {
@@ -18,16 +18,35 @@ export async function runListTools(context, dependencies) {
18
18
  allTools.push(...tools);
19
19
  roots[scope] = scopeRoot;
20
20
  }
21
+ const packRoots = {
22
+ projectRoot: roots.project,
23
+ userRoot: roots.user,
24
+ };
21
25
  const inspectPack = dependencies.inventoryPack ?? inventoryPack;
22
- const packs = await Promise.all(PACK_MANIFEST.map(({ name }) => inspectPack({
26
+ const inspected = await Promise.all(PACK_MANIFEST.map(({ name }) => inspectPack({
23
27
  pack: name,
24
28
  assetsRoot,
25
29
  projectRoot: roots.project,
26
30
  userRoot: roots.user,
27
- })));
31
+ }).then((canonical) => ({
32
+ canonical,
33
+ evidence: projectRenderablePackEvidence(canonical, packRoots),
34
+ }), (error) => ({
35
+ canonical: null,
36
+ evidence: unavailablePackEvidence({
37
+ pack: name,
38
+ scopes,
39
+ reason: error instanceof Error ? error.message : String(error),
40
+ roots: packRoots,
41
+ }),
42
+ }))));
43
+ const packs = inspected
44
+ .map(({ canonical }) => canonical)
45
+ .filter((pack) => pack !== null);
46
+ const packEvidence = packEvidenceBlock(inspected.map(({ evidence }) => evidence));
28
47
  if (context.json) {
29
- logger.json({ tools: allTools, packs });
30
- return { tools: allTools, packs };
48
+ logger.json({ tools: allTools, packs, packEvidence });
49
+ return { tools: allTools, packs, packEvidence };
31
50
  }
32
51
  if (allTools.length === 0) {
33
52
  logger.info('No tools installed.');
@@ -37,7 +56,11 @@ export async function runListTools(context, dependencies) {
37
56
  for (const line of formatPackInventoryDetails(pack))
38
57
  logger.info(line);
39
58
  }
40
- return { tools: allTools, packs };
59
+ for (const evidence of packEvidence.items) {
60
+ for (const line of formatPackEvidenceDetails(evidence))
61
+ logger.info(line);
62
+ }
63
+ return { tools: allTools, packs, packEvidence };
41
64
  }
42
65
  logger.info('Installed tools:\n');
43
66
  const header = formatRow('NAME', 'TYPE', 'VERSION', 'PACK', 'SCOPE', 'STATUS');
@@ -56,7 +79,13 @@ export async function runListTools(context, dependencies) {
56
79
  for (const line of formatPackInventoryDetails(pack))
57
80
  logger.info(line);
58
81
  }
59
- return { tools: allTools, packs };
82
+ logger.info('\nNormalized pack evidence:');
83
+ for (const evidence of packEvidence.items) {
84
+ logger.info(`${evidence.pack}: ${evidence.realizedPlacement}`);
85
+ for (const line of formatPackEvidenceDetails(evidence))
86
+ logger.info(line);
87
+ }
88
+ return { tools: allTools, packs, packEvidence };
60
89
  }
61
90
  function formatRow(name, type, version, pack, scope, status) {
62
91
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAS1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AAmExB,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAiHT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAW1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,uBAAuB,EAM7B,MAAM,gBAAgB,CAAC;AAqExB,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAkOT"}
@@ -5,12 +5,13 @@ import { buildCommandContext } from '../../../app/command-context.js';
5
5
  import { withScopeOption } from '../../shared/scope-option.js';
6
6
  import { readGlobalOptions, resolveConcreteScopes, } from '../../shared/shared.utils.js';
7
7
  import { autoSync, } from '../../tools/shared/auto-sync.js';
8
+ import { inventoryScopedPack } from '../../tools/shared/pack-inventory.js';
8
9
  import { scanTools } from '../../tools/shared/scan-tools.js';
9
10
  import { hasScopedPackOwnershipEvidence, writeScopedPackIntent, } from '../../tools/shared/scoped-pack-intent.js';
10
11
  import { resolveAssetsRoot } from '../../../fs/assets.js';
11
12
  import { resolveProjectRoot, resolveScopeRoot } from '../../../fs/paths.js';
12
13
  import { Command } from 'commander';
13
- import { removeTools, } from './remove-tools.js';
14
+ import { failedPostRemovalLifecycleOutcomes, failedRemovalLifecycleOutcomes, removalLifecycleOutcomes, removeTools, selectedPacks, } from './remove-tools.js';
14
15
  const defaultDependencies = {
15
16
  scanTools,
16
17
  resolveScopeRoot: async (scope, cwd, home) => {
@@ -41,6 +42,8 @@ const defaultDependencies = {
41
42
  }
42
43
  },
43
44
  hasPackOwnershipEvidence: async (pack, scope, scopeRoot) => hasScopedPackOwnershipEvidence({ pack, scope, scopeRoot }),
45
+ inventoryScopedPack,
46
+ writeScopedPackIntent,
44
47
  };
45
48
  const defaultSyncDependencies = {
46
49
  runSync: async ({ scope, cwd, removedCanonicalPaths }) => {
@@ -94,28 +97,98 @@ export function createToolsRemoveCommand(dependencies = defaultDependencies, syn
94
97
  }
95
98
  const scopes = resolveConcreteScopes(context.scope);
96
99
  const dryRun = opts.dryRun ?? false;
97
- const result = await removeTools(target, scopes, context.cwd, context.home, dryRun, dependencies);
100
+ let result;
101
+ try {
102
+ result = await removeTools(target, scopes, context.cwd, context.home, dryRun, dependencies);
103
+ }
104
+ catch (error) {
105
+ if (target.kind === 'name' || !context.json)
106
+ throw error;
107
+ const lifecycle = failedRemovalLifecycleOutcomes(target, scopes, error);
108
+ logger.json({
109
+ target: describeTarget(target),
110
+ dryRun,
111
+ result: {
112
+ removed: [],
113
+ removedAssets: [],
114
+ retainedOwnerData: [],
115
+ packOutcomes: [],
116
+ notInstalled: [],
117
+ },
118
+ lifecycle,
119
+ });
120
+ process.exitCode = 1;
121
+ return;
122
+ }
98
123
  if (!dryRun && target.kind !== 'name') {
99
124
  const packs = target.kind === 'pack' ? [target.pack] : [...VALID_PACKS];
100
- for (const scope of scopes) {
101
- const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
102
- for (const pack of packs) {
103
- // Durable scoped intent is what lets `oat tools update` restore a
104
- // pack whose files are all missing, so it may only be cleared for a
105
- // pack this run actually removed something for. A removal that
106
- // removed nothing reports nothing and must leave intent alone.
107
- const removedForPack = result.packOutcomes.some((outcome) => outcome.pack === pack &&
108
- outcome.scope === scope &&
109
- outcome.removed);
110
- if (!removedForPack)
111
- continue;
112
- await writeScopedPackIntent({
113
- pack,
114
- scope,
115
- scopeRoot,
116
- enabled: false,
125
+ let stage = 'intent-write';
126
+ let currentPack = packs[0];
127
+ let currentScope = scopes[0];
128
+ try {
129
+ for (const scope of scopes) {
130
+ currentScope = scope;
131
+ const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
132
+ for (const pack of packs) {
133
+ currentPack = pack;
134
+ // Durable scoped intent is what lets `oat tools update` restore a
135
+ // pack whose files are all missing, so it may only be cleared for a
136
+ // pack this run actually removed something for.
137
+ const removedForPack = result.packOutcomes.some((outcome) => outcome.pack === pack &&
138
+ outcome.scope === scope &&
139
+ outcome.removed);
140
+ if (!removedForPack)
141
+ continue;
142
+ await (dependencies.writeScopedPackIntent ?? writeScopedPackIntent)({
143
+ pack,
144
+ scope,
145
+ scopeRoot,
146
+ enabled: false,
147
+ });
148
+ }
149
+ }
150
+ if (dependencies.inventoryScopedPack) {
151
+ stage = 'final-inventory';
152
+ const assetsRoot = await dependencies.resolveAssetsRoot();
153
+ const finalInventories = [];
154
+ for (const scope of scopes) {
155
+ currentScope = scope;
156
+ const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
157
+ for (const pack of selectedPacks(target)) {
158
+ currentPack = pack;
159
+ finalInventories.push(await dependencies.inventoryScopedPack({
160
+ pack,
161
+ scope,
162
+ scopeRoot,
163
+ assetsRoot,
164
+ }));
165
+ }
166
+ }
167
+ result.lifecycle = removalLifecycleOutcomes(selectedPacks(target), scopes, result.packOutcomes, false, finalInventories);
168
+ }
169
+ }
170
+ catch (error) {
171
+ const lifecycle = failedPostRemovalLifecycleOutcomes(target, scopes, result.packOutcomes, stage, currentPack, currentScope, error);
172
+ const legacyResult = { ...result };
173
+ delete legacyResult.lifecycle;
174
+ if (context.json) {
175
+ logger.json({
176
+ target: describeTarget(target),
177
+ dryRun,
178
+ result: legacyResult,
179
+ lifecycle,
117
180
  });
118
181
  }
182
+ else {
183
+ for (const tool of result.removed) {
184
+ logger.success(`Removed: ${tool.name} (${tool.scope})`);
185
+ }
186
+ for (const outcome of lifecycle) {
187
+ logger.warn(outcome.recovery.map(({ message }) => message).join('; '));
188
+ }
189
+ }
190
+ process.exitCode = 1;
191
+ return;
119
192
  }
120
193
  }
121
194
  if (result.notInstalled.length > 0) {
@@ -129,17 +202,29 @@ export function createToolsRemoveCommand(dependencies = defaultDependencies, syn
129
202
  return;
130
203
  }
131
204
  // Auto-sync after mutations (before output so sync errors are captured)
205
+ const syncResults = [];
132
206
  if (!dryRun && opts.sync !== false) {
133
207
  for (const scope of scopes) {
134
208
  const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
135
209
  const removedCanonicalPaths = canonicalRemovalPaths(result, scope, scopeRoot);
136
210
  if (removedCanonicalPaths.length === 0)
137
211
  continue;
138
- await autoSync([scope], context.cwd, context.home, logger, syncDependencies, { removedCanonicalPaths });
212
+ syncResults.push(await autoSync([scope], context.cwd, context.home, logger, syncDependencies, { removedCanonicalPaths }));
139
213
  }
140
214
  }
215
+ const lifecycle = finalizeRemovalLifecycle(result.lifecycle, syncResults);
216
+ const legacyResult = { ...result };
217
+ delete legacyResult.lifecycle;
141
218
  if (context.json) {
142
- logger.json({ target: describeTarget(target), dryRun, result });
219
+ logger.json({
220
+ target: describeTarget(target),
221
+ dryRun,
222
+ result: legacyResult,
223
+ ...(lifecycle ? { lifecycle } : {}),
224
+ });
225
+ if (lifecycle?.some(({ status }) => status !== 'complete')) {
226
+ process.exitCode = 1;
227
+ }
143
228
  return;
144
229
  }
145
230
  if (result.removed.length > 0) {
@@ -151,6 +236,50 @@ export function createToolsRemoveCommand(dependencies = defaultDependencies, syn
151
236
  else {
152
237
  logger.info('No tools to remove.');
153
238
  }
239
+ for (const outcome of lifecycle ?? []) {
240
+ if (outcome.status === 'complete')
241
+ continue;
242
+ logger.warn(`Pack ${outcome.selection.pack} removal ${outcome.status}: ${outcome.recovery.map(({ message }) => message).join('; ')}`);
243
+ process.exitCode = 1;
244
+ }
245
+ });
246
+ }
247
+ function finalizeRemovalLifecycle(lifecycle, syncResults) {
248
+ if (!lifecycle || syncResults.length === 0)
249
+ return lifecycle;
250
+ return lifecycle.map((outcome) => {
251
+ const relevant = syncResults.filter(({ scopes }) => scopes.some((scope) => outcome.selection.targetScopes.includes(scope)));
252
+ if (relevant.length === 0 || relevant.every(({ synced }) => synced)) {
253
+ return relevant.length === 0
254
+ ? outcome
255
+ : {
256
+ ...outcome,
257
+ sync: {
258
+ scopes: [...new Set(relevant.flatMap(({ scopes }) => scopes))],
259
+ status: 'complete',
260
+ providers: [],
261
+ },
262
+ };
263
+ }
264
+ const error = relevant.find((result) => result.error)?.error;
265
+ return {
266
+ ...outcome,
267
+ sync: {
268
+ scopes: [...new Set(relevant.flatMap(({ scopes }) => scopes))],
269
+ status: 'failed',
270
+ providers: [],
271
+ ...(error ? { error } : {}),
272
+ },
273
+ status: 'partial',
274
+ recovery: [
275
+ ...outcome.recovery,
276
+ {
277
+ code: 'provider-sync-incomplete',
278
+ message: error ??
279
+ `Run oat sync for ${outcome.selection.targetScopes.join(', ')} scope`,
280
+ },
281
+ ],
282
+ };
154
283
  });
155
284
  }
156
285
  function canonicalRemovalPaths(result, scope, scopeRoot) {
@@ -1,3 +1,5 @@
1
+ import type { InventoryScopedPackInput, ScopedPackInventory } from '../../tools/shared/pack-inventory.js';
2
+ import type { PackLifecycleOutcome } from '../../tools/shared/pack-lifecycle-outcome.js';
1
3
  import type { ScanToolsOptions } from '../../tools/shared/scan-tools.js';
2
4
  import type { PackName, ToolInfo } from '../../tools/shared/types.js';
3
5
  import type { ConcreteScope } from '../../../shared/types.js';
@@ -18,6 +20,13 @@ export interface RemoveToolsDependencies {
18
20
  removeFile: (path: string) => Promise<void>;
19
21
  pathExists: (path: string) => Promise<boolean>;
20
22
  hasPackOwnershipEvidence: (pack: PackName, scope: ConcreteScope, scopeRoot: string) => Promise<boolean>;
23
+ inventoryScopedPack?: (input: InventoryScopedPackInput) => Promise<ScopedPackInventory>;
24
+ writeScopedPackIntent?: (input: {
25
+ pack: PackName;
26
+ scope: ConcreteScope;
27
+ scopeRoot: string;
28
+ enabled: boolean;
29
+ }) => Promise<unknown>;
21
30
  }
22
31
  interface RemovedTool {
23
32
  name: string;
@@ -53,7 +62,18 @@ export interface RemoveResult {
53
62
  }>;
54
63
  packOutcomes: PackRemovalOutcome[];
55
64
  notInstalled: string[];
65
+ lifecycle?: PackLifecycleOutcome[];
56
66
  }
67
+ export declare function selectedPacks(target: Exclude<RemoveTarget, {
68
+ kind: 'name';
69
+ }>): PackName[];
57
70
  export declare function removeTools(target: RemoveTarget, scopes: ConcreteScope[], cwd: string, home: string, dryRun: boolean, deps: RemoveToolsDependencies): Promise<RemoveResult>;
71
+ export declare function removalLifecycleOutcomes(packs: readonly PackName[], scopes: readonly ConcreteScope[], outcomes: readonly PackRemovalOutcome[], dryRun: boolean, finalInventories: readonly ScopedPackInventory[]): PackLifecycleOutcome[];
72
+ export declare function failedRemovalLifecycleOutcomes(target: Exclude<RemoveTarget, {
73
+ kind: 'name';
74
+ }>, scopes: readonly ConcreteScope[], error: unknown): PackLifecycleOutcome[];
75
+ export declare function failedPostRemovalLifecycleOutcomes(target: Exclude<RemoveTarget, {
76
+ kind: 'name';
77
+ }>, scopes: readonly ConcreteScope[], outcomes: readonly PackRemovalOutcome[], stage: 'intent-write' | 'final-inventory', failedPack: PackName, failedScope: ConcreteScope, error: unknown): PackLifecycleOutcome[];
58
78
  export {};
59
79
  //# sourceMappingURL=remove-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remove-tools.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/remove-tools.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAEV,QAAQ,EACR,QAAQ,EACT,MAAM,8BAA8B,CAAC;AAMtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpB,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,wBAAwB,EAAE,CACxB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,KAAK,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IAC7D,iBAAiB,EAAE,KAAK,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,aAAa,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA8MD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,aAAa,EAAE,EACvB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAsGvB"}
1
+ {"version":3,"file":"remove-tools.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/remove-tools.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { join } from 'node:path';
2
+ import { packScopeFactsFromInventory, projectPackEvidence, } from '../../tools/shared/pack-evidence.js';
2
3
  import { PACK_MANIFEST } from '../../tools/shared/pack-manifest.js';
3
4
  import { resolveSharedOwnerRetentions } from '../../tools/shared/pack-reconcile.js';
4
5
  import { resolveManagedScopeRoots, validateManagedPath, } from '../../../fs/paths.js';
@@ -27,7 +28,7 @@ async function removeTool(tool, scopeRoot, dryRun, deps) {
27
28
  function isDirectoryAsset(asset) {
28
29
  return asset.kind === 'skill' || asset.kind === 'directory';
29
30
  }
30
- function selectedPacks(target) {
31
+ export function selectedPacks(target) {
31
32
  return target.kind === 'pack'
32
33
  ? [target.pack]
33
34
  : PACK_MANIFEST.map(({ name }) => name);
@@ -146,6 +147,14 @@ export async function removeTools(target, scopes, cwd, home, dryRun, deps) {
146
147
  const tools = await deps.scanTools({ scope, scopeRoot, assetsRoot });
147
148
  const matched = tools.filter((tool) => matchesTarget(tool, target));
148
149
  const managedPlan = await planManagedPackRemoval(selectedPacks(target), scope, scopeRoot, dryRun, deps);
150
+ const beforeInventories = deps.inventoryScopedPack
151
+ ? await Promise.all(selectedPacks(target).map((pack) => deps.inventoryScopedPack({
152
+ pack,
153
+ scope,
154
+ scopeRoot,
155
+ assetsRoot,
156
+ })))
157
+ : [];
149
158
  const seedData = PACK_MANIFEST.filter(({ name }) => selectedPacks(target).includes(name)).flatMap(({ assets }) => assets
150
159
  .filter((asset) => asset.scopes.includes(scope) &&
151
160
  asset.ownership[scope] === 'seed-if-missing')
@@ -160,6 +169,7 @@ export async function removeTools(target, scopes, cwd, home, dryRun, deps) {
160
169
  managedTargets: managedPlan.targets,
161
170
  retainedOwnerData: [...managedPlan.retained, ...seedData],
162
171
  presentPacks: managedPlan.presentPacks,
172
+ beforeInventories,
163
173
  });
164
174
  }
165
175
  for (const plan of plans) {
@@ -184,11 +194,122 @@ export async function removeTools(target, scopes, cwd, home, dryRun, deps) {
184
194
  plan.presentPacks.includes(pack),
185
195
  })));
186
196
  }
197
+ const finalInventories = dryRun
198
+ ? plans.flatMap(({ beforeInventories }) => beforeInventories)
199
+ : [];
187
200
  return {
188
201
  removed,
189
202
  removedAssets,
190
203
  retainedOwnerData,
191
204
  packOutcomes,
192
205
  notInstalled: [],
206
+ lifecycle: removalLifecycleOutcomes(selectedPacks(target), scopes, packOutcomes, dryRun, finalInventories),
193
207
  };
194
208
  }
209
+ export function removalLifecycleOutcomes(packs, scopes, outcomes, dryRun, finalInventories) {
210
+ if (finalInventories.length === 0)
211
+ return [];
212
+ return packs.map((pack) => {
213
+ const packInventories = finalInventories.filter((inventory) => inventory.pack === pack);
214
+ const finalEvidence = packInventories.length === 0
215
+ ? null
216
+ : projectPackEvidence({
217
+ canonical: null,
218
+ scopes: packInventories.map(packScopeFactsFromInventory),
219
+ });
220
+ const removed = outcomes.some((outcome) => outcome.pack === pack && outcome.removed);
221
+ const inventoriedScopes = new Set(packInventories.map(({ scope }) => scope));
222
+ const inventoryVerified = finalEvidence !== null &&
223
+ finalEvidence.unknownScopes.length === 0 &&
224
+ scopes.every((scope) => inventoriedScopes.has(scope));
225
+ const remainingScopes = finalEvidence
226
+ ? scopes.filter((scope) => finalEvidence.knownRealizedScopes.includes(scope))
227
+ : [...scopes];
228
+ const verified = inventoryVerified && (dryRun || remainingScopes.length === 0);
229
+ const recovery = !inventoryVerified
230
+ ? [
231
+ {
232
+ code: 'final-inventory-unverified',
233
+ message: `Re-run status for ${pack}; final removal state could not be verified`,
234
+ },
235
+ ]
236
+ : !dryRun && remainingScopes.length > 0
237
+ ? remainingScopes.map((scope) => ({
238
+ code: 'canonical-verification-failed',
239
+ message: `Removal remains incomplete for ${pack} at ${scope} scope; rerun oat tools remove --pack ${pack} --scope ${scope}`,
240
+ }))
241
+ : [];
242
+ return {
243
+ schemaVersion: 1,
244
+ selection: {
245
+ pack,
246
+ requested: scopes.includes('project') && scopes.includes('user')
247
+ ? 'both'
248
+ : scopes[0],
249
+ retainedRealizedScopes: finalEvidence?.knownRealizedScopes ?? [],
250
+ targetScopes: scopes,
251
+ },
252
+ canonical: {
253
+ status: removed && !dryRun ? 'applied' : 'unchanged',
254
+ results: [],
255
+ },
256
+ sync: { scopes: [], status: 'not-run', providers: [] },
257
+ finalEvidence,
258
+ status: verified ? 'complete' : inventoryVerified ? 'partial' : 'failed',
259
+ recovery,
260
+ };
261
+ });
262
+ }
263
+ export function failedRemovalLifecycleOutcomes(target, scopes, error) {
264
+ const message = error instanceof Error ? error.message : String(error);
265
+ return selectedPacks(target).map((pack) => ({
266
+ schemaVersion: 1,
267
+ selection: {
268
+ pack,
269
+ requested: scopes.includes('project') && scopes.includes('user')
270
+ ? 'both'
271
+ : scopes[0],
272
+ retainedRealizedScopes: [],
273
+ targetScopes: scopes,
274
+ },
275
+ canonical: { status: 'failed', results: [] },
276
+ sync: { scopes: [], status: 'not-run', providers: [] },
277
+ finalEvidence: null,
278
+ status: 'failed',
279
+ recovery: [{ code: 'canonical-apply-failed', message }],
280
+ }));
281
+ }
282
+ export function failedPostRemovalLifecycleOutcomes(target, scopes, outcomes, stage, failedPack, failedScope, error) {
283
+ const detail = error instanceof Error ? error.message : String(error);
284
+ return selectedPacks(target).map((pack) => {
285
+ const canonicalApplied = outcomes.some((outcome) => outcome.pack === pack && outcome.removed);
286
+ const stageLabel = stage === 'intent-write'
287
+ ? 'durable intent update failed'
288
+ : 'final inventory failed';
289
+ const canonicalSummary = canonicalApplied
290
+ ? `Canonical removal was applied for ${pack}, but final state is unverified`
291
+ : `No canonical removal was observed for ${pack}; final state remains unverified`;
292
+ return {
293
+ schemaVersion: 1,
294
+ selection: {
295
+ pack,
296
+ requested: scopes.includes('project') && scopes.includes('user')
297
+ ? 'both'
298
+ : scopes[0],
299
+ retainedRealizedScopes: [],
300
+ targetScopes: scopes,
301
+ },
302
+ canonical: {
303
+ status: canonicalApplied ? 'applied' : 'unchanged',
304
+ results: [],
305
+ },
306
+ sync: { scopes: [], status: 'not-run', providers: [] },
307
+ finalEvidence: null,
308
+ status: 'failed',
309
+ recovery: scopes.map((scope) => ({
310
+ code: 'final-inventory-unverified',
311
+ message: `${canonicalSummary} because ${stageLabel} for ${failedPack} at ${failedScope} scope: ${detail}. Rerun oat tools remove --pack ${pack} --scope ${scope}`,
312
+ })),
313
+ };
314
+ });
315
+ }
@@ -1,3 +1,22 @@
1
+ import type { ConcreteScope } from '../../../shared/types.js';
2
+ import { type PackEvidenceDiagnostic, type ToolPackEvidence } from './pack-evidence.js';
1
3
  import type { PackInventory } from './pack-inventory.js';
4
+ import { type PackPathRoots } from './pack-paths.js';
5
+ import type { PackName } from './types.js';
6
+ export interface PackEvidenceBlockV1 {
7
+ schemaVersion: 1;
8
+ status: 'ok' | 'partial' | 'error';
9
+ items: readonly ToolPackEvidence[];
10
+ diagnostics: readonly PackEvidenceDiagnostic[];
11
+ }
12
+ export declare function unavailablePackEvidence(input: {
13
+ pack: PackName;
14
+ scopes: readonly ConcreteScope[];
15
+ reason: string;
16
+ roots?: PackPathRoots;
17
+ }): ToolPackEvidence;
18
+ export declare function projectRenderablePackEvidence(canonical: PackInventory, roots: PackPathRoots): ToolPackEvidence;
19
+ export declare function packEvidenceBlock(items: readonly ToolPackEvidence[]): PackEvidenceBlockV1;
20
+ export declare function formatPackEvidenceDetails(evidence: ToolPackEvidence, indent?: string): string[];
2
21
  export declare function formatPackInventoryDetails(inventory: PackInventory, indent?: string): string[];
3
22
  //# sourceMappingURL=format-pack-inventory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-pack-inventory.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/format-pack-inventory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,aAAa,EACxB,MAAM,SAAO,GACZ,MAAM,EAAE,CAuBV"}
1
+ {"version":3,"file":"format-pack-inventory.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/format-pack-inventory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAC;IACjB,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnC,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,GAAG,gBAAgB,CAiBnB;AA4CD,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,aAAa,GACnB,gBAAgB,CAiClB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,gBAAgB,EAAE,GACjC,mBAAmB,CAQrB;AAUD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,SAAO,GACZ,MAAM,EAAE,CAuBV;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,aAAa,EACxB,MAAM,SAAO,GACZ,MAAM,EAAE,CAuBV"}