tackle-harness 0.0.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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +259 -0
  3. package/README.md +261 -0
  4. package/bin/tackle.js +150 -0
  5. package/package.json +29 -0
  6. package/plugins/contracts/plugin-interface.js +244 -0
  7. package/plugins/core/hook-skill-gate/index.js +437 -0
  8. package/plugins/core/hook-skill-gate/plugin.json +12 -0
  9. package/plugins/core/provider-memory-store/index.js +403 -0
  10. package/plugins/core/provider-memory-store/plugin.json +9 -0
  11. package/plugins/core/provider-role-registry/index.js +477 -0
  12. package/plugins/core/provider-role-registry/plugin.json +9 -0
  13. package/plugins/core/provider-state-store/index.js +244 -0
  14. package/plugins/core/provider-state-store/plugin.json +9 -0
  15. package/plugins/core/skill-agent-dispatcher/plugin.json +13 -0
  16. package/plugins/core/skill-agent-dispatcher/skill.md +912 -0
  17. package/plugins/core/skill-batch-task-creator/plugin.json +13 -0
  18. package/plugins/core/skill-batch-task-creator/skill.md +616 -0
  19. package/plugins/core/skill-checklist/plugin.json +10 -0
  20. package/plugins/core/skill-checklist/skill.md +115 -0
  21. package/plugins/core/skill-completion-report/plugin.json +10 -0
  22. package/plugins/core/skill-completion-report/skill.md +331 -0
  23. package/plugins/core/skill-experience-logger/plugin.json +10 -0
  24. package/plugins/core/skill-experience-logger/skill.md +235 -0
  25. package/plugins/core/skill-human-checkpoint/plugin.json +10 -0
  26. package/plugins/core/skill-human-checkpoint/skill.md +194 -0
  27. package/plugins/core/skill-progress-tracker/plugin.json +10 -0
  28. package/plugins/core/skill-progress-tracker/skill.md +204 -0
  29. package/plugins/core/skill-role-manager/plugin.json +10 -0
  30. package/plugins/core/skill-role-manager/skill.md +252 -0
  31. package/plugins/core/skill-split-work-package/plugin.json +13 -0
  32. package/plugins/core/skill-split-work-package/skill.md +446 -0
  33. package/plugins/core/skill-task-creator/plugin.json +13 -0
  34. package/plugins/core/skill-task-creator/skill.md +744 -0
  35. package/plugins/core/skill-team-cleanup/plugin.json +10 -0
  36. package/plugins/core/skill-team-cleanup/skill.md +266 -0
  37. package/plugins/core/skill-workflow-orchestrator/plugin.json +13 -0
  38. package/plugins/core/skill-workflow-orchestrator/skill.md +274 -0
  39. package/plugins/core/validator-doc-sync/index.js +248 -0
  40. package/plugins/core/validator-doc-sync/plugin.json +9 -0
  41. package/plugins/core/validator-work-package/index.js +300 -0
  42. package/plugins/core/validator-work-package/plugin.json +9 -0
  43. package/plugins/plugin-registry.json +118 -0
  44. package/plugins/runtime/config-manager.js +306 -0
  45. package/plugins/runtime/event-bus.js +187 -0
  46. package/plugins/runtime/harness-build.js +1019 -0
  47. package/plugins/runtime/logger.js +174 -0
  48. package/plugins/runtime/plugin-loader.js +339 -0
  49. package/plugins/runtime/state-store.js +277 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Provider: State Store
