harness-everything 0.2.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/CHANGELOG.md +7 -0
- package/build-multi-agent-system/SKILL.md +68 -68
- package/create-agent-launcher/SKILL.md +48 -48
- package/docs/workflows/build-multi-agent-system.md +62 -62
- package/docs/workflows/create-agent-launcher.md +62 -62
- package/docs/workflows/environment-detection.md +63 -63
- package/docs/workflows/eval-harness.md +57 -57
- package/docs/workflows/fable-discipline.md +59 -59
- package/docs/workflows/fable-mode.md +32 -32
- package/docs/workflows/git-commit.md +62 -62
- package/docs/workflows/grill-me.md +62 -62
- package/docs/workflows/grill-with-docs.md +62 -62
- package/docs/workflows/improve-codebase-architecture.md +60 -60
- package/docs/workflows/repo-docs.md +59 -59
- package/docs/workflows/rewrite-commits.md +60 -60
- package/docs/workflows/security-review.md +58 -58
- package/docs/workflows/self-evolve.md +59 -59
- package/docs/workflows/tdd.md +39 -39
- package/docs/workflows/todo-driven-workflow.md +36 -36
- package/docs/workflows/using-git-worktrees.md +63 -63
- package/docs/workflows/verification-loop.md +69 -69
- package/docs/workflows/verify-before-claim.md +60 -60
- package/docs/workflows/zoom-out.md +62 -62
- package/environment-detection/SKILL.md +77 -77
- package/eval-framework/behavioral-test.js +105 -105
- package/eval-framework/mechanism-test.js +251 -251
- package/eval-harness/SKILL.md +59 -59
- package/fable-discipline/SKILL.md +38 -38
- package/fable-mode/SKILL.md +51 -51
- package/git-commit/SKILL.md +55 -55
- package/grill-me/SKILL.md +36 -36
- package/grill-with-docs/SKILL.md +99 -99
- package/harness-everything/SKILL.md +141 -141
- package/harness-everything/examples/README.md +9 -9
- package/harness-everything/examples/todo-workflow.md +22 -22
- package/harness-everything/scripts/todo-cli.js +157 -157
- package/harness-everything/scripts/verify-gate.js +31 -31
- package/hooks/scripts/atomic-commit-check.js +68 -68
- package/hooks/scripts/context-compact.js +114 -114
- package/hooks/scripts/lib/harness-state.js +29 -3
- package/hooks/scripts/lib/platforms/claude.js +42 -42
- package/hooks/scripts/lib/platforms/codex.js +46 -46
- package/hooks/scripts/lib/platforms/continue.js +41 -41
- package/hooks/scripts/lib/platforms/copilot.js +41 -41
- package/hooks/scripts/lib/platforms/cursor.js +41 -41
- package/hooks/scripts/rule-of-3.js +176 -176
- package/improve-codebase-architecture/SKILL.md +44 -44
- package/install-cognitive-os/SKILL.md +95 -95
- package/package.json +1 -1
- package/repo-docs/SKILL.md +45 -45
- package/rewrite-commits/SKILL.md +32 -32
- package/scripts/installer.js +649 -649
- package/scripts/lib/advisory-text.js +163 -163
- package/scripts/lib/claude-hooks.js +71 -71
- package/scripts/lib/gitignore.js +80 -58
- package/scripts/lib/manifest.js +82 -82
- package/scripts/lib/prompts.js +241 -241
- package/scripts/lib/skills.js +172 -172
- package/scripts/lib/workspace.js +28 -28
- package/security-review/SKILL.md +510 -510
- package/self-evolve/SKILL.md +54 -54
- package/skill-creator/SKILL.md +91 -91
- package/skill-creator/references/testing-workflow.md +32 -32
- package/skill-style/SKILL.md +48 -48
- package/tdd/SKILL.md +53 -53
- package/todo-driven-workflow/SKILL.md +54 -54
- package/using-git-worktrees/SKILL.md +161 -161
- package/verification-loop/SKILL.md +138 -138
- package/verify-before-claim/SKILL.md +86 -86
- package/zoom-out/SKILL.md +90 -90
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { execSync } = require('child_process');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { getWorkspaceRoot, getSessionDir } = require('./lib/harness-state');
|
|
6
|
-
|
|
7
|
-
function main(payload) {
|
|
8
|
-
try {
|
|
9
|
-
// Let's run a quick Git check to estimate context size from modified files
|
|
10
|
-
const statusRaw = execSync('git status --porcelain', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
11
|
-
if (!statusRaw) {
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const lines = statusRaw.split('\n').filter(Boolean);
|
|
16
|
-
const modifiedCount = lines.length;
|
|
17
|
-
|
|
18
|
-
let totalDiffLines = 0;
|
|
19
|
-
try {
|
|
20
|
-
const diffStat = execSync('git diff --numstat', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
21
|
-
if (diffStat) {
|
|
22
|
-
diffStat.split('\n').forEach(line => {
|
|
23
|
-
const [added, deleted] = line.split('\t');
|
|
24
|
-
if (added && added !== '-' && deleted && deleted !== '-') {
|
|
25
|
-
totalDiffLines += parseInt(added) + parseInt(deleted);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
} catch (err) {
|
|
30
|
-
// Ignore git errors
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Thresholds for warning
|
|
34
|
-
const HIGH_FILE_LIMIT = 6;
|
|
35
|
-
const HIGH_LINE_LIMIT = 400;
|
|
36
|
-
|
|
37
|
-
const overThreshold = modifiedCount >= HIGH_FILE_LIMIT || totalDiffLines >= HIGH_LINE_LIMIT;
|
|
38
|
-
|
|
39
|
-
// Throttle: this hook fires on EVERY Bash/Edit/Write call, and a warning
|
|
40
|
-
// about context bloat that repeats on every call becomes context bloat
|
|
41
|
-
// itself (and trains the model to ignore hook output). Warn on the first
|
|
42
|
-
// crossing, then only every 10th call while still over - or when the diff
|
|
43
|
-
// has grown another 50% since the last warning.
|
|
44
|
-
const stateFile = path.join(getSessionDir(getWorkspaceRoot(), payload && payload.session_id), 'context-compact-state.json');
|
|
45
|
-
let state = { overCount: 0, lastWarnedLines: 0 };
|
|
46
|
-
try {
|
|
47
|
-
if (fs.existsSync(stateFile)) state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
48
|
-
} catch (err) { /* use default */ }
|
|
49
|
-
|
|
50
|
-
if (!overThreshold) {
|
|
51
|
-
if (state.overCount > 0) {
|
|
52
|
-
try {
|
|
53
|
-
fs.writeFileSync(stateFile, JSON.stringify({ overCount: 0, lastWarnedLines: 0 }), 'utf8');
|
|
54
|
-
} catch (err) { /* ignore */ }
|
|
55
|
-
}
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
state.overCount += 1;
|
|
60
|
-
const onBeat = state.overCount === 1 || state.overCount % 10 === 0;
|
|
61
|
-
const grewALot = totalDiffLines >= (state.lastWarnedLines || 0) * 1.5 && totalDiffLines > state.lastWarnedLines;
|
|
62
|
-
const shouldWarn = onBeat || grewALot;
|
|
63
|
-
if (shouldWarn) state.lastWarnedLines = totalDiffLines;
|
|
64
|
-
try {
|
|
65
|
-
fs.writeFileSync(stateFile, JSON.stringify(state), 'utf8');
|
|
66
|
-
} catch (err) { /* ignore */ }
|
|
67
|
-
|
|
68
|
-
if (shouldWarn) {
|
|
69
|
-
// Plain stdout on exit 0 is only surfaced to Claude for UserPromptSubmit/
|
|
70
|
-
// SessionStart - for PreToolUse it's written to a debug log Claude never
|
|
71
|
-
// sees. To actually get an advisory (non-blocking) message in front of
|
|
72
|
-
// Claude here, it has to go through hookSpecificOutput.additionalContext.
|
|
73
|
-
const message = [
|
|
74
|
-
`Harness OS - Context Bloat Warning`,
|
|
75
|
-
`- Modified Files: ${modifiedCount}`,
|
|
76
|
-
`- Accumulated Diff: ${totalDiffLines} lines`,
|
|
77
|
-
``,
|
|
78
|
-
`Caution: Large number of modified files or big diffs will bloat the Agent context window, leading to:`,
|
|
79
|
-
` 1. "Lost in the Middle" reasoning degradation`,
|
|
80
|
-
` 2. Rapidly inflating token costs`,
|
|
81
|
-
``,
|
|
82
|
-
`Recommended Action:`,
|
|
83
|
-
` - Run atomic commits or stage completed files.`,
|
|
84
|
-
` - Use targeted sub-folders rather than broad searches.`,
|
|
85
|
-
` - Ask user to run '/compact' or '/clear' if supported.`
|
|
86
|
-
].join('\n');
|
|
87
|
-
|
|
88
|
-
console.log(JSON.stringify({
|
|
89
|
-
hookSpecificOutput: {
|
|
90
|
-
hookEventName: "PreToolUse",
|
|
91
|
-
additionalContext: message
|
|
92
|
-
}
|
|
93
|
-
}));
|
|
94
|
-
}
|
|
95
|
-
} catch (err) {
|
|
96
|
-
// Fail open - never block user execution on compaction checker
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
process.exit(0);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
let inputData = '';
|
|
103
|
-
const timeout = setTimeout(() => { main(null); }, 200);
|
|
104
|
-
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
105
|
-
process.stdin.on('end', () => {
|
|
106
|
-
clearTimeout(timeout);
|
|
107
|
-
let payload = null;
|
|
108
|
-
try { payload = JSON.parse(inputData.trim()); } catch (err) { /* no payload */ }
|
|
109
|
-
main(payload);
|
|
110
|
-
});
|
|
111
|
-
process.stdin.on('error', () => {
|
|
112
|
-
clearTimeout(timeout);
|
|
113
|
-
main(null);
|
|
114
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { getWorkspaceRoot, getSessionDir } = require('./lib/harness-state');
|
|
6
|
+
|
|
7
|
+
function main(payload) {
|
|
8
|
+
try {
|
|
9
|
+
// Let's run a quick Git check to estimate context size from modified files
|
|
10
|
+
const statusRaw = execSync('git status --porcelain', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
11
|
+
if (!statusRaw) {
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const lines = statusRaw.split('\n').filter(Boolean);
|
|
16
|
+
const modifiedCount = lines.length;
|
|
17
|
+
|
|
18
|
+
let totalDiffLines = 0;
|
|
19
|
+
try {
|
|
20
|
+
const diffStat = execSync('git diff --numstat', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
21
|
+
if (diffStat) {
|
|
22
|
+
diffStat.split('\n').forEach(line => {
|
|
23
|
+
const [added, deleted] = line.split('\t');
|
|
24
|
+
if (added && added !== '-' && deleted && deleted !== '-') {
|
|
25
|
+
totalDiffLines += parseInt(added) + parseInt(deleted);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// Ignore git errors
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Thresholds for warning
|
|
34
|
+
const HIGH_FILE_LIMIT = 6;
|
|
35
|
+
const HIGH_LINE_LIMIT = 400;
|
|
36
|
+
|
|
37
|
+
const overThreshold = modifiedCount >= HIGH_FILE_LIMIT || totalDiffLines >= HIGH_LINE_LIMIT;
|
|
38
|
+
|
|
39
|
+
// Throttle: this hook fires on EVERY Bash/Edit/Write call, and a warning
|
|
40
|
+
// about context bloat that repeats on every call becomes context bloat
|
|
41
|
+
// itself (and trains the model to ignore hook output). Warn on the first
|
|
42
|
+
// crossing, then only every 10th call while still over - or when the diff
|
|
43
|
+
// has grown another 50% since the last warning.
|
|
44
|
+
const stateFile = path.join(getSessionDir(getWorkspaceRoot(), payload && payload.session_id), 'context-compact-state.json');
|
|
45
|
+
let state = { overCount: 0, lastWarnedLines: 0 };
|
|
46
|
+
try {
|
|
47
|
+
if (fs.existsSync(stateFile)) state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
48
|
+
} catch (err) { /* use default */ }
|
|
49
|
+
|
|
50
|
+
if (!overThreshold) {
|
|
51
|
+
if (state.overCount > 0) {
|
|
52
|
+
try {
|
|
53
|
+
fs.writeFileSync(stateFile, JSON.stringify({ overCount: 0, lastWarnedLines: 0 }), 'utf8');
|
|
54
|
+
} catch (err) { /* ignore */ }
|
|
55
|
+
}
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
state.overCount += 1;
|
|
60
|
+
const onBeat = state.overCount === 1 || state.overCount % 10 === 0;
|
|
61
|
+
const grewALot = totalDiffLines >= (state.lastWarnedLines || 0) * 1.5 && totalDiffLines > state.lastWarnedLines;
|
|
62
|
+
const shouldWarn = onBeat || grewALot;
|
|
63
|
+
if (shouldWarn) state.lastWarnedLines = totalDiffLines;
|
|
64
|
+
try {
|
|
65
|
+
fs.writeFileSync(stateFile, JSON.stringify(state), 'utf8');
|
|
66
|
+
} catch (err) { /* ignore */ }
|
|
67
|
+
|
|
68
|
+
if (shouldWarn) {
|
|
69
|
+
// Plain stdout on exit 0 is only surfaced to Claude for UserPromptSubmit/
|
|
70
|
+
// SessionStart - for PreToolUse it's written to a debug log Claude never
|
|
71
|
+
// sees. To actually get an advisory (non-blocking) message in front of
|
|
72
|
+
// Claude here, it has to go through hookSpecificOutput.additionalContext.
|
|
73
|
+
const message = [
|
|
74
|
+
`Harness OS - Context Bloat Warning`,
|
|
75
|
+
`- Modified Files: ${modifiedCount}`,
|
|
76
|
+
`- Accumulated Diff: ${totalDiffLines} lines`,
|
|
77
|
+
``,
|
|
78
|
+
`Caution: Large number of modified files or big diffs will bloat the Agent context window, leading to:`,
|
|
79
|
+
` 1. "Lost in the Middle" reasoning degradation`,
|
|
80
|
+
` 2. Rapidly inflating token costs`,
|
|
81
|
+
``,
|
|
82
|
+
`Recommended Action:`,
|
|
83
|
+
` - Run atomic commits or stage completed files.`,
|
|
84
|
+
` - Use targeted sub-folders rather than broad searches.`,
|
|
85
|
+
` - Ask user to run '/compact' or '/clear' if supported.`
|
|
86
|
+
].join('\n');
|
|
87
|
+
|
|
88
|
+
console.log(JSON.stringify({
|
|
89
|
+
hookSpecificOutput: {
|
|
90
|
+
hookEventName: "PreToolUse",
|
|
91
|
+
additionalContext: message
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
// Fail open - never block user execution on compaction checker
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let inputData = '';
|
|
103
|
+
const timeout = setTimeout(() => { main(null); }, 200);
|
|
104
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
105
|
+
process.stdin.on('end', () => {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
let payload = null;
|
|
108
|
+
try { payload = JSON.parse(inputData.trim()); } catch (err) { /* no payload */ }
|
|
109
|
+
main(payload);
|
|
110
|
+
});
|
|
111
|
+
process.stdin.on('error', () => {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
main(null);
|
|
114
|
+
});
|
|
@@ -112,9 +112,35 @@ function ensureHarnessStateIgnored(rootPath) {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
// This runs once per hook invocation - i.e. once per Claude Code
|
|
116
|
+
// subprocess - with no cross-process lock around the read-then-append
|
|
117
|
+
// below. Two hook invocations firing close together (e.g. two tool
|
|
118
|
+
// calls in the same turn) can each read the file before either has
|
|
119
|
+
// written, so both decide the same pattern is missing and both append
|
|
120
|
+
// it, leaving an exact duplicate line behind. Rather than add real
|
|
121
|
+
// cross-process locking for a housekeeping file that already fails
|
|
122
|
+
// silently by design, every call also collapses any exact-duplicate
|
|
123
|
+
// non-comment/non-blank line it finds - so a duplicate from a lost
|
|
124
|
+
// race self-heals on the very next invocation instead of accumulating.
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
let sawDuplicate = false;
|
|
127
|
+
const dedupedLines = lines.filter(line => {
|
|
128
|
+
const trimmed = line.trim();
|
|
129
|
+
if (trimmed === '' || trimmed.startsWith('#')) return true;
|
|
130
|
+
if (seen.has(trimmed)) {
|
|
131
|
+
sawDuplicate = true;
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
seen.add(trimmed);
|
|
135
|
+
return true;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (patternsToAdd.length > 0 || sawDuplicate) {
|
|
139
|
+
while (dedupedLines.length > 0 && dedupedLines[dedupedLines.length - 1] === '') {
|
|
140
|
+
dedupedLines.pop();
|
|
141
|
+
}
|
|
142
|
+
const finalLines = dedupedLines.concat(patternsToAdd);
|
|
143
|
+
fs.writeFileSync(gitignorePath, finalLines.join('\n') + '\n', 'utf8');
|
|
118
144
|
}
|
|
119
145
|
} catch (err) {
|
|
120
146
|
// Fail silently to avoid breaking execution if .gitignore is write-locked
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
|
|
4
|
-
// Claude Code has no native project-skill directory this package can piggy
|
|
5
|
-
// back on, so everything Harness adds locally - runtime state AND the
|
|
6
|
-
// installed skill copies - lives under one self-contained subfolder of the
|
|
7
|
-
// platform's own directory: .claude/harness-everything/. That keeps it out
|
|
8
|
-
// of a self-invented top-level folder (the old .harness/) while still being
|
|
9
|
-
// exclusively ours - nothing else creates a directory literally named
|
|
10
|
-
// "harness-everything" inside .claude/, so it's trivial to add/remove
|
|
11
|
-
// without touching anything else Claude Code or the user put in .claude/.
|
|
12
|
-
module.exports = {
|
|
13
|
-
name: 'claude',
|
|
14
|
-
label: 'Claude Code',
|
|
15
|
-
getHarnessDir(workspaceRoot) {
|
|
16
|
-
return path.join(workspaceRoot, '.claude', 'harness-everything');
|
|
17
|
-
},
|
|
18
|
-
getStateDir(workspaceRoot) {
|
|
19
|
-
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
20
|
-
},
|
|
21
|
-
getSkillsDir(workspaceRoot) {
|
|
22
|
-
return path.join(this.getHarnessDir(workspaceRoot), 'skills');
|
|
23
|
-
},
|
|
24
|
-
getIgnorePatterns(workspaceRoot) {
|
|
25
|
-
return ['.claude/harness-everything/'];
|
|
26
|
-
},
|
|
27
|
-
isMatch(pattern, trimmedLine) {
|
|
28
|
-
if (pattern === '.claude/harness-everything/') {
|
|
29
|
-
return trimmedLine === '.claude/' ||
|
|
30
|
-
trimmedLine === '.claude' ||
|
|
31
|
-
trimmedLine === '.claude/harness-everything' ||
|
|
32
|
-
trimmedLine === '.claude/harness-everything/';
|
|
33
|
-
}
|
|
34
|
-
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
35
|
-
},
|
|
36
|
-
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
37
|
-
if (isGlobal) {
|
|
38
|
-
return fs.existsSync(path.join(userHome, '.claude', 'settings.json'));
|
|
39
|
-
}
|
|
40
|
-
return fs.existsSync(path.join(workspaceRoot, '.claude', 'settings.json'));
|
|
41
|
-
}
|
|
42
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// Claude Code has no native project-skill directory this package can piggy
|
|
5
|
+
// back on, so everything Harness adds locally - runtime state AND the
|
|
6
|
+
// installed skill copies - lives under one self-contained subfolder of the
|
|
7
|
+
// platform's own directory: .claude/harness-everything/. That keeps it out
|
|
8
|
+
// of a self-invented top-level folder (the old .harness/) while still being
|
|
9
|
+
// exclusively ours - nothing else creates a directory literally named
|
|
10
|
+
// "harness-everything" inside .claude/, so it's trivial to add/remove
|
|
11
|
+
// without touching anything else Claude Code or the user put in .claude/.
|
|
12
|
+
module.exports = {
|
|
13
|
+
name: 'claude',
|
|
14
|
+
label: 'Claude Code',
|
|
15
|
+
getHarnessDir(workspaceRoot) {
|
|
16
|
+
return path.join(workspaceRoot, '.claude', 'harness-everything');
|
|
17
|
+
},
|
|
18
|
+
getStateDir(workspaceRoot) {
|
|
19
|
+
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
20
|
+
},
|
|
21
|
+
getSkillsDir(workspaceRoot) {
|
|
22
|
+
return path.join(this.getHarnessDir(workspaceRoot), 'skills');
|
|
23
|
+
},
|
|
24
|
+
getIgnorePatterns(workspaceRoot) {
|
|
25
|
+
return ['.claude/harness-everything/'];
|
|
26
|
+
},
|
|
27
|
+
isMatch(pattern, trimmedLine) {
|
|
28
|
+
if (pattern === '.claude/harness-everything/') {
|
|
29
|
+
return trimmedLine === '.claude/' ||
|
|
30
|
+
trimmedLine === '.claude' ||
|
|
31
|
+
trimmedLine === '.claude/harness-everything' ||
|
|
32
|
+
trimmedLine === '.claude/harness-everything/';
|
|
33
|
+
}
|
|
34
|
+
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
35
|
+
},
|
|
36
|
+
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
37
|
+
if (isGlobal) {
|
|
38
|
+
return fs.existsSync(path.join(userHome, '.claude', 'settings.json'));
|
|
39
|
+
}
|
|
40
|
+
return fs.existsSync(path.join(workspaceRoot, '.claude', 'settings.json'));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
|
|
4
|
-
// Codex CLI's real project-scoped home is `.codex/` (it reads `.codex/skills/`
|
|
5
|
-
// for project skills and `.codex/config.toml` for CLI/sandbox config, walking
|
|
6
|
-
// up to the `.git` root exactly like AGENTS.md - see
|
|
7
|
-
// https://developers.openai.com/codex/config-advanced and
|
|
8
|
-
// https://www.agensi.io/learn/codex-cli-agents-md-complete-guide). Skills
|
|
9
|
-
// stay at that native `.codex/skills/` location; only bookkeeping that never
|
|
10
|
-
// had a home (runtime state, install manifest) converges into
|
|
11
|
-
// `.codex/harness-everything/`.
|
|
12
|
-
module.exports = {
|
|
13
|
-
name: 'codex',
|
|
14
|
-
label: 'Codex / Gemini',
|
|
15
|
-
getHarnessDir(workspaceRoot) {
|
|
16
|
-
return path.join(workspaceRoot, '.codex', 'harness-everything');
|
|
17
|
-
},
|
|
18
|
-
getStateDir(workspaceRoot) {
|
|
19
|
-
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
20
|
-
},
|
|
21
|
-
getSkillsDir(workspaceRoot) {
|
|
22
|
-
return path.join(workspaceRoot, '.codex', 'skills');
|
|
23
|
-
},
|
|
24
|
-
getIgnorePatterns(workspaceRoot) {
|
|
25
|
-
const patterns = ['.codex/harness-everything/'];
|
|
26
|
-
if (fs.existsSync(path.join(workspaceRoot, '.codex', 'skills'))) {
|
|
27
|
-
patterns.push('.codex/skills/');
|
|
28
|
-
}
|
|
29
|
-
return patterns;
|
|
30
|
-
},
|
|
31
|
-
isMatch(pattern, trimmedLine) {
|
|
32
|
-
if (pattern === '.codex/harness-everything/') {
|
|
33
|
-
return trimmedLine === '.codex/' ||
|
|
34
|
-
trimmedLine === '.codex' ||
|
|
35
|
-
trimmedLine === '.codex/harness-everything' ||
|
|
36
|
-
trimmedLine === '.codex/harness-everything/';
|
|
37
|
-
}
|
|
38
|
-
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
39
|
-
},
|
|
40
|
-
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
41
|
-
if (isGlobal) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
return fs.existsSync(path.join(workspaceRoot, 'AGENTS.md'));
|
|
45
|
-
}
|
|
46
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// Codex CLI's real project-scoped home is `.codex/` (it reads `.codex/skills/`
|
|
5
|
+
// for project skills and `.codex/config.toml` for CLI/sandbox config, walking
|
|
6
|
+
// up to the `.git` root exactly like AGENTS.md - see
|
|
7
|
+
// https://developers.openai.com/codex/config-advanced and
|
|
8
|
+
// https://www.agensi.io/learn/codex-cli-agents-md-complete-guide). Skills
|
|
9
|
+
// stay at that native `.codex/skills/` location; only bookkeeping that never
|
|
10
|
+
// had a home (runtime state, install manifest) converges into
|
|
11
|
+
// `.codex/harness-everything/`.
|
|
12
|
+
module.exports = {
|
|
13
|
+
name: 'codex',
|
|
14
|
+
label: 'Codex / Gemini',
|
|
15
|
+
getHarnessDir(workspaceRoot) {
|
|
16
|
+
return path.join(workspaceRoot, '.codex', 'harness-everything');
|
|
17
|
+
},
|
|
18
|
+
getStateDir(workspaceRoot) {
|
|
19
|
+
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
20
|
+
},
|
|
21
|
+
getSkillsDir(workspaceRoot) {
|
|
22
|
+
return path.join(workspaceRoot, '.codex', 'skills');
|
|
23
|
+
},
|
|
24
|
+
getIgnorePatterns(workspaceRoot) {
|
|
25
|
+
const patterns = ['.codex/harness-everything/'];
|
|
26
|
+
if (fs.existsSync(path.join(workspaceRoot, '.codex', 'skills'))) {
|
|
27
|
+
patterns.push('.codex/skills/');
|
|
28
|
+
}
|
|
29
|
+
return patterns;
|
|
30
|
+
},
|
|
31
|
+
isMatch(pattern, trimmedLine) {
|
|
32
|
+
if (pattern === '.codex/harness-everything/') {
|
|
33
|
+
return trimmedLine === '.codex/' ||
|
|
34
|
+
trimmedLine === '.codex' ||
|
|
35
|
+
trimmedLine === '.codex/harness-everything' ||
|
|
36
|
+
trimmedLine === '.codex/harness-everything/';
|
|
37
|
+
}
|
|
38
|
+
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
39
|
+
},
|
|
40
|
+
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
41
|
+
if (isGlobal) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return fs.existsSync(path.join(workspaceRoot, 'AGENTS.md'));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
|
|
4
|
-
// Continue's own skills location (.continue/skills/) is unchanged - it
|
|
5
|
-
// already has an established home. Only bookkeeping that never had a home
|
|
6
|
-
// (runtime state, install manifest) converges into .continue/harness-everything/.
|
|
7
|
-
module.exports = {
|
|
8
|
-
name: 'continue',
|
|
9
|
-
label: 'Continue.dev',
|
|
10
|
-
getHarnessDir(workspaceRoot) {
|
|
11
|
-
return path.join(workspaceRoot, '.continue', 'harness-everything');
|
|
12
|
-
},
|
|
13
|
-
getStateDir(workspaceRoot) {
|
|
14
|
-
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
15
|
-
},
|
|
16
|
-
getSkillsDir(workspaceRoot) {
|
|
17
|
-
return path.join(workspaceRoot, '.continue', 'skills');
|
|
18
|
-
},
|
|
19
|
-
getIgnorePatterns(workspaceRoot) {
|
|
20
|
-
const patterns = ['.continue/harness-everything/'];
|
|
21
|
-
if (fs.existsSync(path.join(workspaceRoot, '.continue', 'skills'))) {
|
|
22
|
-
patterns.push('.continue/skills/');
|
|
23
|
-
}
|
|
24
|
-
return patterns;
|
|
25
|
-
},
|
|
26
|
-
isMatch(pattern, trimmedLine) {
|
|
27
|
-
if (pattern === '.continue/harness-everything/') {
|
|
28
|
-
return trimmedLine === '.continue/' ||
|
|
29
|
-
trimmedLine === '.continue' ||
|
|
30
|
-
trimmedLine === '.continue/harness-everything' ||
|
|
31
|
-
trimmedLine === '.continue/harness-everything/';
|
|
32
|
-
}
|
|
33
|
-
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
34
|
-
},
|
|
35
|
-
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
36
|
-
if (isGlobal) {
|
|
37
|
-
return fs.existsSync(path.join(userHome, '.continue', 'rules', 'harness.md'));
|
|
38
|
-
}
|
|
39
|
-
return fs.existsSync(path.join(workspaceRoot, '.continue', 'rules', 'harness.md'));
|
|
40
|
-
}
|
|
41
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// Continue's own skills location (.continue/skills/) is unchanged - it
|
|
5
|
+
// already has an established home. Only bookkeeping that never had a home
|
|
6
|
+
// (runtime state, install manifest) converges into .continue/harness-everything/.
|
|
7
|
+
module.exports = {
|
|
8
|
+
name: 'continue',
|
|
9
|
+
label: 'Continue.dev',
|
|
10
|
+
getHarnessDir(workspaceRoot) {
|
|
11
|
+
return path.join(workspaceRoot, '.continue', 'harness-everything');
|
|
12
|
+
},
|
|
13
|
+
getStateDir(workspaceRoot) {
|
|
14
|
+
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
15
|
+
},
|
|
16
|
+
getSkillsDir(workspaceRoot) {
|
|
17
|
+
return path.join(workspaceRoot, '.continue', 'skills');
|
|
18
|
+
},
|
|
19
|
+
getIgnorePatterns(workspaceRoot) {
|
|
20
|
+
const patterns = ['.continue/harness-everything/'];
|
|
21
|
+
if (fs.existsSync(path.join(workspaceRoot, '.continue', 'skills'))) {
|
|
22
|
+
patterns.push('.continue/skills/');
|
|
23
|
+
}
|
|
24
|
+
return patterns;
|
|
25
|
+
},
|
|
26
|
+
isMatch(pattern, trimmedLine) {
|
|
27
|
+
if (pattern === '.continue/harness-everything/') {
|
|
28
|
+
return trimmedLine === '.continue/' ||
|
|
29
|
+
trimmedLine === '.continue' ||
|
|
30
|
+
trimmedLine === '.continue/harness-everything' ||
|
|
31
|
+
trimmedLine === '.continue/harness-everything/';
|
|
32
|
+
}
|
|
33
|
+
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
34
|
+
},
|
|
35
|
+
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
36
|
+
if (isGlobal) {
|
|
37
|
+
return fs.existsSync(path.join(userHome, '.continue', 'rules', 'harness.md'));
|
|
38
|
+
}
|
|
39
|
+
return fs.existsSync(path.join(workspaceRoot, '.continue', 'rules', 'harness.md'));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
|
|
4
|
-
// Copilot's own skills location (.github/skills/) is unchanged - it already
|
|
5
|
-
// has an established home. Only bookkeeping that never had a home (runtime
|
|
6
|
-
// state, install manifest) converges into .github/harness-everything/.
|
|
7
|
-
module.exports = {
|
|
8
|
-
name: 'copilot',
|
|
9
|
-
label: 'GitHub Copilot',
|
|
10
|
-
getHarnessDir(workspaceRoot) {
|
|
11
|
-
return path.join(workspaceRoot, '.github', 'harness-everything');
|
|
12
|
-
},
|
|
13
|
-
getStateDir(workspaceRoot) {
|
|
14
|
-
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
15
|
-
},
|
|
16
|
-
getSkillsDir(workspaceRoot) {
|
|
17
|
-
return path.join(workspaceRoot, '.github', 'skills');
|
|
18
|
-
},
|
|
19
|
-
getIgnorePatterns(workspaceRoot) {
|
|
20
|
-
const patterns = ['.github/harness-everything/'];
|
|
21
|
-
if (fs.existsSync(path.join(workspaceRoot, '.github', 'skills'))) {
|
|
22
|
-
patterns.push('.github/skills/');
|
|
23
|
-
}
|
|
24
|
-
return patterns;
|
|
25
|
-
},
|
|
26
|
-
isMatch(pattern, trimmedLine) {
|
|
27
|
-
if (pattern === '.github/harness-everything/') {
|
|
28
|
-
return trimmedLine === '.github/' ||
|
|
29
|
-
trimmedLine === '.github' ||
|
|
30
|
-
trimmedLine === '.github/harness-everything' ||
|
|
31
|
-
trimmedLine === '.github/harness-everything/';
|
|
32
|
-
}
|
|
33
|
-
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
34
|
-
},
|
|
35
|
-
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
36
|
-
if (isGlobal) {
|
|
37
|
-
return false; // Handled via global userPromptsDir check
|
|
38
|
-
}
|
|
39
|
-
return fs.existsSync(path.join(workspaceRoot, '.github', 'copilot-instructions.md'));
|
|
40
|
-
}
|
|
41
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// Copilot's own skills location (.github/skills/) is unchanged - it already
|
|
5
|
+
// has an established home. Only bookkeeping that never had a home (runtime
|
|
6
|
+
// state, install manifest) converges into .github/harness-everything/.
|
|
7
|
+
module.exports = {
|
|
8
|
+
name: 'copilot',
|
|
9
|
+
label: 'GitHub Copilot',
|
|
10
|
+
getHarnessDir(workspaceRoot) {
|
|
11
|
+
return path.join(workspaceRoot, '.github', 'harness-everything');
|
|
12
|
+
},
|
|
13
|
+
getStateDir(workspaceRoot) {
|
|
14
|
+
return path.join(this.getHarnessDir(workspaceRoot), 'state');
|
|
15
|
+
},
|
|
16
|
+
getSkillsDir(workspaceRoot) {
|
|
17
|
+
return path.join(workspaceRoot, '.github', 'skills');
|
|
18
|
+
},
|
|
19
|
+
getIgnorePatterns(workspaceRoot) {
|
|
20
|
+
const patterns = ['.github/harness-everything/'];
|
|
21
|
+
if (fs.existsSync(path.join(workspaceRoot, '.github', 'skills'))) {
|
|
22
|
+
patterns.push('.github/skills/');
|
|
23
|
+
}
|
|
24
|
+
return patterns;
|
|
25
|
+
},
|
|
26
|
+
isMatch(pattern, trimmedLine) {
|
|
27
|
+
if (pattern === '.github/harness-everything/') {
|
|
28
|
+
return trimmedLine === '.github/' ||
|
|
29
|
+
trimmedLine === '.github' ||
|
|
30
|
+
trimmedLine === '.github/harness-everything' ||
|
|
31
|
+
trimmedLine === '.github/harness-everything/';
|
|
32
|
+
}
|
|
33
|
+
return trimmedLine === pattern || trimmedLine === pattern.slice(0, -1);
|
|
34
|
+
},
|
|
35
|
+
isInstalled(workspaceRoot, userHome, isGlobal) {
|
|
36
|
+
if (isGlobal) {
|
|
37
|
+
return false; // Handled via global userPromptsDir check
|
|
38
|
+
}
|
|
39
|
+
return fs.existsSync(path.join(workspaceRoot, '.github', 'copilot-instructions.md'));
|
|
40
|
+
}
|
|
41
|
+
};
|