runlist 0.0.0 → 0.94.2

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 (167) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1112 -6
  3. package/assets/app/app.css +283 -0
  4. package/assets/app/app.mjs +381 -0
  5. package/assets/app/block-editor.mjs +182 -0
  6. package/assets/app/block-model.mjs +52 -0
  7. package/assets/app/document-create.mjs +86 -0
  8. package/assets/app/document-lifecycle.mjs +36 -0
  9. package/assets/app/document-stages.mjs +22 -0
  10. package/assets/app/document-views.mjs +33 -0
  11. package/assets/app/document-yardstick.mjs +258 -0
  12. package/assets/app/editor-navigation.mjs +51 -0
  13. package/assets/app/filing-navigation.mjs +138 -0
  14. package/assets/app/git-changes.mjs +80 -0
  15. package/assets/app/git-commit.mjs +46 -0
  16. package/assets/app/index.html +70 -0
  17. package/assets/app/library-navigation.mjs +93 -0
  18. package/assets/app/outline.mjs +18 -0
  19. package/assets/app/quick-navigation.mjs +52 -0
  20. package/assets/app/record-navigation.mjs +78 -0
  21. package/assets/app/recovery-center.mjs +53 -0
  22. package/assets/app/semantic-search.mjs +14 -0
  23. package/assets/app/settings.mjs +15 -0
  24. package/assets/app/shared.mjs +104 -0
  25. package/assets/app/stage-source.mjs +75 -0
  26. package/assets/app/template-editor.mjs +47 -0
  27. package/assets/app/theme.mjs +25 -0
  28. package/assets/app/transport.mjs +43 -0
  29. package/assets/contracts/source-editing-v1.md +232 -0
  30. package/assets/opencode/plugin.js +162 -0
  31. package/assets/schemas/runlist-record-v1.schema.json +912 -0
  32. package/bin/dotmd.mjs +5 -0
  33. package/bin/runlist.mjs +2714 -0
  34. package/package.json +53 -6
  35. package/plugins/runlist-codex/.codex-plugin/plugin.json +18 -0
  36. package/plugins/runlist-codex/bin/runlist-hook +86 -0
  37. package/plugins/runlist-codex/hooks/hooks.json +16 -0
  38. package/plugins/runlist-codex/skills/runlist/SKILL.md +25 -0
  39. package/runlist.config.example.mjs +370 -0
  40. package/scripts/postinstall.mjs +56 -0
  41. package/src/agent-context.mjs +201 -0
  42. package/src/ai.mjs +30 -0
  43. package/src/app-create.mjs +169 -0
  44. package/src/app-filing.mjs +139 -0
  45. package/src/app-git-commits.mjs +48 -0
  46. package/src/app-git.mjs +180 -0
  47. package/src/app-library.mjs +152 -0
  48. package/src/app-lifecycle-worker.mjs +12 -0
  49. package/src/app-lifecycle.mjs +79 -0
  50. package/src/app-records.mjs +134 -0
  51. package/src/app-search.mjs +80 -0
  52. package/src/app-semantic-search.mjs +105 -0
  53. package/src/app-service.mjs +208 -0
  54. package/src/app-yardstick.mjs +269 -0
  55. package/src/app.mjs +102 -0
  56. package/src/atomic-mutation.mjs +1736 -0
  57. package/src/baton.mjs +435 -0
  58. package/src/body-link.mjs +48 -0
  59. package/src/bulk-tag.mjs +174 -0
  60. package/src/check-collapse.mjs +75 -0
  61. package/src/claude-commands.mjs +75 -0
  62. package/src/cli-editor.mjs +8 -0
  63. package/src/code-refs.mjs +545 -0
  64. package/src/codex-integration.mjs +81 -0
  65. package/src/color.mjs +14 -0
  66. package/src/commands.mjs +374 -0
  67. package/src/completions.mjs +93 -0
  68. package/src/config-edit.mjs +606 -0
  69. package/src/config.mjs +705 -0
  70. package/src/decision-action.mjs +58 -0
  71. package/src/decision.mjs +220 -0
  72. package/src/decisions.mjs +787 -0
  73. package/src/deps.mjs +317 -0
  74. package/src/desktop-install.mjs +158 -0
  75. package/src/desktop-runtime.mjs +4 -0
  76. package/src/desktop.mjs +25 -0
  77. package/src/diff.mjs +101 -0
  78. package/src/doctor.mjs +591 -0
  79. package/src/durable-rename.mjs +55 -0
  80. package/src/errors-read.mjs +44 -0
  81. package/src/export.mjs +496 -0
  82. package/src/extractors.mjs +101 -0
  83. package/src/filing.mjs +255 -0
  84. package/src/fix-membership.mjs +134 -0
  85. package/src/fix-refs.mjs +174 -0
  86. package/src/flags.mjs +318 -0
  87. package/src/frontmatter-fix.mjs +195 -0
  88. package/src/frontmatter.mjs +252 -0
  89. package/src/git-commit-filters.mjs +32 -0
  90. package/src/git-commit-protocol.mjs +198 -0
  91. package/src/git-commit-signing.mjs +75 -0
  92. package/src/git-commit-store.mjs +26 -0
  93. package/src/git-commit-support.mjs +16 -0
  94. package/src/git-commit-worker.mjs +32 -0
  95. package/src/git.mjs +909 -0
  96. package/src/glossary-check.mjs +35 -0
  97. package/src/glossary.mjs +243 -0
  98. package/src/graph.mjs +298 -0
  99. package/src/guard.mjs +488 -0
  100. package/src/health.mjs +212 -0
  101. package/src/hints.mjs +129 -0
  102. package/src/host-integration.mjs +339 -0
  103. package/src/hub-membership.mjs +284 -0
  104. package/src/hub.mjs +296 -0
  105. package/src/hud.mjs +436 -0
  106. package/src/index-file.mjs +163 -0
  107. package/src/index.mjs +478 -0
  108. package/src/init.mjs +512 -0
  109. package/src/install.mjs +222 -0
  110. package/src/journal-read.mjs +116 -0
  111. package/src/journal.mjs +472 -0
  112. package/src/lifecycle.mjs +1444 -0
  113. package/src/lint.mjs +386 -0
  114. package/src/managed-path.mjs +192 -0
  115. package/src/markdown-code-spans.mjs +58 -0
  116. package/src/migrate-prompts.mjs +171 -0
  117. package/src/migrate-template.mjs +170 -0
  118. package/src/migrate.mjs +90 -0
  119. package/src/misuse-read.mjs +61 -0
  120. package/src/model-request.mjs +33 -0
  121. package/src/model.mjs +523 -0
  122. package/src/modules.mjs +355 -0
  123. package/src/naming.mjs +55 -0
  124. package/src/native-action.mjs +59 -0
  125. package/src/native-record.mjs +244 -0
  126. package/src/new.mjs +1321 -0
  127. package/src/output-identity.mjs +111 -0
  128. package/src/parent-plan.mjs +58 -0
  129. package/src/parse-cache.mjs +99 -0
  130. package/src/path-containment.mjs +15 -0
  131. package/src/pickup-card.mjs +293 -0
  132. package/src/pickup.mjs +671 -0
  133. package/src/prompt.mjs +25 -0
  134. package/src/prompts.mjs +585 -0
  135. package/src/public-inspection.mjs +19 -0
  136. package/src/query.mjs +977 -0
  137. package/src/record-action.mjs +11 -0
  138. package/src/record-create.mjs +82 -0
  139. package/src/reference-planner.mjs +388 -0
  140. package/src/reference-values.mjs +11 -0
  141. package/src/rename.mjs +107 -0
  142. package/src/render.mjs +678 -0
  143. package/src/roadmap.mjs +184 -0
  144. package/src/runlist.mjs +944 -0
  145. package/src/section.mjs +225 -0
  146. package/src/semantic-search-client.mjs +58 -0
  147. package/src/ship.mjs +166 -0
  148. package/src/show.mjs +101 -0
  149. package/src/skill-drift.mjs +98 -0
  150. package/src/source-editor.mjs +491 -0
  151. package/src/stages.mjs +73 -0
  152. package/src/state-migration.mjs +123 -0
  153. package/src/stats.mjs +200 -0
  154. package/src/status-metadata.mjs +87 -0
  155. package/src/statuses.mjs +721 -0
  156. package/src/summary.mjs +74 -0
  157. package/src/surfaces.mjs +28 -0
  158. package/src/sync-status.mjs +316 -0
  159. package/src/template-store.mjs +62 -0
  160. package/src/update.mjs +338 -0
  161. package/src/use.mjs +58 -0
  162. package/src/util.mjs +337 -0
  163. package/src/validate.mjs +795 -0
  164. package/src/watch.mjs +56 -0
  165. package/src/xref.mjs +406 -0
  166. package/src/yardstick-command.mjs +178 -0
  167. package/src/yardstick.mjs +112 -0
