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.
Files changed (70) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build-multi-agent-system/SKILL.md +68 -68
  3. package/create-agent-launcher/SKILL.md +48 -48
  4. package/docs/workflows/build-multi-agent-system.md +62 -62
  5. package/docs/workflows/create-agent-launcher.md +62 -62
  6. package/docs/workflows/environment-detection.md +63 -63
  7. package/docs/workflows/eval-harness.md +57 -57
  8. package/docs/workflows/fable-discipline.md +59 -59
  9. package/docs/workflows/fable-mode.md +32 -32
  10. package/docs/workflows/git-commit.md +62 -62
  11. package/docs/workflows/grill-me.md +62 -62
  12. package/docs/workflows/grill-with-docs.md +62 -62
  13. package/docs/workflows/improve-codebase-architecture.md +60 -60
  14. package/docs/workflows/repo-docs.md +59 -59
  15. package/docs/workflows/rewrite-commits.md +60 -60
  16. package/docs/workflows/security-review.md +58 -58
  17. package/docs/workflows/self-evolve.md +59 -59
  18. package/docs/workflows/tdd.md +39 -39
  19. package/docs/workflows/todo-driven-workflow.md +36 -36
  20. package/docs/workflows/using-git-worktrees.md +63 -63
  21. package/docs/workflows/verification-loop.md +69 -69
  22. package/docs/workflows/verify-before-claim.md +60 -60
  23. package/docs/workflows/zoom-out.md +62 -62
  24. package/environment-detection/SKILL.md +77 -77
  25. package/eval-framework/behavioral-test.js +105 -105
  26. package/eval-framework/mechanism-test.js +251 -251
  27. package/eval-harness/SKILL.md +59 -59
  28. package/fable-discipline/SKILL.md +38 -38
  29. package/fable-mode/SKILL.md +51 -51
  30. package/git-commit/SKILL.md +55 -55
  31. package/grill-me/SKILL.md +36 -36
  32. package/grill-with-docs/SKILL.md +99 -99
  33. package/harness-everything/SKILL.md +141 -141
  34. package/harness-everything/examples/README.md +9 -9
  35. package/harness-everything/examples/todo-workflow.md +22 -22
  36. package/harness-everything/scripts/todo-cli.js +157 -157
  37. package/harness-everything/scripts/verify-gate.js +31 -31
  38. package/hooks/scripts/atomic-commit-check.js +68 -68
  39. package/hooks/scripts/context-compact.js +114 -114
  40. package/hooks/scripts/lib/harness-state.js +29 -3
  41. package/hooks/scripts/lib/platforms/claude.js +42 -42
  42. package/hooks/scripts/lib/platforms/codex.js +46 -46
  43. package/hooks/scripts/lib/platforms/continue.js +41 -41
  44. package/hooks/scripts/lib/platforms/copilot.js +41 -41
  45. package/hooks/scripts/lib/platforms/cursor.js +41 -41
  46. package/hooks/scripts/rule-of-3.js +176 -176
  47. package/improve-codebase-architecture/SKILL.md +44 -44
  48. package/install-cognitive-os/SKILL.md +95 -95
  49. package/package.json +1 -1
  50. package/repo-docs/SKILL.md +45 -45
  51. package/rewrite-commits/SKILL.md +32 -32
  52. package/scripts/installer.js +649 -649
  53. package/scripts/lib/advisory-text.js +163 -163
  54. package/scripts/lib/claude-hooks.js +71 -71
  55. package/scripts/lib/gitignore.js +80 -58
  56. package/scripts/lib/manifest.js +82 -82
  57. package/scripts/lib/prompts.js +241 -241
  58. package/scripts/lib/skills.js +172 -172
  59. package/scripts/lib/workspace.js +28 -28
  60. package/security-review/SKILL.md +510 -510
  61. package/self-evolve/SKILL.md +54 -54
  62. package/skill-creator/SKILL.md +91 -91
  63. package/skill-creator/references/testing-workflow.md +32 -32
  64. package/skill-style/SKILL.md +48 -48
  65. package/tdd/SKILL.md +53 -53
  66. package/todo-driven-workflow/SKILL.md +54 -54
  67. package/using-git-worktrees/SKILL.md +161 -161
  68. package/verification-loop/SKILL.md +138 -138
  69. package/verify-before-claim/SKILL.md +86 -86
  70. 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
- if (patternsToAdd.length > 0) {
116
- const separator = content.length === 0 || content.endsWith('\n') ? '' : '\n';
117
- fs.appendFileSync(gitignorePath, separator + patternsToAdd.join('\n') + '\n', 'utf8');
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
+ };