workspace-maxxing 0.1.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/.agents/skills/workspace-maxxing/.workspace-templates/CONTEXT.md +44 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/SYSTEM.md +44 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/references/anti-patterns.md +16 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/references/iron-laws.md +26 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/references/reporting-format.md +52 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/benchmark.ts +171 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/dispatch.ts +473 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/generate-tests.ts +158 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/install-tool.ts +82 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/iterate.ts +265 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/orchestrator.ts +539 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/scaffold.ts +282 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/scripts/validate.ts +452 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/architecture/SKILL.md +95 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/fixer/SKILL.md +109 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/iteration/SKILL.md +89 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/prompt-engineering/SKILL.md +87 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/research/SKILL.md +94 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/testing/SKILL.md +89 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/tooling/SKILL.md +87 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/validation/SKILL.md +103 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/skills/worker/SKILL.md +79 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/00-meta/CONTEXT.md +6 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/00-meta/execution-log.md +27 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/01-input/CONTEXT.md +29 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/02-process/CONTEXT.md +29 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/03-output/CONTEXT.md +29 -0
- package/.agents/skills/workspace-maxxing/.workspace-templates/workspace/README.md +14 -0
- package/.agents/skills/workspace-maxxing/SKILL.md +312 -0
- package/.agents/skills/workspace-maxxing/scripts/benchmark.ts +171 -0
- package/.agents/skills/workspace-maxxing/scripts/dispatch.ts +473 -0
- package/.agents/skills/workspace-maxxing/scripts/generate-tests.ts +158 -0
- package/.agents/skills/workspace-maxxing/scripts/install-tool.ts +82 -0
- package/.agents/skills/workspace-maxxing/scripts/iterate.ts +265 -0
- package/.agents/skills/workspace-maxxing/scripts/orchestrator.ts +539 -0
- package/.agents/skills/workspace-maxxing/scripts/scaffold.ts +282 -0
- package/.agents/skills/workspace-maxxing/scripts/validate.ts +452 -0
- package/README.md +144 -0
- package/dist/agent-creator.d.ts +9 -0
- package/dist/agent-creator.d.ts.map +1 -0
- package/dist/agent-creator.js +199 -0
- package/dist/agent-creator.js.map +1 -0
- package/dist/agent-iterator.d.ts +38 -0
- package/dist/agent-iterator.d.ts.map +1 -0
- package/dist/agent-iterator.js +327 -0
- package/dist/agent-iterator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +197 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +18 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +117 -0
- package/dist/install.js.map +1 -0
- package/dist/platforms/claude.d.ts +7 -0
- package/dist/platforms/claude.d.ts.map +1 -0
- package/dist/platforms/claude.js +70 -0
- package/dist/platforms/claude.js.map +1 -0
- package/dist/platforms/copilot.d.ts +7 -0
- package/dist/platforms/copilot.d.ts.map +1 -0
- package/dist/platforms/copilot.js +75 -0
- package/dist/platforms/copilot.js.map +1 -0
- package/dist/platforms/gemini.d.ts +7 -0
- package/dist/platforms/gemini.d.ts.map +1 -0
- package/dist/platforms/gemini.js +81 -0
- package/dist/platforms/gemini.js.map +1 -0
- package/dist/platforms/index.d.ts +8 -0
- package/dist/platforms/index.d.ts.map +1 -0
- package/dist/platforms/index.js +41 -0
- package/dist/platforms/index.js.map +1 -0
- package/dist/platforms/opencode.d.ts +7 -0
- package/dist/platforms/opencode.d.ts.map +1 -0
- package/dist/platforms/opencode.js +70 -0
- package/dist/platforms/opencode.js.map +1 -0
- package/dist/scripts/benchmark.d.ts +20 -0
- package/dist/scripts/benchmark.d.ts.map +1 -0
- package/dist/scripts/benchmark.js +170 -0
- package/dist/scripts/benchmark.js.map +1 -0
- package/dist/scripts/dispatch.d.ts +32 -0
- package/dist/scripts/dispatch.d.ts.map +1 -0
- package/dist/scripts/dispatch.js +386 -0
- package/dist/scripts/dispatch.js.map +1 -0
- package/dist/scripts/generate-tests.d.ts +11 -0
- package/dist/scripts/generate-tests.d.ts.map +1 -0
- package/dist/scripts/generate-tests.js +118 -0
- package/dist/scripts/generate-tests.js.map +1 -0
- package/dist/scripts/install-tool.d.ts +8 -0
- package/dist/scripts/install-tool.d.ts.map +1 -0
- package/dist/scripts/install-tool.js +98 -0
- package/dist/scripts/install-tool.js.map +1 -0
- package/dist/scripts/iterate.d.ts +44 -0
- package/dist/scripts/iterate.d.ts.map +1 -0
- package/dist/scripts/iterate.js +260 -0
- package/dist/scripts/iterate.js.map +1 -0
- package/dist/scripts/orchestrator.d.ts +40 -0
- package/dist/scripts/orchestrator.d.ts.map +1 -0
- package/dist/scripts/orchestrator.js +378 -0
- package/dist/scripts/orchestrator.js.map +1 -0
- package/dist/scripts/scaffold.d.ts +8 -0
- package/dist/scripts/scaffold.d.ts.map +1 -0
- package/dist/scripts/scaffold.js +279 -0
- package/dist/scripts/scaffold.js.map +1 -0
- package/dist/scripts/validate.d.ts +11 -0
- package/dist/scripts/validate.d.ts.map +1 -0
- package/dist/scripts/validate.js +472 -0
- package/dist/scripts/validate.js.map +1 -0
- package/docs/superpowers/plans/2026-04-07-autonomous-iteration-plan.md +1123 -0
- package/docs/superpowers/plans/2026-04-07-autonomous-iteration-sub-agent-batches.md +1923 -0
- package/docs/superpowers/plans/2026-04-07-autonomous-workflow-sub-skill-plan.md +1505 -0
- package/docs/superpowers/plans/2026-04-07-benchmarking-multi-agent-plan.md +854 -0
- package/docs/superpowers/plans/2026-04-07-workspace-builder-logic-plan.md +1426 -0
- package/docs/superpowers/plans/2026-04-07-workspace-maxxing-plan.md +1299 -0
- package/docs/superpowers/plans/2026-04-08-session-294c-subagent-invocation-plan.md +320 -0
- package/docs/superpowers/plans/2026-04-08-workflow-prompt-hardening-plan.md +1025 -0
- package/docs/superpowers/plans/2026-04-12-workspace-agent-creation-plan.md +992 -0
- package/docs/superpowers/specs/2026-04-07-autonomous-iteration-design.md +214 -0
- package/docs/superpowers/specs/2026-04-07-autonomous-iteration-sub-agent-batches-design.md +188 -0
- package/docs/superpowers/specs/2026-04-07-autonomous-workflow-sub-skill-design.md +137 -0
- package/docs/superpowers/specs/2026-04-07-benchmarking-multi-agent-design.md +105 -0
- package/docs/superpowers/specs/2026-04-07-workspace-builder-logic-design.md +179 -0
- package/docs/superpowers/specs/2026-04-07-workspace-maxxing-design.md +227 -0
- package/docs/superpowers/specs/2026-04-08-session-294c-subagent-invocation-design.md +265 -0
- package/docs/superpowers/specs/2026-04-08-workflow-prompt-hardening-design.md +146 -0
- package/docs/superpowers/specs/2026-04-12-workspace-agent-creation-design.md +239 -0
- package/jest.config.js +8 -0
- package/package.json +32 -0
- package/src/agent-creator.ts +180 -0
- package/src/agent-iterator.ts +397 -0
- package/src/index.ts +189 -0
- package/src/install.ts +105 -0
- package/src/platforms/claude.ts +40 -0
- package/src/platforms/copilot.ts +50 -0
- package/src/platforms/gemini.ts +55 -0
- package/src/platforms/index.ts +45 -0
- package/src/platforms/opencode.ts +41 -0
- package/src/scripts/benchmark.ts +171 -0
- package/src/scripts/dispatch.ts +473 -0
- package/src/scripts/generate-tests.ts +112 -0
- package/src/scripts/install-tool.ts +82 -0
- package/src/scripts/iterate.ts +271 -0
- package/src/scripts/orchestrator.ts +539 -0
- package/src/scripts/scaffold.ts +282 -0
- package/src/scripts/validate.ts +516 -0
- package/templates/.workspace-templates/CONTEXT.md +44 -0
- package/templates/.workspace-templates/SYSTEM.md +44 -0
- package/templates/.workspace-templates/references/anti-patterns.md +16 -0
- package/templates/.workspace-templates/references/iron-laws.md +26 -0
- package/templates/.workspace-templates/references/reporting-format.md +52 -0
- package/templates/.workspace-templates/scripts/benchmark.ts +171 -0
- package/templates/.workspace-templates/scripts/dispatch.ts +473 -0
- package/templates/.workspace-templates/scripts/generate-tests.ts +158 -0
- package/templates/.workspace-templates/scripts/install-tool.ts +82 -0
- package/templates/.workspace-templates/scripts/iterate.ts +265 -0
- package/templates/.workspace-templates/scripts/orchestrator.ts +539 -0
- package/templates/.workspace-templates/scripts/scaffold.ts +282 -0
- package/templates/.workspace-templates/scripts/validate.ts +452 -0
- package/templates/.workspace-templates/skills/architecture/SKILL.md +95 -0
- package/templates/.workspace-templates/skills/fixer/SKILL.md +109 -0
- package/templates/.workspace-templates/skills/iteration/SKILL.md +89 -0
- package/templates/.workspace-templates/skills/prompt-engineering/SKILL.md +87 -0
- package/templates/.workspace-templates/skills/research/SKILL.md +94 -0
- package/templates/.workspace-templates/skills/testing/SKILL.md +89 -0
- package/templates/.workspace-templates/skills/tooling/SKILL.md +87 -0
- package/templates/.workspace-templates/skills/validation/SKILL.md +103 -0
- package/templates/.workspace-templates/skills/worker/SKILL.md +79 -0
- package/templates/.workspace-templates/workspace/00-meta/CONTEXT.md +6 -0
- package/templates/.workspace-templates/workspace/00-meta/execution-log.md +27 -0
- package/templates/.workspace-templates/workspace/01-input/CONTEXT.md +29 -0
- package/templates/.workspace-templates/workspace/02-process/CONTEXT.md +29 -0
- package/templates/.workspace-templates/workspace/03-output/CONTEXT.md +29 -0
- package/templates/.workspace-templates/workspace/README.md +14 -0
- package/templates/SKILL.md +347 -0
- package/tests/benchmark.test.ts +158 -0
- package/tests/cli.test.ts +109 -0
- package/tests/dispatch-parallel.test.ts +124 -0
- package/tests/dispatch.test.ts +218 -0
- package/tests/fixer-skill.test.ts +203 -0
- package/tests/generate-tests.test.ts +101 -0
- package/tests/install-tool.test.ts +141 -0
- package/tests/install.test.ts +144 -0
- package/tests/integration.test.ts +324 -0
- package/tests/iterate.test.ts +219 -0
- package/tests/orchestrator.test.ts +710 -0
- package/tests/scaffold.test.ts +238 -0
- package/tests/templates-enhanced.test.ts +208 -0
- package/tests/templates.test.ts +219 -0
- package/tests/validate.test.ts +421 -0
- package/tests/validation-enhanced.test.ts +303 -0
- package/tests/worker-skill.test.ts +88 -0
- package/tsconfig.json +19 -0
- package/workspace/00-meta/CONTEXT.md +3 -0
- package/workspace/00-meta/execution-log.md +17 -0
- package/workspace/00-meta/tools.md +11 -0
- package/workspace/01-input/CONTEXT.md +27 -0
- package/workspace/CONTEXT.md +35 -0
- package/workspace/README.md +14 -0
- package/workspace/SYSTEM.md +36 -0
- package/workspace-maxxing-0.1.0.tgz +0 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import { execFileSync } from 'child_process';
|
|
6
|
+
|
|
7
|
+
const repoRoot = path.join(__dirname, '..');
|
|
8
|
+
const cliPath = path.join(repoRoot, 'dist', 'index.js');
|
|
9
|
+
const templatesPath = path.join(repoRoot, 'templates');
|
|
10
|
+
const orchestratorPath = path.join(repoRoot, 'dist', 'scripts', 'orchestrator.js');
|
|
11
|
+
const dispatchPath = path.join(repoRoot, 'dist', 'scripts', 'dispatch.js');
|
|
12
|
+
|
|
13
|
+
function writeFileWithParents(filePath: string, content: string): void {
|
|
14
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
15
|
+
fs.writeFileSync(filePath, content);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createBasicOrchestratorWorkspace(baseDir: string): string {
|
|
19
|
+
const workspacePath = path.join(baseDir, 'workspace');
|
|
20
|
+
fs.mkdirSync(workspacePath, { recursive: true });
|
|
21
|
+
|
|
22
|
+
const stageNames = ['01-input', '02-process', '03-output'];
|
|
23
|
+
for (const stageName of stageNames) {
|
|
24
|
+
const contextPath = path.join(workspacePath, stageName, 'CONTEXT.md');
|
|
25
|
+
writeFileWithParents(
|
|
26
|
+
contextPath,
|
|
27
|
+
[
|
|
28
|
+
'## Purpose',
|
|
29
|
+
`${stageName} purpose for automated integration testing.`,
|
|
30
|
+
'',
|
|
31
|
+
'## Input',
|
|
32
|
+
'Structured data from the prior stage input.',
|
|
33
|
+
'',
|
|
34
|
+
'## Output',
|
|
35
|
+
'Structured output produced by this stage.',
|
|
36
|
+
'',
|
|
37
|
+
'## Dependencies',
|
|
38
|
+
'Depends on upstream context and files.',
|
|
39
|
+
'',
|
|
40
|
+
'## Success Criteria',
|
|
41
|
+
'Produces deterministic and complete output.',
|
|
42
|
+
'',
|
|
43
|
+
'## Approach',
|
|
44
|
+
'Follow the stage workflow and validation checks.',
|
|
45
|
+
'',
|
|
46
|
+
'## Risks',
|
|
47
|
+
'Incorrect transformations can reduce quality.',
|
|
48
|
+
'',
|
|
49
|
+
'## Timeline',
|
|
50
|
+
'This stage completes in a single iteration.',
|
|
51
|
+
'',
|
|
52
|
+
'## Resources',
|
|
53
|
+
'Uses the local skill templates and reports.',
|
|
54
|
+
'',
|
|
55
|
+
'## Validation',
|
|
56
|
+
'Validate outputs against expected structure.',
|
|
57
|
+
'',
|
|
58
|
+
].join('\n'),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
writeFileWithParents(
|
|
63
|
+
path.join(workspacePath, '.agents', 'skills', 'workspace-maxxing', 'skills', 'worker', 'SKILL.md'),
|
|
64
|
+
'---\nname: worker\n---\n\n# Worker\n\nIntegration worker skill fixture.\n',
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
writeFileWithParents(
|
|
68
|
+
path.join(workspacePath, '.agents', 'skills', 'workspace-maxxing', 'skills', 'fixer', 'SKILL.md'),
|
|
69
|
+
'---\nname: fixer\n---\n\n# Fixer\n\nIntegration fixer skill fixture.\n',
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return workspacePath;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function runOrchestrator(orchestratorPath: string, workspacePath: string, extraArgs: string[] = []): string {
|
|
76
|
+
return execFileSync(
|
|
77
|
+
process.execPath,
|
|
78
|
+
[orchestratorPath, '--workspace', workspacePath, '--batch-size', '2', ...extraArgs],
|
|
79
|
+
{ encoding: 'utf-8' },
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function runDispatch(dispatchScriptPath: string, args: string[]): string {
|
|
84
|
+
return execFileSync(
|
|
85
|
+
process.execPath,
|
|
86
|
+
[dispatchScriptPath, ...args],
|
|
87
|
+
{ encoding: 'utf-8' },
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function runBuildOnce(): void {
|
|
92
|
+
const npmExecPath = process.env.npm_execpath;
|
|
93
|
+
|
|
94
|
+
if (npmExecPath) {
|
|
95
|
+
execFileSync(process.execPath, [npmExecPath, 'run', 'build'], {
|
|
96
|
+
cwd: repoRoot,
|
|
97
|
+
stdio: 'pipe',
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
execFileSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['run', 'build'], {
|
|
103
|
+
cwd: repoRoot,
|
|
104
|
+
stdio: 'pipe',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function runInstaller(targetDir: string): string {
|
|
109
|
+
return execFileSync(process.execPath, [cliPath, '--opencode'], {
|
|
110
|
+
cwd: targetDir,
|
|
111
|
+
encoding: 'utf-8',
|
|
112
|
+
env: {
|
|
113
|
+
...process.env,
|
|
114
|
+
WORKSPACE_MAXXING_TEMPLATES: templatesPath,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function snapshotDirectory(rootDir: string): { files: string[]; hash: string } {
|
|
120
|
+
const files: string[] = [];
|
|
121
|
+
|
|
122
|
+
const walk = (currentDir: string): void => {
|
|
123
|
+
for (const entry of fs.readdirSync(currentDir, { withFileTypes: true })) {
|
|
124
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
125
|
+
if (entry.isDirectory()) {
|
|
126
|
+
walk(absolutePath);
|
|
127
|
+
} else {
|
|
128
|
+
files.push(path.relative(rootDir, absolutePath));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
walk(rootDir);
|
|
134
|
+
files.sort();
|
|
135
|
+
|
|
136
|
+
const hash = createHash('sha256');
|
|
137
|
+
for (const relativeFilePath of files) {
|
|
138
|
+
hash.update(relativeFilePath);
|
|
139
|
+
hash.update('\0');
|
|
140
|
+
hash.update(fs.readFileSync(path.join(rootDir, relativeFilePath)));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
files,
|
|
145
|
+
hash: hash.digest('hex'),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
beforeAll(() => {
|
|
150
|
+
runBuildOnce();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('Integration', () => {
|
|
154
|
+
let tempDir: string;
|
|
155
|
+
|
|
156
|
+
beforeEach(() => {
|
|
157
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workspace-maxxing-integration-'));
|
|
158
|
+
fs.writeFileSync(path.join(tempDir, 'package.json'), '{}');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
afterEach(() => {
|
|
162
|
+
if (tempDir) {
|
|
163
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('end-to-end: install and verify complete structure', () => {
|
|
168
|
+
// Run installer
|
|
169
|
+
const output = runInstaller(tempDir);
|
|
170
|
+
|
|
171
|
+
expect(output).toContain('installed');
|
|
172
|
+
|
|
173
|
+
// Verify skill directory
|
|
174
|
+
const skillDir = path.join(tempDir, '.agents', 'skills', 'workspace-maxxing');
|
|
175
|
+
expect(fs.existsSync(skillDir)).toBe(true);
|
|
176
|
+
|
|
177
|
+
// Verify all expected files exist
|
|
178
|
+
const expectedFiles = [
|
|
179
|
+
'SKILL.md',
|
|
180
|
+
'.workspace-templates/SYSTEM.md',
|
|
181
|
+
'.workspace-templates/CONTEXT.md',
|
|
182
|
+
'.workspace-templates/workspace/00-meta/CONTEXT.md',
|
|
183
|
+
'.workspace-templates/workspace/01-input/CONTEXT.md',
|
|
184
|
+
'.workspace-templates/workspace/02-process/CONTEXT.md',
|
|
185
|
+
'.workspace-templates/workspace/03-output/CONTEXT.md',
|
|
186
|
+
'.workspace-templates/workspace/README.md',
|
|
187
|
+
'scripts/scaffold.ts',
|
|
188
|
+
'scripts/validate.ts',
|
|
189
|
+
'scripts/install-tool.ts',
|
|
190
|
+
'scripts/iterate.ts',
|
|
191
|
+
'scripts/generate-tests.ts',
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
for (const file of expectedFiles) {
|
|
195
|
+
const filePath = path.join(skillDir, file);
|
|
196
|
+
expect(fs.existsSync(filePath)).toBe(true);
|
|
197
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
198
|
+
expect(content.trim().length).toBeGreaterThan(0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Verify SKILL.md has required sections
|
|
202
|
+
const skillContent = fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf-8');
|
|
203
|
+
expect(skillContent).toContain('## Overview');
|
|
204
|
+
expect(skillContent).toContain('## When to Use');
|
|
205
|
+
expect(skillContent).toContain('## The Iron Law');
|
|
206
|
+
expect(skillContent).toContain('## Hybrid Flow');
|
|
207
|
+
expect(skillContent).toContain('## Sub-Skill Dispatch');
|
|
208
|
+
expect(skillContent).toContain('## Available Scripts');
|
|
209
|
+
expect(skillContent).toContain('## Anti-Rationalization Table');
|
|
210
|
+
expect(skillContent).toContain('## Integration');
|
|
211
|
+
expect(skillContent).toContain('## ICM Rules');
|
|
212
|
+
expect(skillContent).toContain('## Output Format');
|
|
213
|
+
expect(skillContent).toContain('scaffold.ts');
|
|
214
|
+
expect(skillContent).toContain('validate.ts');
|
|
215
|
+
expect(skillContent).toContain('install-tool.ts');
|
|
216
|
+
expect(skillContent).toContain('dispatch.ts');
|
|
217
|
+
expect(skillContent).toContain('iterate.ts');
|
|
218
|
+
expect(skillContent).toContain('generate-tests.ts');
|
|
219
|
+
expect(skillContent).toContain('benchmark.ts');
|
|
220
|
+
|
|
221
|
+
// Verify SYSTEM.md has Layer 0 content
|
|
222
|
+
const systemContent = fs.readFileSync(path.join(skillDir, '.workspace-templates', 'SYSTEM.md'), 'utf-8');
|
|
223
|
+
expect(systemContent.toLowerCase()).toContain('folder map');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('idempotency: running install twice produces valid result', () => {
|
|
227
|
+
const firstOutput = runInstaller(tempDir);
|
|
228
|
+
expect(firstOutput).toContain('installed');
|
|
229
|
+
|
|
230
|
+
const skillDir = path.join(tempDir, '.agents', 'skills', 'workspace-maxxing');
|
|
231
|
+
expect(fs.existsSync(path.join(skillDir, 'SKILL.md'))).toBe(true);
|
|
232
|
+
|
|
233
|
+
const firstSnapshot = snapshotDirectory(skillDir);
|
|
234
|
+
expect(firstSnapshot.files.length).toBeGreaterThan(0);
|
|
235
|
+
expect(firstSnapshot.files).toContain('SKILL.md');
|
|
236
|
+
expect(firstSnapshot.files).toContain(path.join('scripts', 'iterate.ts'));
|
|
237
|
+
|
|
238
|
+
const secondOutput = runInstaller(tempDir);
|
|
239
|
+
expect(secondOutput).toContain('installed');
|
|
240
|
+
|
|
241
|
+
const secondSnapshot = snapshotDirectory(skillDir);
|
|
242
|
+
expect(secondSnapshot.files).toEqual(firstSnapshot.files);
|
|
243
|
+
expect(secondSnapshot.hash).toBe(firstSnapshot.hash);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe('orchestrator integration', () => {
|
|
248
|
+
let orchestratorTempDir: string;
|
|
249
|
+
|
|
250
|
+
beforeEach(() => {
|
|
251
|
+
orchestratorTempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workspace-maxxing-orchestrator-integration-'));
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
afterEach(() => {
|
|
255
|
+
if (orchestratorTempDir) {
|
|
256
|
+
fs.rmSync(orchestratorTempDir, { recursive: true, force: true });
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('runs full batch lifecycle on a valid workspace via dist orchestrator script', () => {
|
|
261
|
+
const workspacePath = createBasicOrchestratorWorkspace(orchestratorTempDir);
|
|
262
|
+
|
|
263
|
+
const output = runOrchestrator(orchestratorPath, workspacePath);
|
|
264
|
+
const result = JSON.parse(output);
|
|
265
|
+
|
|
266
|
+
expect(result.totalBatches).toBeGreaterThan(0);
|
|
267
|
+
expect(Array.isArray(result.batchReports)).toBe(true);
|
|
268
|
+
expect(result.batchReports.length).toBe(result.totalBatches);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('writes summary.json to .agents/iteration', () => {
|
|
272
|
+
const workspacePath = createBasicOrchestratorWorkspace(orchestratorTempDir);
|
|
273
|
+
|
|
274
|
+
runOrchestrator(orchestratorPath, workspacePath);
|
|
275
|
+
|
|
276
|
+
const summaryPath = path.join(workspacePath, '.agents', 'iteration', 'summary.json');
|
|
277
|
+
expect(fs.existsSync(summaryPath)).toBe(true);
|
|
278
|
+
|
|
279
|
+
const summary = JSON.parse(fs.readFileSync(summaryPath, 'utf-8'));
|
|
280
|
+
expect(summary.totalBatches).toBeGreaterThan(0);
|
|
281
|
+
expect(typeof summary.timestamp).toBe('string');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('worker dispatch fails without external runner command', () => {
|
|
285
|
+
const workspacePath = createBasicOrchestratorWorkspace(orchestratorTempDir);
|
|
286
|
+
|
|
287
|
+
const output = runDispatch(dispatchPath, [
|
|
288
|
+
'--skill', 'worker',
|
|
289
|
+
'--workspace', workspacePath,
|
|
290
|
+
'--batch-id', '1',
|
|
291
|
+
'--test-case-id', 'tc-001',
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
const report = JSON.parse(output);
|
|
295
|
+
expect(report.status).toBe('failed');
|
|
296
|
+
expect(report.findings.join(' ')).toContain('External sub-agent runner is required');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('dispatch-recursion runner command does not produce a successful worker execution', () => {
|
|
300
|
+
const workspacePath = createBasicOrchestratorWorkspace(orchestratorTempDir);
|
|
301
|
+
const recursiveRunner = `"${process.execPath}" "${dispatchPath}" --skill {skill} --workspace "{workspace}" --batch-id {batchId} --test-case-id {testCaseId}`;
|
|
302
|
+
|
|
303
|
+
const output = runDispatch(dispatchPath, [
|
|
304
|
+
'--skill', 'worker',
|
|
305
|
+
'--workspace', workspacePath,
|
|
306
|
+
'--batch-id', '1',
|
|
307
|
+
'--test-case-id', 'tc-002',
|
|
308
|
+
'--runner-command', recursiveRunner,
|
|
309
|
+
]);
|
|
310
|
+
|
|
311
|
+
const report = JSON.parse(output);
|
|
312
|
+
expect(report.status).toBe('failed');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('orchestrator does not mark passing batches when worker execution cannot run', () => {
|
|
316
|
+
const workspacePath = createBasicOrchestratorWorkspace(orchestratorTempDir);
|
|
317
|
+
|
|
318
|
+
const output = runOrchestrator(orchestratorPath, workspacePath, ['--score-threshold', '95']);
|
|
319
|
+
const result = JSON.parse(output);
|
|
320
|
+
|
|
321
|
+
expect(result.passedBatches).toBe(0);
|
|
322
|
+
expect(result.failedBatches + result.escalatedBatches).toBe(result.totalBatches);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { iterateWorkspace, IterateResult, scoreWorkspace, runChecklist } from '../src/scripts/iterate';
|
|
5
|
+
import * as validate from '../src/scripts/validate';
|
|
6
|
+
|
|
7
|
+
jest.mock('../src/scripts/validate');
|
|
8
|
+
|
|
9
|
+
describe('iterate', () => {
|
|
10
|
+
let tempDir: string;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'iterate-test-'));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
function createBasicWorkspace(): string {
|
|
22
|
+
const ws = path.join(tempDir, 'workspace');
|
|
23
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
24
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Test\n\n## Role\nWorkspace role\n\n## Folder Map\n\n- `01-input/`\n- `02-output/`\n\n## Rules\nICM rules\n');
|
|
25
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n\n## Routing Table\n\n- `01-input/` → `01-input/CONTEXT.md`\n- `02-output/` → `02-output/CONTEXT.md`\n');
|
|
26
|
+
fs.mkdirSync(path.join(ws, '01-input'), { recursive: true });
|
|
27
|
+
fs.writeFileSync(path.join(ws, '01-input', 'CONTEXT.md'), '# 01-input\n\n## Purpose\nInput stage\n\n## Inputs\nRaw data\n\n## Outputs\nValidated data\n\n## Dependencies\nNone\n');
|
|
28
|
+
fs.mkdirSync(path.join(ws, '02-output'), { recursive: true });
|
|
29
|
+
fs.writeFileSync(path.join(ws, '02-output', 'CONTEXT.md'), '# 02-output\n\n## Purpose\nOutput stage\n\n## Inputs\nProcessed data\n\n## Outputs\nFinal report\n\n## Dependencies\n01-input\n');
|
|
30
|
+
fs.mkdirSync(path.join(ws, '00-meta'), { recursive: true });
|
|
31
|
+
fs.writeFileSync(path.join(ws, '00-meta', 'tools.md'), '# Tool Inventory\n\n## Installed Tools\n\n| Tool | Version | Manager | Installed |\n|------|---------|---------|-----------|\n| — | — | — | — |\n');
|
|
32
|
+
fs.writeFileSync(path.join(ws, 'README.md'), '# Test Workspace\n\n## Usage\nFollow stages in order.\n');
|
|
33
|
+
return ws;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('iterateWorkspace', () => {
|
|
37
|
+
it('passes all three passes on a good workspace', () => {
|
|
38
|
+
const ws = createBasicWorkspace();
|
|
39
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
40
|
+
passed: true,
|
|
41
|
+
checks: [],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const result = iterateWorkspace(ws, { maxRetries: 3 });
|
|
45
|
+
|
|
46
|
+
expect(result.passes.validate.status).toBe('passed');
|
|
47
|
+
expect(result.passes.score.score).toBeGreaterThan(0);
|
|
48
|
+
expect(result.passes.checklist.items).toBeGreaterThan(0);
|
|
49
|
+
expect(result.escalate).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('retries validation failures up to maxRetries', () => {
|
|
53
|
+
const ws = createBasicWorkspace();
|
|
54
|
+
(validate.validateWorkspace as jest.Mock)
|
|
55
|
+
.mockReturnValueOnce({ passed: false, checks: [{ name: 'SYSTEM.md exists', passed: false, message: 'Missing' }] })
|
|
56
|
+
.mockReturnValueOnce({ passed: true, checks: [] });
|
|
57
|
+
|
|
58
|
+
const result = iterateWorkspace(ws, { maxRetries: 3 });
|
|
59
|
+
|
|
60
|
+
expect(result.passes.validate.retries).toBe(1);
|
|
61
|
+
expect(result.passes.validate.status).toBe('passed');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('escalates when validation fails after max retries', () => {
|
|
65
|
+
const ws = createBasicWorkspace();
|
|
66
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
67
|
+
passed: false,
|
|
68
|
+
checks: [{ name: 'SYSTEM.md exists', passed: false, message: 'Missing' }],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const result = iterateWorkspace(ws, { maxRetries: 2 });
|
|
72
|
+
|
|
73
|
+
expect(result.escalate).toBe(true);
|
|
74
|
+
expect(result.passes.validate.status).toBe('escalated');
|
|
75
|
+
expect(result.passes.validate.retries).toBe(2);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('returns score with improvements for low-quality workspace', () => {
|
|
79
|
+
const ws = path.join(tempDir, 'workspace');
|
|
80
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
81
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Minimal\n');
|
|
82
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n');
|
|
83
|
+
fs.mkdirSync(path.join(ws, '01-input'), { recursive: true });
|
|
84
|
+
fs.writeFileSync(path.join(ws, '01-input', 'CONTEXT.md'), '# 01-input\n');
|
|
85
|
+
fs.mkdirSync(path.join(ws, '00-meta'), { recursive: true });
|
|
86
|
+
fs.writeFileSync(path.join(ws, '00-meta', 'tools.md'), '# Tools\n');
|
|
87
|
+
|
|
88
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
89
|
+
passed: true,
|
|
90
|
+
checks: [],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const result = iterateWorkspace(ws, { maxRetries: 1 });
|
|
94
|
+
|
|
95
|
+
expect(result.passes.score.score).toBeLessThan(80);
|
|
96
|
+
expect(result.passes.score.improvements.length).toBeGreaterThan(0);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('checklist reports pass/fail per item', () => {
|
|
100
|
+
const ws = createBasicWorkspace();
|
|
101
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
102
|
+
passed: true,
|
|
103
|
+
checks: [],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const result = iterateWorkspace(ws, { maxRetries: 1 });
|
|
107
|
+
|
|
108
|
+
expect(result.passes.checklist.items).toBe(result.passes.checklist.passed + result.passes.checklist.failed);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('scoreWorkspace', () => {
|
|
113
|
+
it('scores a perfect workspace 100', () => {
|
|
114
|
+
const ws = createBasicWorkspace();
|
|
115
|
+
const score = scoreWorkspace(ws);
|
|
116
|
+
|
|
117
|
+
expect(score.total).toBe(85);
|
|
118
|
+
expect(score.improvements).toHaveLength(0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('deducts points for missing SYSTEM.md sections', () => {
|
|
122
|
+
const ws = path.join(tempDir, 'workspace');
|
|
123
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
124
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Minimal\n');
|
|
125
|
+
|
|
126
|
+
const score = scoreWorkspace(ws);
|
|
127
|
+
|
|
128
|
+
expect(score.system).toBeLessThan(20);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('deducts points for missing CONTEXT.md routing', () => {
|
|
132
|
+
const ws = path.join(tempDir, 'workspace');
|
|
133
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
134
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Test\n\n## Folder Map\n\n');
|
|
135
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n');
|
|
136
|
+
|
|
137
|
+
const score = scoreWorkspace(ws);
|
|
138
|
+
|
|
139
|
+
expect(score.context).toBeLessThan(20);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('deducts points for incomplete stage CONTEXT.md', () => {
|
|
143
|
+
const ws = path.join(tempDir, 'workspace');
|
|
144
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
145
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Test\n\n## Folder Map\n\n- `01-input/`\n');
|
|
146
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n\n## Routing Table\n\n- `01-input/`\n');
|
|
147
|
+
fs.mkdirSync(path.join(ws, '01-input'), { recursive: true });
|
|
148
|
+
fs.writeFileSync(path.join(ws, '01-input', 'CONTEXT.md'), '# 01-input\n');
|
|
149
|
+
|
|
150
|
+
const score = scoreWorkspace(ws);
|
|
151
|
+
|
|
152
|
+
expect(score.stages).toBeLessThan(15);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('deducts points for missing tools.md', () => {
|
|
156
|
+
const ws = path.join(tempDir, 'workspace');
|
|
157
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
158
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Test\n\n## Role\nRole\n\n## Folder Map\n\n');
|
|
159
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n\n## Routing Table\n\n');
|
|
160
|
+
|
|
161
|
+
const score = scoreWorkspace(ws);
|
|
162
|
+
|
|
163
|
+
expect(score.tools).toBe(0);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('runChecklist', () => {
|
|
168
|
+
it('passes all items on a complete workspace', () => {
|
|
169
|
+
const ws = createBasicWorkspace();
|
|
170
|
+
const result = runChecklist(ws);
|
|
171
|
+
|
|
172
|
+
expect(result.failed).toBe(0);
|
|
173
|
+
expect(result.passed).toBe(result.items);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('fails items for incomplete stages', () => {
|
|
177
|
+
const ws = path.join(tempDir, 'workspace');
|
|
178
|
+
fs.mkdirSync(ws, { recursive: true });
|
|
179
|
+
fs.writeFileSync(path.join(ws, 'SYSTEM.md'), '# Test\n\n## Folder Map\n\n- `01-input/`\n');
|
|
180
|
+
fs.writeFileSync(path.join(ws, 'CONTEXT.md'), '# Router\n\n## Routing Table\n\n- `01-input/`\n');
|
|
181
|
+
fs.mkdirSync(path.join(ws, '01-input'), { recursive: true });
|
|
182
|
+
fs.writeFileSync(path.join(ws, '01-input', 'CONTEXT.md'), '# 01-input\n');
|
|
183
|
+
fs.writeFileSync(path.join(ws, 'README.md'), '# README\n');
|
|
184
|
+
|
|
185
|
+
const result = runChecklist(ws);
|
|
186
|
+
|
|
187
|
+
expect(result.failed).toBeGreaterThan(0);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('benchmark integration', () => {
|
|
192
|
+
it('includes benchmark data in result', () => {
|
|
193
|
+
const ws = createBasicWorkspace();
|
|
194
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
195
|
+
passed: true,
|
|
196
|
+
checks: [],
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const result = iterateWorkspace(ws, { maxRetries: 1 });
|
|
200
|
+
|
|
201
|
+
expect(result.benchmark).toBeDefined();
|
|
202
|
+
expect(result.benchmark?.stages.length).toBeGreaterThan(0);
|
|
203
|
+
expect(result.benchmark?.weightedScore).toBeGreaterThanOrEqual(0);
|
|
204
|
+
expect(result.benchmark?.weightedScore).toBeLessThanOrEqual(100);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('passes agent flag to benchmark result', () => {
|
|
208
|
+
const ws = createBasicWorkspace();
|
|
209
|
+
(validate.validateWorkspace as jest.Mock).mockReturnValue({
|
|
210
|
+
passed: true,
|
|
211
|
+
checks: [],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const result = iterateWorkspace(ws, { maxRetries: 1, agent: 'claude' });
|
|
215
|
+
|
|
216
|
+
expect(result.benchmark?.agent).toBe('claude');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|