@open-agent-toolkit/cli 0.1.30 → 0.1.32

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 (95) hide show
  1. package/assets/docs/cli-utilities/config-and-local-state.md +18 -5
  2. package/assets/docs/cli-utilities/tool-packs.md +13 -8
  3. package/assets/docs/reference/cli-reference.md +14 -13
  4. package/assets/docs/reference/file-locations.md +2 -1
  5. package/assets/docs/reference/oat-directory-structure.md +35 -22
  6. package/assets/migration/pjm-restructure.md +500 -0
  7. package/assets/public-package-versions.json +4 -4
  8. package/assets/skills/deep-research/SKILL.md +2 -2
  9. package/assets/skills/oat-brainstorm/SKILL.md +3 -3
  10. package/assets/skills/oat-brainstorm/references/destinations.md +10 -2
  11. package/assets/skills/oat-brainstorm/references/dogfood-results.md +4 -4
  12. package/assets/skills/oat-pjm-add-backlog-item/SKILL.md +17 -20
  13. package/assets/skills/oat-pjm-decision/SKILL.md +129 -0
  14. package/assets/skills/oat-pjm-review-backlog/SKILL.md +17 -17
  15. package/assets/skills/oat-pjm-review-backlog/references/backlog-review-template.md +2 -2
  16. package/assets/skills/oat-pjm-review-backlog/references/priority-alignment-template.md +13 -13
  17. package/assets/skills/oat-pjm-update-repo-reference/SKILL.md +34 -25
  18. package/assets/skills/oat-project-complete/SKILL.md +2 -2
  19. package/assets/skills/oat-project-document/SKILL.md +4 -3
  20. package/assets/skills/oat-project-import-plan/SKILL.md +2 -2
  21. package/assets/skills/oat-project-summary/SKILL.md +76 -8
  22. package/assets/templates/backlog-item.md +1 -1
  23. package/assets/templates/current-state.md +11 -2
  24. package/assets/templates/decision.md +18 -0
  25. package/assets/templates/pjm-agents.md +13 -0
  26. package/assets/templates/reference-agents.md +14 -0
  27. package/assets/templates/repo-agents.md +13 -0
  28. package/assets/templates/roadmap.md +8 -3
  29. package/dist/commands/backlog/index.d.ts +1 -0
  30. package/dist/commands/backlog/index.d.ts.map +1 -1
  31. package/dist/commands/backlog/index.js +48 -11
  32. package/dist/commands/backlog/init.js +1 -1
  33. package/dist/commands/backlog/regenerate-index.d.ts.map +1 -1
  34. package/dist/commands/backlog/regenerate-index.js +24 -5
  35. package/dist/commands/backlog/shared/generate-id.d.ts +1 -3
  36. package/dist/commands/backlog/shared/generate-id.d.ts.map +1 -1
  37. package/dist/commands/backlog/shared/generate-id.js +4 -64
  38. package/dist/commands/cleanup/artifacts/artifacts.d.ts.map +1 -1
  39. package/dist/commands/cleanup/artifacts/artifacts.js +4 -1
  40. package/dist/commands/decision/index.d.ts +20 -0
  41. package/dist/commands/decision/index.d.ts.map +1 -0
  42. package/dist/commands/decision/index.js +177 -0
  43. package/dist/commands/decision/init.d.ts +7 -0
  44. package/dist/commands/decision/init.d.ts.map +1 -0
  45. package/dist/commands/decision/init.js +53 -0
  46. package/dist/commands/decision/migrate.d.ts +24 -0
  47. package/dist/commands/decision/migrate.d.ts.map +1 -0
  48. package/dist/commands/decision/migrate.js +270 -0
  49. package/dist/commands/decision/new.d.ts +16 -0
  50. package/dist/commands/decision/new.d.ts.map +1 -0
  51. package/dist/commands/decision/new.js +118 -0
  52. package/dist/commands/decision/regenerate-index.d.ts +14 -0
  53. package/dist/commands/decision/regenerate-index.d.ts.map +1 -0
  54. package/dist/commands/decision/regenerate-index.js +122 -0
  55. package/dist/commands/decision/shared/generate-id.d.ts +2 -0
  56. package/dist/commands/decision/shared/generate-id.d.ts.map +1 -0
  57. package/dist/commands/decision/shared/generate-id.js +5 -0
  58. package/dist/commands/doctor/index.d.ts +2 -0
  59. package/dist/commands/doctor/index.d.ts.map +1 -1
  60. package/dist/commands/doctor/index.js +6 -0
  61. package/dist/commands/index.d.ts.map +1 -1
  62. package/dist/commands/index.js +2 -0
  63. package/dist/commands/init/tools/shared/skill-manifest.d.ts +2 -2
  64. package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
  65. package/dist/commands/init/tools/shared/skill-manifest.js +5 -1
  66. package/dist/commands/pjm/doctor.d.ts +3 -0
  67. package/dist/commands/pjm/doctor.d.ts.map +1 -0
  68. package/dist/commands/pjm/doctor.js +238 -0
  69. package/dist/commands/pjm/index.d.ts +7 -0
  70. package/dist/commands/pjm/index.d.ts.map +1 -1
  71. package/dist/commands/pjm/index.js +132 -10
  72. package/dist/commands/pjm/init.d.ts +3 -2
  73. package/dist/commands/pjm/init.d.ts.map +1 -1
  74. package/dist/commands/pjm/init.js +42 -33
  75. package/dist/commands/pjm/migrate.d.ts +36 -0
  76. package/dist/commands/pjm/migrate.d.ts.map +1 -0
  77. package/dist/commands/pjm/migrate.js +393 -0
  78. package/dist/commands/shared/date-id.d.ts +2 -0
  79. package/dist/commands/shared/date-id.d.ts.map +1 -0
  80. package/dist/commands/shared/date-id.js +10 -0
  81. package/dist/commands/shared/managed-index.d.ts +22 -0
  82. package/dist/commands/shared/managed-index.d.ts.map +1 -0
  83. package/dist/commands/shared/managed-index.js +92 -0
  84. package/dist/commands/shared/slug.d.ts +2 -0
  85. package/dist/commands/shared/slug.d.ts.map +1 -0
  86. package/dist/commands/shared/slug.js +57 -0
  87. package/dist/commands/shared/strip-template-frontmatter.d.ts +2 -0
  88. package/dist/commands/shared/strip-template-frontmatter.d.ts.map +1 -0
  89. package/dist/commands/shared/strip-template-frontmatter.js +16 -0
  90. package/dist/engine/hook.d.ts.map +1 -1
  91. package/dist/engine/hook.js +13 -0
  92. package/dist/release/public-package-contract.d.ts.map +1 -1
  93. package/dist/release/public-package-contract.js +10 -1
  94. package/package.json +2 -2
  95. package/assets/templates/decision-record.md +0 -21
