dev-harness-cli 1.0.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/README.md +299 -0
- package/adapters/amazon-q/README.md +23 -0
- package/adapters/antigravity/README.md +22 -0
- package/adapters/claude-code/README.md +30 -0
- package/adapters/cline/README.md +23 -0
- package/adapters/codex/README.md +31 -0
- package/adapters/copilot/README.md +23 -0
- package/adapters/cursor/README.md +29 -0
- package/adapters/gemini/README.md +23 -0
- package/adapters/generic/README.md +40 -0
- package/adapters/hermes/README.md +31 -0
- package/adapters/hermes/SKILL.md +89 -0
- package/adapters/hermes/scripts/init.mjs +27 -0
- package/adapters/hermes/scripts/phase.mjs +27 -0
- package/adapters/hermes/scripts/validate.mjs +27 -0
- package/adapters/kilo-code/README.md +23 -0
- package/adapters/openclaw/README.md +22 -0
- package/adapters/pi/README.md +22 -0
- package/adapters/roo/README.md +23 -0
- package/adapters/windsurf/README.md +23 -0
- package/cli/commands/checkpoint.mjs +94 -0
- package/cli/commands/config.mjs +268 -0
- package/cli/commands/contract.mjs +155 -0
- package/cli/commands/detect-tool.mjs +112 -0
- package/cli/commands/init.mjs +351 -0
- package/cli/commands/learn.mjs +47 -0
- package/cli/commands/pause.mjs +34 -0
- package/cli/commands/phase.mjs +182 -0
- package/cli/commands/resume.mjs +33 -0
- package/cli/commands/rollback.mjs +261 -0
- package/cli/commands/set-mode.mjs +75 -0
- package/cli/commands/status.mjs +168 -0
- package/cli/commands/validate.mjs +118 -0
- package/cli/commands/worktree.mjs +298 -0
- package/cli/harness-dev.mjs +88 -0
- package/cli/lib/args.mjs +111 -0
- package/cli/lib/command-helpers.mjs +50 -0
- package/cli/lib/config-registry.mjs +329 -0
- package/cli/lib/constants.mjs +30 -0
- package/cli/lib/contract.mjs +306 -0
- package/cli/lib/detect-stack.mjs +235 -0
- package/cli/lib/errors.mjs +71 -0
- package/cli/lib/file-io.mjs +90 -0
- package/cli/lib/gates.mjs +492 -0
- package/cli/lib/git.mjs +144 -0
- package/cli/lib/help.mjs +246 -0
- package/cli/lib/modes.mjs +92 -0
- package/cli/lib/output.mjs +49 -0
- package/cli/lib/paths.mjs +75 -0
- package/cli/lib/phases.mjs +58 -0
- package/cli/lib/platform.mjs +78 -0
- package/cli/lib/progress.mjs +357 -0
- package/cli/lib/ralph-inner.mjs +314 -0
- package/cli/lib/ralph-outer.mjs +249 -0
- package/cli/lib/ralph-output.mjs +178 -0
- package/cli/lib/scaffold.mjs +431 -0
- package/cli/lib/schemas/stacks.json +477 -0
- package/cli/lib/state.mjs +333 -0
- package/cli/lib/templates.mjs +264 -0
- package/cli/lib/tool-registry.mjs +218 -0
- package/cli/lib/validate-schema.mjs +131 -0
- package/cli/lib/vars.mjs +114 -0
- package/package.json +50 -0
- package/schema/harness-config.schema.json +127 -0
- package/templates/AGENTS.md +63 -0
- package/templates/ci/github-actions.yml +78 -0
- package/templates/ci/gitlab-ci.yml +59 -0
- package/templates/docs/agents/evaluator.md +14 -0
- package/templates/docs/agents/generator.md +13 -0
- package/templates/docs/agents/planner.md +13 -0
- package/templates/docs/agents/simplifier.md +13 -0
- package/templates/docs/phases/build.md +41 -0
- package/templates/docs/phases/define.md +51 -0
- package/templates/docs/phases/plan.md +36 -0
- package/templates/docs/phases/review.md +42 -0
- package/templates/docs/phases/ship.md +43 -0
- package/templates/docs/phases/simplify.md +40 -0
- package/templates/docs/phases/verify.md +38 -0
- package/templates/evaluator-rubric.md +28 -0
- package/templates/init.ps1 +97 -0
- package/templates/init.sh +102 -0
- package/templates/sprint-contract.md +31 -0
package/cli/lib/args.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal argument parser — no external deps.
|
|
3
|
+
*
|
|
4
|
+
* Parses: --flag value, --flag=value, --boolean, -h, --, positional args
|
|
5
|
+
* Supports: --json, --help, --version as named flags
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string[]} argv — typically process.argv
|
|
10
|
+
* @returns {{
|
|
11
|
+
* command: string|null,
|
|
12
|
+
* subcommand: string|null,
|
|
13
|
+
* flags: Record<string, string|boolean>,
|
|
14
|
+
* positionals: string[],
|
|
15
|
+
* json: boolean,
|
|
16
|
+
* help: boolean,
|
|
17
|
+
* version: boolean,
|
|
18
|
+
* }}
|
|
19
|
+
*/
|
|
20
|
+
export function parseArgs(argv) {
|
|
21
|
+
const result = {
|
|
22
|
+
command: null,
|
|
23
|
+
subcommand: null,
|
|
24
|
+
flags: {},
|
|
25
|
+
positionals: [],
|
|
26
|
+
json: false,
|
|
27
|
+
help: false,
|
|
28
|
+
version: false,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// skip node binary + script path
|
|
32
|
+
const tokens = argv.slice(2);
|
|
33
|
+
let stopParsing = false;
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
36
|
+
const token = tokens[i];
|
|
37
|
+
|
|
38
|
+
// everything after -- is a positional
|
|
39
|
+
if (stopParsing) {
|
|
40
|
+
result.positionals.push(token);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (token === '--') {
|
|
45
|
+
stopParsing = true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// flag tokens
|
|
50
|
+
if (token.startsWith('--')) {
|
|
51
|
+
const eqIdx = token.indexOf('=');
|
|
52
|
+
|
|
53
|
+
if (eqIdx !== -1) {
|
|
54
|
+
// --key=value
|
|
55
|
+
const key = token.slice(2, eqIdx);
|
|
56
|
+
result.flags[key] = token.slice(eqIdx + 1);
|
|
57
|
+
// promote well-known flags
|
|
58
|
+
if (key === 'json') {result.json = true;}
|
|
59
|
+
if (key === 'help') {result.help = true;}
|
|
60
|
+
if (key === 'version') {result.version = true;}
|
|
61
|
+
} else {
|
|
62
|
+
const key = token.slice(2);
|
|
63
|
+
|
|
64
|
+
// promote before value detection so --json alone is boolean
|
|
65
|
+
if (key === 'json') { result.json = true; continue; }
|
|
66
|
+
if (key === 'help') { result.help = true; continue; }
|
|
67
|
+
if (key === 'version') { result.version = true; continue; }
|
|
68
|
+
|
|
69
|
+
// peek next token for value
|
|
70
|
+
if (i + 1 < tokens.length && !tokens[i + 1].startsWith('-')) {
|
|
71
|
+
result.flags[key] = tokens[i + 1];
|
|
72
|
+
i++;
|
|
73
|
+
} else {
|
|
74
|
+
// boolean flag (no value)
|
|
75
|
+
result.flags[key] = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// short flags
|
|
82
|
+
if (token.startsWith('-') && token.length > 1 && token[1] !== '-') {
|
|
83
|
+
if (token === '-h') { result.help = true; continue; }
|
|
84
|
+
result.flags[token.slice(1)] = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// positional — first one is the command
|
|
89
|
+
if (!result.command) {
|
|
90
|
+
result.command = token;
|
|
91
|
+
} else {
|
|
92
|
+
result.positionals.push(token);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// The first positional becomes the subcommand (e.g. "phase build" → command=phase, subcommand=build)
|
|
97
|
+
if (result.positionals.length > 0) {
|
|
98
|
+
result.subcommand = result.positionals[0];
|
|
99
|
+
result.positionals = result.positionals.slice(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Determine if stdout should be JSON based on args.
|
|
107
|
+
* Mirrors the implicit promotion logic in parseArgs for external callers.
|
|
108
|
+
* @param {{ json?: boolean, flags?: Record<string,any> }} args
|
|
109
|
+
* @returns {boolean}
|
|
110
|
+
*/
|
|
111
|
+
// wantsJson removed — use parseCommandArgs().json from command-helpers.mjs instead.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* command-helpers — Shared utilities for command handlers.
|
|
3
|
+
*
|
|
4
|
+
* Eliminates the repeated `const json = !!(args.json || args.flags?.json)`
|
|
5
|
+
* and `const targetDir = ...` boilerplate duplicated across all 13 commands,
|
|
6
|
+
* plus the phaseLabel helper duplicated in 3 files.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* import { parseCommandArgs, phaseLabel } from '../lib/command-helpers.mjs';
|
|
10
|
+
* const { json, targetDir, flags } = parseCommandArgs(args);
|
|
11
|
+
*/
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extract common command options from parsed args.
|
|
16
|
+
* @param {object} args — parsed args from args.mjs parseArgs()
|
|
17
|
+
* @returns {{
|
|
18
|
+
* json: boolean,
|
|
19
|
+
* targetDir: string,
|
|
20
|
+
* flags: object,
|
|
21
|
+
* positionals: string[],
|
|
22
|
+
* subcommand: string|null,
|
|
23
|
+
* force: boolean,
|
|
24
|
+
* gitOps: boolean,
|
|
25
|
+
* }}
|
|
26
|
+
*/
|
|
27
|
+
export function parseCommandArgs(args) {
|
|
28
|
+
const json = !!(args.json || args.flags?.json);
|
|
29
|
+
const rawTarget = args.flags?.target;
|
|
30
|
+
const targetDir = (typeof rawTarget === 'string') ? resolve(rawTarget) : process.cwd();
|
|
31
|
+
return {
|
|
32
|
+
json,
|
|
33
|
+
targetDir,
|
|
34
|
+
flags: args.flags || {},
|
|
35
|
+
positionals: args.positionals || [],
|
|
36
|
+
subcommand: args.subcommand ?? null,
|
|
37
|
+
force: !!(args.flags?.force),
|
|
38
|
+
gitOps: !!(args.flags?.['git-ops'] || args.flags?.gitOps),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Format a phase name for display (uppercase, or UNKNOWN if null).
|
|
44
|
+
* Centralized here to avoid 3× duplication across ralph-inner/validate/phase.
|
|
45
|
+
* @param {string|null} phase
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
export function phaseLabel(phase) {
|
|
49
|
+
return phase ? phase.toUpperCase() : 'UNKNOWN';
|
|
50
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config-registry — Metadata for all configurable harness parameters.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for parameter descriptions, types, allowed values,
|
|
5
|
+
* and defaults. Used by:
|
|
6
|
+
* - `harness-dev config list` — interactive parameter listing
|
|
7
|
+
* - docs/CONFIGURATION.md — generated documentation
|
|
8
|
+
* - config command — validation of set values
|
|
9
|
+
*
|
|
10
|
+
* Each entry: { key, group, label, type, description, default, options?, editable }
|
|
11
|
+
* - editable: false for runtime state (currentPhase, retryCount, etc.)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* import { CONFIG_PARAMS, getParamMeta, EDITABLE_PARAMS } from './config-registry.mjs';
|
|
15
|
+
*/
|
|
16
|
+
export const CONFIG_PARAMS = [
|
|
17
|
+
// ── Execution Mode ────────────────────────────────────────────────────────
|
|
18
|
+
{
|
|
19
|
+
key: 'mode',
|
|
20
|
+
group: 'Execution',
|
|
21
|
+
label: 'Mode',
|
|
22
|
+
type: 'enum',
|
|
23
|
+
description: 'Execution mode. copilot = human runs each phase manually. autopilot = harness auto-advances through phases after each gate passes.',
|
|
24
|
+
default: 'copilot',
|
|
25
|
+
options: ['copilot', 'autopilot'],
|
|
26
|
+
editable: true,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: 'paused',
|
|
30
|
+
group: 'Execution',
|
|
31
|
+
label: 'Paused',
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
description: 'Autopilot pause state. When true, autopilot stops after current phase gate. Set by pause/resume commands.',
|
|
34
|
+
default: false,
|
|
35
|
+
editable: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: 'maxRetries',
|
|
39
|
+
group: 'Execution',
|
|
40
|
+
label: 'Max Retries',
|
|
41
|
+
type: 'integer',
|
|
42
|
+
description: 'Maximum retry attempts per phase before escalating to human. Each retry gets fresh context (git reset if --git-ops enabled).',
|
|
43
|
+
default: 3,
|
|
44
|
+
editable: true,
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// ── Stack ──────────────────────────────────────────────────────────────────
|
|
48
|
+
{
|
|
49
|
+
key: 'stack',
|
|
50
|
+
group: 'Stack',
|
|
51
|
+
label: 'Stack',
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Project programming stack. 31 built-in stacks (python, node, go, rust, etc.) or any custom name (fill stackMeta).',
|
|
54
|
+
default: null,
|
|
55
|
+
editable: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: 'stackMeta',
|
|
59
|
+
group: 'Stack',
|
|
60
|
+
label: 'Stack Metadata',
|
|
61
|
+
type: 'object',
|
|
62
|
+
description: 'Custom stack metadata (overrides built-in stacks.json). Fill during DEFINE for unknown stacks. Keys: label, testCmd, lintCmd, typeCheckCmd, buildCmd, installCmd, coverageCmd, versionFile, configFile, extensions, detectFiles.',
|
|
63
|
+
default: null,
|
|
64
|
+
editable: true,
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// ── Agent Tool ─────────────────────────────────────────────────────────────
|
|
68
|
+
{
|
|
69
|
+
key: 'agentTool',
|
|
70
|
+
group: 'Agent Tool',
|
|
71
|
+
label: 'Agent Tool',
|
|
72
|
+
type: 'enum',
|
|
73
|
+
description: 'Which agentic coding tool the project uses. Determines tool-specific file generated (CLAUDE.md, .cursorrules, etc.). null = unspecified.',
|
|
74
|
+
default: null,
|
|
75
|
+
options: [null, 'generic', 'claude-code', 'codex', 'cursor', 'windsurf', 'gemini', 'copilot', 'cline', 'roo', 'kilo-code', 'aider', 'continue', 'opencode', 'amazon-q', 'antigravity', 'openclaw', 'pi', 'hermes'],
|
|
76
|
+
editable: true,
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
// ── Gates ──────────────────────────────────────────────────────────────────
|
|
80
|
+
{
|
|
81
|
+
key: 'gates.enabled',
|
|
82
|
+
group: 'Gates',
|
|
83
|
+
label: 'Gates Enabled',
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
description: 'Master switch for phase gate validation. When false, validate reports gates disabled. Enable to enforce lint/test/coverage checks.',
|
|
86
|
+
default: false,
|
|
87
|
+
editable: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
key: 'gates.checks',
|
|
91
|
+
group: 'Gates',
|
|
92
|
+
label: 'Gate Checks',
|
|
93
|
+
type: 'array',
|
|
94
|
+
description: 'Which checks to run. ["all"] runs every check for the phase. Or specify individual: git-repo, config-exists, git-clean, lint, tests, coverage, contract-agreed, etc.',
|
|
95
|
+
default: ['all'],
|
|
96
|
+
editable: true,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
key: 'gates.coverage.enabled',
|
|
100
|
+
group: 'Gates',
|
|
101
|
+
label: 'Coverage Gate',
|
|
102
|
+
type: 'boolean',
|
|
103
|
+
description: 'Enable coverage threshold check in BUILD/VERIFY phases.',
|
|
104
|
+
default: false,
|
|
105
|
+
editable: true,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
key: 'gates.coverage.threshold',
|
|
109
|
+
group: 'Gates',
|
|
110
|
+
label: 'Coverage Threshold',
|
|
111
|
+
type: 'integer',
|
|
112
|
+
description: 'Minimum coverage percentage (0-100) to pass coverage gate.',
|
|
113
|
+
default: 80,
|
|
114
|
+
editable: true,
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// ── Git ────────────────────────────────────────────────────────────────────
|
|
118
|
+
{
|
|
119
|
+
key: 'git.autoCommit',
|
|
120
|
+
group: 'Git',
|
|
121
|
+
label: 'Auto-Commit',
|
|
122
|
+
type: 'boolean',
|
|
123
|
+
description: 'Automatically commit after each successful phase iteration. Recommended for autopilot.',
|
|
124
|
+
default: false,
|
|
125
|
+
editable: true,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
key: 'git.autoTag',
|
|
129
|
+
group: 'Git',
|
|
130
|
+
label: 'Auto-Tag',
|
|
131
|
+
type: 'boolean',
|
|
132
|
+
description: 'Create git tag when pipeline completes. Tags named pipeline-<date>-<timestamp>.',
|
|
133
|
+
default: false,
|
|
134
|
+
editable: true,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: 'git.resetOnRetry',
|
|
138
|
+
group: 'Git',
|
|
139
|
+
label: 'Reset on Retry',
|
|
140
|
+
type: 'boolean',
|
|
141
|
+
description: 'Reset git working tree on retry (fresh context). Also via --git-ops flag on phase command.',
|
|
142
|
+
default: false,
|
|
143
|
+
editable: true,
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// ── Phases ─────────────────────────────────────────────────────────────────
|
|
147
|
+
{
|
|
148
|
+
key: 'phases.enabled',
|
|
149
|
+
group: 'Phases',
|
|
150
|
+
label: 'Enabled Phases',
|
|
151
|
+
type: 'array',
|
|
152
|
+
description: 'Phases in pipeline. Default excludes simplify. Add "simplify" to enable. Order: define, plan, build, verify, [simplify], review, ship.',
|
|
153
|
+
default: ['define', 'plan', 'build', 'verify', 'review', 'ship'],
|
|
154
|
+
editable: true,
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// ── Agent Tones ────────────────────────────────────────────────────────────
|
|
158
|
+
{
|
|
159
|
+
key: 'agents.tone.planner',
|
|
160
|
+
group: 'Agent Tones',
|
|
161
|
+
label: 'Planner Tone',
|
|
162
|
+
type: 'string',
|
|
163
|
+
description: 'Personality/instructions for the Planner agent persona.',
|
|
164
|
+
default: 'Analytical and precise. Define clear boundaries.',
|
|
165
|
+
editable: true,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
key: 'agents.tone.generator',
|
|
169
|
+
group: 'Agent Tones',
|
|
170
|
+
label: 'Generator Tone',
|
|
171
|
+
type: 'string',
|
|
172
|
+
description: 'Personality/instructions for the Generator agent persona.',
|
|
173
|
+
default: 'Focused and practical. Build what\'s specified, nothing more.',
|
|
174
|
+
editable: true,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
key: 'agents.tone.evaluator',
|
|
178
|
+
group: 'Agent Tones',
|
|
179
|
+
label: 'Evaluator Tone',
|
|
180
|
+
type: 'string',
|
|
181
|
+
description: 'Personality/instructions for the Evaluator agent persona.',
|
|
182
|
+
default: 'Skeptical and thorough. Accept only compelling evidence.',
|
|
183
|
+
editable: true,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
key: 'agents.tone.simplifier',
|
|
187
|
+
group: 'Agent Tones',
|
|
188
|
+
label: 'Simplifier Tone',
|
|
189
|
+
type: 'string',
|
|
190
|
+
description: 'Personality/instructions for the Simplifier agent persona.',
|
|
191
|
+
default: 'Relentless about clarity. Delete more than you add.',
|
|
192
|
+
editable: true,
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// ── Runtime State (read-only — managed by harness) ─────────────────────────
|
|
196
|
+
{
|
|
197
|
+
key: 'currentPhase',
|
|
198
|
+
group: 'Runtime State',
|
|
199
|
+
label: 'Current Phase',
|
|
200
|
+
type: 'string',
|
|
201
|
+
description: 'Current pipeline phase. Managed by harness-dev phase — do not edit.',
|
|
202
|
+
default: null,
|
|
203
|
+
editable: false,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: 'retryCount',
|
|
207
|
+
group: 'Runtime State',
|
|
208
|
+
label: 'Retry Count',
|
|
209
|
+
type: 'integer',
|
|
210
|
+
description: 'Retry count for active phase. Reset on transition. Managed by harness.',
|
|
211
|
+
default: 0,
|
|
212
|
+
editable: false,
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
key: 'pipelineIteration',
|
|
216
|
+
group: 'Runtime State',
|
|
217
|
+
label: 'Pipeline Iteration',
|
|
218
|
+
type: 'integer',
|
|
219
|
+
description: 'Full pipeline completion count. Incremented on SHIP. Managed by harness.',
|
|
220
|
+
default: 0,
|
|
221
|
+
editable: false,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
key: 'gateHistory',
|
|
225
|
+
group: 'Runtime State',
|
|
226
|
+
label: 'Gate History',
|
|
227
|
+
type: 'array',
|
|
228
|
+
description: 'Record of gate pass/fail results. Managed by harness.',
|
|
229
|
+
default: [],
|
|
230
|
+
editable: false,
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
key: 'features.remaining',
|
|
234
|
+
group: 'Runtime State',
|
|
235
|
+
label: 'Features Remaining',
|
|
236
|
+
type: 'integer',
|
|
237
|
+
description: 'Incomplete feature count. Managed by harness.',
|
|
238
|
+
default: 0,
|
|
239
|
+
editable: false,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
key: 'features.passing',
|
|
243
|
+
group: 'Runtime State',
|
|
244
|
+
label: 'Features Passing',
|
|
245
|
+
type: 'integer',
|
|
246
|
+
description: 'Completed feature count. Managed by harness.',
|
|
247
|
+
default: 0,
|
|
248
|
+
editable: false,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
key: 'features.total',
|
|
252
|
+
group: 'Runtime State',
|
|
253
|
+
label: 'Features Total',
|
|
254
|
+
type: 'integer',
|
|
255
|
+
description: 'Total feature count. Managed by harness.',
|
|
256
|
+
default: 0,
|
|
257
|
+
editable: false,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
key: 'git.branch',
|
|
261
|
+
group: 'Runtime State',
|
|
262
|
+
label: 'Git Branch',
|
|
263
|
+
type: 'string',
|
|
264
|
+
description: 'Current git branch. Auto-detected — do not edit.',
|
|
265
|
+
default: null,
|
|
266
|
+
editable: false,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
key: 'git.clean',
|
|
270
|
+
group: 'Runtime State',
|
|
271
|
+
label: 'Git Clean',
|
|
272
|
+
type: 'boolean',
|
|
273
|
+
description: 'Working tree clean state. Auto-detected — do not edit.',
|
|
274
|
+
default: true,
|
|
275
|
+
editable: false,
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
key: 'git.hasUpstream',
|
|
279
|
+
group: 'Runtime State',
|
|
280
|
+
label: 'Has Upstream',
|
|
281
|
+
type: 'boolean',
|
|
282
|
+
description: 'Branch upstream tracking. Auto-detected — do not edit.',
|
|
283
|
+
default: false,
|
|
284
|
+
editable: false,
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
key: 'git.lastCommitMessage',
|
|
288
|
+
group: 'Runtime State',
|
|
289
|
+
label: 'Last Commit',
|
|
290
|
+
type: 'string',
|
|
291
|
+
description: 'Last git commit message. Auto-detected — do not edit.',
|
|
292
|
+
default: null,
|
|
293
|
+
editable: false,
|
|
294
|
+
},
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get metadata for a specific parameter key.
|
|
299
|
+
* @param {string} key
|
|
300
|
+
* @returns {object|null}
|
|
301
|
+
*/
|
|
302
|
+
export function getParamMeta(key) {
|
|
303
|
+
return CONFIG_PARAMS.find(p => p.key === key) || null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get all parameters in a specific group.
|
|
308
|
+
* @param {string} group
|
|
309
|
+
* @returns {object[]}
|
|
310
|
+
*/
|
|
311
|
+
export function getParamsByGroup(group) {
|
|
312
|
+
return CONFIG_PARAMS.filter(p => p.group === group);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get unique group names (preserving order).
|
|
317
|
+
* @returns {string[]}
|
|
318
|
+
*/
|
|
319
|
+
export function getGroups() {
|
|
320
|
+
const seen = new Set();
|
|
321
|
+
const groups = [];
|
|
322
|
+
for (const p of CONFIG_PARAMS) {
|
|
323
|
+
if (!seen.has(p.group)) {
|
|
324
|
+
seen.add(p.group);
|
|
325
|
+
groups.push(p.group);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return groups;
|
|
329
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* constants — Centralized magic numbers and strings.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for tunable values scattered across modules.
|
|
5
|
+
* Keeping them here makes intent clear and changes auditable.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { GATE_TIMEOUT, COVERAGE_TIMEOUT, MAX_NEGOTIATION_ROUNDS } from './constants.mjs';
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Default max retries per phase before escalating to human. */
|
|
12
|
+
export const DEFAULT_MAX_RETRIES = 3;
|
|
13
|
+
|
|
14
|
+
/** Timeout (ms) for standard git/shell commands. */
|
|
15
|
+
export const COMMAND_TIMEOUT = 30000;
|
|
16
|
+
|
|
17
|
+
/** Timeout (ms) for coverage checks (longer — coverage runs the full test suite). */
|
|
18
|
+
export const COVERAGE_TIMEOUT = 120000;
|
|
19
|
+
|
|
20
|
+
/** Default coverage threshold percentage. */
|
|
21
|
+
export const COVERAGE_THRESHOLD_DEFAULT = 80;
|
|
22
|
+
|
|
23
|
+
/** Max sprint-contract negotiation rounds before auto-escalation. */
|
|
24
|
+
export const MAX_NEGOTIATION_ROUNDS = 5;
|
|
25
|
+
|
|
26
|
+
/** Directory scan depth for stack detection. */
|
|
27
|
+
export const STACK_SCAN_DEPTH = 2;
|
|
28
|
+
|
|
29
|
+
/** File mode for executable scripts (init.sh). */
|
|
30
|
+
export const EXECUTABLE_MODE = 0o755;
|