@bicorne/task-flow 0.1.0 → 0.2.1

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 (58) hide show
  1. package/README.md +337 -145
  2. package/SKILL.md +9 -5
  3. package/assets/.harnessrc +0 -1
  4. package/dist/commands/analyze.js +160 -318
  5. package/dist/commands/archive.js +44 -48
  6. package/dist/commands/design.js +225 -400
  7. package/dist/commands/extract.js +174 -303
  8. package/dist/commands/init.js +103 -148
  9. package/dist/commands/merge/index.js +184 -295
  10. package/dist/commands/merge/merger.js +112 -134
  11. package/dist/commands/merge/types.js +3 -5
  12. package/dist/commands/merge/validators.js +115 -132
  13. package/dist/commands/merge.js +46 -13
  14. package/dist/commands/start.js +155 -248
  15. package/dist/commands/status.js +68 -129
  16. package/dist/commands/sync.js +37 -53
  17. package/dist/commands/tasks-gen/doc-parser.js +148 -228
  18. package/dist/commands/tasks-gen/generators.js +104 -116
  19. package/dist/commands/tasks-gen/index.js +206 -314
  20. package/dist/commands/tasks-gen/parsers.js +131 -232
  21. package/dist/commands/tasks-gen/templates.js +9 -10
  22. package/dist/commands/tasks-gen/types.js +36 -14
  23. package/dist/commands/tasks-gen/validators.js +33 -49
  24. package/dist/commands/tasks.js +58 -20
  25. package/dist/commands/worktree.js +167 -249
  26. package/dist/hooks/check-prd-exists.js +45 -55
  27. package/dist/hooks/check-worktree-conflict.js +68 -101
  28. package/dist/hooks/hook-runner/executor.js +134 -126
  29. package/dist/hooks/hook-runner/index.js +181 -196
  30. package/dist/hooks/hook-runner/loader.js +74 -113
  31. package/dist/hooks/hook-runner/types.js +3 -5
  32. package/dist/hooks/hook-runner.js +94 -28
  33. package/dist/hooks/phase-complete-detector.js +125 -191
  34. package/dist/hooks/phase-gate-validator.js +315 -376
  35. package/dist/hooks/save-checkpoint.js +87 -130
  36. package/dist/hooks/start-mcp-servers.js +50 -65
  37. package/dist/hooks/stop-mcp-servers.js +40 -49
  38. package/dist/index.js +84 -153
  39. package/dist/lib/archive.js +126 -209
  40. package/dist/lib/config.d.ts +0 -2
  41. package/dist/lib/config.js +141 -230
  42. package/dist/lib/constants.js +155 -145
  43. package/dist/lib/interactive.js +98 -148
  44. package/dist/lib/mcp-client.js +197 -320
  45. package/dist/lib/state.js +142 -253
  46. package/dist/slash/executor.js +309 -233
  47. package/dist/slash/index.js +69 -43
  48. package/dist/slash/parser.js +84 -97
  49. package/dist/slash/registry.js +100 -88
  50. package/dist/spec/openspec-to-task/builders.js +96 -109
  51. package/dist/spec/openspec-to-task/index.js +112 -173
  52. package/dist/spec/openspec-to-task/parsers.js +148 -219
  53. package/dist/spec/openspec-to-task/types.js +3 -5
  54. package/dist/spec/sync-openspec-to-task.js +47 -19
  55. package/dist/spec/sync-task-to-openspec.js +241 -272
  56. package/dist/types/ai-context.js +3 -8
  57. package/package.json +9 -7
  58. package/references/CLI-TUTORIAL.md +4 -10
@@ -1,45 +1,71 @@
1
+ async function e(e) {
2
+ if (!(0, m.isSlashCommand)(e)) return {
3
+ success: !1,
4
+ command: '',
5
+ message: `Not a valid slash command: "${e}". Format: /tf:<command> [args]`,
6
+ error: 'Invalid slash command format'
7
+ };
8
+ let r = (0, m.parseSlashCommand)(e);
9
+ return r.valid ? (0, n.executeSlashCommand)(r) : {
10
+ success: !1,
11
+ command: '',
12
+ message: r.error,
13
+ error: r.error
14
+ };
15
+ }
1
16
  "use strict";
