@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.
- package/README.md +337 -145
- package/SKILL.md +9 -5
- package/assets/.harnessrc +0 -1
- package/dist/commands/analyze.js +160 -318
- package/dist/commands/archive.js +44 -48
- package/dist/commands/design.js +225 -400
- package/dist/commands/extract.js +174 -303
- package/dist/commands/init.js +103 -148
- package/dist/commands/merge/index.js +184 -295
- package/dist/commands/merge/merger.js +112 -134
- package/dist/commands/merge/types.js +3 -5
- package/dist/commands/merge/validators.js +115 -132
- package/dist/commands/merge.js +46 -13
- package/dist/commands/start.js +155 -248
- package/dist/commands/status.js +68 -129
- package/dist/commands/sync.js +37 -53
- package/dist/commands/tasks-gen/doc-parser.js +148 -228
- package/dist/commands/tasks-gen/generators.js +104 -116
- package/dist/commands/tasks-gen/index.js +206 -314
- package/dist/commands/tasks-gen/parsers.js +131 -232
- package/dist/commands/tasks-gen/templates.js +9 -10
- package/dist/commands/tasks-gen/types.js +36 -14
- package/dist/commands/tasks-gen/validators.js +33 -49
- package/dist/commands/tasks.js +58 -20
- package/dist/commands/worktree.js +167 -249
- package/dist/hooks/check-prd-exists.js +45 -55
- package/dist/hooks/check-worktree-conflict.js +68 -101
- package/dist/hooks/hook-runner/executor.js +134 -126
- package/dist/hooks/hook-runner/index.js +181 -196
- package/dist/hooks/hook-runner/loader.js +74 -113
- package/dist/hooks/hook-runner/types.js +3 -5
- package/dist/hooks/hook-runner.js +94 -28
- package/dist/hooks/phase-complete-detector.js +125 -191
- package/dist/hooks/phase-gate-validator.js +315 -376
- package/dist/hooks/save-checkpoint.js +87 -130
- package/dist/hooks/start-mcp-servers.js +50 -65
- package/dist/hooks/stop-mcp-servers.js +40 -49
- package/dist/index.js +84 -153
- package/dist/lib/archive.js +126 -209
- package/dist/lib/config.d.ts +0 -2
- package/dist/lib/config.js +141 -230
- package/dist/lib/constants.js +155 -145
- package/dist/lib/interactive.js +98 -148
- package/dist/lib/mcp-client.js +197 -320
- package/dist/lib/state.js +142 -253
- package/dist/slash/executor.js +309 -233
- package/dist/slash/index.js +69 -43
- package/dist/slash/parser.js +84 -97
- package/dist/slash/registry.js +100 -88
- package/dist/spec/openspec-to-task/builders.js +96 -109
- package/dist/spec/openspec-to-task/index.js +112 -173
- package/dist/spec/openspec-to-task/parsers.js +148 -219
- package/dist/spec/openspec-to-task/types.js +3 -5
- package/dist/spec/sync-openspec-to-task.js +47 -19
- package/dist/spec/sync-task-to-openspec.js +241 -272
- package/dist/types/ai-context.js +3 -8
- package/package.json +9 -7
- package/references/CLI-TUTORIAL.md +4 -10
package/dist/slash/index.js
CHANGED
|
@@ -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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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");
|
package/dist/slash/parser.js
CHANGED
|
@@ -1,101 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
100
|
-
return `/${
|
|
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
|
+
];
|
package/dist/slash/registry.js
CHANGED
|
@@ -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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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:
|
|
20
|
-
requiresTaskId:
|
|
21
|
-
steps: [
|
|
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:
|
|
30
|
-
requiresTaskId:
|
|
31
|
-
steps: [
|
|
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:
|
|
40
|
-
requiresTaskId:
|
|
41
|
-
steps: [
|
|
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:
|
|
50
|
-
requiresTaskId:
|
|
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:
|
|
59
|
-
requiresTaskId:
|
|
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:
|
|
68
|
-
requiresTaskId:
|
|
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:
|
|
77
|
-
requiresTaskId:
|
|
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:
|
|
86
|
-
requiresTaskId:
|
|
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:
|
|
95
|
-
requiresTaskId:
|
|
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:
|
|
104
|
-
requiresTaskId:
|
|
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:
|
|
113
|
-
requiresTaskId:
|
|
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
|
-
|
|
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
|
+
};
|