@duypham93/openkit 0.2.4 → 0.2.6
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/architect-agent.md +10 -9
- package/agents/ba-agent.md +8 -7
- package/agents/code-reviewer.md +4 -3
- package/agents/fullstack-agent.md +5 -4
- package/agents/master-orchestrator.md +15 -15
- package/agents/pm-agent.md +8 -7
- package/agents/qa-agent.md +9 -8
- package/agents/tech-lead-agent.md +9 -8
- package/assets/install-bundle/opencode/agents/ArchitectAgent.md +13 -7
- package/assets/install-bundle/opencode/agents/BAAgent.md +11 -5
- package/assets/install-bundle/opencode/agents/CodeReviewer.md +7 -1
- package/assets/install-bundle/opencode/agents/FullstackAgent.md +9 -2
- package/assets/install-bundle/opencode/agents/MasterOrchestrator.md +19 -11
- package/assets/install-bundle/opencode/agents/PMAgent.md +11 -5
- package/assets/install-bundle/opencode/agents/QAAgent.md +13 -6
- package/assets/install-bundle/opencode/agents/TechLeadAgent.md +12 -6
- package/assets/install-bundle/opencode/commands/brainstorm.md +13 -6
- package/assets/install-bundle/opencode/commands/delivery.md +15 -8
- package/assets/install-bundle/opencode/commands/execute-plan.md +15 -8
- package/assets/install-bundle/opencode/commands/migrate.md +16 -9
- package/assets/install-bundle/opencode/commands/quick-task.md +14 -7
- package/assets/install-bundle/opencode/commands/task.md +16 -8
- package/assets/install-bundle/opencode/commands/write-plan.md +15 -8
- package/commands/brainstorm.md +10 -9
- package/commands/delivery.md +12 -12
- package/commands/execute-plan.md +12 -11
- package/commands/migrate.md +13 -13
- package/commands/quick-task.md +11 -11
- package/commands/task.md +12 -12
- package/commands/write-plan.md +12 -11
- package/package.json +1 -1
- package/src/global/paths.js +6 -0
- package/src/global/workspace-shim.js +187 -0
- package/src/global/workspace-state.js +7 -1
- package/tests/cli/openkit-cli.test.js +71 -0
package/commands/write-plan.md
CHANGED
|
@@ -8,9 +8,10 @@ Use `/write-plan` to create an implementation plan for work currently in `Full D
|
|
|
8
8
|
|
|
9
9
|
## Global OpenKit path rule
|
|
10
10
|
|
|
11
|
-
- In globally installed OpenKit sessions,
|
|
12
|
-
-
|
|
13
|
-
- Use
|
|
11
|
+
- In globally installed OpenKit sessions, treat `.opencode/openkit/` as the repo-local compatibility surface for OpenKit-owned docs, templates, and workflow tools.
|
|
12
|
+
- Read canonical OpenKit docs from `.opencode/openkit/...`, not from repo-root `context/`, repo-root `AGENTS.md`, or repo-root `.opencode/`.
|
|
13
|
+
- Use `.opencode/openkit/workflow-state.json` for resumable workflow state.
|
|
14
|
+
- Use `node .opencode/openkit/workflow-state.js <command>` for workflow-state checks in global mode.
|
|
14
15
|
|
|
15
16
|
## Preconditions
|
|
16
17
|
|
|
@@ -21,13 +22,13 @@ Use `/write-plan` to create an implementation plan for work currently in `Full D
|
|
|
21
22
|
|
|
22
23
|
## Canonical docs to load
|
|
23
24
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- `.opencode/workflow-state.json`
|
|
29
|
-
-
|
|
30
|
-
-
|
|
25
|
+
- `.opencode/openkit/AGENTS.md`
|
|
26
|
+
- `.opencode/openkit/context/navigation.md`
|
|
27
|
+
- `.opencode/openkit/context/core/workflow.md`
|
|
28
|
+
- `.opencode/openkit/context/core/project-config.md`
|
|
29
|
+
- `.opencode/openkit/workflow-state.json`
|
|
30
|
+
- `.opencode/openkit/docs/templates/implementation-plan-template.md`
|
|
31
|
+
- `.opencode/openkit/docs/templates/migration-report-template.md` when migration work benefits from one running artifact
|
|
31
32
|
- skill `writing-plans`
|
|
32
33
|
|
|
33
34
|
For operator checks, use the current workflow-state utility surface: `status`, `doctor`, `show`, and `validate`.
|
|
@@ -53,4 +54,4 @@ For operator checks, use the current workflow-state utility surface: `status`, `
|
|
|
53
54
|
- The plan should name the strongest real validation path available in the repository
|
|
54
55
|
- In migration mode, use `migration_report` when handoffs would benefit from a single running narrative instead of scattered notes
|
|
55
56
|
- If no repo-native app build, lint, or test command exists, say that explicitly in the plan instead of guessing a stack command
|
|
56
|
-
- Use
|
|
57
|
+
- Use `node .opencode/openkit/workflow-state.js validate` only to confirm workflow state, not to stand in for implementation verification
|
package/package.json
CHANGED
package/src/global/paths.js
CHANGED
|
@@ -82,5 +82,11 @@ export function getWorkspacePaths({ projectRoot, env = process.env, platform = p
|
|
|
82
82
|
legacyRuntimeDir: path.join(resolvedProjectRoot, '.opencode'),
|
|
83
83
|
legacyWorkflowStatePath: path.join(resolvedProjectRoot, '.opencode', 'workflow-state.json'),
|
|
84
84
|
legacyWorkItemsDir: path.join(resolvedProjectRoot, '.opencode', 'work-items'),
|
|
85
|
+
workspaceShimDir: path.join(resolvedProjectRoot, '.opencode', 'openkit'),
|
|
86
|
+
workspaceShimContextDir: path.join(resolvedProjectRoot, '.opencode', 'openkit', 'context'),
|
|
87
|
+
workspaceShimTemplatesDir: path.join(resolvedProjectRoot, '.opencode', 'openkit', 'docs', 'templates'),
|
|
88
|
+
workspaceShimAgentsPath: path.join(resolvedProjectRoot, '.opencode', 'openkit', 'AGENTS.md'),
|
|
89
|
+
workspaceShimWorkflowStatePath: path.join(resolvedProjectRoot, '.opencode', 'openkit', 'workflow-state.json'),
|
|
90
|
+
workspaceShimWorkflowCliPath: path.join(resolvedProjectRoot, '.opencode', 'openkit', 'workflow-state.js'),
|
|
85
91
|
};
|
|
86
92
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
function removePathIfPresent(targetPath) {
|
|
5
|
+
try {
|
|
6
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
7
|
+
} catch {
|
|
8
|
+
// ignore cleanup failures
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function ensureParent(filePath) {
|
|
13
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function writeFile(filePath, content, mode) {
|
|
17
|
+
ensureParent(filePath);
|
|
18
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
19
|
+
if (typeof mode === 'number') {
|
|
20
|
+
fs.chmodSync(filePath, mode);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function relativeTarget(fromPath, toPath) {
|
|
25
|
+
return path.relative(path.dirname(fromPath), toPath) || '.';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createSymlinkOrCopy({ linkPath, targetPath, type = 'file' }) {
|
|
29
|
+
ensureParent(linkPath);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
if (fs.existsSync(linkPath) || fs.lstatSync(linkPath)) {
|
|
33
|
+
removePathIfPresent(linkPath);
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
// ignore cleanup misses
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
fs.symlinkSync(relativeTarget(linkPath, targetPath), linkPath, type);
|
|
41
|
+
return 'symlink';
|
|
42
|
+
} catch {
|
|
43
|
+
const stats = fs.statSync(targetPath);
|
|
44
|
+
if (stats.isDirectory()) {
|
|
45
|
+
fs.cpSync(targetPath, linkPath, { recursive: true });
|
|
46
|
+
} else {
|
|
47
|
+
fs.copyFileSync(targetPath, linkPath);
|
|
48
|
+
}
|
|
49
|
+
return 'copy';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createIfMissing(createdPaths, { linkPath, targetPath, type = 'file' }) {
|
|
54
|
+
if (fs.existsSync(linkPath)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const mode = createSymlinkOrCopy({ linkPath, targetPath, type });
|
|
59
|
+
createdPaths.push(linkPath);
|
|
60
|
+
return mode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function ensureWorkspaceShim(paths) {
|
|
64
|
+
const createdPaths = [];
|
|
65
|
+
|
|
66
|
+
fs.mkdirSync(paths.workspaceShimDir, { recursive: true });
|
|
67
|
+
|
|
68
|
+
createIfMissing(createdPaths, {
|
|
69
|
+
linkPath: paths.workspaceShimAgentsPath,
|
|
70
|
+
targetPath: path.join(paths.kitRoot, 'AGENTS.md'),
|
|
71
|
+
type: 'file',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
createIfMissing(createdPaths, {
|
|
75
|
+
linkPath: paths.workspaceShimContextDir,
|
|
76
|
+
targetPath: path.join(paths.kitRoot, 'context'),
|
|
77
|
+
type: 'dir',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
createIfMissing(createdPaths, {
|
|
81
|
+
linkPath: paths.workspaceShimTemplatesDir,
|
|
82
|
+
targetPath: path.join(paths.kitRoot, 'docs', 'templates'),
|
|
83
|
+
type: 'dir',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
createIfMissing(createdPaths, {
|
|
87
|
+
linkPath: paths.workspaceShimWorkflowStatePath,
|
|
88
|
+
targetPath: paths.workflowStatePath,
|
|
89
|
+
type: 'file',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const workflowCli = `#!/usr/bin/env node
|
|
93
|
+
import { spawnSync } from 'node:child_process';
|
|
94
|
+
|
|
95
|
+
const args = process.argv.slice(2);
|
|
96
|
+
const result = spawnSync(process.execPath, [${JSON.stringify(path.join(paths.kitRoot, '.opencode', 'workflow-state.js'))}, '--state', ${JSON.stringify(paths.workflowStatePath)}, ...args], {
|
|
97
|
+
stdio: 'inherit',
|
|
98
|
+
env: process.env,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (result.error) {
|
|
102
|
+
throw result.error;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
process.exit(typeof result.status === 'number' ? result.status : 1);
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(paths.workspaceShimWorkflowCliPath)) {
|
|
109
|
+
writeFile(paths.workspaceShimWorkflowCliPath, workflowCli, 0o755);
|
|
110
|
+
createdPaths.push(paths.workspaceShimWorkflowCliPath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
createIfMissing(createdPaths, {
|
|
114
|
+
linkPath: path.join(paths.projectRoot, 'AGENTS.md'),
|
|
115
|
+
targetPath: paths.workspaceShimAgentsPath,
|
|
116
|
+
type: 'file',
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
createIfMissing(createdPaths, {
|
|
120
|
+
linkPath: path.join(paths.projectRoot, 'context'),
|
|
121
|
+
targetPath: paths.workspaceShimContextDir,
|
|
122
|
+
type: 'dir',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
createIfMissing(createdPaths, {
|
|
126
|
+
linkPath: path.join(paths.projectRoot, '.opencode', 'workflow-state.json'),
|
|
127
|
+
targetPath: paths.workspaceShimWorkflowStatePath,
|
|
128
|
+
type: 'file',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!fs.existsSync(path.join(paths.projectRoot, '.opencode', 'workflow-state.js'))) {
|
|
132
|
+
const rootWorkflowCli = `#!/usr/bin/env node
|
|
133
|
+
import { spawnSync } from 'node:child_process';
|
|
134
|
+
|
|
135
|
+
const args = process.argv.slice(2);
|
|
136
|
+
const result = spawnSync(process.execPath, [${JSON.stringify(paths.workspaceShimWorkflowCliPath)}, ...args], {
|
|
137
|
+
stdio: 'inherit',
|
|
138
|
+
env: process.env,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (result.error) {
|
|
142
|
+
throw result.error;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
process.exit(typeof result.status === 'number' ? result.status : 1);
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const rootWorkflowCliPath = path.join(paths.projectRoot, '.opencode', 'workflow-state.js');
|
|
149
|
+
writeFile(rootWorkflowCliPath, rootWorkflowCli, 0o755);
|
|
150
|
+
createdPaths.push(rootWorkflowCliPath);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!fs.existsSync(path.join(paths.projectRoot, '.opencode', 'work-items'))) {
|
|
154
|
+
createIfMissing(createdPaths, {
|
|
155
|
+
linkPath: path.join(paths.projectRoot, '.opencode', 'work-items'),
|
|
156
|
+
targetPath: paths.workItemsDir,
|
|
157
|
+
type: 'dir',
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
paths,
|
|
163
|
+
createdPaths,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function cleanupWorkspaceShim(shim) {
|
|
168
|
+
if (!shim?.createdPaths) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
for (const createdPath of [...shim.createdPaths].reverse()) {
|
|
173
|
+
removePathIfPresent(createdPath);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const maybeShimDir = shim.paths?.workspaceShimDir;
|
|
177
|
+
if (maybeShimDir && fs.existsSync(maybeShimDir)) {
|
|
178
|
+
try {
|
|
179
|
+
const entries = fs.readdirSync(maybeShimDir);
|
|
180
|
+
if (entries.length === 0) {
|
|
181
|
+
removePathIfPresent(maybeShimDir);
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
// ignore cleanup misses
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
import { getWorkspacePaths } from './paths.js';
|
|
5
|
+
import { ensureWorkspaceShim } from './workspace-shim.js';
|
|
5
6
|
|
|
6
7
|
const WORKSPACE_STATE_SCHEMA = 'openkit/workspace-state@1';
|
|
7
8
|
|
|
@@ -50,7 +51,12 @@ export function ensureWorkspaceBootstrap(options = {}) {
|
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
const shim = ensureWorkspaceShim(paths);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...paths,
|
|
58
|
+
workspaceShim: shim,
|
|
59
|
+
};
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
export function readWorkspaceMeta(options = {}) {
|
|
@@ -33,6 +33,10 @@ function writeExecutable(filePath, content) {
|
|
|
33
33
|
fs.chmodSync(filePath, 0o755);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function removePathIfPresent(targetPath) {
|
|
37
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
test('openkit --help shows global-install oriented help', () => {
|
|
37
41
|
const result = runCli(['--help']);
|
|
38
42
|
|
|
@@ -222,6 +226,14 @@ process.stdout.write('mock opencode launched\\n');
|
|
|
222
226
|
assert.equal(invocation.configDir, path.join(tempHome, 'kits', 'openkit'));
|
|
223
227
|
assert.match(invocation.workflowState, /workspaces\/.*\/openkit\/\.opencode\/workflow-state\.json$/);
|
|
224
228
|
assert.equal(invocation.kitRoot, path.join(tempHome, 'kits', 'openkit'));
|
|
229
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'AGENTS.md')), true);
|
|
230
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'context', 'core', 'workflow.md')), true);
|
|
231
|
+
assert.equal(fs.lstatSync(path.join(projectRoot, '.opencode', 'openkit', 'workflow-state.json')).isSymbolicLink() || fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'workflow-state.json')), true);
|
|
232
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'workflow-state.js')), true);
|
|
233
|
+
assert.equal(fs.existsSync(path.join(projectRoot, 'AGENTS.md')), true);
|
|
234
|
+
assert.equal(fs.existsSync(path.join(projectRoot, 'context', 'core', 'workflow.md')), true);
|
|
235
|
+
assert.equal(fs.lstatSync(path.join(projectRoot, '.opencode', 'workflow-state.json')).isSymbolicLink() || fs.existsSync(path.join(projectRoot, '.opencode', 'workflow-state.json')), true);
|
|
236
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'workflow-state.js')), true);
|
|
225
237
|
});
|
|
226
238
|
|
|
227
239
|
test('openkit run does not reinstall when the global install already exists', () => {
|
|
@@ -294,6 +306,65 @@ process.stdout.write('mock opencode launched after auto-install\\n');
|
|
|
294
306
|
const invocation = readJson(logPath);
|
|
295
307
|
assert.deepEqual(invocation.argv, [projectRoot]);
|
|
296
308
|
assert.equal(invocation.kitRoot, path.join(tempHome, 'kits', 'openkit'));
|
|
309
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'AGENTS.md')), true);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('openkit run does not overwrite existing repo-local workflow files when creating shims', () => {
|
|
313
|
+
const tempHome = makeTempDir();
|
|
314
|
+
const projectRoot = makeTempDir();
|
|
315
|
+
const fakeBinDir = path.join(tempHome, 'bin');
|
|
316
|
+
|
|
317
|
+
fs.mkdirSync(path.join(projectRoot, '.opencode'), { recursive: true });
|
|
318
|
+
fs.mkdirSync(path.join(projectRoot, 'context', 'core'), { recursive: true });
|
|
319
|
+
fs.writeFileSync(path.join(projectRoot, 'AGENTS.md'), 'project agents\n', 'utf8');
|
|
320
|
+
fs.writeFileSync(path.join(projectRoot, 'context', 'core', 'workflow.md'), 'project workflow\n', 'utf8');
|
|
321
|
+
fs.writeFileSync(path.join(projectRoot, '.opencode', 'workflow-state.json'), '{"project":true}\n', 'utf8');
|
|
322
|
+
fs.writeFileSync(path.join(projectRoot, '.opencode', 'workflow-state.js'), '#!/usr/bin/env node\n', 'utf8');
|
|
323
|
+
|
|
324
|
+
writeExecutable(path.join(fakeBinDir, 'opencode'), '#!/bin/sh\nexit 0\n');
|
|
325
|
+
|
|
326
|
+
const result = runCli(['run'], {
|
|
327
|
+
cwd: projectRoot,
|
|
328
|
+
env: {
|
|
329
|
+
...process.env,
|
|
330
|
+
OPENCODE_HOME: tempHome,
|
|
331
|
+
PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH}`,
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
assert.equal(result.status, 0);
|
|
336
|
+
assert.equal(fs.readFileSync(path.join(projectRoot, 'AGENTS.md'), 'utf8'), 'project agents\n');
|
|
337
|
+
assert.equal(fs.readFileSync(path.join(projectRoot, 'context', 'core', 'workflow.md'), 'utf8'), 'project workflow\n');
|
|
338
|
+
assert.equal(fs.readFileSync(path.join(projectRoot, '.opencode', 'workflow-state.json'), 'utf8'), '{"project":true}\n');
|
|
339
|
+
assert.equal(fs.readFileSync(path.join(projectRoot, '.opencode', 'workflow-state.js'), 'utf8'), '#!/usr/bin/env node\n');
|
|
340
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'AGENTS.md')), true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test('openkit run cleans root compatibility shims when created files are removed', () => {
|
|
344
|
+
const tempHome = makeTempDir();
|
|
345
|
+
const projectRoot = makeTempDir();
|
|
346
|
+
const fakeBinDir = path.join(tempHome, 'bin');
|
|
347
|
+
|
|
348
|
+
writeExecutable(path.join(fakeBinDir, 'opencode'), '#!/bin/sh\nexit 0\n');
|
|
349
|
+
|
|
350
|
+
const result = runCli(['run'], {
|
|
351
|
+
cwd: projectRoot,
|
|
352
|
+
env: {
|
|
353
|
+
...process.env,
|
|
354
|
+
OPENCODE_HOME: tempHome,
|
|
355
|
+
PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH}`,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
assert.equal(result.status, 0);
|
|
360
|
+
assert.equal(fs.existsSync(path.join(projectRoot, 'AGENTS.md')), true);
|
|
361
|
+
|
|
362
|
+
removePathIfPresent(path.join(projectRoot, 'AGENTS.md'));
|
|
363
|
+
removePathIfPresent(path.join(projectRoot, 'context'));
|
|
364
|
+
removePathIfPresent(path.join(projectRoot, '.opencode', 'workflow-state.json'));
|
|
365
|
+
removePathIfPresent(path.join(projectRoot, '.opencode', 'workflow-state.js'));
|
|
366
|
+
|
|
367
|
+
assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'AGENTS.md')), true);
|
|
297
368
|
});
|
|
298
369
|
|
|
299
370
|
test('openkit run reports missing opencode after first-time setup completes', () => {
|