2
- /**
3
- * slash/index.ts
4
- * Facade module for the slash command system
5
- *
6
- * Provides a single entry point for parsing and executing slash commands.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.executeSlashCommand = exports.printSlashHelp = exports.hasCommand = exports.getSingleCommands = exports.getCompositeCommands = exports.getAllCommands = exports.getCommand = exports.formatSlashCommand = exports.isSlashCommand = exports.parseSlashCommand = void 0;
10
- exports.runSlashCommand = runSlashCommand;
11
- var parser_1 = require("./parser");
12
- Object.defineProperty(exports, "parseSlashCommand", { enumerable: true, get: function () { return parser_1.parseSlashCommand; } });
13
- Object.defineProperty(exports, "isSlashCommand", { enumerable: true, get: function () { return parser_1.isSlashCommand; } });
14
- Object.defineProperty(exports, "formatSlashCommand", { enumerable: true, get: function () { return parser_1.formatSlashCommand; } });
15
- var registry_1 = require("./registry");
16
- Object.defineProperty(exports, "getCommand", { enumerable: true, get: function () { return registry_1.getCommand; } });
17
- Object.defineProperty(exports, "getAllCommands", { enumerable: true, get: function () { return registry_1.getAllCommands; } });
18
- Object.defineProperty(exports, "getCompositeCommands", { enumerable: true, get: function () { return registry_1.getCompositeCommands; } });
19
- Object.defineProperty(exports, "getSingleCommands", { enumerable: true, get: function () { return registry_1.getSingleCommands; } });
20
- Object.defineProperty(exports, "hasCommand", { enumerable: true, get: function () { return registry_1.hasCommand; } });
21
- Object.defineProperty(exports, "printSlashHelp", { enumerable: true, get: function () { return registry_1.printSlashHelp; } });
22
- var executor_1 = require("./executor");
23
- Object.defineProperty(exports, "executeSlashCommand", { enumerable: true, get: function () { return executor_1.executeSlashCommand; } });
24
- const parser_2 = require("./parser");
25
- const executor_2 = require("./executor");
26
- async function runSlashCommand(input) {
27
- if (!(0, parser_2.isSlashCommand)(input)) {
28
- return {
29
- success: false,
30
- command: '',
31
- message: `Not a valid slash command: "${input}". Format: /tf:<command> [args]`,
32
- error: 'Invalid slash command format',
33
- };
34
- }
35
- const parsed = (0, parser_2.parseSlashCommand)(input);
36
- if (!parsed.valid) {
37
- return {
38
- success: false,
39
- command: '',
40
- message: parsed.error,
41
- error: parsed.error,
42
- };
17
+ Object.defineProperty(exports, "__esModule", {
18
+ value: !0
19
+ });
20
+ var r = exports, t = {
21
+ get ParsedSlashCommand () {
22
+ return m.ParsedSlashCommand;
23
+ },
24
+ get SlashCommandDef () {
25
+ return s.SlashCommandDef;
26
+ },
27
+ get SlashExecResult () {
28
+ return n.SlashExecResult;
29
+ },
30
+ get StepResult () {
31
+ return n.StepResult;
32
+ },
33
+ get executeSlashCommand () {
34
+ return n.executeSlashCommand;
35
+ },
36
+ get formatSlashCommand () {
37
+ return m.formatSlashCommand;
38
+ },
39
+ get getAllCommands () {
40
+ return s.getAllCommands;
41
+ },
42
+ get getCommand () {
43
+ return s.getCommand;
44
+ },
45
+ get getCompositeCommands () {
46
+ return s.getCompositeCommands;
47
+ },
48
+ get getSingleCommands () {
49
+ return s.getSingleCommands;
50
+ },
51
+ get hasCommand () {
52
+ return s.hasCommand;
53
+ },
54
+ get isSlashCommand () {
55
+ return m.isSlashCommand;
56
+ },
57
+ get parseSlashCommand () {
58
+ return m.parseSlashCommand;
59
+ },
60
+ get printSlashHelp () {
61
+ return s.printSlashHelp;
62
+ },
63
+ get runSlashCommand () {
64
+ return e;
43
65
  }
44
- return (0, executor_2.executeSlashCommand)(parsed);
45
- }
66
+ };
67
+ for(var a in t)Object.defineProperty(r, a, {
68
+ enumerable: !0,
69
+ get: Object.getOwnPropertyDescriptor(t, a).get
70
+ });
71
+ let m = require("./parser"), s = require("./registry"), n = require("./executor");
@@ -1,101 +1,88 @@
1
- "use strict";
2
- /**
3
- * slash/parser.ts
4
- * Parse slash command strings like /tf:propose or /taskflow:apply
5
- *
6
- * Format: /<namespace>:<command> [args...]
7
- * Examples:
8
- * /tf:propose add-dark-mode
9
- * /taskflow:apply
10
- * /tf:archive --task-id my-feature
11
- */
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.VALID_NAMESPACES = exports.DEFAULT_NAMESPACE = void 0;
14
- exports.parseSlashCommand = parseSlashCommand;
15
- exports.isSlashCommand = isSlashCommand;
16
- exports.formatSlashCommand = formatSlashCommand;
17
- const DEFAULT_NAMESPACE = 'tf';
18
- exports.DEFAULT_NAMESPACE = DEFAULT_NAMESPACE;
19
- const VALID_NAMESPACES = ['tf', 'taskflow'];
20
- exports.VALID_NAMESPACES = VALID_NAMESPACES;
21
- function isValidNamespace(ns) {
22
- return VALID_NAMESPACES.includes(ns);
23
- }
24
- function parseSlashCommand(input) {
25
- const trimmed = input.trim();
26
- if (!trimmed.startsWith('/')) {
27
- return {
28
- valid: false,
29
- namespace: '',
30
- command: '',
31
- args: [],
32
- raw: trimmed,
33
- error: `Slash command must start with "/". Got: "${trimmed}"`,
34
- };
35
- }
36
- const withoutSlash = trimmed.slice(1);
37
- const colonIndex = withoutSlash.indexOf(':');
38
- if (colonIndex === -1) {
39
- return {
40
- valid: false,
41
- namespace: '',
42
- command: '',
43
- args: [],
44
- raw: trimmed,
45
- error: `Slash command must contain ":" separator. Format: /<namespace>:<command>. Got: "${trimmed}"`,
46
- };
47
- }
48
- const namespace = withoutSlash.slice(0, colonIndex);
49
- const remainder = withoutSlash.slice(colonIndex + 1);
50
- if (!namespace) {
51
- return {
52
- valid: false,
53
- namespace: '',
54
- command: '',
55
- args: [],
56
- raw: trimmed,
57
- error: `Missing namespace before ":". Format: /<namespace>:<command>. Got: "${trimmed}"`,
58
- };
59
- }
60
- if (!isValidNamespace(namespace)) {
61
- return {
62
- valid: false,
63
- namespace,
64
- command: '',
65
- args: [],
66
- raw: trimmed,
67
- error: `Unknown namespace "${namespace}". Valid namespaces: ${VALID_NAMESPACES.join(', ')}`,
68
- };
69
- }
70
- const tokens = remainder.split(/\s+/).filter(Boolean);
71
- const command = tokens[0] || '';
72
- if (!command) {
73
- return {
74
- valid: false,
75
- namespace,
76
- command: '',
77
- args: [],
78
- raw: trimmed,
79
- error: `Missing command after "${namespace}:". Format: /${namespace}:<command>. Got: "${trimmed}"`,
80
- };
81
- }
82
- const args = tokens.slice(1);
83
- return {
84
- valid: true,
85
- namespace,
86
- command,
87
- args,
88
- raw: trimmed,
1
+ function e(e) {
2
+ let r = e.trim();
3
+ if (!r.startsWith('/')) return {
4
+ valid: !1,
5
+ namespace: '',
6
+ command: '',
7
+ args: [],
8
+ raw: r,
9
+ error: `Slash command must start with "/". Got: "${r}"`
10
+ };
11
+ let a = r.slice(1), t = a.indexOf(':');
12
+ if (-1 === t) return {
13
+ valid: !1,
14
+ namespace: '',
15
+ command: '',
16
+ args: [],
17
+ raw: r,
18
+ error: `Slash command must contain ":" separator. Format: /<namespace>:<command>. Got: "${r}"`
19
+ };
20
+ let n = a.slice(0, t), s = a.slice(t + 1);
21
+ if (!n) return {
22
+ valid: !1,
23
+ namespace: '',
24
+ command: '',
25
+ args: [],
26
+ raw: r,
27
+ error: `Missing namespace before ":". Format: /<namespace>:<command>. Got: "${r}"`
28
+ };
29
+ if (!m.includes(n)) return {
30
+ valid: !1,
31
+ namespace: n,
32
+ command: '',
33
+ args: [],
34
+ raw: r,
35
+ error: `Unknown namespace "${n}". Valid namespaces: ${m.join(', ')}`
36
+ };
37
+ let o = s.split(/\s+/).filter(Boolean), i = o[0] || '';
38
+ return i ? {
39
+ valid: !0,
40
+ namespace: n,
41
+ command: i,
42
+ args: o.slice(1),
43
+ raw: r
44
+ } : {
45
+ valid: !1,
46
+ namespace: n,
47
+ command: '',
48
+ args: [],
49
+ raw: r,
50
+ error: `Missing command after "${n}:". Format: /${n}:<command>. Got: "${r}"`
89
51
  };
90
52
  }
91
- function isSlashCommand(input) {
92
- const trimmed = input.trim();
93
- if (!trimmed.startsWith('/')) {
94
- return false;
95
- }
96
- const withoutSlash = trimmed.slice(1);
97
- return withoutSlash.includes(':');
53
+ function r(e) {
54
+ let r = e.trim();
55
+ return !!r.startsWith('/') && r.slice(1).includes(':');
98
56
  }
99
- function formatSlashCommand(namespace, command) {
100
- return `/${namespace}:${command}`;
57
+ function a(e, r) {
58
+ return `/${e}:${r}`;
101
59
  }
60
+ "use strict";
61
+ Object.defineProperty(exports, "__esModule", {
62
+ value: !0
63
+ });
64
+ var t = exports, n = {
65
+ get DEFAULT_NAMESPACE () {
66
+ return o;
67
+ },
68
+ get VALID_NAMESPACES () {
69
+ return m;
70
+ },
71
+ get formatSlashCommand () {
72
+ return a;
73
+ },
74
+ get isSlashCommand () {
75
+ return r;
76
+ },
77
+ get parseSlashCommand () {
78
+ return e;
79
+ }
80
+ };
81
+ for(var s in n)Object.defineProperty(t, s, {
82
+ enumerable: !0,
83
+ get: Object.getOwnPropertyDescriptor(n, s).get
84
+ });
85
+ let o = 'tf', m = [
86
+ 'tf',
87
+ 'taskflow'
88
+ ];
@@ -1,155 +1,167 @@
1
+ function e(e) {
2
+ return c[e];
3
+ }
4
+ function t() {
5
+ return Object.values(c);
6
+ }
7
+ function a() {
8
+ return Object.values(c).filter((e)=>'composite' === e.category);
9
+ }
10
+ function r() {
11
+ return Object.values(c).filter((e)=>'single' === e.category);
12
+ }
13
+ function s(e) {
14
+ return e in c;
15
+ }
16
+ function n() {
17
+ let e = [
18
+ '',
19
+ 'Slash Commands:',
20
+ '',
21
+ ' Composite (multi-step):'
22
+ ];
23
+ for (let t of a())e.push(` ${t.usage.padEnd(40)} ${t.description}`);
24
+ for (let t of (e.push(''), e.push(' Single:'), r()))e.push(` ${t.usage.padEnd(40)} ${t.description}`);
25
+ return e.push(''), e.push(' Examples:'), e.push(' /tf:propose add-dark-mode → extract + design + tasks'), e.push(' /tf:apply add-dark-mode → create worktree'), e.push(' /tf:archive --task-id feat → archive + sync'), e.push(''), e.join('\n');
26
+ }
1
27
  "use strict";
2
- /**
3
- * slash/registry.ts
4
- * Slash command registry — defines all available slash commands,
5
- * their argument schemas, and whether they are composite (multi-step).
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.getCommand = getCommand;
9
- exports.getAllCommands = getAllCommands;
10
- exports.getCompositeCommands = getCompositeCommands;
11
- exports.getSingleCommands = getSingleCommands;
12
- exports.hasCommand = hasCommand;
13
- exports.printSlashHelp = printSlashHelp;
14
- const COMMANDS = {
28
+ Object.defineProperty(exports, "__esModule", {
29
+ value: !0
30
+ });
31
+ var i = exports, o = {
32
+ get getAllCommands () {
33
+ return t;
34
+ },
35
+ get getCommand () {
36
+ return e;
37
+ },
38
+ get getCompositeCommands () {
39
+ return a;
40
+ },
41
+ get getSingleCommands () {
42
+ return r;
43
+ },
44
+ get hasCommand () {
45
+ return s;
46
+ },
47
+ get printSlashHelp () {
48
+ return n;
49
+ }
50
+ };
51
+ for(var d in o)Object.defineProperty(i, d, {
52
+ enumerable: !0,
53
+ get: Object.getOwnPropertyDescriptor(o, d).get
54
+ });
55
+ let c = {
15
56
  propose: {
16
57
  name: 'propose',
17
58
  description: 'Create a full change proposal (extract → design → tasks)',
18
59
  category: 'composite',
19
- requiresChange: true,
20
- requiresTaskId: false,
21
- steps: ['extract', 'design', 'tasks'],
60
+ requiresChange: !0,
61
+ requiresTaskId: !1,
62
+ steps: [
63
+ 'extract',
64
+ 'design',
65
+ 'tasks'
66
+ ],
22
67
  usage: '/tf:propose <change-name>',
23
- example: '/tf:propose add-dark-mode',
68
+ example: '/tf:propose add-dark-mode'
24
69
  },
25
70
  apply: {
26
71
  name: 'apply',
27
72
  description: 'Apply a change by creating worktree and starting implementation',
28
73
  category: 'composite',
29
- requiresChange: true,
30
- requiresTaskId: false,
31
- steps: ['worktree'],
74
+ requiresChange: !0,
75
+ requiresTaskId: !1,
76
+ steps: [
77
+ 'worktree'
78
+ ],
32
79
  usage: '/tf:apply <change-name>',
33
- example: '/tf:apply add-dark-mode',
80
+ example: '/tf:apply add-dark-mode'
34
81
  },
35
82
  archive: {
36
83
  name: 'archive',
37
84
  description: 'Archive a completed change (archive → sync)',
38
85
  category: 'composite',
39
- requiresChange: false,
40
- requiresTaskId: true,
41
- steps: ['archive', 'sync'],
86
+ requiresChange: !1,
87
+ requiresTaskId: !0,
88
+ steps: [
89
+ 'archive',
90
+ 'sync'
91
+ ],
42
92
  usage: '/tf:archive --task-id <task-id>',
43
- example: '/tf:archive --task-id add-dark-mode',
93
+ example: '/tf:archive --task-id add-dark-mode'
44
94
  },
45
95
  init: {
46
96
  name: 'init',
47
97
  description: 'Initialize task flow in current project',
48
98
  category: 'single',
49
- requiresChange: false,
50
- requiresTaskId: false,
99
+ requiresChange: !1,
100
+ requiresTaskId: !1,
51
101
  usage: '/tf:init',
52
- example: '/tf:init',
102
+ example: '/tf:init'
53
103
  },
54
104
  status: {
55
105
  name: 'status',
56
106
  description: 'Show current task and phase status',
57
107
  category: 'single',
58
- requiresChange: false,
59
- requiresTaskId: false,
108
+ requiresChange: !1,
109
+ requiresTaskId: !1,
60
110
  usage: '/tf:status',
61
- example: '/tf:status',
111
+ example: '/tf:status'
62
112
  },
63
113
  extract: {
64
114
  name: 'extract',
65
115
  description: 'Extract project requirements and generate PRD document',
66
116
  category: 'single',
67
- requiresChange: true,
68
- requiresTaskId: false,
117
+ requiresChange: !0,
118
+ requiresTaskId: !1,
69
119
  usage: '/tf:extract <change-name>',
70
- example: '/tf:extract add-dark-mode',
120
+ example: '/tf:extract add-dark-mode'
71
121
  },
72
122
  design: {
73
123
  name: 'design',
74
124
  description: 'Generate technical specification from PRD',
75
125
  category: 'single',
76
- requiresChange: true,
77
- requiresTaskId: false,
126
+ requiresChange: !0,
127
+ requiresTaskId: !1,
78
128
  usage: '/tf:design <change-name>',
79
- example: '/tf:design add-dark-mode',
129
+ example: '/tf:design add-dark-mode'
80
130
  },
81
131
  tasks: {
82
132
  name: 'tasks',
83
133
  description: 'Generate PHASE-*.json task files from PRD and design',
84
134
  category: 'single',
85
- requiresChange: true,
86
- requiresTaskId: false,
135
+ requiresChange: !0,
136
+ requiresTaskId: !1,
87
137
  usage: '/tf:tasks <change-name>',
88
- example: '/tf:tasks add-dark-mode',
138
+ example: '/tf:tasks add-dark-mode'
89
139
  },
90
140
  worktree: {
91
141
  name: 'worktree',
92
142
  description: 'Create isolated git worktree for task execution',
93
143
  category: 'single',
94
- requiresChange: true,
95
- requiresTaskId: false,
144
+ requiresChange: !0,
145
+ requiresTaskId: !1,
96
146
  usage: '/tf:worktree <change-name>',
97
- example: '/tf:worktree add-dark-mode',
147
+ example: '/tf:worktree add-dark-mode'
98
148
  },
99
149
  merge: {
100
150
  name: 'merge',
101
151
  description: 'Merge completed worktree back to main branch',
102
152
  category: 'single',
103
- requiresChange: false,
104
- requiresTaskId: true,
153
+ requiresChange: !1,
154
+ requiresTaskId: !0,
105
155
  usage: '/tf:merge <task-id>',
106
- example: '/tf:merge add-dark-mode',
156
+ example: '/tf:merge add-dark-mode'
107
157
  },
108
158
  sync: {
109
159
  name: 'sync',
110
160
  description: 'Sync task execution status to spec',
111
161
  category: 'single',
112
- requiresChange: false,
113
- requiresTaskId: true,
162
+ requiresChange: !1,
163
+ requiresTaskId: !0,
114
164
  usage: '/tf:sync --task-id <task-id>',
115
- example: '/tf:sync --task-id add-dark-mode',
116
- },
117
- };
118
- function getCommand(name) {
119
- return COMMANDS[name];
120
- }
121
- function getAllCommands() {
122
- return Object.values(COMMANDS);
123
- }
124
- function getCompositeCommands() {
125
- return Object.values(COMMANDS).filter((cmd) => cmd.category === 'composite');
126
- }
127
- function getSingleCommands() {
128
- return Object.values(COMMANDS).filter((cmd) => cmd.category === 'single');
129
- }
130
- function hasCommand(name) {
131
- return name in COMMANDS;
132
- }
133
- function printSlashHelp() {
134
- const lines = [
135
- '',
136
- 'Slash Commands:',
137
- '',
138
- ' Composite (multi-step):',
139
- ];
140
- for (const cmd of getCompositeCommands()) {
141
- lines.push(` ${cmd.usage.padEnd(40)} ${cmd.description}`);
165
+ example: '/tf:sync --task-id add-dark-mode'
142
166
  }
143
- lines.push('');
144
- lines.push(' Single:');
145
- for (const cmd of getSingleCommands()) {
146
- lines.push(` ${cmd.usage.padEnd(40)} ${cmd.description}`);
147
- }
148
- lines.push('');
149
- lines.push(' Examples:');
150
- lines.push(' /tf:propose add-dark-mode → extract + design + tasks');
151
- lines.push(' /tf:apply add-dark-mode → create worktree');
152
- lines.push(' /tf:archive --task-id feat → archive + sync');
153
- lines.push('');
154
- return lines.join('\n');
155
- }
167
+ };