@open-agent-toolkit/cli 0.2.36 → 0.2.37

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 (183) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/backlog-lifecycle.md +18 -0
  3. package/assets/docs/cli-utilities/bootstrap.md +6 -3
  4. package/assets/docs/cli-utilities/config-and-local-state.md +26 -12
  5. package/assets/docs/cli-utilities/configuration.md +36 -13
  6. package/assets/docs/cli-utilities/tool-packs.md +423 -51
  7. package/assets/docs/provider-sync/scope-and-surface.md +4 -1
  8. package/assets/docs/reference/cli-reference.md +5 -3
  9. package/assets/docs/reference/file-locations.md +28 -4
  10. package/assets/docs/reference/troubleshooting.md +132 -2
  11. package/assets/docs/workflows/projects/lifecycle.md +21 -2
  12. package/assets/public-package-versions.json +4 -4
  13. package/assets/scripts/generate-oat-state.sh +441 -0
  14. package/assets/scripts/generate-thin-index.sh +200 -0
  15. package/assets/skills/oat-agent-instructions-analyze/SKILL.md +10 -5
  16. package/assets/skills/oat-agent-instructions-apply/SKILL.md +30 -5
  17. package/assets/skills/oat-brainstorm/SKILL.md +34 -8
  18. package/assets/skills/oat-brainstorm/references/destinations.md +6 -1
  19. package/assets/skills/oat-docs-analyze/SKILL.md +9 -4
  20. package/assets/skills/oat-docs-apply/SKILL.md +6 -3
  21. package/assets/skills/oat-pjm-add-backlog-item/SKILL.md +14 -1
  22. package/assets/skills/oat-pjm-decision/SKILL.md +22 -10
  23. package/assets/skills/oat-pjm-review-backlog/SKILL.md +20 -3
  24. package/assets/skills/oat-pjm-update-repo-reference/SKILL.md +20 -10
  25. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  26. package/assets/skills/oat-project-document/SKILL.md +21 -3
  27. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  28. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  29. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  30. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  31. package/assets/skills/oat-project-summary/SKILL.md +23 -11
  32. package/assets/skills/oat-repo-knowledge-index/SKILL.md +6 -3
  33. package/dist/commands/backlog/index.d.ts +2 -0
  34. package/dist/commands/backlog/index.d.ts.map +1 -1
  35. package/dist/commands/backlog/index.js +67 -23
  36. package/dist/commands/backlog/new.d.ts +3 -0
  37. package/dist/commands/backlog/new.d.ts.map +1 -1
  38. package/dist/commands/backlog/new.js +8 -21
  39. package/dist/commands/decision/agents-guidance.d.ts.map +1 -1
  40. package/dist/commands/decision/agents-guidance.js +2 -1
  41. package/dist/commands/decision/index.d.ts +2 -0
  42. package/dist/commands/decision/index.d.ts.map +1 -1
  43. package/dist/commands/decision/index.js +19 -3
  44. package/dist/commands/decision/new.d.ts +4 -0
  45. package/dist/commands/decision/new.d.ts.map +1 -1
  46. package/dist/commands/decision/new.js +11 -30
  47. package/dist/commands/doctor/index.d.ts +4 -0
  48. package/dist/commands/doctor/index.d.ts.map +1 -1
  49. package/dist/commands/doctor/index.js +254 -9
  50. package/dist/commands/init/tools/brainstorm/index.d.ts.map +1 -1
  51. package/dist/commands/init/tools/brainstorm/index.js +20 -6
  52. package/dist/commands/init/tools/docs/index.d.ts.map +1 -1
  53. package/dist/commands/init/tools/docs/index.js +4 -1
  54. package/dist/commands/init/tools/ideas/index.d.ts.map +1 -1
  55. package/dist/commands/init/tools/ideas/index.js +4 -1
  56. package/dist/commands/init/tools/index.d.ts +11 -2
  57. package/dist/commands/init/tools/index.d.ts.map +1 -1
  58. package/dist/commands/init/tools/index.js +459 -351
  59. package/dist/commands/init/tools/install-state.d.ts +2 -0
  60. package/dist/commands/init/tools/install-state.d.ts.map +1 -1
  61. package/dist/commands/init/tools/install-state.js +11 -0
  62. package/dist/commands/init/tools/project-management/agents-guidance.d.ts.map +1 -1
  63. package/dist/commands/init/tools/project-management/agents-guidance.js +3 -1
  64. package/dist/commands/init/tools/project-management/index.d.ts +1 -0
  65. package/dist/commands/init/tools/project-management/index.d.ts.map +1 -1
  66. package/dist/commands/init/tools/project-management/index.js +24 -55
  67. package/dist/commands/init/tools/project-management/install-project-management.d.ts +4 -0
  68. package/dist/commands/init/tools/project-management/install-project-management.d.ts.map +1 -1
  69. package/dist/commands/init/tools/project-management/install-project-management.js +4 -1
  70. package/dist/commands/init/tools/research/index.d.ts.map +1 -1
  71. package/dist/commands/init/tools/research/index.js +4 -1
  72. package/dist/commands/init/tools/shared/copy-helpers.d.ts.map +1 -1
  73. package/dist/commands/init/tools/shared/copy-helpers.js +10 -0
  74. package/dist/commands/init/tools/shared/skill-manifest.d.ts +15 -15
  75. package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
  76. package/dist/commands/init/tools/shared/skill-manifest.js +17 -122
  77. package/dist/commands/init/tools/utility/index.d.ts.map +1 -1
  78. package/dist/commands/init/tools/utility/index.js +4 -1
  79. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  80. package/dist/commands/init/tools/workflows/index.js +4 -1
  81. package/dist/commands/init/tools/workflows/install-workflows.d.ts.map +1 -1
  82. package/dist/commands/init/tools/workflows/install-workflows.js +2 -4
  83. package/dist/commands/pjm/adoption.d.ts +12 -0
  84. package/dist/commands/pjm/adoption.d.ts.map +1 -0
  85. package/dist/commands/pjm/adoption.js +47 -0
  86. package/dist/commands/pjm/doctor.d.ts +3 -2
  87. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  88. package/dist/commands/pjm/doctor.js +28 -13
  89. package/dist/commands/pjm/index.d.ts +2 -0
  90. package/dist/commands/pjm/index.d.ts.map +1 -1
  91. package/dist/commands/pjm/index.js +11 -3
  92. package/dist/commands/pjm/init.d.ts +3 -0
  93. package/dist/commands/pjm/init.d.ts.map +1 -1
  94. package/dist/commands/pjm/init.js +37 -32
  95. package/dist/commands/pjm/migrate.d.ts +1 -0
  96. package/dist/commands/pjm/migrate.d.ts.map +1 -1
  97. package/dist/commands/pjm/migrate.js +1 -0
  98. package/dist/commands/pjm/template-source.d.ts +14 -0
  99. package/dist/commands/pjm/template-source.d.ts.map +1 -0
  100. package/dist/commands/pjm/template-source.js +56 -0
  101. package/dist/commands/remove/skills/remove-skills.d.ts.map +1 -1
  102. package/dist/commands/remove/skills/remove-skills.js +10 -19
  103. package/dist/commands/status/index.d.ts +5 -0
  104. package/dist/commands/status/index.d.ts.map +1 -1
  105. package/dist/commands/status/index.js +203 -2
  106. package/dist/commands/sync/index.d.ts.map +1 -1
  107. package/dist/commands/sync/index.js +40 -7
  108. package/dist/commands/sync/sync.types.d.ts +4 -0
  109. package/dist/commands/sync/sync.types.d.ts.map +1 -1
  110. package/dist/commands/tools/has/has-pack.d.ts +11 -2
  111. package/dist/commands/tools/has/has-pack.d.ts.map +1 -1
  112. package/dist/commands/tools/has/has-pack.js +33 -20
  113. package/dist/commands/tools/index.d.ts.map +1 -1
  114. package/dist/commands/tools/index.js +3 -1
  115. package/dist/commands/tools/info/info-tool.d.ts +3 -0
  116. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  117. package/dist/commands/tools/info/info-tool.js +29 -4
  118. package/dist/commands/tools/list/list-tools.d.ts +3 -0
  119. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  120. package/dist/commands/tools/list/list-tools.js +31 -4
  121. package/dist/commands/tools/migrate/index.d.ts +26 -0
  122. package/dist/commands/tools/migrate/index.d.ts.map +1 -0
  123. package/dist/commands/tools/migrate/index.js +312 -0
  124. package/dist/commands/tools/migrate/migrate-pack.d.ts +81 -0
  125. package/dist/commands/tools/migrate/migrate-pack.d.ts.map +1 -0
  126. package/dist/commands/tools/migrate/migrate-pack.js +324 -0
  127. package/dist/commands/tools/outdated/outdated-tools.d.ts +11 -0
  128. package/dist/commands/tools/outdated/outdated-tools.d.ts.map +1 -1
  129. package/dist/commands/tools/outdated/outdated-tools.js +33 -5
  130. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  131. package/dist/commands/tools/remove/index.js +73 -20
  132. package/dist/commands/tools/remove/remove-tools.d.ts +28 -0
  133. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  134. package/dist/commands/tools/remove/remove-tools.js +156 -26
  135. package/dist/commands/tools/shared/apply-pack-reconcile.d.ts +41 -0
  136. package/dist/commands/tools/shared/apply-pack-reconcile.d.ts.map +1 -0
  137. package/dist/commands/tools/shared/apply-pack-reconcile.js +126 -0
  138. package/dist/commands/tools/shared/auto-sync.d.ts +5 -2
  139. package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
  140. package/dist/commands/tools/shared/auto-sync.js +1 -0
  141. package/dist/commands/tools/shared/content-digest.d.ts +3 -0
  142. package/dist/commands/tools/shared/content-digest.d.ts.map +1 -0
  143. package/dist/commands/tools/shared/content-digest.js +57 -0
  144. package/dist/commands/tools/shared/format-pack-inventory.d.ts +3 -0
  145. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -0
  146. package/dist/commands/tools/shared/format-pack-inventory.js +21 -0
  147. package/dist/commands/tools/shared/install-sync-context.d.ts.map +1 -1
  148. package/dist/commands/tools/shared/install-sync-context.js +2 -25
  149. package/dist/commands/tools/shared/pack-inventory.d.ts +46 -0
  150. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -0
  151. package/dist/commands/tools/shared/pack-inventory.js +207 -0
  152. package/dist/commands/tools/shared/pack-lifecycle.d.ts +34 -0
  153. package/dist/commands/tools/shared/pack-lifecycle.d.ts.map +1 -0
  154. package/dist/commands/tools/shared/pack-lifecycle.js +67 -0
  155. package/dist/commands/tools/shared/pack-manifest.d.ts +11 -0
  156. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -0
  157. package/dist/commands/tools/shared/pack-manifest.js +384 -0
  158. package/dist/commands/tools/shared/pack-paths.d.ts +21 -0
  159. package/dist/commands/tools/shared/pack-paths.d.ts.map +1 -0
  160. package/dist/commands/tools/shared/pack-paths.js +35 -0
  161. package/dist/commands/tools/shared/pack-reconcile.d.ts +64 -0
  162. package/dist/commands/tools/shared/pack-reconcile.d.ts.map +1 -0
  163. package/dist/commands/tools/shared/pack-reconcile.js +158 -0
  164. package/dist/commands/tools/shared/project-tools-config.d.ts.map +1 -1
  165. package/dist/commands/tools/shared/project-tools-config.js +12 -38
  166. package/dist/commands/tools/shared/scan-tools.js +2 -2
  167. package/dist/commands/tools/shared/scoped-pack-intent.d.ts +34 -0
  168. package/dist/commands/tools/shared/scoped-pack-intent.d.ts.map +1 -0
  169. package/dist/commands/tools/shared/scoped-pack-intent.js +116 -0
  170. package/dist/commands/tools/shared/types.d.ts +22 -0
  171. package/dist/commands/tools/shared/types.d.ts.map +1 -1
  172. package/dist/commands/tools/update/index.d.ts.map +1 -1
  173. package/dist/commands/tools/update/index.js +30 -5
  174. package/dist/commands/tools/update/update-tools.d.ts +9 -1
  175. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  176. package/dist/commands/tools/update/update-tools.js +176 -64
  177. package/dist/config/oat-config.d.ts +6 -0
  178. package/dist/config/oat-config.d.ts.map +1 -1
  179. package/dist/config/oat-config.js +49 -20
  180. package/dist/fs/paths.d.ts +12 -0
  181. package/dist/fs/paths.d.ts.map +1 -1
  182. package/dist/fs/paths.js +87 -1
  183. package/package.json +2 -2
