mainflow 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +324 -0
- package/dist/dist-BktkzRuK.js +1615 -0
- package/dist/dist-D2NK-QQP.js +511 -0
- package/dist/facts.d.ts +518 -0
- package/dist/facts.js +516 -0
- package/dist/hooks.d.ts +41 -0
- package/dist/hooks.js +171 -0
- package/dist/host.d.ts +24 -0
- package/dist/host.js +89 -0
- package/dist/launch-BR70uSMc.js +584 -0
- package/dist/launch.d.ts +44 -0
- package/dist/launch.js +2 -0
- package/dist/web/assets/index-BshtZ25f.js +78 -0
- package/dist/web/assets/index-qO7SaeFe.css +1 -0
- package/dist/web/assets/index.browser-C_4gp6WJ.js +169 -0
- package/dist/web/index.html +13 -0
- package/package.json +48 -0
package/dist/facts.js
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import { C as TASK_SECTIONS, S as TASK_REQUIRED_SECTIONS, _ as PRIORITIES, a as DECISION_STATUS, b as SESSION_STATUS, c as FINDING_STATUS, d as ISSUE_SECTIONS, f as ISSUE_STATUS, g as MERGE_STATES, h as MAINLINE_STATUS, i as DECISION_SECTIONS, l as FORMAT_VERSION, m as MAINLINE_SECTIONS, n as CLOSED_STATUS, o as DEFAULT_CATEGORIES, p as LINK_RELS, r as DECIDERS, s as FINDING_SECTIONS, t as CHECKLIST_REF, u as ID_PATTERNS, w as WORK_STATUS, x as SLUG } from "./dist-D2NK-QQP.js";
|
|
2
|
+
//#region src/facts.ts
|
|
3
|
+
const COMMAND_SPECS = {
|
|
4
|
+
init: {
|
|
5
|
+
usage: "init <hub-name>",
|
|
6
|
+
summary: "Create .mainflow/ in the current directory",
|
|
7
|
+
args: 1,
|
|
8
|
+
needsHub: false
|
|
9
|
+
},
|
|
10
|
+
status: {
|
|
11
|
+
usage: "status [--all]",
|
|
12
|
+
summary: "List mainlines with checklist progress",
|
|
13
|
+
args: 0,
|
|
14
|
+
needsHub: true
|
|
15
|
+
},
|
|
16
|
+
check: {
|
|
17
|
+
usage: "check",
|
|
18
|
+
summary: "Validate every file under .mainflow/",
|
|
19
|
+
args: 0,
|
|
20
|
+
needsHub: true
|
|
21
|
+
},
|
|
22
|
+
migrate: {
|
|
23
|
+
usage: "migrate [--dry-run]",
|
|
24
|
+
summary: "Convert the hub to the data format this CLI reads; --dry-run lists the changes without writing",
|
|
25
|
+
args: 0,
|
|
26
|
+
needsHub: true
|
|
27
|
+
},
|
|
28
|
+
ui: {
|
|
29
|
+
usage: "ui [--port <port>] [--no-open]",
|
|
30
|
+
summary: "Open the web interface at {hub}.mainflow.localhost, starting it on a free port if it is not running",
|
|
31
|
+
args: 0,
|
|
32
|
+
needsHub: true
|
|
33
|
+
},
|
|
34
|
+
"repo add": {
|
|
35
|
+
usage: "repo add <name> <path>",
|
|
36
|
+
summary: "Register a repository that tasks can point at (path relative to the hub root)",
|
|
37
|
+
args: 2,
|
|
38
|
+
needsHub: true
|
|
39
|
+
},
|
|
40
|
+
"hub add": {
|
|
41
|
+
usage: "hub add <name> <path>",
|
|
42
|
+
summary: "Register another hub that references may point into as {name}:m001 (path relative to the hub root)",
|
|
43
|
+
args: 2,
|
|
44
|
+
needsHub: true
|
|
45
|
+
},
|
|
46
|
+
"session start": {
|
|
47
|
+
usage: "session start [--agent <agent>] [--id <id>] [--delegated-from <session>] [--handoff-from <session>]",
|
|
48
|
+
summary: "Start a session; --handoff-from carries over its unfinished actions",
|
|
49
|
+
args: 0,
|
|
50
|
+
needsHub: true
|
|
51
|
+
},
|
|
52
|
+
"session show": {
|
|
53
|
+
usage: "session show [session]",
|
|
54
|
+
summary: "Print the briefing a hook would give this session",
|
|
55
|
+
args: 0,
|
|
56
|
+
optionalArgs: 1,
|
|
57
|
+
needsHub: true
|
|
58
|
+
},
|
|
59
|
+
"session set": {
|
|
60
|
+
usage: "session set <session> --status <status>",
|
|
61
|
+
summary: "Change session status",
|
|
62
|
+
args: 1,
|
|
63
|
+
needsHub: true
|
|
64
|
+
},
|
|
65
|
+
"session end": {
|
|
66
|
+
usage: "session end [session]",
|
|
67
|
+
summary: "Mark a session as ended",
|
|
68
|
+
args: 0,
|
|
69
|
+
optionalArgs: 1,
|
|
70
|
+
needsHub: true
|
|
71
|
+
},
|
|
72
|
+
"session archive": {
|
|
73
|
+
usage: "session archive <session>",
|
|
74
|
+
summary: "Hide a session from default views; the status stays as it is",
|
|
75
|
+
args: 1,
|
|
76
|
+
needsHub: true
|
|
77
|
+
},
|
|
78
|
+
"session unarchive": {
|
|
79
|
+
usage: "session unarchive <session>",
|
|
80
|
+
summary: "Show an archived session again",
|
|
81
|
+
args: 1,
|
|
82
|
+
needsHub: true
|
|
83
|
+
},
|
|
84
|
+
"action add": {
|
|
85
|
+
usage: "action add <text> --serves <m/t#c>[,<m/t#c>] [--before <a>] [--session <session>]",
|
|
86
|
+
summary: "Add an action to the session queue",
|
|
87
|
+
args: 1,
|
|
88
|
+
needsHub: true
|
|
89
|
+
},
|
|
90
|
+
"action set": {
|
|
91
|
+
usage: "action set <a|session#a> [--status] [--text] [--serves] [--before <a>] [--note <text>] [--session <session>]",
|
|
92
|
+
summary: "Change, reorder or finish an action",
|
|
93
|
+
args: 1,
|
|
94
|
+
needsHub: true
|
|
95
|
+
},
|
|
96
|
+
hook: {
|
|
97
|
+
usage: "hook <platform> <event>",
|
|
98
|
+
summary: "Handle a host hook event read from stdin, e.g. hook claude-code session-start",
|
|
99
|
+
args: 2,
|
|
100
|
+
needsHub: false
|
|
101
|
+
},
|
|
102
|
+
"new mainline": {
|
|
103
|
+
usage: "new mainline <slug> --title <title>",
|
|
104
|
+
summary: "Create mainline.md with the next id and the section template; write the rest in the file",
|
|
105
|
+
args: 1,
|
|
106
|
+
needsHub: true
|
|
107
|
+
},
|
|
108
|
+
"new task": {
|
|
109
|
+
usage: "new task <m> <slug> --title <title> [--kind phase|branch] [--parent <t>] [--repo <name>]",
|
|
110
|
+
summary: "Create task.md with the next id and the section template; write the rest in the file",
|
|
111
|
+
args: 2,
|
|
112
|
+
needsHub: true
|
|
113
|
+
},
|
|
114
|
+
"new decision": {
|
|
115
|
+
usage: "new decision <m> <slug> --title <title> [--status proposed] [--by user|ai|relay] [--affects <m/t or m/t#c>,...]",
|
|
116
|
+
summary: "Create a decision file; proposed while the question is still open",
|
|
117
|
+
args: 2,
|
|
118
|
+
needsHub: true
|
|
119
|
+
},
|
|
120
|
+
"new issue": {
|
|
121
|
+
usage: "new issue <slug> --title <title> [--origin <ref>]",
|
|
122
|
+
summary: "Create an issue file for a follow-up that must outlive its mainline",
|
|
123
|
+
args: 1,
|
|
124
|
+
needsHub: true
|
|
125
|
+
},
|
|
126
|
+
"new finding": {
|
|
127
|
+
usage: "new finding <slug> --title <title> [--origin <ref>] [--labels a,b]",
|
|
128
|
+
summary: "Create a finding file for a lesson the next task should read",
|
|
129
|
+
args: 1,
|
|
130
|
+
needsHub: true
|
|
131
|
+
},
|
|
132
|
+
"mainline set": {
|
|
133
|
+
usage: "mainline set <m> --status <status>",
|
|
134
|
+
summary: "Change status; done needs every criterion met and no proposed decision",
|
|
135
|
+
args: 1,
|
|
136
|
+
needsHub: true
|
|
137
|
+
},
|
|
138
|
+
"mainline archive": {
|
|
139
|
+
usage: "mainline archive <m>",
|
|
140
|
+
summary: "Hide a mainline from default lists",
|
|
141
|
+
args: 1,
|
|
142
|
+
needsHub: true
|
|
143
|
+
},
|
|
144
|
+
"mainline unarchive": {
|
|
145
|
+
usage: "mainline unarchive <m>",
|
|
146
|
+
summary: "Show an archived mainline again",
|
|
147
|
+
args: 1,
|
|
148
|
+
needsHub: true
|
|
149
|
+
},
|
|
150
|
+
"criterion check": {
|
|
151
|
+
usage: "criterion check <m#r> --evidence <evidence>",
|
|
152
|
+
summary: "Mark a criterion as met",
|
|
153
|
+
args: 1,
|
|
154
|
+
needsHub: true
|
|
155
|
+
},
|
|
156
|
+
"criterion uncheck": {
|
|
157
|
+
usage: "criterion uncheck <m#r>",
|
|
158
|
+
summary: "Mark a criterion as not met",
|
|
159
|
+
args: 1,
|
|
160
|
+
needsHub: true
|
|
161
|
+
},
|
|
162
|
+
"task set": {
|
|
163
|
+
usage: "task set <m/t> [--status] [--reason --waiting-for --signal] [--repo] [--branch --worktree --base --merge]",
|
|
164
|
+
summary: "Change status, repository or branch state; --status blocked needs --reason",
|
|
165
|
+
args: 1,
|
|
166
|
+
needsHub: true
|
|
167
|
+
},
|
|
168
|
+
"item check": {
|
|
169
|
+
usage: "item check <m/t#c> --evidence <evidence>",
|
|
170
|
+
summary: "Check an item with evidence",
|
|
171
|
+
args: 1,
|
|
172
|
+
needsHub: true
|
|
173
|
+
},
|
|
174
|
+
"item uncheck": {
|
|
175
|
+
usage: "item uncheck <m/t#c>",
|
|
176
|
+
summary: "Uncheck an item",
|
|
177
|
+
args: 1,
|
|
178
|
+
needsHub: true
|
|
179
|
+
},
|
|
180
|
+
"decision accept": {
|
|
181
|
+
usage: "decision accept <m/d> [--by user|ai|relay]",
|
|
182
|
+
summary: "Settle a proposed decision; the items it affects stop waiting for it",
|
|
183
|
+
args: 1,
|
|
184
|
+
needsHub: true
|
|
185
|
+
},
|
|
186
|
+
"item drop": {
|
|
187
|
+
usage: "item drop <m/t#c> [--by <ref>] [--note <text>]",
|
|
188
|
+
summary: "Mark an item as no longer needed, naming what replaced it",
|
|
189
|
+
args: 1,
|
|
190
|
+
needsHub: true
|
|
191
|
+
},
|
|
192
|
+
"issue plan": {
|
|
193
|
+
usage: "issue plan <i> <m/t>",
|
|
194
|
+
summary: "Schedule an issue into the task that will carry it out",
|
|
195
|
+
args: 2,
|
|
196
|
+
needsHub: true
|
|
197
|
+
},
|
|
198
|
+
"issue close": {
|
|
199
|
+
usage: "issue close <i> --by <what closed it>",
|
|
200
|
+
summary: "Close an issue",
|
|
201
|
+
args: 1,
|
|
202
|
+
needsHub: true
|
|
203
|
+
},
|
|
204
|
+
"issue reopen": {
|
|
205
|
+
usage: "issue reopen <i>",
|
|
206
|
+
summary: "Reopen an issue",
|
|
207
|
+
args: 1,
|
|
208
|
+
needsHub: true
|
|
209
|
+
},
|
|
210
|
+
"issue archive": {
|
|
211
|
+
usage: "issue archive <i>",
|
|
212
|
+
summary: "Hide an issue from default views; the status stays as it is",
|
|
213
|
+
args: 1,
|
|
214
|
+
needsHub: true
|
|
215
|
+
},
|
|
216
|
+
"issue unarchive": {
|
|
217
|
+
usage: "issue unarchive <i>",
|
|
218
|
+
summary: "Show an archived issue again",
|
|
219
|
+
args: 1,
|
|
220
|
+
needsHub: true
|
|
221
|
+
},
|
|
222
|
+
"issue list": {
|
|
223
|
+
usage: "issue list [--all]",
|
|
224
|
+
summary: "List open and planned issues (--all includes closed)",
|
|
225
|
+
args: 0,
|
|
226
|
+
needsHub: true
|
|
227
|
+
},
|
|
228
|
+
"finding set": {
|
|
229
|
+
usage: "finding set <f> --status valid|obsolete",
|
|
230
|
+
summary: "Mark a finding obsolete or valid again",
|
|
231
|
+
args: 1,
|
|
232
|
+
needsHub: true
|
|
233
|
+
},
|
|
234
|
+
"finding archive": {
|
|
235
|
+
usage: "finding archive <f>",
|
|
236
|
+
summary: "Hide a finding from default views; the status stays as it is",
|
|
237
|
+
args: 1,
|
|
238
|
+
needsHub: true
|
|
239
|
+
},
|
|
240
|
+
"finding unarchive": {
|
|
241
|
+
usage: "finding unarchive <f>",
|
|
242
|
+
summary: "Show an archived finding again",
|
|
243
|
+
args: 1,
|
|
244
|
+
needsHub: true
|
|
245
|
+
},
|
|
246
|
+
"finding list": {
|
|
247
|
+
usage: "finding list [--all]",
|
|
248
|
+
summary: "List valid findings (--all includes obsolete)",
|
|
249
|
+
args: 0,
|
|
250
|
+
needsHub: true
|
|
251
|
+
},
|
|
252
|
+
"ops add": {
|
|
253
|
+
usage: "ops add --target <system> --op <operation> --result <result> [--ref <ref>]",
|
|
254
|
+
summary: "Append an external operation to the audit log",
|
|
255
|
+
args: 0,
|
|
256
|
+
needsHub: true
|
|
257
|
+
},
|
|
258
|
+
"ops list": {
|
|
259
|
+
usage: "ops list [--month YYYY-MM]",
|
|
260
|
+
summary: "List logged external operations",
|
|
261
|
+
args: 0,
|
|
262
|
+
needsHub: true
|
|
263
|
+
},
|
|
264
|
+
"decision supersede": {
|
|
265
|
+
usage: "decision supersede <m/d> --by <d>",
|
|
266
|
+
summary: "Mark a decision as replaced by another",
|
|
267
|
+
args: 1,
|
|
268
|
+
needsHub: true
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const OPTIONS = {
|
|
272
|
+
title: { type: "string" },
|
|
273
|
+
status: { type: "string" },
|
|
274
|
+
kind: { type: "string" },
|
|
275
|
+
parent: { type: "string" },
|
|
276
|
+
repo: { type: "string" },
|
|
277
|
+
evidence: { type: "string" },
|
|
278
|
+
by: { type: "string" },
|
|
279
|
+
port: { type: "string" },
|
|
280
|
+
"no-open": {
|
|
281
|
+
type: "boolean",
|
|
282
|
+
default: false
|
|
283
|
+
},
|
|
284
|
+
session: { type: "string" },
|
|
285
|
+
agent: { type: "string" },
|
|
286
|
+
id: { type: "string" },
|
|
287
|
+
"delegated-from": { type: "string" },
|
|
288
|
+
"handoff-from": { type: "string" },
|
|
289
|
+
text: { type: "string" },
|
|
290
|
+
serves: { type: "string" },
|
|
291
|
+
before: { type: "string" },
|
|
292
|
+
note: { type: "string" },
|
|
293
|
+
reason: { type: "string" },
|
|
294
|
+
"waiting-for": { type: "string" },
|
|
295
|
+
signal: { type: "string" },
|
|
296
|
+
branch: { type: "string" },
|
|
297
|
+
worktree: { type: "string" },
|
|
298
|
+
base: { type: "string" },
|
|
299
|
+
merge: { type: "string" },
|
|
300
|
+
affects: { type: "string" },
|
|
301
|
+
origin: { type: "string" },
|
|
302
|
+
labels: { type: "string" },
|
|
303
|
+
target: { type: "string" },
|
|
304
|
+
op: { type: "string" },
|
|
305
|
+
result: { type: "string" },
|
|
306
|
+
ref: { type: "string" },
|
|
307
|
+
month: { type: "string" },
|
|
308
|
+
all: {
|
|
309
|
+
type: "boolean",
|
|
310
|
+
default: false
|
|
311
|
+
},
|
|
312
|
+
"dry-run": {
|
|
313
|
+
type: "boolean",
|
|
314
|
+
default: false
|
|
315
|
+
},
|
|
316
|
+
version: {
|
|
317
|
+
type: "boolean",
|
|
318
|
+
default: false
|
|
319
|
+
},
|
|
320
|
+
help: {
|
|
321
|
+
type: "boolean",
|
|
322
|
+
default: false
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
const STATUSES = {
|
|
326
|
+
mainline: MAINLINE_STATUS,
|
|
327
|
+
task: WORK_STATUS,
|
|
328
|
+
action: WORK_STATUS,
|
|
329
|
+
decision: DECISION_STATUS,
|
|
330
|
+
issue: ISSUE_STATUS,
|
|
331
|
+
finding: FINDING_STATUS,
|
|
332
|
+
session: SESSION_STATUS,
|
|
333
|
+
merge: MERGE_STATES,
|
|
334
|
+
decider: DECIDERS
|
|
335
|
+
};
|
|
336
|
+
/** Reference formats, one example each, in the order a reader meets them. */
|
|
337
|
+
const REFERENCES = [
|
|
338
|
+
{
|
|
339
|
+
target: "mainline",
|
|
340
|
+
format: "m{NNN}",
|
|
341
|
+
example: "m001"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
target: "task",
|
|
345
|
+
format: "m{NNN}/t{NNN}",
|
|
346
|
+
example: "m001/t002"
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
target: "checklist item",
|
|
350
|
+
format: "m{NNN}/t{NNN}#c{NNN}",
|
|
351
|
+
example: "m001/t002#c003"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
target: "criterion",
|
|
355
|
+
format: "m{NNN}#r{NNN}",
|
|
356
|
+
example: "m001#r001"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
target: "decision",
|
|
360
|
+
format: "m{NNN}/d{NNN}",
|
|
361
|
+
example: "m001/d001"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
target: "issue",
|
|
365
|
+
format: "i{NNN}",
|
|
366
|
+
example: "i001"
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
target: "finding",
|
|
370
|
+
format: "f{NNN}",
|
|
371
|
+
example: "f001"
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
target: "another hub",
|
|
375
|
+
format: "{hub}:{reference}",
|
|
376
|
+
example: "other-hub:m001/t002"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
target: "action",
|
|
380
|
+
format: "{sessionId}#a{NNN}",
|
|
381
|
+
example: "claude-code-1a2b3c4d#a003"
|
|
382
|
+
}
|
|
383
|
+
];
|
|
384
|
+
/** Relation types a document's links take; readers derive the reverse direction. */
|
|
385
|
+
const LINKS = { rels: LINK_RELS };
|
|
386
|
+
/** Where each kind of entry lives under the hub root. */
|
|
387
|
+
const LAYOUT = {
|
|
388
|
+
config: ".mainflow/config.yaml",
|
|
389
|
+
mainline: ".mainflow/mainlines/m{NNN}-{slug}/mainline.md",
|
|
390
|
+
decision: ".mainflow/mainlines/m{NNN}-{slug}/decisions/d{NNN}-{slug}.md",
|
|
391
|
+
task: ".mainflow/mainlines/m{NNN}-{slug}/tasks/t{NNN}-{slug}/task.md",
|
|
392
|
+
issue: ".mainflow/issues/i{NNN}-{slug}.md",
|
|
393
|
+
finding: ".mainflow/findings/f{NNN}-{slug}.md",
|
|
394
|
+
ops: ".mainflow/ops/{YYYY-MM}.log",
|
|
395
|
+
sessions: ".mainflow/local/sessions/{sessionId}.yaml"
|
|
396
|
+
};
|
|
397
|
+
/** Statuses that close each kind of document; the CLI stamps closedAt when a document enters one. */
|
|
398
|
+
const CLOSED_STATUSES = CLOSED_STATUS;
|
|
399
|
+
/** Classification every document shares: one category from the list (a hub adds more in config.yaml), P0 to P3. */
|
|
400
|
+
const CLASSIFICATION = {
|
|
401
|
+
categories: DEFAULT_CATEGORIES,
|
|
402
|
+
priorities: PRIORITIES,
|
|
403
|
+
defaultPriority: "P2"
|
|
404
|
+
};
|
|
405
|
+
/** Body sections each document is created with; the task sections in `taskRequired` must be filled while it is open. */
|
|
406
|
+
const SECTIONS = {
|
|
407
|
+
mainline: MAINLINE_SECTIONS,
|
|
408
|
+
task: TASK_SECTIONS,
|
|
409
|
+
taskRequired: TASK_REQUIRED_SECTIONS,
|
|
410
|
+
decision: DECISION_SECTIONS,
|
|
411
|
+
issue: ISSUE_SECTIONS,
|
|
412
|
+
finding: FINDING_SECTIONS
|
|
413
|
+
};
|
|
414
|
+
const field = (name, required, description) => ({
|
|
415
|
+
name,
|
|
416
|
+
required,
|
|
417
|
+
description
|
|
418
|
+
});
|
|
419
|
+
/** Fields every document shares, described once and reused by each kind below. */
|
|
420
|
+
const COMMON = {
|
|
421
|
+
id: field("id", true, "由 new 指令配發的編號,與目錄或檔名前綴一致"),
|
|
422
|
+
title: field("title", true, "一句話說明這份文件是什麼"),
|
|
423
|
+
status: field("status", true, "狀態值見 STATUSES,只用狀態轉移指令改"),
|
|
424
|
+
priority: field("priority", false, "P0 至 P3,沒填視為 P2"),
|
|
425
|
+
category: field("category", false, "預設類別或 config.yaml 追加的類別,擇一"),
|
|
426
|
+
labels: field("labels", false, "自由分類,字串清單"),
|
|
427
|
+
created: field("created", true, "建立的日期,決策帶時分"),
|
|
428
|
+
closedAt: field("closedAt", false, "狀態轉為結束時由 CLI 寫入"),
|
|
429
|
+
resolution: field("resolution", false, "怎麼結束的,一句話"),
|
|
430
|
+
origin: field("origin", false, "從哪個主脈絡、任務、項目、決策、待辦或發現產生,可指向其他 hub"),
|
|
431
|
+
refs: field("refs", false, "參考來源清單,每筆 title 加 url 或 path,可附讀取日期 date"),
|
|
432
|
+
links: field("links", false, "和其他主脈絡或其他 hub 的關係清單,每筆的欄位見 link;同一條主脈絡內用 parent、dependsOn、affects")
|
|
433
|
+
};
|
|
434
|
+
const shared = (...names) => names.map((name) => COMMON[name]);
|
|
435
|
+
const EVERY = [
|
|
436
|
+
"id",
|
|
437
|
+
"title",
|
|
438
|
+
"status",
|
|
439
|
+
"priority",
|
|
440
|
+
"category",
|
|
441
|
+
"labels",
|
|
442
|
+
"created",
|
|
443
|
+
"closedAt",
|
|
444
|
+
"resolution",
|
|
445
|
+
"origin",
|
|
446
|
+
"refs",
|
|
447
|
+
"links"
|
|
448
|
+
];
|
|
449
|
+
/** Criteria and checklist items share these; items add serves. */
|
|
450
|
+
const LIST_ITEM = [
|
|
451
|
+
field("id", true, "清單內不重複的編號,解決條件為 r{NNN},checklist 項目為 c{NNN};直接改檔時自己寫下一個"),
|
|
452
|
+
field("text", true, "要做到的事,一句話"),
|
|
453
|
+
field("doneWhen", false, "怎樣才算完成;還沒結束的條目必填,check 會檢查"),
|
|
454
|
+
field("done", true, "是否已完成,用 check 指令改"),
|
|
455
|
+
field("evidence", false, "完成的證據,done 為 true 時必填"),
|
|
456
|
+
field("doneAt", false, "完成的日期,由 CLI 寫入"),
|
|
457
|
+
field("dropped", false, "不再需要時為 true,用 item drop 標記"),
|
|
458
|
+
field("supersededBy", false, "被哪個參照取代"),
|
|
459
|
+
field("note", false, "一句備註,例如放棄的原因")
|
|
460
|
+
];
|
|
461
|
+
/** Every front matter field of each document and list entry; facts.test keeps it equal to the schema. */
|
|
462
|
+
const FIELDS = {
|
|
463
|
+
mainline: [
|
|
464
|
+
...shared(...EVERY),
|
|
465
|
+
field("due", false, "預計完成的日期"),
|
|
466
|
+
field("archivedAt", false, "封存的日期,和狀態分開"),
|
|
467
|
+
field("criteria", true, "解決條件清單,每條的欄位見 criterion"),
|
|
468
|
+
field("budget", false, "預算的金額與單位"),
|
|
469
|
+
field("costs", false, "花費清單,每筆有日期、項目、單位,可附預估、實際、備註")
|
|
470
|
+
],
|
|
471
|
+
task: [
|
|
472
|
+
...shared(...EVERY),
|
|
473
|
+
field("kind", true, "phase 是依序推進的階段,branch 是從某個任務岔出的分支"),
|
|
474
|
+
field("parent", false, "上層任務,branch 必填"),
|
|
475
|
+
field("order", false, "在主脈絡內的順序,小的在前"),
|
|
476
|
+
field("dependsOn", false, "開始前必須先完成的任務"),
|
|
477
|
+
field("repo", false, "主要動到的倉庫,名稱需在 config.yaml 登記"),
|
|
478
|
+
field("startedAt", false, "第一次轉為 doing 時由 CLI 寫入"),
|
|
479
|
+
field("checklist", true, "checklist 項目清單,每項的欄位見 checklistItem"),
|
|
480
|
+
field("blockedBy", false, "卡住時的原因、等待對象與繼續的訊號,blocked 時必填"),
|
|
481
|
+
field("branch", false, "工作所在的分支"),
|
|
482
|
+
field("worktree", false, "worktree 的路徑"),
|
|
483
|
+
field("base", false, "分支基於哪個 commit"),
|
|
484
|
+
field("merge", false, "合併狀態:open、merged、abandoned")
|
|
485
|
+
],
|
|
486
|
+
decision: [
|
|
487
|
+
...shared(...EVERY),
|
|
488
|
+
field("decidedAt", false, "裁決的時間,由 CLI 寫入"),
|
|
489
|
+
field("supersededBy", false, "取代它的決策,superseded 時必填"),
|
|
490
|
+
field("by", false, "決策者:user、ai、relay"),
|
|
491
|
+
field("affects", false, "影響的任務或 checklist 項目;待裁決時其中的項目在等它"),
|
|
492
|
+
field("reversible", false, "之後能不能低成本改回來")
|
|
493
|
+
],
|
|
494
|
+
issue: [
|
|
495
|
+
...shared(...EVERY),
|
|
496
|
+
field("order", false, "待辦之間的順序"),
|
|
497
|
+
field("due", false, "預計完成的日期"),
|
|
498
|
+
field("plannedIn", false, "排進的任務,planned 時必填"),
|
|
499
|
+
field("archivedAt", false, "封存的日期,和狀態分開")
|
|
500
|
+
],
|
|
501
|
+
finding: [
|
|
502
|
+
...shared("id", "title", "status", "category", "labels", "created", "closedAt", "resolution", "origin", "refs", "links"),
|
|
503
|
+
field("appliesTo", false, "這個經驗適用的倉庫或路徑"),
|
|
504
|
+
field("reviewAfter", false, "到這天要重新確認它還成立"),
|
|
505
|
+
field("archivedAt", false, "封存的日期,和狀態分開")
|
|
506
|
+
],
|
|
507
|
+
criterion: LIST_ITEM,
|
|
508
|
+
checklistItem: [...LIST_ITEM, field("serves", false, "這個項目推進的解決條件,r{NNN} 清單")],
|
|
509
|
+
link: [
|
|
510
|
+
field("rel", true, "關係類型:depends-on、relates、split-from,反向由讀者推出"),
|
|
511
|
+
field("to", true, "對方的參照,不能在同一條主脈絡內;其他 hub 的加 {hub}: 前綴"),
|
|
512
|
+
field("note", false, "一句話說明這個關係")
|
|
513
|
+
]
|
|
514
|
+
};
|
|
515
|
+
//#endregion
|
|
516
|
+
export { CHECKLIST_REF, CLASSIFICATION, CLOSED_STATUSES, COMMAND_SPECS, FIELDS, FORMAT_VERSION, ID_PATTERNS, LAYOUT, LINKS, OPTIONS, REFERENCES, SECTIONS, SLUG, STATUSES };
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/hooks.d.ts
|
|
2
|
+
/** Fields Claude Code sends on stdin to every command hook, plus the ones specific to the events handled here. */
|
|
3
|
+
export interface ClaudeCodePayload {
|
|
4
|
+
session_id?: string;
|
|
5
|
+
transcript_path?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
source?: string;
|
|
8
|
+
agent_id?: string;
|
|
9
|
+
agent_type?: string;
|
|
10
|
+
last_assistant_message?: string;
|
|
11
|
+
effort?: {
|
|
12
|
+
level?: string;
|
|
13
|
+
};
|
|
14
|
+
/** PostToolUse: the tool that ran and its input */
|
|
15
|
+
tool_name?: string;
|
|
16
|
+
tool_input?: {
|
|
17
|
+
file_path?: string;
|
|
18
|
+
command?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** The parent transcript `<dir>/<session>.jsonl` keeps its subagents under `<dir>/<session>/subagents/`. */
|
|
22
|
+
export declare function subagentTranscript(parentTranscript: string, agentId: string): string;
|
|
23
|
+
export interface HookContext {
|
|
24
|
+
payload: ClaudeCodePayload;
|
|
25
|
+
/** Path from $CLAUDE_ENV_FILE; SessionStart writes MAINFLOW_SESSION there so later Bash calls see it */
|
|
26
|
+
envFile?: string;
|
|
27
|
+
/** How the executor should invoke the CLI inside the hub, used in the texts it reads */
|
|
28
|
+
cli: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const claudeCodeSessionId: (raw: string) => string;
|
|
31
|
+
type Handler = (root: string, ctx: HookContext) => string | null;
|
|
32
|
+
export declare const HOOK_PLATFORMS: Record<string, Record<string, Handler>>;
|
|
33
|
+
/**
|
|
34
|
+
* Run a hook handler. A hook must never break the host session, so outside a hub it stays silent and any
|
|
35
|
+
* failure is reported on stderr while the caller still exits 0.
|
|
36
|
+
*/
|
|
37
|
+
export declare function runHook(platform: string, event: string, ctx: HookContext): {
|
|
38
|
+
stdout: string | null;
|
|
39
|
+
error: string | null;
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|