3
+ *
4
+ * Wraps the StateStore runtime module to provide unified state and task data access.
5
+ * Implements the ProviderPlugin interface from plugin-interface.js.
6
+ *
7
+ * Capabilities:
8
+ * - get(key) read arbitrary state via dot-notation key
9
+ * - getTasks() parse task.md into a structured task list
10
+ * - set(key, value) write state
11
+ * - delete(key) remove a state key
12
+ * - keys() list all stored keys
13
+ * - subscribe(key, cb) watch for changes on a key
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ var path = require('path');
19
+ var fs = require('fs');
20
+ var { ProviderPlugin } = require('../../contracts/plugin-interface');
21
+ var { StateStore, FileSystemAdapter } = require('../../runtime/state-store');
22
+
23
+ /**
24
+ * Minimal YAML-like parser for task.md
25
+ * Extracts the task table rows (WP-xxx entries) and status info.
26
+ */
27
+ function parseTaskMarkdown(content) {
28
+ var lines = content.split('\n');
29
+ var tasks = [];
30
+ var stats = { total: 0, completed: 0, inProgress: 0, pending: 0 };
31
+
32
+ // Find the table header row that starts with | WP |
33
+ var tableStarted = false;
34
+ var headerSkipped = false;
35
+ var separatorSkipped = false;
36
+
37
+ for (var i = 0; i < lines.length; i++) {
38
+ var line = lines[i];
39
+
40
+ if (!tableStarted) {
41
+ if (line.indexOf('| WP ') === 0 || line.indexOf('| WP\t') === 0) {
42
+ tableStarted = true;
43
+ headerSkipped = true; // this line IS the header, already skipped by continue
44
+ }
45
+ continue;
46
+ }
47
+
48
+ // The first line after tableStarted is the header - skip it
49
+ if (!headerSkipped) {
50
+ headerSkipped = true;
51
+ continue;
52
+ }
53
+
54
+ // The second line is the separator (|---|---|...) - skip it
55
+ if (!separatorSkipped) {
56
+ separatorSkipped = true;
57
+ continue;
58
+ }
59
+
60
+ // Parse data rows
61
+ var trimmed = line.trim();
62
+ if (!trimmed || trimmed.indexOf('|') !== 0) {
63
+ // End of table
64
+ break;
65
+ }
66
+
67
+ var cells = trimmed.split('|').filter(function (c) { return c.trim() !== ''; });
68
+ if (cells.length < 2) continue;
69
+
70
+ var wpId = cells[0].trim();
71
+ if (!wpId.match(/^WP-\d+$/)) continue;
72
+
73
+ var title = cells.length > 1 ? cells[1].trim() : '';
74
+ var statusCell = cells.length > 2 ? cells[2].trim() : '';
75
+ var phase = cells.length > 3 ? cells[3].trim() : '';
76
+ var priority = cells.length > 4 ? cells[4].trim() : '';
77
+ var deps = cells.length > 5 ? cells[5].trim() : '';
78
+ var estimate = cells.length > 6 ? cells[6].trim() : '';
79
+
80
+ var status = 'pending';
81
+ if (statusCell.indexOf('完成') !== -1 || statusCell.indexOf('Completed') !== -1) {
82
+ status = 'completed';
83
+ } else if (statusCell.indexOf('进行') !== -1 || statusCell.indexOf('In Progress') !== -1) {
84
+ status = 'in_progress';
85
+ } else if (statusCell.indexOf('待开始') !== -1 || statusCell.indexOf('Pending') !== -1) {
86
+ status = 'pending';
87
+ }
88
+
89
+ stats.total++;
90
+ if (status === 'completed') stats.completed++;
91
+ else if (status === 'in_progress') stats.inProgress++;
92
+ else stats.pending++;
93
+
94
+ tasks.push({
95
+ id: wpId,
96
+ title: title,
97
+ status: status,
98
+ phase: phase,
99
+ priority: priority,
100
+ dependencies: deps ? deps.split(',').map(function (d) { return d.trim(); }) : [],
101
+ estimate: estimate,
102
+ });
103
+ }
104
+
105
+ return { tasks: tasks, stats: stats };
106
+ }
107
+
108
+ /**
109
+ * StateStoreProvider - provides state access and task parsing
110
+ */
111
+ class StateStoreProvider extends ProviderPlugin {
112
+ constructor() {
113
+ super();
114
+ this.name = 'provider-state-store';
115
+ this.version = '1.0.0';
116
+ this.description = 'State Store Provider';
117
+ this.provides = 'provider:state-store';
118
+ this.dependencies = {};
119
+
120
+ /** @type {StateStore|null} */
121
+ this._store = null;
122
+ /** @type {string} */
123
+ this._projectRoot = '';
124
+ }
125
+
126
+ /**
127
+ * Called when the plugin is activated.
128
+ * Initializes the StateStore with the project root path.
129
+ *
130
+ * @param {PluginContext} context
131
+ */
132
+ async onActivate(context) {
133
+ this._projectRoot = this._resolveProjectRoot();
134
+ var stateFilePath = path.join(this._projectRoot, '.claude-state');
135
+ this._store = new StateStore({ filePath: stateFilePath });
136
+ }
137
+
138
+ /**
139
+ * Factory method - returns the provider instance (this provider itself).
140
+ *
141
+ * @param {PluginContext} context
142
+ * @returns {Promise<object>} the state store provider API
143
+ */
144
+ async factory(context) {
145
+ var self = this;
146
+
147
+ return {
148
+ /**
149
+ * Get a value by dot-notation key from the state store.
150
+ * @param {string} key - e.g. 'harness.state'
151
+ * @returns {Promise<*|undefined>}
152
+ */
153
+ get: function (key) {
154
+ return self._store.get(key);
155
+ },
156
+
157
+ /**
158
+ * Set a value by dot-notation key.
159
+ * @param {string} key
160
+ * @param {*} value
161
+ * @returns {Promise<void>}
162
+ */
163
+ set: function (key, value) {
164
+ return self._store.set(key, value);
165
+ },
166
+
167
+ /**
168
+ * Delete a key from the state store.
169
+ * @param {string} key
170
+ * @returns {Promise<void>}
171
+ */
172
+ delete: function (key) {
173
+ return self._store.delete(key);
174
+ },
175
+
176
+ /**
177
+ * List all stored keys.
178
+ * @returns {Promise<string[]>}
179
+ */
180
+ keys: function () {
181
+ return self._store.keys();
182
+ },
183
+
184
+ /**
185
+ * Subscribe to changes on a specific key.
186
+ * @param {string} key
187
+ * @param {Function} callback - callback(key, oldValue, newValue)
188
+ * @returns {{ unsubscribe: Function }}
189
+ */
190
+ subscribe: function (key, callback) {
191
+ return self._store.subscribe(key, callback);
192
+ },
193
+
194
+ /**
195
+ * Parse task.md into a structured task list.
196
+ * @returns {Promise<{ tasks: object[], stats: object }>}
197
+ */
198
+ getTasks: function () {
199
+ return self._parseTasks();
200
+ },
201
+
202
+ /**
203
+ * Get the raw state store instance for advanced usage.
204
+ * @returns {StateStore}
205
+ */
206
+ getStore: function () {
207
+ return self._store;
208
+ },
209
+ };
210
+ }
211
+
212
+ /**
213
+ * Parse the task.md file.
214
+ * @returns {Promise<{ tasks: object[], stats: object }>}
215
+ */
216
+ async _parseTasks() {
217
+ var taskFile = path.join(this._projectRoot, 'task.md');
218
+ try {
219
+ var content = fs.readFileSync(taskFile, 'utf-8');
220
+ return parseTaskMarkdown(content);
221
+ } catch (err) {
222
+ return { tasks: [], stats: { total: 0, completed: 0, inProgress: 0, pending: 0 } };
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Resolve the project root directory.
228
+ * Walks up from cwd to find a directory containing task.md or .claude/.
229
+ * @returns {string}
230
+ */
231
+ _resolveProjectRoot() {
232
+ var dir = process.cwd();
233
+ for (var i = 0; i < 10; i++) {
234
+ if (fs.existsSync(path.join(dir, 'task.md'))) return dir;
235
+ if (fs.existsSync(path.join(dir, '.claude'))) return dir;
236
+ var parent = path.dirname(dir);
237
+ if (parent === dir) break;
238
+ dir = parent;
239
+ }
240
+ return process.cwd();
241
+ }
242
+ }
243
+
244
+ module.exports = StateStoreProvider;
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "provider-state-store",
3
+ "version": "1.0.0",
4
+ "type": "provider",
5
+ "description": "状态存储 Provider - 包装 StateStore 运行时模块,提供统一的状态和任务数据访问接口",
6
+ "dependencies": [],
7
+ "provides": ["provider:state-store"],
8
+ "config": {}
9
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "skill-agent-dispatcher",
3
+ "version": "1.0.0",
4
+ "type": "skill",
5
+ "description": "子代理批量调度 Skill - 基于 Agent Teams 机制的子代理批量任务调度,支持角色赋能、记忆注入、依赖分析和并行执行",
6
+ "triggers": ["批量执行", "并行执行", "调度子代理", "agent-dispatcher", "batch execute", "parallel execute", "dispatch agents"],
7
+ "dependencies": ["provider:role-registry", "provider:memory-store"],
8
+ "provides": ["skill:agent-dispatcher"],
9
+ "metadata": {
10
+ "gatedByCode": true
11
+ },
12
+ "config": {}
13
+ }