@@ -1,6 +1,8 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { buildCommandContext } from '../../app/command-context.js';
3
+ import { resolvePjmAdoption } from '../pjm/adoption.js';
3
4
  import { readGlobalOptions } from '../shared/shared.utils.js';
5
+ import { CliError } from '../../errors/index.js';
4
6
  import { resolveAssetsRoot } from '../../fs/assets.js';
5
7
  import { resolveProjectRoot } from '../../fs/paths.js';
6
8
  import { Command } from 'commander';
@@ -13,6 +15,7 @@ const DEFAULT_DEPENDENCIES = {
13
15
  buildCommandContext,
14
16
  resolveProjectRoot,
15
17
  resolveAssetsRoot,
18
+ resolvePjmAdoption,
16
19
  initializeDecisionAgentsGuidance,
17
20
  initializeDecisionRecords,
18
21
  regenerateDecisionIndex,
@@ -41,6 +44,18 @@ function reportError(context, error) {
41
44
  }
42
45
  process.exitCode = 1;
43
46
  }
47
+ async function requireRepositoryPjm(context, dependencies) {
48
+ const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
49
+ const repoRoot = resolve(projectRoot, '.oat', 'repo');
50
+ const adoption = await dependencies.resolvePjmAdoption({
51
+ projectRoot,
52
+ repoRoot,
53
+ });
54
+ if (adoption.state !== 'declared' && adoption.state !== 'inferred-legacy') {
55
+ throw new CliError(`PJM is not initialized for repository ${repoRoot}. Run \`oat pjm init\` before writing PJM state.`, 1);
56
+ }
57
+ return projectRoot;
58
+ }
44
59
  export function createDecisionCommand(overrides = {}) {
45
60
  const dependencies = {
46
61
  ...DEFAULT_DEPENDENCIES,
@@ -54,7 +69,7 @@ export function createDecisionCommand(overrides = {}) {
54
69
  .action(async (options, command) => {
55
70
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
56
71
  try {
57
- const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
72
+ const projectRoot = await requireRepositoryPjm(context, dependencies);
58
73
  const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
59
74
  const result = await dependencies.initializeDecisionRecords(decisionsRoot);
60
75
  let guidance;
@@ -94,7 +109,7 @@ export function createDecisionCommand(overrides = {}) {
94
109
  .action(async (options, command) => {
95
110
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
96
111
  try {
97
- const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
112
+ const projectRoot = await requireRepositoryPjm(context, dependencies);
98
113
  const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
99
114
  await dependencies.regenerateDecisionIndex(decisionsRoot);
100
115
  if (context.json) {
@@ -122,13 +137,14 @@ export function createDecisionCommand(overrides = {}) {
122
137
  .action(async (title, options, command) => {
123
138
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
124
139
  try {
125
- const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
140
+ const projectRoot = await requireRepositoryPjm(context, dependencies);
126
141
  const decisionsRoot = await resolveDecisionsRoot(context, projectRoot, options.decisionsRoot);
127
142
  const assetsRoot = await dependencies.resolveAssetsRoot();
128
143
  const result = await dependencies.createDecisionRecord({
129
144
  decisionsRoot,
130
145
  assetsRoot,
131
146
  templatesRoot: resolve(projectRoot, '.oat', 'templates'),
147
+ home: context.home,
132
148
  title,
133
149
  status: options.status,
134
150
  context: options.context,
@@ -1,7 +1,9 @@
1
+ import { type PjmTemplateTier } from '../pjm/template-source.js';
1
2
  export interface CreateDecisionRecordOptions {
2
3
  decisionsRoot: string;
3
4
  assetsRoot: string;
4
5
  templatesRoot?: string;
6
+ home?: string;
5
7
  title: string;
6
8
  status?: string;
7
9
  context?: string;
@@ -13,6 +15,8 @@ export interface CreateDecisionRecordResult {
13
15
  id: string;
14
16
  decisionsRoot: string;
15
17
  filePath: string;
18
+ templatePath: string;
19
+ templateTier: PjmTemplateTier;
16
20
  }
17
21
  export declare function createDecisionRecord(options: CreateDecisionRecordOptions): Promise<CreateDecisionRecordResult>;
18
22
  //# sourceMappingURL=new.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/commands/decision/new.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,2BAA2B;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4HD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAgDrC"}
1
+ {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/commands/decision/new.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAUvC,MAAM,WAAW,2BAA2B;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,eAAe,CAAC;CAC/B;AAkFD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAoDrC"}
@@ -1,5 +1,6 @@
1
- import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
1
+ import { access, mkdir, rm, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join } from 'node:path';
3
+ import { resolvePjmTemplate, } from '../pjm/template-source.js';
3
4
  import { stripTemplateFrontmatter } from '../shared/strip-template-frontmatter.js';
4
5
  import YAML from 'yaml';
5
6
  import { assertDecisionIndexScaffold, regenerateDecisionIndex, } from './regenerate-index.js';
@@ -19,33 +20,6 @@ async function pathExists(path) {
19
20
  return false;
20
21
  }
21
22
  }
22
- async function readIfExists(path) {
23
- try {
24
- return await readFile(path, 'utf8');
25
- }
26
- catch (error) {
27
- const code = error && typeof error === 'object' && 'code' in error
28
- ? String(error.code)
29
- : null;
30
- if (code !== 'ENOENT') {
31
- throw error;
32
- }
33
- return null;
34
- }
35
- }
36
- async function resolveDecisionTemplate(assetsRoot, templatesRoot) {
37
- if (templatesRoot) {
38
- const localTemplate = await readIfExists(join(templatesRoot, 'decision.md'));
39
- if (localTemplate !== null) {
40
- return localTemplate;
41
- }
42
- }
43
- const bundledTemplate = await readIfExists(join(assetsRoot, 'templates', 'decision.md'));
44
- if (bundledTemplate !== null) {
45
- return bundledTemplate;
46
- }
47
- throw new Error('Template decision.md was not found in repo-local templates or bundled assets.');
48
- }
49
23
  function normalizeCreatedAt(createdAt) {
50
24
  const date = new Date(createdAt);
51
25
  if (Number.isNaN(date.getTime())) {
@@ -88,8 +62,13 @@ export async function createDecisionRecord(options) {
88
62
  if (await pathExists(filePath)) {
89
63
  throw new Error(`Decision record ${id} already exists. Use a more specific title to disambiguate.`);
90
64
  }
91
- const template = await resolveDecisionTemplate(options.assetsRoot, options.templatesRoot);
92
- const content = renderDecisionRecord(template, {
65
+ const template = await resolvePjmTemplate({
66
+ name: 'decision.md',
67
+ assetsRoot: options.assetsRoot,
68
+ templatesRoot: options.templatesRoot,
69
+ home: options.home,
70
+ });
71
+ const content = renderDecisionRecord(template.content, {
93
72
  id,
94
73
  title: options.title,
95
74
  date: createdAt.date,
@@ -116,5 +95,7 @@ export async function createDecisionRecord(options) {
116
95
  id,
117
96
  decisionsRoot: options.decisionsRoot,
118
97
  filePath,
98
+ templatePath: template.path,
99
+ templateTier: template.tier,
119
100
  };
120
101
  }
@@ -1,5 +1,7 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
2
+ import { type PjmAdoption, type ResolvePjmAdoptionOptions } from '../pjm/adoption.js';
2
3
  import { type PjmDoctorOptions } from '../pjm/doctor.js';
4
+ import { type InventoryPackInput, type PackInventory } from '../tools/shared/pack-inventory.js';
3
5
  import { type OatConfig, type OatLocalConfig, type UserConfig } from '../../config/oat-config.js';
4
6
  import { type Manifest } from '../../manifest/index.js';
5
7
  import { type CursorMaterializedModelDiagnostic, type MatrixCellAvailabilityResponse, type ValidateMatrixCellOptions } from '../../providers/identity/availability.js';
@@ -29,6 +31,8 @@ interface DoctorDependencies {
29
31
  validateDispatchMatrixRefs: typeof validateDispatchMatrixRefs;
30
32
  processEnv: NodeJS.ProcessEnv;
31
33
  runPjmDoctorChecks: (repoRoot: string, options?: PjmDoctorOptions) => Promise<DoctorCheck[]>;
34
+ resolvePjmAdoption: (options: ResolvePjmAdoptionOptions) => Promise<PjmAdoption>;
35
+ inventoryPack: (input: InventoryPackInput) => Promise<PackInventory>;
32
36
  checkSkillVersions: (scopeRoot: string, assetsRoot: string, pathExists: (path: string) => Promise<boolean>) => Promise<SkillVersionReport>;
33
37
  checkStaleInvocations: (repoRoot: string) => Promise<DoctorCheck>;
34
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,yBAAyB,EAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,uCAAuC,CAAC;AAa/C,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAQ9D,OAAO,EAGL,KAAK,iCAAiC,EAEtC,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,KACd,OAAO,CACV,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CACnE,CAAC;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,gCAAgC,EAAE,CAChC,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,iCAAiC,EAAE,CAAC,CAAC;IAClD,mCAAmC,EAAE,OAAO,mCAAmC,CAAC;IAChF,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,gBAAgB,KACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5B,kBAAkB,EAAE,CAClB,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACrE,kBAAkB,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,KAC3C,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjC,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACnE;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B,EAAE,MAAM,CAAC;IACnC,cAAc,EAAE,oBAAoB,EAAE,CAAC;CACxC;AA+oCD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAcT"}
@@ -3,10 +3,14 @@ import { tmpdir } from 'node:os';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { buildCommandContext, } from '../../app/command-context.js';
5
5
  import { compareVersions } from '../init/tools/shared/version.js';
6
- import { createPjmDisabledCheck, runPjmDoctorChecks, } from '../pjm/doctor.js';
6
+ import { resolvePjmAdoption, } from '../pjm/adoption.js';
7
+ import { runPjmDoctorChecks, } from '../pjm/doctor.js';
7
8
  import { getSkillVersion } from '../shared/frontmatter.js';
8
9
  import { withScopeOption } from '../shared/scope-option.js';
9
10
  import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
11
+ import { hasScopedPackPlacementEvidence, inventoryPack, } from '../tools/shared/pack-inventory.js';
12
+ import { PACK_NAMES } from '../tools/shared/pack-manifest.js';
13
+ import { formatPackPaths, updatePackRecovery, } from '../tools/shared/pack-paths.js';
10
14
  import { walkDispatchMatrix, } from '../../config/dispatch-matrix.js';
11
15
  import { readOatConfig, readOatLocalConfig, readUserConfig, } from '../../config/oat-config.js';
12
16
  import { resolveAssetsRoot } from '../../fs/assets.js';
@@ -143,6 +147,8 @@ function createDependencies() {
143
147
  validateDispatchMatrixRefs,
144
148
  processEnv: process.env,
145
149
  runPjmDoctorChecks,
150
+ resolvePjmAdoption,
151
+ inventoryPack,
146
152
  // Default binding remains self-contained, but still honors the caller-
147
153
  // provided pathExists dependency from runChecksForScope when available.
148
154
  checkSkillVersions: (scopeRoot, assetsRoot, pathExists = pathExistsDefault) => checkSkillVersionsDefault(scopeRoot, assetsRoot, pathExists),
@@ -462,6 +468,219 @@ async function runCodexChecksForScope(scope, scopeRoot, userHome, dependencies)
462
468
  });
463
469
  return checks;
464
470
  }
471
+ function collectPackStateFindings(inventories) {
472
+ const findings = [];
473
+ for (const inventory of inventories) {
474
+ for (const scoped of inventory.scopes) {
475
+ const { scope } = scoped;
476
+ if (!hasScopedPackPlacementEvidence(scoped)) {
477
+ const sharedPresent = scoped.assets.filter((asset) => asset.definition.sharedOwner !== undefined &&
478
+ asset.status !== 'missing');
479
+ if (sharedPresent.length > 0) {
480
+ findings.push({
481
+ pack: inventory.pack,
482
+ scope,
483
+ code: 'shared-owner-observation',
484
+ detail: 'shared managed assets are present without pack ownership evidence',
485
+ paths: sharedPresent.map(({ path }) => path),
486
+ recovery: null,
487
+ });
488
+ }
489
+ continue;
490
+ }
491
+ const managed = scoped.assets.filter((asset) => asset.definition.ownership[scope] === 'managed');
492
+ if (scoped.completeness !== 'complete') {
493
+ const missing = managed.filter(({ status }) => status === 'missing');
494
+ findings.push({
495
+ pack: inventory.pack,
496
+ scope,
497
+ code: 'partial',
498
+ detail: scoped.completeness === 'absent'
499
+ ? 'declared intent with no installed managed assets'
500
+ : `missing ${missing.length} of ${managed.length} managed asset(s)`,
501
+ paths: missing.map(({ path }) => path),
502
+ recovery: updatePackRecovery(inventory.pack, scope),
503
+ });
504
+ }
505
+ const stale = scoped.assets.filter(({ status }) => status === 'outdated');
506
+ if (stale.length > 0) {
507
+ findings.push({
508
+ pack: inventory.pack,
509
+ scope,
510
+ code: 'stale',
511
+ detail: `${stale.length} managed asset(s) behind the bundled release`,
512
+ paths: stale.map(({ path }) => path),
513
+ recovery: updatePackRecovery(inventory.pack, scope),
514
+ });
515
+ }
516
+ const newer = scoped.assets.filter(({ status }) => status === 'newer');
517
+ if (newer.length > 0) {
518
+ findings.push({
519
+ pack: inventory.pack,
520
+ scope,
521
+ code: 'newer',
522
+ detail: `${newer.length} installed asset(s) are newer than the bundled release`,
523
+ paths: newer.map(({ path }) => path),
524
+ recovery: null,
525
+ });
526
+ }
527
+ const retained = scoped.assets.filter((asset) => asset.definition.ownership[scope] === 'seed-if-missing' &&
528
+ asset.status === 'present');
529
+ if (retained.length > 0) {
530
+ findings.push({
531
+ pack: inventory.pack,
532
+ scope,
533
+ code: 'retained-override',
534
+ detail: `${retained.length} owner-owned override(s) retained; managed defaults are not applied here`,
535
+ paths: retained.map(({ path }) => path),
536
+ recovery: null,
537
+ });
538
+ }
539
+ for (const diagnostic of scoped.diagnostics) {
540
+ if (diagnostic.code === 'legacy-false-conflict') {
541
+ findings.push({
542
+ pack: inventory.pack,
543
+ scope,
544
+ code: 'legacy-false-conflict',
545
+ detail: 'legacy false intent with installed managed assets; adopt or remove the install',
546
+ paths: diagnostic.paths,
547
+ recovery: updatePackRecovery(inventory.pack, scope),
548
+ });
549
+ continue;
550
+ }
551
+ if (diagnostic.code === 'user-agent-unmaterialized') {
552
+ // A documented scope limitation rather than drift: `oat tools update`
553
+ // cannot repair it, so no recovery command is offered and the check
554
+ // stays a pass. The message still names every affected agent so the
555
+ // absent capability is not reported as a complete pack.
556
+ findings.push({
557
+ pack: inventory.pack,
558
+ scope,
559
+ code: 'user-agent-unmaterialized',
560
+ detail: `${diagnostic.paths.length} user-scope agent(s) reach no provider; user-scope agent materialization is limited to the bundled managed role files, so install this pack at project scope to use them`,
561
+ paths: diagnostic.paths,
562
+ recovery: null,
563
+ });
564
+ }
565
+ }
566
+ }
567
+ for (const diagnostic of inventory.diagnostics) {
568
+ if (diagnostic.code !== 'duplicate-scope')
569
+ continue;
570
+ findings.push({
571
+ pack: inventory.pack,
572
+ scope: null,
573
+ code: 'duplicate-scope',
574
+ detail: 'installed at project and user scope; provider precedence is not inferred',
575
+ paths: diagnostic.paths,
576
+ recovery: `oat tools migrate --pack ${inventory.pack} --from project --to user`,
577
+ });
578
+ }
579
+ }
580
+ return findings;
581
+ }
582
+ function formatPackFinding(finding, roots) {
583
+ const paths = formatPackPaths(finding.paths, roots);
584
+ return paths.length > 0
585
+ ? `${finding.pack} [${finding.code}]: ${finding.detail} (${paths})`
586
+ : `${finding.pack} [${finding.code}]: ${finding.detail}`;
587
+ }
588
+ function uniqueRecoveries(findings) {
589
+ return [
590
+ ...new Set(findings
591
+ .map(({ recovery }) => recovery)
592
+ .filter((recovery) => recovery !== null)),
593
+ ];
594
+ }
595
+ function createScopedPackStateCheck(scope, findings, roots) {
596
+ const scoped = findings.filter((finding) => finding.scope === scope);
597
+ if (scoped.length === 0) {
598
+ return {
599
+ name: `${scope}:pack_state`,
600
+ description: 'Managed pack completeness and drift',
601
+ status: 'pass',
602
+ message: 'All installed managed packs are complete and current.',
603
+ };
604
+ }
605
+ const recoveries = uniqueRecoveries(scoped);
606
+ return {
607
+ name: `${scope}:pack_state`,
608
+ description: 'Managed pack completeness and drift',
609
+ status: recoveries.length > 0 ? 'warn' : 'pass',
610
+ message: scoped
611
+ .map((finding) => formatPackFinding(finding, roots))
612
+ .join('; '),
613
+ fix: recoveries.length > 0 ? recoveries.join('; ') : undefined,
614
+ };
615
+ }
616
+ function createPackDuplicationCheck(findings, roots) {
617
+ const duplicates = findings.filter((finding) => finding.code === 'duplicate-scope');
618
+ if (duplicates.length === 0) {
619
+ return {
620
+ name: 'packs:scope_duplication',
621
+ description: 'Cross-scope pack duplication',
622
+ status: 'pass',
623
+ message: 'No managed pack is installed at both project and user scope.',
624
+ };
625
+ }
626
+ return {
627
+ name: 'packs:scope_duplication',
628
+ description: 'Cross-scope pack duplication',
629
+ status: 'warn',
630
+ message: duplicates
631
+ .map((finding) => formatPackFinding(finding, roots))
632
+ .join('; '),
633
+ fix: uniqueRecoveries(duplicates).join('; '),
634
+ };
635
+ }
636
+ async function createPackStateChecks(scopeRoots, dependencies) {
637
+ if (scopeRoots.size === 0) {
638
+ return [];
639
+ }
640
+ const roots = {
641
+ ...(scopeRoots.has('project')
642
+ ? { projectRoot: scopeRoots.get('project') }
643
+ : {}),
644
+ ...(scopeRoots.has('user') ? { userRoot: scopeRoots.get('user') } : {}),
645
+ };
646
+ let findings;
647
+ try {
648
+ const assetsRoot = await dependencies.resolveAssetsRoot();
649
+ const inventories = await Promise.all(PACK_NAMES.map((pack) => dependencies.inventoryPack({ pack, assetsRoot, ...roots })));
650
+ findings = collectPackStateFindings(inventories);
651
+ }
652
+ catch (error) {
653
+ return [
654
+ {
655
+ name: 'packs:inventory',
656
+ description: 'Managed pack inventory availability',
657
+ status: 'warn',
658
+ message: error instanceof Error
659
+ ? `Unable to inventory managed packs: ${error.message}`
660
+ : 'Unable to inventory managed packs.',
661
+ fix: 'Run `pnpm build` and rerun `oat doctor`.',
662
+ },
663
+ ];
664
+ }
665
+ const checks = [];
666
+ for (const scope of scopeRoots.keys()) {
667
+ checks.push(createScopedPackStateCheck(scope, findings, roots));
668
+ }
669
+ if (scopeRoots.has('project') && scopeRoots.has('user')) {
670
+ checks.push(createPackDuplicationCheck(findings, roots));
671
+ }
672
+ return checks;
673
+ }
674
+ function createScopeUnavailableCheck(scope, error) {
675
+ const reason = error instanceof Error ? `: ${error.message}` : '.';
676
+ return {
677
+ name: `${scope}:scope_availability`,
678
+ description: `${scope === 'project' ? 'Project' : 'User'} scope availability`,
679
+ status: 'warn',
680
+ message: `${scope === 'project' ? 'Project' : 'User'} scope is unavailable${reason}`,
681
+ fix: `Run \`oat doctor --scope ${scope === 'project' ? 'user' : 'project'}\`, or rerun inside a directory where ${scope} scope resolves.`,
682
+ };
683
+ }
465
684
  async function runChecksForScope(scope, scopeRoot, userConfigDir, dependencies) {
466
685
  const checks = [];
467
686
  const skillsPath = join(scopeRoot, '.agents', 'skills');
@@ -603,25 +822,51 @@ async function runChecksForScope(scope, scopeRoot, userConfigDir, dependencies)
603
822
  { source: 'repo-config', config },
604
823
  { source: 'local-config', config: localConfig },
605
824
  ], dependencies));
606
- const projectManagementEnabled = config.tools?.['project-management'] === true;
607
- if (projectManagementEnabled) {
825
+ // PJM capability now normally lives at user scope, so repository pack
826
+ // intent is no longer evidence of repository adoption. Adoption state is
827
+ // authoritative and already covers every case where a PJM canonical file
828
+ // exists (`partial-initialization` is returned whenever any is present), so
829
+ // the presence of `.oat/repo` adds nothing. Keying off it as well would fire
830
+ // only when `.oat/repo` exists with zero PJM canonical files — a repository
831
+ // that uses `.oat/repo` for non-PJM content such as `oat index` knowledge,
832
+ // and deliberately declined PJM. That is a false positive, and it made
833
+ // `oat doctor` disagree with `oat status`'s `shouldReportPjmAdoption`.
834
+ const adoption = await dependencies.resolvePjmAdoption({
835
+ projectRoot: scopeRoot,
836
+ repoRoot: repoReferenceRoot,
837
+ });
838
+ if (adoption.state !== 'none') {
608
839
  checks.push(...(await dependencies.runPjmDoctorChecks(repoReferenceRoot, {
609
- projectManagementEnabled: true,
840
+ projectRoot: scopeRoot,
841
+ adoption,
610
842
  })));
611
843
  }
612
- else if (await dependencies.pathExists(repoReferenceRoot)) {
613
- checks.push(createPjmDisabledCheck());
614
- }
615
844
  }
616
845
  return checks;
617
846
  }
618
847
  async function runDoctorCommand(context, dependencies) {
619
848
  const checks = [];
620
- for (const scope of resolveConcreteScopes(context.scope)) {
621
- const scopeRoot = await dependencies.resolveScopeRoot(scope, context);
849
+ const scopes = resolveConcreteScopes(context.scope);
850
+ const scopeRoots = new Map();
851
+ for (const scope of scopes) {
852
+ let scopeRoot;
853
+ try {
854
+ scopeRoot = await dependencies.resolveScopeRoot(scope, context);
855
+ }
856
+ catch (error) {
857
+ // `--scope all` outside a Git repository still completes user-scope
858
+ // diagnostics; an explicitly requested scope stays a hard failure.
859
+ if (scope === 'project' && scopes.includes('user')) {
860
+ checks.push(createScopeUnavailableCheck(scope, error));
861
+ continue;
862
+ }
863
+ throw error;
864
+ }
865
+ scopeRoots.set(scope, scopeRoot);
622
866
  const scopeChecks = await runChecksForScope(scope, scopeRoot, join(context.home, '.oat'), dependencies);
623
867
  checks.push(...scopeChecks);
624
868
  }
869
+ checks.push(...(await createPackStateChecks(scopeRoots, dependencies)));
625
870
  if (context.json) {
626
871
  context.logger.json({ scope: context.scope, checks });
627
872
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/brainstorm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAM9B,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,+BAA+B;IACvC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,iBAAiB,EAAE,CACjB,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC/D;AA+JD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,GACvD,OAAO,CA2BT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/brainstorm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAM9B,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,+BAA+B;IACvC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,iBAAiB,EAAE,CACjB,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC/D;AA2KD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,GACvD,OAAO,CA2BT"}
@@ -31,11 +31,13 @@ async function resolveInstallScope(context, projectRoot, userRoot, assetsRoot, d
31
31
  // defaultScope is consulted, so re-installing a pack already placed at
32
32
  // a particular scope never silently migrates the user across scopes.
33
33
  const [projectTools, userTools] = await Promise.all([
34
- dependencies.scanTools({
35
- scope: 'project',
36
- scopeRoot: projectRoot,
37
- assetsRoot,
38
- }),
34
+ projectRoot
35
+ ? dependencies.scanTools({
36
+ scope: 'project',
37
+ scopeRoot: projectRoot,
38
+ assetsRoot,
39
+ })
40
+ : Promise.resolve([]),
39
41
  dependencies.scanTools({
40
42
  scope: 'user',
41
43
  scopeRoot: userRoot,
@@ -80,10 +82,22 @@ function reportSuccess(context, scope, targetRoot, assetsRoot, result) {
80
82
  }
81
83
  async function runInitToolsBrainstorm(context, options, dependencies) {
82
84
  try {
83
- const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
85
+ let projectRoot = null;
86
+ if (context.scope !== 'user') {
87
+ try {
88
+ projectRoot = await dependencies.resolveProjectRoot(context.cwd);
89
+ }
90
+ catch (error) {
91
+ if (context.scope === 'project')
92
+ throw error;
93
+ }
94
+ }
84
95
  const userRoot = dependencies.resolveScopeRoot('user', context.cwd, context.home);
85
96
  const assetsRoot = await dependencies.resolveAssetsRoot();
86
97
  const { scope } = await resolveInstallScope(context, projectRoot, userRoot, assetsRoot, dependencies);
98
+ if (scope === 'project' && !projectRoot) {
99
+ throw new Error('Project scope is unavailable outside a repository');
100
+ }
87
101
  const targetRoot = scope === 'project' ? projectRoot : userRoot;
88
102
  if (options.force && context.interactive) {
89
103
  const confirmed = await dependencies.confirmAction(`Force overwrite existing brainstorm assets in ${scope} scope?`, { interactive: context.interactive });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,KAAK,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuID,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAeT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AASzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,KAAK,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAyID,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAeT"}
@@ -3,6 +3,7 @@ import { withScopeOption } from '../../../shared/scope-option.js';
3
3
  import { confirmAction, selectManyWithAbort, } from '../../../shared/shared.prompts.js';
4
4
  import { readGlobalOptions } from '../../../shared/shared.utils.js';
5
5
  import { canonicalSkillPaths, setInstalledCanonicalPaths, } from '../../../tools/shared/install-sync-context.js';
6
+ import { getPackDefinition } from '../../../tools/shared/pack-manifest.js';
6
7
  import { resolveAssetsRoot } from '../../../../fs/assets.js';
7
8
  import { resolveProjectRoot, resolveScopeRoot } from '../../../../fs/paths.js';
8
9
  import { Command } from 'commander';
@@ -17,7 +18,9 @@ const DEFAULT_DEPENDENCIES = {
17
18
  confirmAction,
18
19
  };
19
20
  function resolveScope(context) {
20
- return context.scope === 'user' ? 'user' : 'project';
21
+ return context.scope === 'project' || context.scope === 'user'
22
+ ? context.scope
23
+ : getPackDefinition('docs').defaultScope;
21
24
  }
22
25
  function reportSuccess(context, scope, targetRoot, assetsRoot, selectedSkills, result) {
23
26
  if (context.json) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/ideas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAMzB,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,0BAA0B;IAClC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuGD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CAsBT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/ideas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AASzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAMzB,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,0BAA0B;IAClC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAyGD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CAsBT"}
@@ -3,6 +3,7 @@ import { withScopeOption } from '../../../shared/scope-option.js';
3
3
  import { confirmAction, } from '../../../shared/shared.prompts.js';
4
4
  import { readGlobalOptions } from '../../../shared/shared.utils.js';
5
5
  import { canonicalPathsForPack, setInstalledCanonicalPaths, } from '../../../tools/shared/install-sync-context.js';
6
+ import { getPackDefinition } from '../../../tools/shared/pack-manifest.js';
6
7
  import { resolveAssetsRoot } from '../../../../fs/assets.js';
7
8
  import { resolveProjectRoot, resolveScopeRoot } from '../../../../fs/paths.js';
8
9
  import { Command } from 'commander';
@@ -16,7 +17,9 @@ const DEFAULT_DEPENDENCIES = {
16
17
  confirmAction,
17
18
  };
18
19
  function resolveInstallScope(context) {
19
- return context.scope === 'user' ? 'user' : 'project';
20
+ return context.scope === 'project' || context.scope === 'user'
21
+ ? context.scope
22
+ : getPackDefinition('ideas').defaultScope;
20
23
  }
21
24
  function getCountSummary(result) {
22
25
  return {
@@ -1,6 +1,8 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
2
2
  import { type UpsertSectionResult } from '../../shared/agents-md.js';
3
3
  import { type MultiSelectChoice, type PromptContext, type SelectChoice } from '../../shared/shared.prompts.js';
4
+ import { type InventoryPackInput, type PackInventory } from '../../tools/shared/pack-inventory.js';
5
+ import { type PackLifecycleRequest, type PackLifecycleResult } from '../../tools/shared/pack-lifecycle.js';
4
6
  import type { ScanToolsOptions } from '../../tools/shared/scan-tools.js';
5
7
  import type { ToolInfo } from '../../tools/shared/types.js';
6
8
  import { type OatConfig } from '../../../config/oat-config.js';
@@ -34,8 +36,10 @@ export interface InitToolsDependencies {
34
36
  installResearch: (options: InstallResearchOptions) => Promise<InstallResearchResult>;
35
37
  installBrainstorm: (options: InstallBrainstormOptions) => Promise<InstallBrainstormResult>;
36
38
  copyDirWithStatus: (source: string, destination: string, force: boolean) => Promise<'copied' | 'updated' | 'skipped'>;
37
- removeDirectory: (target: string) => Promise<void>;
38
- removeFile: (target: string) => Promise<void>;
39
+ /** @deprecated Phase 2 installs are additive; retained for test-harness compatibility. */
40
+ removeDirectory?: (target: string) => Promise<void>;
41
+ /** @deprecated Phase 2 installs are additive; retained for test-harness compatibility. */
42
+ removeFile?: (target: string) => Promise<void>;
39
43
  addLocalPaths: (repoRoot: string, paths: string[]) => Promise<{
40
44
  added: string[];
41
45
  all: string[];
@@ -48,9 +52,14 @@ export interface InitToolsDependencies {
48
52
  resolveLocalPaths: (config: OatConfig) => string[];
49
53
  upsertAgentsMdSection: (repoRoot: string, key: string, body: string) => Promise<UpsertSectionResult>;
50
54
  removeAgentsMdSection: (repoRoot: string, key: string) => Promise<boolean>;
55
+ reconcilePacks?: (requests: readonly PackLifecycleRequest[], options?: {
56
+ dryRun?: boolean;
57
+ }) => Promise<PackLifecycleResult[]>;
58
+ inventoryPack?: (input: InventoryPackInput) => Promise<PackInventory>;
51
59
  }
52
60
  interface InitToolsRunMetadata {
53
61
  affectedScopes: ConcreteScope[];
62
+ appliedScopes: ConcreteScope[];
54
63
  }
55
64
  interface PackScopeChange {
56
65
  pack: ToolPack;