@@ -0,0 +1,184 @@
1
+ import { buildRoadmapIndex, hubLabel } from './runlist.mjs';
2
+ import { resolveDocArg } from './index.mjs';
3
+ import { toRepoPath, die } from './util.mjs';
4
+ import { bold, dim, green } from './color.mjs';
5
+
6
+ // Strip ANSI for width math (query.mjs has its own copy but doesn't export it).
7
+ function visibleLen(s) {
8
+ // eslint-disable-next-line no-control-regex
9
+ return s.replace(/\x1b\[[0-9;]*m/g, '').length;
10
+ }
11
+
12
+ // Structured form of one roadmap, shared by every `--json` path.
13
+ function roadmapJson(info) {
14
+ return {
15
+ path: info.doc.path,
16
+ title: info.doc.title ?? null,
17
+ status: info.doc.status ?? null,
18
+ childCount: info.childCount,
19
+ grandTotal: info.grandTotal,
20
+ grandDone: info.grandDone,
21
+ grandParked: info.grandParked,
22
+ children: info.children.map(c => ({
23
+ path: c.path,
24
+ label: hubLabel(c.doc),
25
+ kind: c.kind,
26
+ total: c.total,
27
+ doneCount: c.doneCount,
28
+ parkedCount: c.parkedCount,
29
+ nextPath: c.nextPath,
30
+ nextLabel: c.nextLabel,
31
+ })),
32
+ };
33
+ }
34
+
35
+ // One child-runlist row: label · done/total · next → · one-line descriptor.
36
+ function roadmapChildRow(child, maxSlug, maxWidth) {
37
+ const label = hubLabel(child.doc).padEnd(maxSlug);
38
+ const roll = `${child.doneCount}/${child.total}`.padStart(7);
39
+ const next = child.nextLabel ? `${green('→')} ${child.nextLabel} ` : '';
40
+ const status = child.doc.status && child.doc.status !== 'active' ? ` ${dim(`[${child.doc.status}]`)}` : '';
41
+ const desc = (child.doc.nextStep || child.doc.currentState || child.doc.title || '').replace(/\s+/g, ' ').trim();
42
+ const left = ` ${label} ${dim(roll)} `;
43
+ const budget = Math.max(10, maxWidth - visibleLen(left) - visibleLen(next) - visibleLen(status) - 2);
44
+ const descR = desc.length > budget ? desc.slice(0, Math.max(0, budget - 3)) + '...' : desc;
45
+ return `${left}${next}${dim(descR)}${status}`;
46
+ }
47
+
48
+ // Full single-roadmap view: header with the recursive grand total, then one row
49
+ // per child runlist (its own done/total + that runlist's next pickup).
50
+ function renderRoadmap(info, maxWidth) {
51
+ const lines = [];
52
+ const pct = info.grandTotal > 0 ? Math.round((info.grandDone / info.grandTotal) * 100) : 0;
53
+ const parked = info.grandParked > 0 ? ` ${dim(`${info.grandParked} parked`)}` : '';
54
+ lines.push(`${bold(`Roadmap: ${info.doc.title || hubLabel(info.doc)}`)} ${bold(`${info.grandDone}/${info.grandTotal}`)} ${dim(`(${pct}%)`)}${parked}`);
55
+ if (info.children.length === 0) {
56
+ lines.push(dim(' (no child runlists — wire runlists into related_plans:)'));
57
+ return lines.join('\n') + '\n';
58
+ }
59
+ const maxSlug = Math.min(34, Math.max(...info.children.map(c => hubLabel(c.doc).length)));
60
+ for (const c of info.children) lines.push(roadmapChildRow(c, maxSlug, maxWidth));
61
+ return lines.join('\n') + '\n';
62
+ }
63
+
64
+ const NO_ROADMAPS = 'No roadmaps found. A roadmap is a plan with `execution_mode: roadmap` that composes runlists.\nScaffold one: runlist new plan <name> --roadmap\n';
65
+
66
+ // `runlist roadmaps` — the dashboard over every roadmap hub (mirrors `runlist
67
+ // runlists`): one row per roadmap with its recursive grand total + child count.
68
+ export function runRoadmaps(index, argv, config) {
69
+ const json = argv.includes('--json');
70
+ const roadmaps = [...buildRoadmapIndex(index, config).values()]
71
+ .sort((a, b) => (b.doc.daysSinceUpdate ?? 0) - (a.doc.daysSinceUpdate ?? 0));
72
+
73
+ if (json) {
74
+ process.stdout.write(JSON.stringify({ count: roadmaps.length, roadmaps: roadmaps.map(roadmapJson) }, null, 2) + '\n');
75
+ return;
76
+ }
77
+ if (roadmaps.length === 0) {
78
+ process.stdout.write(NO_ROADMAPS);
79
+ return;
80
+ }
81
+ process.stdout.write(`\n${bold(`Roadmaps (${roadmaps.length})`)}\n`);
82
+ const maxSlug = Math.min(34, Math.max(...roadmaps.map(r => hubLabel(r.doc).length)));
83
+ for (const info of roadmaps) {
84
+ const slug = hubLabel(info.doc).padEnd(maxSlug);
85
+ const age = info.doc.daysSinceUpdate != null ? `${info.doc.daysSinceUpdate}d` : '—';
86
+ const roll = `${info.grandDone}/${info.grandTotal}`.padStart(8);
87
+ const kids = dim(`${info.childCount} ${info.childCount === 1 ? 'runlist' : 'runlists'}`);
88
+ process.stdout.write(` ${slug} ${dim(age.padStart(4))} ${dim(roll)} ${kids}\n`);
89
+ }
90
+ process.stdout.write('\n');
91
+ }
92
+
93
+ // `runlist roadmap [<hub>]` — the single-roadmap view. No arg: show the sole
94
+ // roadmap, or fall back to the `roadmaps` dashboard when there are several.
95
+ export function runRoadmap(index, argv, config) {
96
+ const json = argv.includes('--json');
97
+ const positional = argv.filter(a => !a.startsWith('-') && a !== 'next');
98
+ const hubArg = positional[0] ?? null;
99
+
100
+ const roadmaps = buildRoadmapIndex(index, config);
101
+
102
+ if (hubArg) {
103
+ const abs = resolveDocArg(hubArg, config, { dieOnMiss: false });
104
+ if (!abs) die(`Roadmap not found: ${hubArg}`);
105
+ const repoPath = toRepoPath(abs, config.repoRoot);
106
+ const info = roadmaps.get(repoPath);
107
+ if (!info) {
108
+ die(`${repoPath} is not a roadmap hub (needs \`execution_mode: roadmap\`).\n` +
109
+ `See \`runlist roadmaps\` for roadmaps, or \`runlist runlist ${hubArg}\` if it's a runlist.`);
110
+ }
111
+ if (json) { process.stdout.write(JSON.stringify(roadmapJson(info), null, 2) + '\n'); return; }
112
+ process.stdout.write('\n' + renderRoadmap(info, process.stdout.columns || 100) + '\n');
113
+ return;
114
+ }
115
+
116
+ if (roadmaps.size === 0) {
117
+ if (json) { process.stdout.write(JSON.stringify({ count: 0, roadmaps: [] }, null, 2) + '\n'); return; }
118
+ process.stdout.write(NO_ROADMAPS);
119
+ return;
120
+ }
121
+ if (roadmaps.size === 1) {
122
+ const info = [...roadmaps.values()][0];
123
+ if (json) { process.stdout.write(JSON.stringify(roadmapJson(info), null, 2) + '\n'); return; }
124
+ process.stdout.write('\n' + renderRoadmap(info, process.stdout.columns || 100) + '\n');
125
+ return;
126
+ }
127
+ // Several roadmaps and no target named → the dashboard.
128
+ return runRoadmaps(index, argv, config);
129
+ }
130
+
131
+ // Resolve which roadmap a `next` / pickup verb targets: an explicit hub arg, or
132
+ // the sole roadmap when there's exactly one. Dies with an actionable message
133
+ // otherwise (none → scaffold; several → name one).
134
+ function resolveRoadmapTarget(roadmaps, hubArg, config) {
135
+ if (hubArg) {
136
+ const abs = resolveDocArg(hubArg, config, { dieOnMiss: false });
137
+ if (!abs) die(`Roadmap not found: ${hubArg}`);
138
+ const info = roadmaps.get(toRepoPath(abs, config.repoRoot));
139
+ if (!info) die(`${hubArg} is not a roadmap hub (needs \`execution_mode: roadmap\`).`);
140
+ return info;
141
+ }
142
+ if (roadmaps.size === 0) die('No roadmaps found. Scaffold one: runlist new plan <name> --roadmap');
143
+ if (roadmaps.size > 1) {
144
+ const listed = [...roadmaps.values()].map(r => ` ${hubLabel(r.doc)}`).join('\n');
145
+ die(`Multiple roadmaps — name one: runlist roadmap next <hub>\n${listed}`);
146
+ }
147
+ return [...roadmaps.values()][0];
148
+ }
149
+
150
+ // `runlist roadmap [<hub>] next` — the cross-runlist next-pickup. Walk the
151
+ // roadmap's child runlists in `related_plans` (priority) order and open the FIRST
152
+ // startable plan found inside any of them — the "what do I do next across the
153
+ // whole roadmap?" verb. Each child's `nextPath` was already resolved by
154
+ // buildRoadmapIndex (sprint via its runlist order, coordination via its body
155
+ // order, a leaf-plan child = itself). When nothing is startable anywhere, list
156
+ // each child runlist with why, so the blocker is visible.
157
+ export async function runRoadmapNext(index, argv, config, opts = {}) {
158
+ const json = argv.includes('--json');
159
+ const hubArg = argv.find(a => !a.startsWith('-')) ?? null;
160
+ const roadmaps = buildRoadmapIndex(index, config);
161
+ const info = resolveRoadmapTarget(roadmaps, hubArg, config);
162
+
163
+ const target = info.children.find(c => c.nextPath);
164
+ if (!target) {
165
+ const lines = info.children.map(c => {
166
+ const state = c.total === 0 ? 'empty'
167
+ : c.doneCount >= c.total ? 'all done'
168
+ : c.parkedCount > 0 ? `${c.parkedCount} parked` : 'no pickup-able child';
169
+ return ` ${hubLabel(c.doc)} (${c.doneCount}/${c.total} · ${state})`;
170
+ }).join('\n');
171
+ die(`No pickup-able plan across roadmap ${hubLabel(info.doc)} — every child runlist is done or parked:\n${lines}\n` +
172
+ `Unstick one (e.g. \`runlist set active <child>\`), or inspect a runlist: \`runlist runlist <hub>\`.`);
173
+ }
174
+
175
+ if (!json) {
176
+ process.stdout.write(dim(`roadmap ${hubLabel(info.doc)} → ${hubLabel(target.doc)} → next pickup:\n`));
177
+ }
178
+ const { startPlan } = await import('./lifecycle.mjs');
179
+ const startArgs = [target.nextPath];
180
+ if (argv.includes('--full')) startArgs.push('--full');
181
+ if (argv.includes('--no-index')) startArgs.push('--no-index');
182
+ if (json) startArgs.push('--json');
183
+ await startPlan(startArgs, config, opts);
184
+ }