@@ -0,0 +1,14 @@
1
+ export declare const DECISION_INDEX_START = "<!-- OAT DECISION-INDEX -->";
2
+ export declare const DECISION_INDEX_END = "<!-- END OAT DECISION-INDEX -->";
3
+ interface DecisionIndexRecord {
4
+ id: string;
5
+ date: string;
6
+ status: string;
7
+ title: string;
8
+ legacyId: string;
9
+ }
10
+ export declare function assertDecisionIndexScaffold(decisionsRoot: string): Promise<void>;
11
+ export declare function renderDecisionManagedSection(records: DecisionIndexRecord[]): string;
12
+ export declare function regenerateDecisionIndex(decisionsRoot: string): Promise<void>;
13
+ export {};
14
+ //# sourceMappingURL=regenerate-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regenerate-index.d.ts","sourceRoot":"","sources":["../../../src/commands/decision/regenerate-index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAClE,eAAO,MAAM,kBAAkB,oCAAoC,CAAC;AAEpE,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AA2GD,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,mBAAmB,EAAE,GAC7B,MAAM,CAgBR;AAED,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
@@ -0,0 +1,122 @@
1
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { getFrontmatterBlock } from '../shared/frontmatter.js';
4
+ import { computeManagedIndexUpdate } from '../shared/managed-index.js';
5
+ import YAML from 'yaml';
6
+ export const DECISION_INDEX_START = '<!-- OAT DECISION-INDEX -->';
7
+ export const DECISION_INDEX_END = '<!-- END OAT DECISION-INDEX -->';
8
+ function parseDecisionFrontmatter(content, filePath) {
9
+ const rawFrontmatter = getFrontmatterBlock(content);
10
+ if (!rawFrontmatter) {
11
+ return null;
12
+ }
13
+ const parsed = YAML.parse(rawFrontmatter);
14
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
15
+ throw new Error(`Frontmatter in ${filePath} must be a YAML object.`);
16
+ }
17
+ const frontmatter = parsed;
18
+ return {
19
+ id: String(frontmatter.id ?? ''),
20
+ date: String(frontmatter.date ?? ''),
21
+ status: String(frontmatter.status ?? ''),
22
+ title: String(frontmatter.title ?? ''),
23
+ legacyId: frontmatter.legacy_id === null || frontmatter.legacy_id === undefined
24
+ ? ''
25
+ : String(frontmatter.legacy_id),
26
+ };
27
+ }
28
+ function compareRecords(a, b) {
29
+ if (a.date > b.date) {
30
+ return -1;
31
+ }
32
+ if (a.date < b.date) {
33
+ return 1;
34
+ }
35
+ if (a.id < b.id) {
36
+ return -1;
37
+ }
38
+ if (a.id > b.id) {
39
+ return 1;
40
+ }
41
+ return 0;
42
+ }
43
+ function formatCell(value) {
44
+ const trimmed = value.trim();
45
+ if (trimmed.length === 0) {
46
+ return '-';
47
+ }
48
+ return trimmed.replace(/\r?\n/g, ' ').replace(/\|/g, '\\|');
49
+ }
50
+ function isMissingFileError(error) {
51
+ return (error !== null &&
52
+ typeof error === 'object' &&
53
+ 'code' in error &&
54
+ error.code === 'ENOENT');
55
+ }
56
+ async function readDecisionIndex(decisionsRoot) {
57
+ const indexPath = join(decisionsRoot, 'index.md');
58
+ try {
59
+ return {
60
+ content: await readFile(indexPath, 'utf8'),
61
+ indexPath,
62
+ };
63
+ }
64
+ catch (error) {
65
+ if (isMissingFileError(error)) {
66
+ throw new Error(`Decision index scaffold is missing at ${indexPath}. Run \`oat decision init\` before creating or regenerating decision records.`, { cause: error });
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ function findManagedSectionBounds(content, indexPath) {
72
+ const startIndex = content.indexOf(DECISION_INDEX_START);
73
+ const endIndex = content.indexOf(DECISION_INDEX_END);
74
+ if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
75
+ throw new Error(`Managed decision index markers missing in ${indexPath}. Expected the exact marker pair:\n${DECISION_INDEX_START}\n${DECISION_INDEX_END}\nRun \`oat decision init\` if the decision scaffold is missing, or restore those exact markers in \`decisions/index.md\` before rerunning \`oat decision regenerate-index\`.`);
76
+ }
77
+ return { startIndex, endIndex };
78
+ }
79
+ export async function assertDecisionIndexScaffold(decisionsRoot) {
80
+ const { content, indexPath } = await readDecisionIndex(decisionsRoot);
81
+ findManagedSectionBounds(content, indexPath);
82
+ }
83
+ export function renderDecisionManagedSection(records) {
84
+ const rows = records.length > 0
85
+ ? records.map((record) => `| ${formatCell(record.id)} | ${formatCell(record.date)} | ${formatCell(record.status)} | ${formatCell(record.title)} | ${formatCell(record.legacyId)} |`)
86
+ : ['| _No decisions yet_ | - | - | - | - |'];
87
+ return [
88
+ DECISION_INDEX_START,
89
+ '| ID | Date | Status | Title | Legacy |',
90
+ '| --- | --- | --- | --- | --- |',
91
+ ...rows,
92
+ DECISION_INDEX_END,
93
+ ].join('\n');
94
+ }
95
+ export async function regenerateDecisionIndex(decisionsRoot) {
96
+ const { content, indexPath } = await readDecisionIndex(decisionsRoot);
97
+ const { startIndex, endIndex } = findManagedSectionBounds(content, indexPath);
98
+ const entries = (await readdir(decisionsRoot, { withFileTypes: true }))
99
+ .filter((entry) => entry.isFile() &&
100
+ entry.name.endsWith('.md') &&
101
+ entry.name !== 'index.md')
102
+ .map((entry) => entry.name)
103
+ .sort();
104
+ const records = [];
105
+ for (const entry of entries) {
106
+ const filePath = join(decisionsRoot, entry);
107
+ const record = parseDecisionFrontmatter(await readFile(filePath, 'utf8'), filePath);
108
+ if (record) {
109
+ records.push(record);
110
+ }
111
+ }
112
+ records.sort(compareRecords);
113
+ // Content-idempotent gate: when the on-disk managed block is logically equal
114
+ // to the freshly rendered block (cells equal after trimming, so external
115
+ // formatter padding is ignored), preserve the existing bytes and skip the
116
+ // write. Only rewrite on a genuine content change.
117
+ const { content: updated } = computeManagedIndexUpdate(content, startIndex, endIndex + DECISION_INDEX_END.length, renderDecisionManagedSection(records));
118
+ if (updated === null) {
119
+ return;
120
+ }
121
+ await writeFile(indexPath, updated, 'utf8');
122
+ }
@@ -0,0 +1,2 @@
1
+ export declare function generateDecisionId(title: string, createdAt: string | Date): string;
2
+ //# sourceMappingURL=generate-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-id.d.ts","sourceRoot":"","sources":["../../../../src/commands/decision/shared/generate-id.ts"],"names":[],"mappings":"AAGA,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,CAER"}
@@ -0,0 +1,5 @@
1
+ import { yymmdd } from '../../shared/date-id.js';
2
+ import { slugify } from '../../shared/slug.js';
3
+ export function generateDecisionId(title, createdAt) {
4
+ return `DR-${yymmdd(createdAt)}-${slugify(title)}`;
5
+ }
@@ -1,6 +1,7 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
2
2
  import { type Manifest } from '../../manifest/index.js';
3
3
  import type { ConcreteScope } from '../../shared/types.js';
4
+ import { type DoctorCheck } from '../../ui/output.js';
4
5
  import { Command } from 'commander';
5
6
  interface DoctorDependencies {
6
7
  buildCommandContext: (options: GlobalOptions) => CommandContext;
@@ -15,6 +16,7 @@ interface DoctorDependencies {
15
16
  }>>;
16
17
  readFile: (path: string) => Promise<string>;
17
18
  resolveAssetsRoot: () => Promise<string>;
19
+ runPjmDoctorChecks: (repoRoot: string) => Promise<DoctorCheck[]>;
18
20
  checkSkillVersions: (scopeRoot: string, assetsRoot: string, pathExists: (path: string) => Promise<boolean>) => Promise<SkillVersionReport>;
19
21
  }
20
22
  interface OutdatedSkillVersion {
@@ -1 +1 @@
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;AAU9B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAM9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,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,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;CAClC;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;AAsaD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAcT"}
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;AAW9B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAM9D,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;AAEpC,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,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,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;CAClC;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;AA8aD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAcT"}
@@ -3,6 +3,7 @@ import { tmpdir } from 'node:os';
3
3
  import { 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 { runPjmDoctorChecks } from '../pjm/doctor.js';
6
7
  import { getSkillVersion } from '../shared/frontmatter.js';
7
8
  import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
8
9
  import { resolveAssetsRoot } from '../../fs/assets.js';
@@ -125,6 +126,7 @@ function createDependencies() {
125
126
  checkProviders: checkProvidersDefault,
126
127
  readFile: async (path) => readFile(path, 'utf8'),
127
128
  resolveAssetsRoot,
129
+ runPjmDoctorChecks,
128
130
  // Default binding remains self-contained, but still honors the caller-
129
131
  // provided pathExists dependency from runChecksForScope when available.
130
132
  checkSkillVersions: (scopeRoot, assetsRoot, pathExists = pathExistsDefault) => checkSkillVersionsDefault(scopeRoot, assetsRoot, pathExists),
@@ -339,6 +341,10 @@ async function runChecksForScope(scope, scopeRoot, dependencies) {
339
341
  }
340
342
  }
341
343
  }
344
+ const repoReferenceRoot = join(scopeRoot, '.oat', 'repo');
345
+ if (await dependencies.pathExists(repoReferenceRoot)) {
346
+ checks.push(...(await dependencies.runPjmDoctorChecks(repoReferenceRoot)));
347
+ }
342
348
  }
343
349
  return checks;
344
350
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBvD"}
@@ -1,6 +1,7 @@
1
1
  import { createBacklogCommand } from './backlog/index.js';
2
2
  import { createCleanupCommand } from './cleanup/index.js';
3
3
  import { createConfigCommand } from './config/index.js';
4
+ import { createDecisionCommand } from './decision/index.js';
4
5
  import { createDocsCommand } from './docs/index.js';
5
6
  import { createDoctorCommand } from './doctor/index.js';
6
7
  import { createIndexCommand } from './index-cmd/index.js';
@@ -20,6 +21,7 @@ import { createSyncCommand } from './sync/index.js';
20
21
  import { createToolsCommand } from './tools/index.js';
21
22
  export function registerCommands(program) {
22
23
  program.addCommand(createBacklogCommand());
24
+ program.addCommand(createDecisionCommand());
23
25
  program.addCommand(createInitCommand());
24
26
  program.addCommand(createStatusCommand());
25
27
  program.addCommand(createSyncCommand());
@@ -20,8 +20,8 @@ export declare const CORE_SKILLS: readonly ["oat-docs", "oat-doctor"];
20
20
  export declare const DOCS_SKILLS: readonly ["authoring-docs", "oat-agent-instructions-analyze", "oat-agent-instructions-apply", "oat-docs-analyze", "oat-docs-apply", "oat-docs-authoring", "oat-docs-bootstrap"];
21
21
  export declare const DOCS_SCRIPTS: readonly ["resolve-tracking.sh"];
22
22
  export declare const UTILITY_SKILLS: readonly ["create-agnostic-skill", "oat-repo-maintainability-review", "oat-review-provide", "oat-review-provide-remote", "oat-review-receive", "oat-review-receive-remote"];
23
- export declare const PROJECT_MANAGEMENT_SKILLS: readonly ["oat-pjm-add-backlog-item", "oat-pjm-update-repo-reference", "oat-pjm-review-backlog"];
24
- export declare const PROJECT_MANAGEMENT_TEMPLATES: readonly ["backlog-item.md", "roadmap.md", "current-state.md", "decision-record.md"];
23
+ export declare const PROJECT_MANAGEMENT_SKILLS: readonly ["oat-pjm-add-backlog-item", "oat-pjm-decision", "oat-pjm-update-repo-reference", "oat-pjm-review-backlog"];
24
+ export declare const PROJECT_MANAGEMENT_TEMPLATES: readonly ["backlog-item.md", "roadmap.md", "current-state.md", "decision.md", "repo-agents.md", "pjm-agents.md", "reference-agents.md"];
25
25
  export declare const PROJECT_MANAGEMENT_SCRIPTS: readonly [];
26
26
  export declare const BRAINSTORM_SKILLS: readonly ["oat-brainstorm"];
27
27
  export declare const RESEARCH_SKILLS: readonly ["analyze", "compare", "deep-research", "skeptic", "synthesize"];
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/shared/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAKtD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5E;AAID,eAAO,MAAM,eAAe,6xBAgClB,CAAC;AAEX,eAAO,MAAM,eAAe,oFAIlB,CAAC;AAEX,eAAO,MAAM,kBAAkB,6GAQrB,CAAC;AAEX,eAAO,MAAM,gBAAgB,qFAInB,CAAC;AAIX,eAAO,MAAM,WAAW,2FAKd,CAAC;AAIX,eAAO,MAAM,WAAW,qCAAsC,CAAC;AAI/D,eAAO,MAAM,WAAW,iLAQd,CAAC;AAEX,eAAO,MAAM,YAAY,kCAAmC,CAAC;AAI7D,eAAO,MAAM,cAAc,6KAOjB,CAAC;AAIX,eAAO,MAAM,yBAAyB,kGAI5B,CAAC;AAEX,eAAO,MAAM,4BAA4B,sFAK/B,CAAC;AAEX,eAAO,MAAM,0BAA0B,aAAc,CAAC;AAItD,eAAO,MAAM,iBAAiB,6BAA8B,CAAC;AAI7D,eAAO,MAAM,eAAe,2EAMlB,CAAC;AAEX,eAAO,MAAM,eAAe,qCAAsC,CAAC"}
1
+ {"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/shared/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAKtD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5E;AAID,eAAO,MAAM,eAAe,6xBAgClB,CAAC;AAEX,eAAO,MAAM,eAAe,oFAIlB,CAAC;AAEX,eAAO,MAAM,kBAAkB,6GAQrB,CAAC;AAEX,eAAO,MAAM,gBAAgB,qFAInB,CAAC;AAIX,eAAO,MAAM,WAAW,2FAKd,CAAC;AAIX,eAAO,MAAM,WAAW,qCAAsC,CAAC;AAI/D,eAAO,MAAM,WAAW,iLAQd,CAAC;AAEX,eAAO,MAAM,YAAY,kCAAmC,CAAC;AAI7D,eAAO,MAAM,cAAc,6KAOjB,CAAC;AAIX,eAAO,MAAM,yBAAyB,sHAK5B,CAAC;AAEX,eAAO,MAAM,4BAA4B,yIAQ/B,CAAC;AAEX,eAAO,MAAM,0BAA0B,aAAc,CAAC;AAItD,eAAO,MAAM,iBAAiB,6BAA8B,CAAC;AAI7D,eAAO,MAAM,eAAe,2EAMlB,CAAC;AAEX,eAAO,MAAM,eAAe,qCAAsC,CAAC"}
@@ -99,6 +99,7 @@ export const UTILITY_SKILLS = [
99
99
  // ── Project management pack ───────────────────────────────────────
100
100
  export const PROJECT_MANAGEMENT_SKILLS = [
101
101
  'oat-pjm-add-backlog-item',
102
+ 'oat-pjm-decision',
102
103
  'oat-pjm-update-repo-reference',
103
104
  'oat-pjm-review-backlog',
104
105
  ];
@@ -106,7 +107,10 @@ export const PROJECT_MANAGEMENT_TEMPLATES = [
106
107
  'backlog-item.md',
107
108
  'roadmap.md',
108
109
  'current-state.md',
109
- 'decision-record.md',
110
+ 'decision.md',
111
+ 'repo-agents.md',
112
+ 'pjm-agents.md',
113
+ 'reference-agents.md',
110
114
  ];
111
115
  export const PROJECT_MANAGEMENT_SCRIPTS = [];
112
116
  // ── Brainstorm pack ───────────────────────────────────────────────
@@ -0,0 +1,3 @@
1
+ import type { DoctorCheck } from '../../ui/output.js';
2
+ export declare function runPjmDoctorChecks(repoRoot: string): Promise<DoctorCheck[]>;
3
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/doctor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0I9C,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,EAAE,CAAC,CAqJxB"}
@@ -0,0 +1,238 @@
1
+ import { access, readdir, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { getFrontmatterBlock } from '../shared/frontmatter.js';
4
+ import { CANONICAL_REPO_REFERENCE_PATHS } from './init.js';
5
+ const ALLOWED_TOP_LEVEL_DIRECTORIES = new Set([
6
+ 'pjm',
7
+ 'reference',
8
+ 'knowledge',
9
+ 'analysis',
10
+ 'reviews',
11
+ ]);
12
+ // A human-facing `README.md` at the repo-reference root is benign, so it is an
13
+ // allowed top-level file alongside the canonical `AGENTS.md` (F5).
14
+ const ALLOWED_TOP_LEVEL_FILES = new Set(['AGENTS.md', 'README.md']);
15
+ const LEGACY_MONOLITHS = ['reference/decision-record.md'];
16
+ async function pathExists(path) {
17
+ try {
18
+ await access(path);
19
+ return true;
20
+ }
21
+ catch (error) {
22
+ const code = error && typeof error === 'object' && 'code' in error
23
+ ? String(error.code)
24
+ : null;
25
+ if (code !== 'ENOENT') {
26
+ throw error;
27
+ }
28
+ return false;
29
+ }
30
+ }
31
+ async function readIfExists(path) {
32
+ try {
33
+ return await readFile(path, 'utf8');
34
+ }
35
+ catch (error) {
36
+ const code = error && typeof error === 'object' && 'code' in error
37
+ ? String(error.code)
38
+ : null;
39
+ if (code !== 'ENOENT') {
40
+ throw error;
41
+ }
42
+ return null;
43
+ }
44
+ }
45
+ async function listDirectoryNames(path) {
46
+ try {
47
+ return (await readdir(path, { withFileTypes: true }))
48
+ .filter((entry) => entry.isDirectory() || entry.isFile())
49
+ .map((entry) => entry.name)
50
+ .sort();
51
+ }
52
+ catch (error) {
53
+ const code = error && typeof error === 'object' && 'code' in error
54
+ ? String(error.code)
55
+ : null;
56
+ if (code !== 'ENOENT') {
57
+ throw error;
58
+ }
59
+ return [];
60
+ }
61
+ }
62
+ async function listMarkdownFiles(path) {
63
+ try {
64
+ return (await readdir(path, { withFileTypes: true }))
65
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
66
+ .map((entry) => entry.name)
67
+ .sort();
68
+ }
69
+ catch (error) {
70
+ const code = error && typeof error === 'object' && 'code' in error
71
+ ? String(error.code)
72
+ : null;
73
+ if (code !== 'ENOENT') {
74
+ throw error;
75
+ }
76
+ return [];
77
+ }
78
+ }
79
+ // Migrated record directories (relative to the repo-reference root) that hold
80
+ // per-record markdown files and must not retain raw template frontmatter after
81
+ // `oat pjm migrate`. `index.md` is the managed index, not an instantiated
82
+ // record, so it is excluded.
83
+ const MIGRATED_RECORD_DIRECTORIES = [
84
+ 'pjm/backlog/items',
85
+ 'pjm/backlog/archived',
86
+ 'reference/decisions',
87
+ ];
88
+ async function collectMigratedTemplateFrontmatterFiles(repoRoot) {
89
+ const offenders = [];
90
+ for (const relativeDir of MIGRATED_RECORD_DIRECTORIES) {
91
+ const fileNames = await listMarkdownFiles(join(repoRoot, relativeDir));
92
+ for (const fileName of fileNames) {
93
+ if (fileName === 'index.md') {
94
+ continue;
95
+ }
96
+ const relativePath = `${relativeDir}/${fileName}`;
97
+ const content = await readIfExists(join(repoRoot, relativeDir, fileName));
98
+ if (content && containsTemplateFrontmatter(content)) {
99
+ offenders.push(relativePath);
100
+ }
101
+ }
102
+ }
103
+ return offenders;
104
+ }
105
+ function containsTemplateFrontmatter(content) {
106
+ const frontmatter = getFrontmatterBlock(content);
107
+ return Boolean(frontmatter &&
108
+ (/\boat_template\s*:/i.test(frontmatter) ||
109
+ /\boat_template_name\s*:/i.test(frontmatter)));
110
+ }
111
+ function checkStatus(missing) {
112
+ return missing.length === 0 ? 'pass' : 'fail';
113
+ }
114
+ function warnStatus(items) {
115
+ return items.length === 0 ? 'pass' : 'warn';
116
+ }
117
+ export async function runPjmDoctorChecks(repoRoot) {
118
+ const checks = [];
119
+ const missingCanonical = [];
120
+ for (const relativePath of CANONICAL_REPO_REFERENCE_PATHS) {
121
+ if (!(await pathExists(join(repoRoot, relativePath)))) {
122
+ missingCanonical.push(relativePath);
123
+ }
124
+ }
125
+ checks.push({
126
+ name: 'pjm:canonical_files',
127
+ description: 'PJM canonical file existence',
128
+ status: checkStatus(missingCanonical),
129
+ message: missingCanonical.length === 0
130
+ ? 'Canonical PJM files are present.'
131
+ : `Missing canonical PJM files: ${missingCanonical.join(', ')}`,
132
+ fix: missingCanonical.length === 0
133
+ ? undefined
134
+ : 'Run `oat pjm init` to restore the canonical PJM scaffold.',
135
+ });
136
+ const templateFrontmatterFiles = [];
137
+ for (const relativePath of CANONICAL_REPO_REFERENCE_PATHS) {
138
+ if (!relativePath.endsWith('.md')) {
139
+ continue;
140
+ }
141
+ const content = await readIfExists(join(repoRoot, relativePath));
142
+ if (content && containsTemplateFrontmatter(content)) {
143
+ templateFrontmatterFiles.push(relativePath);
144
+ }
145
+ }
146
+ // Also scan migrated per-record files (backlog items/archived, decision
147
+ // records). Dogfooding surfaced that `oat pjm migrate` could leave raw
148
+ // `oat_template` frontmatter on migrated records while doctor only inspected
149
+ // the canonical scaffold and reported a false `pass`.
150
+ const migratedTemplateFiles = await collectMigratedTemplateFrontmatterFiles(repoRoot);
151
+ for (const relativePath of migratedTemplateFiles) {
152
+ if (!templateFrontmatterFiles.includes(relativePath)) {
153
+ templateFrontmatterFiles.push(relativePath);
154
+ }
155
+ }
156
+ checks.push({
157
+ name: 'pjm:template_frontmatter',
158
+ description: 'Instantiated PJM files are not raw templates',
159
+ status: checkStatus(templateFrontmatterFiles),
160
+ message: templateFrontmatterFiles.length === 0
161
+ ? 'No template frontmatter found in canonical PJM files.'
162
+ : `Template frontmatter still present in: ${templateFrontmatterFiles.join(', ')}`,
163
+ fix: templateFrontmatterFiles.length === 0
164
+ ? undefined
165
+ : 'Regenerate or manually remove oat_template frontmatter from instantiated files.',
166
+ });
167
+ const topLevelNames = await listDirectoryNames(repoRoot);
168
+ const unknownTopLevel = topLevelNames.filter((name) => !ALLOWED_TOP_LEVEL_DIRECTORIES.has(name) &&
169
+ !ALLOWED_TOP_LEVEL_FILES.has(name));
170
+ checks.push({
171
+ name: 'pjm:top_level_layout',
172
+ description: 'PJM top-level repo-reference layout',
173
+ status: warnStatus(unknownTopLevel),
174
+ message: unknownTopLevel.length === 0
175
+ ? 'No unknown top-level PJM folders or files found.'
176
+ : `Unknown top-level PJM entries: ${unknownTopLevel.join(', ')}`,
177
+ fix: unknownTopLevel.length === 0
178
+ ? undefined
179
+ : 'Move ad-hoc durable references under reference/ or document an allowed top-level folder.',
180
+ });
181
+ const legacyMonoliths = [];
182
+ for (const relativePath of LEGACY_MONOLITHS) {
183
+ if (await pathExists(join(repoRoot, relativePath))) {
184
+ legacyMonoliths.push(relativePath);
185
+ }
186
+ }
187
+ checks.push({
188
+ name: 'pjm:legacy_monoliths',
189
+ description: 'Legacy PJM monolith files',
190
+ status: warnStatus(legacyMonoliths),
191
+ message: legacyMonoliths.length === 0
192
+ ? 'No legacy PJM monolith files found.'
193
+ : `Legacy PJM monoliths still present: ${legacyMonoliths.join(', ')}`,
194
+ fix: legacyMonoliths.length === 0
195
+ ? undefined
196
+ : 'Run `oat decision migrate` or keep the file explicitly documented as legacy.',
197
+ });
198
+ const referenceEntries = await listDirectoryNames(join(repoRoot, 'reference'));
199
+ const looseReferenceFiles = referenceEntries
200
+ .filter((name) => name.endsWith('.md'))
201
+ .filter((name) => name !== 'AGENTS.md' &&
202
+ name !== 'decision-record.md' &&
203
+ name !== 'roadmap.md' &&
204
+ name !== 'current-state.md')
205
+ .map((name) => `reference/${name}`);
206
+ checks.push({
207
+ name: 'pjm:loose_reference_files',
208
+ description: 'Loose reference files outside documented destinations',
209
+ status: warnStatus(looseReferenceFiles),
210
+ message: looseReferenceFiles.length === 0
211
+ ? 'No loose reference files found.'
212
+ : `Loose reference files found: ${looseReferenceFiles.join(', ')}`,
213
+ fix: looseReferenceFiles.length === 0
214
+ ? undefined
215
+ : 'Move loose files into a documented reference subfolder or add a destination guide.',
216
+ });
217
+ const secondRoadmaps = [];
218
+ for (const relativePath of [
219
+ 'reference/roadmap.md',
220
+ 'reference/current-state.md',
221
+ ]) {
222
+ if (await pathExists(join(repoRoot, relativePath))) {
223
+ secondRoadmaps.push(relativePath);
224
+ }
225
+ }
226
+ checks.push({
227
+ name: 'pjm:second_roadmap',
228
+ description: 'Duplicate active PJM files under reference',
229
+ status: warnStatus(secondRoadmaps),
230
+ message: secondRoadmaps.length === 0
231
+ ? 'No duplicate roadmap/current-state files found under reference/.'
232
+ : `Duplicate active PJM files under reference/: ${secondRoadmaps.join(', ')}`,
233
+ fix: secondRoadmaps.length === 0
234
+ ? undefined
235
+ : 'Move active operational docs to pjm/ and leave reference/ for durable append-mostly artifacts.',
236
+ });
237
+ return checks;
238
+ }
@@ -1,13 +1,20 @@
1
1
  import { buildCommandContext } from '../../app/command-context.js';
2
+ import { readOatConfig } from '../../config/oat-config.js';
2
3
  import { resolveAssetsRoot } from '../../fs/assets.js';
3
4
  import { resolveProjectRoot } from '../../fs/paths.js';
4
5
  import { Command } from 'commander';
6
+ import { runPjmDoctorChecks } from './doctor.js';
5
7
  import { initializeRepoReference } from './init.js';
8
+ import { migratePjmRepo, readPjmMigrationPrompt } from './migrate.js';
6
9
  interface PjmCommandDependencies {
7
10
  buildCommandContext: typeof buildCommandContext;
8
11
  resolveProjectRoot: typeof resolveProjectRoot;
9
12
  resolveAssetsRoot: typeof resolveAssetsRoot;
13
+ readOatConfig: typeof readOatConfig;
10
14
  initializeRepoReference: typeof initializeRepoReference;
15
+ runPjmDoctorChecks: typeof runPjmDoctorChecks;
16
+ migratePjmRepo: typeof migratePjmRepo;
17
+ readPjmMigrationPrompt: typeof readPjmMigrationPrompt;
11
18
  }
12
19
  export declare function createPjmCommand(overrides?: Partial<PjmCommandDependencies>): Command;
13
20
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AAMjD,UAAU,sBAAsB;IAC9B,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;CACzD;AAqBD,wBAAgB,gBAAgB,CAC9B,SAAS,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAC9C,OAAO,CA+DT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAiBnE,UAAU,sBAAsB;IAC9B,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACvD;AA6FD,wBAAgB,gBAAgB,CAC9B,SAAS,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAC9C,OAAO,CAkJT"}