create-harness-vibe-coding 0.8.18 → 0.8.19
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/CHANGELOG.md +13 -0
- package/README.md +1 -0
- package/package.json +5 -2
- package/src/index.js +383 -267
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js +17 -0
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js.map +1 -0
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js +7 -0
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js.map +1 -0
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js +12 -0
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js.map +1 -0
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js +50 -0
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js.map +1 -0
- package/src/ui/dist/assets/TerminalDrawer-6GBZ9nXN.css +32 -0
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js +74 -0
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js.map +1 -0
- package/src/ui/dist/assets/WorkflowRoute-BnuhLJ6X.css +1 -0
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js +39 -0
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js.map +1 -0
- package/src/ui/dist/assets/index-BOVYWntB.js +117 -0
- package/src/ui/dist/assets/index-BOVYWntB.js.map +1 -0
- package/src/ui/dist/assets/index-DaUObq0H.css +1 -0
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js +7 -0
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js.map +1 -0
- package/src/ui/dist/assets/plus-QuTJyoT3.js +7 -0
- package/src/ui/dist/assets/plus-QuTJyoT3.js.map +1 -0
- package/src/ui/dist/assets/proxy-D0vUbds5.js +2 -0
- package/src/ui/dist/assets/proxy-D0vUbds5.js.map +1 -0
- package/src/ui/dist/assets/refresh-cw-JNmExijd.js +7 -0
- package/src/ui/dist/assets/refresh-cw-JNmExijd.js.map +1 -0
- package/src/ui/dist/assets/terminal-BBQvnOAK.js +7 -0
- package/src/ui/dist/assets/terminal-BBQvnOAK.js.map +1 -0
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js +7 -0
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js.map +1 -0
- package/src/ui/dist/assets/x-DoIOGAJz.js +7 -0
- package/src/ui/dist/assets/x-DoIOGAJz.js.map +1 -0
- package/src/ui/dist/index.html +18 -0
- package/src/ui/index.html +17 -0
- package/src/ui/package.json +33 -0
- package/src/ui/pnpm-lock.yaml +1582 -0
- package/src/ui/pnpm-workspace.yaml +2 -0
- package/src/ui/src/App.tsx +86 -0
- package/src/ui/src/api.ts +93 -0
- package/src/ui/src/components/AgentsRoute.tsx +503 -0
- package/src/ui/src/components/Footer.tsx +69 -0
- package/src/ui/src/components/Header.tsx +175 -0
- package/src/ui/src/components/LoadingView.tsx +22 -0
- package/src/ui/src/components/RolesRoute.tsx +169 -0
- package/src/ui/src/components/SettingsRoute.tsx +166 -0
- package/src/ui/src/components/TaskList.tsx +388 -0
- package/src/ui/src/components/TerminalDrawer.tsx +611 -0
- package/src/ui/src/components/WorkflowRoute.tsx +670 -0
- package/src/ui/src/hooks/useReducedMotion.ts +17 -0
- package/src/ui/src/hooks/useServerConnection.ts +114 -0
- package/src/ui/src/index.css +281 -0
- package/src/ui/src/main.tsx +11 -0
- package/src/ui/src/types.ts +108 -0
- package/src/ui/tsconfig.json +21 -0
- package/src/ui/vite.config.ts +19 -0
- package/src/wf-ui-server/__tests__/a2a-store.test.mjs +79 -0
- package/src/wf-ui-server/__tests__/peer-capsule.test.mjs +268 -0
- package/src/wf-ui-server/__tests__/pty-adapter.test.mjs +70 -0
- package/src/wf-ui-server/__tests__/runtime-config.test.mjs +43 -0
- package/src/wf-ui-server/__tests__/runtime-detector.test.mjs +90 -0
- package/src/wf-ui-server/__tests__/security.test.mjs +59 -0
- package/src/wf-ui-server/__tests__/server.integration.test.mjs +150 -0
- package/src/wf-ui-server/__tests__/session-registry.test.mjs +238 -0
- package/src/wf-ui-server/__tests__/settings.test.mjs +135 -0
- package/src/wf-ui-server/__tests__/task-parser.test.mjs +200 -0
- package/src/wf-ui-server/__tests__/terminal-store.test.mjs +138 -0
- package/src/wf-ui-server/__tests__/token.test.mjs +48 -0
- package/src/wf-ui-server/__tests__/ws-events.integration.test.mjs +419 -0
- package/src/wf-ui-server/__tests__/ws-terminal.integration.test.mjs +383 -0
- package/src/wf-ui-server/a2a-store.mjs +296 -0
- package/src/wf-ui-server/peer-capsule.mjs +213 -0
- package/src/wf-ui-server/pty-adapter.mjs +155 -0
- package/src/wf-ui-server/runtime-config.mjs +153 -0
- package/src/wf-ui-server/runtime-detector.mjs +374 -0
- package/src/wf-ui-server/security.mjs +67 -0
- package/src/wf-ui-server/server.mjs +849 -0
- package/src/wf-ui-server/session-registry.mjs +204 -0
- package/src/wf-ui-server/settings.mjs +100 -0
- package/src/wf-ui-server/task-parser.mjs +133 -0
- package/src/wf-ui-server/terminal-store.mjs +225 -0
- package/src/wf-ui-server/token.mjs +41 -0
- package/src/wf-ui-server/ws-events.mjs +354 -0
- package/src/wf-ui-server/ws-terminal.mjs +473 -0
- package/templates/common/.claude/commands/wf-help.md +1 -0
- package/templates/common/.claude/commands/wf-task-list.md +2 -0
- package/templates/common/.claude/commands/wf-ui.md +26 -0
- package/templates/common/.claude/commands/wf-update.md +54 -9
- package/templates/common/.claude/rules/ecc/common.md +1 -1
- package/templates/common/.claude/skills/wf-auto/SKILL.md +3 -3
- package/templates/common/.claude/skills/wf-auto-spark/SKILL.md +2 -2
- package/templates/common/.claude/skills/wf-ui/SKILL.md +78 -0
- package/templates/common/.claude/skills/wf-update/SKILL.md +55 -58
- package/templates/common/.harness-version +63 -39
- package/templates/common/.opencode/commands/wf-help.md +1 -0
- package/templates/common/.opencode/commands/wf-task-list.md +2 -0
- package/templates/common/.opencode/commands/wf-ui.md +26 -0
- package/templates/common/.opencode/commands/wf-update.md +54 -9
- package/templates/common/CLAUDE.md +1 -1
- package/templates/common/Harness/MEMORY.md +2 -0
- package/templates/common/Harness/README.md +6 -4
- package/templates/common/Harness/a2a/role-graph.json +79 -0
- package/templates/common/Harness/a2a/runtime-registry.json +5 -0
- package/templates/common/Harness/a2a/skills/terminal-control.json +15 -0
- package/templates/common/Harness/ownership.manifest.json +57 -2
- package/templates/common/Harness/scripts/README.md +134 -0
- package/templates/common/Harness/scripts/a2a-terminal.mjs +191 -0
- package/templates/common/Harness/scripts/context-budget.mjs +1 -1
- package/templates/common/Harness/scripts/sync-host-global.mjs +278 -0
- package/templates/common/Harness/scripts/task-state.mjs +556 -23
- package/templates/common/Harness/scripts/validate-harness.mjs +229 -19
- package/templates/common/Harness/scripts/wf-remove.mjs +8 -3
- package/templates/common/Harness/scripts/wf-update-check.mjs +37 -9
- package/templates/common/Harness/scripts/wf-update-runner.mjs +325 -0
- package/templates/common/Harness/settings.json +35 -0
- package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +7 -2
- package/templates/common/Harness/specs/runtime/command-surface.json +14 -0
- package/templates/common/Harness/specs/workflows/WF-AUTO-SPARK.md +8 -8
- package/templates/common/Harness/specs/workflows/WF-AUTO.md +12 -12
- package/templates/common/Harness/tasks/_template/NAMING.md +16 -16
- package/templates/common/Harness/tasks/_template/PLAN.md +17 -60
- package/templates/common/Harness/tasks/_template/PROBLEM.md +18 -0
- package/templates/common/Harness/tasks/_template/PROGRESS.md +9 -14
- package/templates/common/Harness/tasks/_template/REFERENCES.md +26 -0
- package/templates/common/Harness/tasks/_template/ARTIFACTS.md +0 -3
- package/templates/common/Harness/tasks/_template/NOTES.md +0 -3
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const SCRIPT_ROOT = path.resolve(__dirname, '..', '..');
|
|
10
|
+
const rawArgs = process.argv.slice(2);
|
|
11
|
+
const JSON_OUT = rawArgs.includes('--json');
|
|
12
|
+
|
|
13
|
+
function readFlagValue(args, flagName) {
|
|
14
|
+
const idx = args.indexOf(flagName);
|
|
15
|
+
if (idx === -1) return null;
|
|
16
|
+
const value = args[idx + 1];
|
|
17
|
+
return value && !value.startsWith('--') ? value : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function stripFlagWithValue(args, flagName) {
|
|
21
|
+
const next = [];
|
|
22
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
23
|
+
if (args[i] === flagName) {
|
|
24
|
+
i += 1;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (args[i].startsWith(`${flagName}=`)) continue;
|
|
28
|
+
next.push(args[i]);
|
|
29
|
+
}
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizePath(value) {
|
|
34
|
+
return String(value || '').replace(/\\/g, '/');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function comparablePath(value) {
|
|
38
|
+
const resolved = path.resolve(value);
|
|
39
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function samePath(a, b) {
|
|
43
|
+
if (!a || !b) return false;
|
|
44
|
+
return comparablePath(a) === comparablePath(b);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseSemver(value) {
|
|
48
|
+
if (!value || typeof value !== 'string') return [0, 0, 0];
|
|
49
|
+
return value.replace(/^[^0-9]*/, '').split('.').slice(0, 3).map(part => Number(part) || 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function cmpSemver(a, b) {
|
|
53
|
+
const left = parseSemver(a);
|
|
54
|
+
const right = parseSemver(b);
|
|
55
|
+
for (let i = 0; i < 3; i += 1) {
|
|
56
|
+
if ((left[i] || 0) > (right[i] || 0)) return 1;
|
|
57
|
+
if ((left[i] || 0) < (right[i] || 0)) return -1;
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function shouldAutoRepair(firstJson, targetVersion) {
|
|
63
|
+
if (firstJson?.status !== 'up-to-date') return false;
|
|
64
|
+
const remote = firstJson.remote || firstJson.to || null;
|
|
65
|
+
if (remote && targetVersion && cmpSemver(remote, targetVersion) < 0) return false;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function defaultGlobalDir() {
|
|
70
|
+
return process.env.HARNESS_GLOBAL_HOME
|
|
71
|
+
|| path.join(os.homedir(), '.harness', 'create-harness-vibe-coding');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function versionPath(root) {
|
|
75
|
+
return path.join(root, 'Harness', '.harness-version');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function updateScriptPath(root) {
|
|
79
|
+
return path.join(root, 'Harness', 'scripts', 'wf-update-check.mjs');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function syncScriptPath(root) {
|
|
83
|
+
return path.join(root, 'Harness', 'scripts', 'sync-host-global.mjs');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function validateScriptPath(root) {
|
|
87
|
+
return path.join(root, 'Harness', 'scripts', 'validate-harness.mjs');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function scanCleanScriptPath(root) {
|
|
91
|
+
return path.join(root, 'Harness', 'scripts', 'scan-clean.mjs');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readVersion(root) {
|
|
95
|
+
try {
|
|
96
|
+
const file = versionPath(root);
|
|
97
|
+
if (!fs.existsSync(file)) return null;
|
|
98
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function hasRunnableUpdater(root) {
|
|
105
|
+
return fs.existsSync(versionPath(root)) && fs.existsSync(updateScriptPath(root));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function discoverGlobalRuntime(projectVersion) {
|
|
109
|
+
const candidates = [];
|
|
110
|
+
if (projectVersion?.globalDir) candidates.push(projectVersion.globalDir);
|
|
111
|
+
if (process.env.HARNESS_GLOBAL_HOME) candidates.push(process.env.HARNESS_GLOBAL_HOME);
|
|
112
|
+
candidates.push(defaultGlobalDir());
|
|
113
|
+
const scriptVersion = readVersion(SCRIPT_ROOT);
|
|
114
|
+
if (scriptVersion?.installScope === 'global') candidates.push(SCRIPT_ROOT);
|
|
115
|
+
|
|
116
|
+
for (const candidate of candidates) {
|
|
117
|
+
if (!candidate) continue;
|
|
118
|
+
const resolved = path.resolve(candidate);
|
|
119
|
+
if (hasRunnableUpdater(resolved)) return resolved;
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function dedupeTargets(targets) {
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
const result = [];
|
|
127
|
+
for (const target of targets) {
|
|
128
|
+
const key = comparablePath(target.root);
|
|
129
|
+
if (seen.has(key)) continue;
|
|
130
|
+
seen.add(key);
|
|
131
|
+
result.push(target);
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function discoverTargets(projectRoot) {
|
|
137
|
+
const targets = [];
|
|
138
|
+
const projectVersion = readVersion(projectRoot);
|
|
139
|
+
const projectHasUpdater = hasRunnableUpdater(projectRoot);
|
|
140
|
+
const globalRoot = discoverGlobalRuntime(projectVersion);
|
|
141
|
+
|
|
142
|
+
if (projectHasUpdater && !samePath(projectRoot, globalRoot)) {
|
|
143
|
+
targets.push({
|
|
144
|
+
scope: projectVersion?.installScope === 'global' && projectVersion?.globalDir ? 'project-bridge' : 'project',
|
|
145
|
+
root: projectRoot,
|
|
146
|
+
version: projectVersion?.generator || null,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (globalRoot) {
|
|
151
|
+
const globalVersion = readVersion(globalRoot);
|
|
152
|
+
targets.push({
|
|
153
|
+
scope: 'global',
|
|
154
|
+
root: globalRoot,
|
|
155
|
+
version: globalVersion?.generator || null,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return dedupeTargets(targets);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function runNode(root, scriptPath, args, { parseJson = false } = {}) {
|
|
163
|
+
const result = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
164
|
+
cwd: root,
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
env: process.env,
|
|
167
|
+
});
|
|
168
|
+
const stdout = result.stdout || '';
|
|
169
|
+
const stderr = result.stderr || '';
|
|
170
|
+
let json = null;
|
|
171
|
+
if (parseJson && stdout.trim()) {
|
|
172
|
+
try {
|
|
173
|
+
json = JSON.parse(stdout.trim());
|
|
174
|
+
} catch {
|
|
175
|
+
json = { rawOutput: stdout };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
status: result.status ?? 1,
|
|
180
|
+
stdout,
|
|
181
|
+
stderr,
|
|
182
|
+
...(parseJson ? { json } : {}),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function wantsApply(args) {
|
|
187
|
+
return args.includes('--apply') || args.includes('--apply-safe') || args.includes('--safe-only') || args.includes('--finalize');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function wantsRepair(args) {
|
|
191
|
+
return args.includes('--repair') || args.includes('--ignore-version') || args.includes('--force-check');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function ensureJsonArg(args) {
|
|
195
|
+
return args.includes('--json') ? args : [...args, '--json'];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function withRepair(args) {
|
|
199
|
+
return wantsRepair(args) ? args : [...args, '--repair'];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function runUpdateForTarget(target, forwardArgs) {
|
|
203
|
+
const parseJson = forwardArgs.includes('--json');
|
|
204
|
+
const script = updateScriptPath(target.root);
|
|
205
|
+
const first = runNode(target.root, script, forwardArgs, { parseJson });
|
|
206
|
+
const runs = [{ command: `node Harness/scripts/wf-update-check.mjs ${forwardArgs.join(' ')}`.trim(), ...first }];
|
|
207
|
+
let effective = first;
|
|
208
|
+
|
|
209
|
+
if (
|
|
210
|
+
parseJson
|
|
211
|
+
&& first.status === 0
|
|
212
|
+
&& shouldAutoRepair(first.json, target.version)
|
|
213
|
+
&& !wantsRepair(forwardArgs)
|
|
214
|
+
) {
|
|
215
|
+
const repairArgs = withRepair(forwardArgs);
|
|
216
|
+
const repair = runNode(target.root, script, repairArgs, { parseJson });
|
|
217
|
+
runs.push({ command: `node Harness/scripts/wf-update-check.mjs ${repairArgs.join(' ')}`.trim(), ...repair });
|
|
218
|
+
effective = repair;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return { ...target, update: effective, runs };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function runPostUpdate(target, forwardArgs) {
|
|
225
|
+
const post = [];
|
|
226
|
+
const apply = wantsApply(forwardArgs);
|
|
227
|
+
const syncScript = syncScriptPath(target.root);
|
|
228
|
+
if (target.scope === 'global' && fs.existsSync(syncScript)) {
|
|
229
|
+
const syncArgs = apply ? ['--apply', '--json'] : ['--json'];
|
|
230
|
+
post.push({
|
|
231
|
+
step: 'sync-host-global',
|
|
232
|
+
...runNode(target.root, syncScript, syncArgs, { parseJson: true }),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
if (apply && fs.existsSync(validateScriptPath(target.root))) {
|
|
236
|
+
post.push({
|
|
237
|
+
step: 'validate',
|
|
238
|
+
...runNode(target.root, validateScriptPath(target.root), [], { parseJson: false }),
|
|
239
|
+
});
|
|
240
|
+
post.push({
|
|
241
|
+
step: 'manifest-audit',
|
|
242
|
+
...runNode(target.root, validateScriptPath(target.root), ['--manifest-audit'], { parseJson: false }),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (apply && target.scope !== 'global' && fs.existsSync(scanCleanScriptPath(target.root))) {
|
|
246
|
+
post.push({
|
|
247
|
+
step: 'scan-clean',
|
|
248
|
+
...runNode(target.root, scanCleanScriptPath(target.root), ['--json'], { parseJson: true }),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return post;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function printText(result) {
|
|
255
|
+
if (!result.targets.length) {
|
|
256
|
+
console.error(result.message);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
for (const target of result.targets) {
|
|
260
|
+
console.log(`\n[${target.scope}] ${target.root}`);
|
|
261
|
+
for (const run of target.runs || []) {
|
|
262
|
+
if (run.stdout) process.stdout.write(run.stdout);
|
|
263
|
+
if (run.stderr) process.stderr.write(run.stderr);
|
|
264
|
+
}
|
|
265
|
+
for (const post of target.post || []) {
|
|
266
|
+
console.log(`[post:${post.step}] exit ${post.status}`);
|
|
267
|
+
if (post.stdout) process.stdout.write(post.stdout);
|
|
268
|
+
if (post.stderr) process.stderr.write(post.stderr);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function main() {
|
|
274
|
+
const projectRoot = path.resolve(readFlagValue(rawArgs, '--project') || process.cwd());
|
|
275
|
+
const forwardArgs = stripFlagWithValue(rawArgs, '--project');
|
|
276
|
+
const effectiveArgs = JSON_OUT ? ensureJsonArg(forwardArgs) : forwardArgs;
|
|
277
|
+
const targets = discoverTargets(projectRoot);
|
|
278
|
+
|
|
279
|
+
if (targets.length === 0) {
|
|
280
|
+
const result = {
|
|
281
|
+
success: false,
|
|
282
|
+
status: 'no-harness-target',
|
|
283
|
+
projectRoot: normalizePath(projectRoot),
|
|
284
|
+
message: 'No project Harness updater or global Harness runtime was found. No project files were modified.',
|
|
285
|
+
targets: [],
|
|
286
|
+
};
|
|
287
|
+
if (JSON_OUT) console.log(JSON.stringify(result, null, 2));
|
|
288
|
+
else printText(result);
|
|
289
|
+
process.exitCode = 1;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const updatedTargets = targets.map(target => {
|
|
294
|
+
const withUpdate = runUpdateForTarget(target, effectiveArgs);
|
|
295
|
+
return {
|
|
296
|
+
...withUpdate,
|
|
297
|
+
post: runPostUpdate(withUpdate, effectiveArgs),
|
|
298
|
+
};
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const failures = [];
|
|
302
|
+
for (const target of updatedTargets) {
|
|
303
|
+
if (target.update.status !== 0) failures.push(`${target.scope}: update exit ${target.update.status}`);
|
|
304
|
+
for (const post of target.post || []) {
|
|
305
|
+
if (post.status !== 0) failures.push(`${target.scope}: ${post.step} exit ${post.status}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const result = {
|
|
310
|
+
success: failures.length === 0,
|
|
311
|
+
status: failures.length === 0 ? 'ok' : 'failed',
|
|
312
|
+
projectRoot: normalizePath(projectRoot),
|
|
313
|
+
targets: updatedTargets.map(target => ({
|
|
314
|
+
...target,
|
|
315
|
+
root: normalizePath(target.root),
|
|
316
|
+
})),
|
|
317
|
+
...(failures.length ? { failures } : {}),
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
if (JSON_OUT) console.log(JSON.stringify(result, null, 2));
|
|
321
|
+
else printText(result);
|
|
322
|
+
if (failures.length) process.exitCode = 1;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
main();
|
|
@@ -39,5 +39,40 @@
|
|
|
39
39
|
"claimMinReadRatioPercent": 95,
|
|
40
40
|
"claimMinUpliftPoints": 2
|
|
41
41
|
}
|
|
42
|
+
},
|
|
43
|
+
"server": {
|
|
44
|
+
"host": "127.0.0.1",
|
|
45
|
+
"port": 0
|
|
46
|
+
},
|
|
47
|
+
"terminal": {
|
|
48
|
+
"enabled": false,
|
|
49
|
+
"attachMode": false,
|
|
50
|
+
"defaultRuntime": "codex"
|
|
51
|
+
},
|
|
52
|
+
"peers": {
|
|
53
|
+
"allowlist": [
|
|
54
|
+
"claude",
|
|
55
|
+
"cc",
|
|
56
|
+
"codex",
|
|
57
|
+
"opencode",
|
|
58
|
+
"gemini",
|
|
59
|
+
"qwen",
|
|
60
|
+
"deepseek",
|
|
61
|
+
"pi",
|
|
62
|
+
"aider",
|
|
63
|
+
"goose",
|
|
64
|
+
"amp",
|
|
65
|
+
"crush",
|
|
66
|
+
"cline",
|
|
67
|
+
"plandex",
|
|
68
|
+
"openclaw",
|
|
69
|
+
"chatgpt",
|
|
70
|
+
"openai"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"ui": {
|
|
74
|
+
"theme": "auto",
|
|
75
|
+
"language": "zh",
|
|
76
|
+
"reducedMotion": false
|
|
42
77
|
}
|
|
43
78
|
}
|
|
@@ -11,7 +11,7 @@ Archived tasks move to `Harness/tasks/_archive/YYYY/<task-id>/`.
|
|
|
11
11
|
## What Is Never Archived
|
|
12
12
|
|
|
13
13
|
- `Harness/tasks/_template/` - scaffold template, never moved.
|
|
14
|
-
- `Harness/tasks/
|
|
14
|
+
- `Harness/tasks/continuous/` - WF-AUTO/WF-AUTO-SPARK permanent state capsule, never moved unless
|
|
15
15
|
explicitly allowed by WF-AUTO docs.
|
|
16
16
|
- `Harness/tasks/_archive/` - the archive directory itself.
|
|
17
17
|
- Active, blocked, in-progress, running, pending, or needs-user-decision tasks.
|
|
@@ -62,11 +62,16 @@ User-facing command:
|
|
|
62
62
|
|
|
63
63
|
Underlying implementation: `Harness/scripts/task-state.mjs archive`.
|
|
64
64
|
|
|
65
|
-
- Default: dry-run.
|
|
65
|
+
- Default: dry-run (respects `--keep` cap, archives oldest-eligible up to cap).
|
|
66
66
|
- `--apply` to execute.
|
|
67
|
+
- Explicit `--apply` with no `--task` filter: archives **ALL** eligible tasks, bypassing `--keep`.
|
|
67
68
|
- `--keep 5` to set the non-archived task threshold.
|
|
68
69
|
- `--task <task-id>` to archive a specific task.
|
|
69
70
|
- `--json` for machine-readable output.
|
|
71
|
+
- After archiving, `Harness/tasks/_archive/INDEX.md` is regenerated with a full
|
|
72
|
+
task graph: roots, dependency chains, blocks relationships, and per-task details
|
|
73
|
+
(status, phase, goal, depends-on, blocks). The graph covers **all** archived tasks
|
|
74
|
+
across all years, so it stays accurate as tasks accumulate.
|
|
70
75
|
- Run `node Harness/scripts/task-state.mjs archive --dry-run --json` before
|
|
71
76
|
applying a risky cleanup.
|
|
72
77
|
|
|
@@ -210,6 +210,20 @@
|
|
|
210
210
|
"codexSkill": true,
|
|
211
211
|
"helpRow": true
|
|
212
212
|
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"id": "wf-ui",
|
|
216
|
+
"classification": "direct",
|
|
217
|
+
"aliases": ["/wf-ui", "$wf-ui", "/skills wf-ui"],
|
|
218
|
+
"entersWf": false,
|
|
219
|
+
"taskCapsulePolicy": "none",
|
|
220
|
+
"surfaces": {
|
|
221
|
+
"claudeCommand": true,
|
|
222
|
+
"opencodeCommand": true,
|
|
223
|
+
"claudeSkill": true,
|
|
224
|
+
"codexSkill": true,
|
|
225
|
+
"helpRow": true
|
|
226
|
+
}
|
|
213
227
|
}
|
|
214
228
|
]
|
|
215
229
|
}
|
|
@@ -28,7 +28,7 @@ For task-state writes, CEO provides concise bullets and decisions; task-scribe f
|
|
|
28
28
|
|
|
29
29
|
## Startup: Roadmap Declaration
|
|
30
30
|
|
|
31
|
-
Before first spark cycle, CEO MUST declare a roadmap. This is written to `Harness/tasks/
|
|
31
|
+
Before first spark cycle, CEO MUST declare a roadmap. This is written to `Harness/tasks/continuous/SPARK-ROADMAP.md`.
|
|
32
32
|
|
|
33
33
|
### Roadmap Format
|
|
34
34
|
|
|
@@ -239,15 +239,15 @@ Re-Anchor Gate (every preset interval)
|
|
|
239
239
|
|
|
240
240
|
## Task Capsule & Recording
|
|
241
241
|
|
|
242
|
-
WF-AUTO-SPARK uses a dedicated task capsule at `Harness/tasks/
|
|
242
|
+
WF-AUTO-SPARK uses a dedicated task capsule at `Harness/tasks/continuous/`. Shared with `/wf-auto` — same capsule, different operational mode.
|
|
243
243
|
|
|
244
244
|
### Capsule Structure
|
|
245
245
|
|
|
246
246
|
| File | Purpose | Updated |
|
|
247
247
|
|------|---------|---------|
|
|
248
|
-
| `Harness/tasks/
|
|
249
|
-
| `Harness/tasks/
|
|
250
|
-
| `Harness/tasks/
|
|
248
|
+
| `Harness/tasks/continuous/SPARK-ROADMAP.md` | North Star + milestones + deviation log | At startup + every milestone change |
|
|
249
|
+
| `Harness/tasks/continuous/PLAN.md` | Current cycle's change spec (write set, acceptance criteria) | Before each implementation |
|
|
250
|
+
| `Harness/tasks/continuous/PROGRESS.md` | Cycle log, value reflections, cumulative stats, evidence | After each cycle |
|
|
251
251
|
| `Harness/PROGRESS.md` | Global task index — active spark session status | At session start, milestone, and stop |
|
|
252
252
|
|
|
253
253
|
### Heartbeat Protocol (per cycle, in `PROGRESS.md`)
|
|
@@ -314,9 +314,9 @@ This replaces the broken `/wf-auto` auto-continue. No silent drift across sessio
|
|
|
314
314
|
| File | Purpose |
|
|
315
315
|
|------|---------|
|
|
316
316
|
| `Harness/specs/workflows/WF-AUTO-SPARK.md` | This spec |
|
|
317
|
-
| `Harness/tasks/
|
|
318
|
-
| `Harness/tasks/
|
|
319
|
-
| `Harness/tasks/
|
|
317
|
+
| `Harness/tasks/continuous/SPARK-ROADMAP.md` | Active roadmap (created at startup) |
|
|
318
|
+
| `Harness/tasks/continuous/PLAN.md` | Per-cycle change spec |
|
|
319
|
+
| `Harness/tasks/continuous/PROGRESS.md` | Cycle log, heartbeat, evidence ledger |
|
|
320
320
|
| `Harness/PROGRESS.md` | Global task index linkage |
|
|
321
321
|
| `.claude/skills/wf-auto-spark/SKILL.md` | Claude Code skill loader |
|
|
322
322
|
| `.agents/skills/wf-auto-spark/SKILL.md` | Codex skill loader (mirror) |
|
|
@@ -113,7 +113,7 @@ WF-AUTO operates in explicit states. Without a state machine, "auto-degrade", "s
|
|
|
113
113
|
| `auto.exhausted` | A-GATE passed permanently | Two different confirmation strategies return no actionable finding |
|
|
114
114
|
| `paused` | User interrupted, waiting for direction | User says "stop" or interrupts at any point |
|
|
115
115
|
|
|
116
|
-
**State transitions are CEO-owned.** The CEO decides which state to enter based on W0 results and checkpoint responses. The state machine is recorded in `Harness/tasks/
|
|
116
|
+
**State transitions are CEO-owned.** The CEO decides which state to enter based on W0 results and checkpoint responses. The state machine is recorded in `Harness/tasks/continuous/PROGRESS.md` at each transition.
|
|
117
117
|
|
|
118
118
|
## Adaptive coverage instead of a magic angle count
|
|
119
119
|
|
|
@@ -271,7 +271,7 @@ CEO NEVER writes production code (per WF-KERNEL State Ownership). Implementer wr
|
|
|
271
271
|
|
|
272
272
|
### RECORD
|
|
273
273
|
|
|
274
|
-
Every cycle writes one entry to `Harness/tasks/
|
|
274
|
+
Every cycle writes one entry to `Harness/tasks/continuous/PROGRESS.md`:
|
|
275
275
|
|
|
276
276
|
```text
|
|
277
277
|
## Cycle N (timestamp) — State: auto.internal | auto.spark | auto.checkpoint
|
|
@@ -304,18 +304,18 @@ enabled `/wf-auto` tick hook may drive long-running auto-optimization.
|
|
|
304
304
|
|
|
305
305
|
Manual or benchmark-driven single-cycle `/wf-auto` runs use the same bounded
|
|
306
306
|
tick contract: they may stop because the caller explicitly requested one tick,
|
|
307
|
-
but they still MUST create or update `Harness/tasks/
|
|
308
|
-
`Harness/tasks/
|
|
307
|
+
but they still MUST create or update `Harness/tasks/continuous/PLAN.md` and
|
|
308
|
+
`Harness/tasks/continuous/PROGRESS.md` before returning.
|
|
309
309
|
|
|
310
310
|
The hook is not a role-enforcement mechanism, not a memory injection mechanism,
|
|
311
311
|
and not WF-MAX state. It is only a bounded tick trigger:
|
|
312
312
|
|
|
313
313
|
```text
|
|
314
314
|
wf-auto hook event
|
|
315
|
-
-> confirm /wf-auto is active in Harness/tasks/
|
|
315
|
+
-> confirm /wf-auto is active in Harness/tasks/continuous/
|
|
316
316
|
-> check STOP/paused/user-interrupt state
|
|
317
317
|
-> request exactly one W0-W5 tick or one Intent Checkpoint
|
|
318
|
-
-> append heartbeat/evidence to Harness/tasks/
|
|
318
|
+
-> append heartbeat/evidence to Harness/tasks/continuous/PROGRESS.md
|
|
319
319
|
-> exit
|
|
320
320
|
```
|
|
321
321
|
|
|
@@ -324,7 +324,7 @@ Hard boundaries:
|
|
|
324
324
|
- no execution-control hook is installed or registered by default
|
|
325
325
|
- only `/wf-auto` may use a runtime hook to drive auto-optimization
|
|
326
326
|
- the hook must run one bounded tick, not an unbounded process
|
|
327
|
-
- the hook must respect `Harness/tasks/
|
|
327
|
+
- the hook must respect `Harness/tasks/continuous/STOP`, `state=paused`, user stop,
|
|
328
328
|
and the Adaptive Coverage Exhaustion Gate
|
|
329
329
|
- the hook must not enforce WF-MAX roles, writeSet, or agent identity
|
|
330
330
|
- the hook must not inject memory directly; use `MEMORY_PROTOCOL.md` scenario
|
|
@@ -449,7 +449,7 @@ If a spark cycle's measured result is NEGLIGIBLE or REVERTED, increment `weakSpa
|
|
|
449
449
|
|
|
450
450
|
## CEO Constraints
|
|
451
451
|
|
|
452
|
-
CEO tool boundaries follow [WF-KERNEL.md](WF-KERNEL.md) State Ownership: CEO plans, dispatches, synthesizes, and writes ONLY the auto task capsule (`Harness/tasks/
|
|
452
|
+
CEO tool boundaries follow [WF-KERNEL.md](WF-KERNEL.md) State Ownership: CEO plans, dispatches, synthesizes, and writes ONLY the auto task capsule (`Harness/tasks/continuous/PROGRESS.md`, `Harness/tasks/continuous/PLAN.md`). CEO never writes production source code — all implementation is delegated to Workers.
|
|
453
453
|
|
|
454
454
|
## Anti-Pattern Catalog
|
|
455
455
|
|
|
@@ -509,10 +509,10 @@ Mini PRD-derived AC IDs in `/wf-auto`.
|
|
|
509
509
|
|
|
510
510
|
## Task Capsule
|
|
511
511
|
|
|
512
|
-
WF-AUTO uses a dedicated task capsule at `Harness/tasks/
|
|
512
|
+
WF-AUTO uses a dedicated task capsule at `Harness/tasks/continuous/`:
|
|
513
513
|
|
|
514
|
-
- `Harness/tasks/
|
|
515
|
-
- `Harness/tasks/
|
|
514
|
+
- `Harness/tasks/continuous/PROGRESS.md` — cycle log, exhaustion evidence, cumulative stats
|
|
515
|
+
- `Harness/tasks/continuous/PLAN.md` — current cycle's change spec
|
|
516
516
|
|
|
517
517
|
Unlike normal task capsules, this one is never archived — it's the permanent home of the auto-optimization state.
|
|
518
518
|
|
|
@@ -522,6 +522,6 @@ Closeout happens exactly once, when A-GATE passes permanently:
|
|
|
522
522
|
|
|
523
523
|
1. CEO records final exhaustion evidence: dynamic obligations, selected and skipped probes, coverage, confidence, and two different confirmation strategies
|
|
524
524
|
2. CEO writes summary: total cycles, files changed, findings addressed, findings rejected, residual risk
|
|
525
|
-
3. CEO marks `Harness/tasks/
|
|
525
|
+
3. CEO marks `Harness/tasks/continuous/PROGRESS.md` as "WF-AUTO EXHAUSTED" with timestamp
|
|
526
526
|
4. `Harness/PROGRESS.md` is updated with the auto session outcome
|
|
527
527
|
5. No further automatic action is taken
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
## Format
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
task-<verb>-<noun>[-detail]
|
|
6
|
+
task-<verb>-<noun>[-detail]-<MMDD>
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
All task directories MUST have the `task-` prefix. This distinguishes tasks from system directories
|
|
9
|
+
All task directories MUST have the `task-` prefix and end with a 4-digit month-day suffix (MMDD, e.g. `0729` for July 29). This distinguishes tasks from system directories and provides chronological ordering.
|
|
10
10
|
|
|
11
11
|
## Rules
|
|
12
12
|
|
|
13
13
|
| Rule | Example ✓ | Example ✗ |
|
|
14
14
|
|------|-----------|-----------|
|
|
15
|
-
| `task-` prefix required | `task-fix-ceo-inheritance` | `fix-ceo-inheritance` |
|
|
16
|
-
| kebab-case (lowercase, hyphens) | `task-fix-ceo-inheritance` | `task-fix_ceo_inheritance` |
|
|
17
|
-
| Verb-first after prefix | `task-add-goal-persistence` | `task-goal-persistence-add` |
|
|
18
|
-
| 2-5 words after prefix, <=46 total chars | `task-refactor-role-contract` | `task-refactor-the-entire-role-contract-model` |
|
|
19
|
-
| No abbreviations unless domain-standard | `task-fix-auth-middleware` | `task-fx-ath-mdw` |
|
|
15
|
+
| `task-` prefix + MMDD suffix required | `task-fix-ceo-inheritance-0730` | `fix-ceo-inheritance-0730` |
|
|
16
|
+
| kebab-case (lowercase, hyphens) | `task-fix-ceo-inheritance-0730` | `task-fix_ceo_inheritance-0730` |
|
|
17
|
+
| Verb-first after prefix | `task-add-goal-persistence-0730` | `task-goal-persistence-add-0730` |
|
|
18
|
+
| 2-5 words after prefix + MMDD date, <=46 total chars | `task-refactor-role-contract-0729` | `task-refactor-the-entire-role-contract-model-0729` |
|
|
19
|
+
| No abbreviations unless domain-standard | `task-fix-auth-middleware-0730` | `task-fx-ath-mdw-0730` |
|
|
20
20
|
|
|
21
21
|
## Reserved Names
|
|
22
22
|
|
|
@@ -27,7 +27,7 @@ All task directories MUST have the `task-` prefix. This distinguishes tasks from
|
|
|
27
27
|
|
|
28
28
|
## Task ID Lifecycle
|
|
29
29
|
|
|
30
|
-
1. Created by copying `_template/` → `task-<verb>-<noun>/`
|
|
30
|
+
1. Created by copying `_template/` → `task-<verb>-<noun>-<MMDD>/`
|
|
31
31
|
2. Directory name IS the task ID - used in `Harness/PROGRESS.md` and dispatch packets
|
|
32
32
|
3. Directory archived (not renamed) when task completes
|
|
33
33
|
4. Task ID is immutable after creation (changing it breaks cross-references)
|
|
@@ -36,12 +36,12 @@ All task directories MUST have the `task-` prefix. This distinguishes tasks from
|
|
|
36
36
|
## Examples
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
task-add-dark-mode-support
|
|
40
|
-
task-fix-auth-token-expiry
|
|
41
|
-
task-update-harness-lifecycle-docs
|
|
42
|
-
task-remove-legacy-config-files
|
|
43
|
-
task-refactor-agent-dispatch-model
|
|
44
|
-
task-migrate-to-esm-imports
|
|
45
|
-
task-audit-security-headers
|
|
46
|
-
task-benchmark-wf-max-throughput
|
|
39
|
+
task-add-dark-mode-support-0729
|
|
40
|
+
task-fix-auth-token-expiry-0730
|
|
41
|
+
task-update-harness-lifecycle-docs-0728
|
|
42
|
+
task-remove-legacy-config-files-0731
|
|
43
|
+
task-refactor-agent-dispatch-model-0801
|
|
44
|
+
task-migrate-to-esm-imports-0802
|
|
45
|
+
task-audit-security-headers-0803
|
|
46
|
+
task-benchmark-wf-max-throughput-0804
|
|
47
47
|
```
|