opencodekit 0.12.6 → 0.12.7
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/dist/index.js +5 -17
- package/dist/template/.opencode/agent/build.md +32 -21
- package/dist/template/.opencode/agent/explore.md +27 -16
- package/dist/template/.opencode/agent/planner.md +103 -63
- package/dist/template/.opencode/agent/review.md +31 -23
- package/dist/template/.opencode/agent/rush.md +27 -19
- package/dist/template/.opencode/agent/scout.md +27 -19
- package/dist/template/.opencode/agent/vision.md +29 -19
- package/dist/template/.opencode/command/accessibility-check.md +1 -0
- package/dist/template/.opencode/command/analyze-mockup.md +1 -0
- package/dist/template/.opencode/command/analyze-project.md +2 -1
- package/dist/template/.opencode/command/brainstorm.md +2 -1
- package/dist/template/.opencode/command/design-audit.md +1 -0
- package/dist/template/.opencode/command/finish.md +39 -4
- package/dist/template/.opencode/command/implement.md +26 -6
- package/dist/template/.opencode/command/init.md +1 -0
- package/dist/template/.opencode/command/pr.md +28 -1
- package/dist/template/.opencode/command/research-ui.md +1 -0
- package/dist/template/.opencode/command/research.md +1 -0
- package/dist/template/.opencode/command/review-codebase.md +1 -0
- package/dist/template/.opencode/command/status.md +3 -2
- package/dist/template/.opencode/command/summarize.md +2 -1
- package/dist/template/.opencode/command/ui-review.md +1 -0
- package/dist/template/.opencode/memory/project/architecture.md +59 -6
- package/dist/template/.opencode/memory/project/commands.md +20 -164
- package/dist/template/.opencode/memory/user.md +24 -7
- package/dist/template/.opencode/opencode.json +496 -496
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/skill/condition-based-waiting/example.ts +71 -65
- package/dist/template/.opencode/tool/memory-read.ts +57 -57
- package/dist/template/.opencode/tool/memory-update.ts +53 -53
- package/dist/template/.opencode/tsconfig.json +19 -19
- package/package.json +4 -16
- package/dist/template/.opencode/command.backup/analyze-project.md +0 -465
- package/dist/template/.opencode/command.backup/finish.md +0 -167
- package/dist/template/.opencode/command.backup/implement.md +0 -143
- package/dist/template/.opencode/command.backup/pr.md +0 -252
- package/dist/template/.opencode/command.backup/status.md +0 -376
- package/dist/template/.opencode/lib/lsp/client.ts +0 -614
- package/dist/template/.opencode/lib/lsp/config.ts +0 -199
- package/dist/template/.opencode/lib/lsp/constants.ts +0 -339
- package/dist/template/.opencode/lib/lsp/types.ts +0 -138
- package/dist/template/.opencode/lib/lsp/utils.ts +0 -190
- package/dist/template/.opencode/memory/project/SHELL_OUTPUT_MIGRATION_PLAN.md +0 -551
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// From: Lace test infrastructure improvements (2025-10-03)
|
|
3
3
|
// Context: Fixed 15 flaky tests by replacing arbitrary timeouts
|
|
4
4
|
|
|
5
|
-
import type { ThreadManager } from
|
|
6
|
-
import type { LaceEvent, LaceEventType } from
|
|
5
|
+
import type { ThreadManager } from "~/threads/thread-manager";
|
|
6
|
+
import type { LaceEvent, LaceEventType } from "~/threads/types";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Wait for a specific event type to appear in thread
|
|
@@ -18,29 +18,33 @@ import type { LaceEvent, LaceEventType } from '~/threads/types';
|
|
|
18
18
|
* await waitForEvent(threadManager, agentThreadId, 'TOOL_RESULT');
|
|
19
19
|
*/
|
|
20
20
|
export function waitForEvent(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
threadManager: ThreadManager,
|
|
22
|
+
threadId: string,
|
|
23
|
+
eventType: LaceEventType,
|
|
24
|
+
timeoutMs = 5000,
|
|
25
25
|
): Promise<LaceEvent> {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const startTime = Date.now();
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const check = () => {
|
|
30
|
+
const events = threadManager.getEvents(threadId);
|
|
31
|
+
const event = events.find((e) => e.type === eventType);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
if (event) {
|
|
34
|
+
resolve(event);
|
|
35
|
+
} else if (Date.now() - startTime > timeoutMs) {
|
|
36
|
+
reject(
|
|
37
|
+
new Error(
|
|
38
|
+
`Timeout waiting for ${eventType} event after ${timeoutMs}ms`,
|
|
39
|
+
),
|
|
40
|
+
);
|
|
41
|
+
} else {
|
|
42
|
+
setTimeout(check, 10); // Poll every 10ms for efficiency
|
|
43
|
+
}
|
|
44
|
+
};
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
check();
|
|
47
|
+
});
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
@@ -58,34 +62,34 @@ export function waitForEvent(
|
|
|
58
62
|
* await waitForEventCount(threadManager, agentThreadId, 'AGENT_MESSAGE', 2);
|
|
59
63
|
*/
|
|
60
64
|
export function waitForEventCount(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
threadManager: ThreadManager,
|
|
66
|
+
threadId: string,
|
|
67
|
+
eventType: LaceEventType,
|
|
68
|
+
count: number,
|
|
69
|
+
timeoutMs = 5000,
|
|
66
70
|
): Promise<LaceEvent[]> {
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const startTime = Date.now();
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
const check = () => {
|
|
75
|
+
const events = threadManager.getEvents(threadId);
|
|
76
|
+
const matchingEvents = events.filter((e) => e.type === eventType);
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
if (matchingEvents.length >= count) {
|
|
79
|
+
resolve(matchingEvents);
|
|
80
|
+
} else if (Date.now() - startTime > timeoutMs) {
|
|
81
|
+
reject(
|
|
82
|
+
new Error(
|
|
83
|
+
`Timeout waiting for ${count} ${eventType} events after ${timeoutMs}ms (got ${matchingEvents.length})`,
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
setTimeout(check, 10);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
86
90
|
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
check();
|
|
92
|
+
});
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
@@ -109,30 +113,32 @@ export function waitForEventCount(
|
|
|
109
113
|
* );
|
|
110
114
|
*/
|
|
111
115
|
export function waitForEventMatch(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
threadManager: ThreadManager,
|
|
117
|
+
threadId: string,
|
|
118
|
+
predicate: (event: LaceEvent) => boolean,
|
|
119
|
+
description: string,
|
|
120
|
+
timeoutMs = 5000,
|
|
117
121
|
): Promise<LaceEvent> {
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const startTime = Date.now();
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
const check = () => {
|
|
126
|
+
const events = threadManager.getEvents(threadId);
|
|
127
|
+
const event = events.find(predicate);
|
|
124
128
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
if (event) {
|
|
130
|
+
resolve(event);
|
|
131
|
+
} else if (Date.now() - startTime > timeoutMs) {
|
|
132
|
+
reject(
|
|
133
|
+
new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`),
|
|
134
|
+
);
|
|
135
|
+
} else {
|
|
136
|
+
setTimeout(check, 10);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
133
139
|
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
check();
|
|
141
|
+
});
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
// Usage example from actual debugging session:
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import { tool } from "@opencode-ai/plugin";
|
|
2
3
|
import fs from "fs/promises";
|
|
3
|
-
import path from "path";
|
|
4
4
|
|
|
5
5
|
export default tool({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
description:
|
|
7
|
+
"Read memory files for persistent cross-session context. Returns current project state, learnings, and active tasks. Supports subdirectories (e.g., 'research/opencode-sessions').",
|
|
8
|
+
args: {
|
|
9
|
+
file: tool.schema
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe(
|
|
13
|
+
"Memory file to read: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic, _templates/task-prd, _templates/task-spec, _templates/task-review, _templates/research, _templates/handoff",
|
|
14
|
+
),
|
|
15
|
+
},
|
|
16
|
+
execute: async (args: { file?: string }) => {
|
|
17
|
+
const fileName = args.file || "memory";
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// Normalize: strip .md extension if present
|
|
20
|
+
const normalizedFile = fileName.replace(/\.md$/i, "");
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
// Location priority: project > global > legacy
|
|
23
|
+
const locations = [
|
|
24
|
+
path.join(process.cwd(), ".opencode/memory", `${normalizedFile}.md`),
|
|
25
|
+
path.join(
|
|
26
|
+
process.env.HOME || "",
|
|
27
|
+
".config/opencode/memory",
|
|
28
|
+
`${normalizedFile}.md`,
|
|
29
|
+
),
|
|
30
|
+
path.join(
|
|
31
|
+
process.cwd(),
|
|
32
|
+
".config/opencode/memory",
|
|
33
|
+
`${normalizedFile}.md`,
|
|
34
|
+
),
|
|
35
|
+
];
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
37
|
+
// Try each location in order
|
|
38
|
+
for (const filePath of locations) {
|
|
39
|
+
try {
|
|
40
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
41
|
+
const locationLabel = filePath.includes(".opencode/memory")
|
|
42
|
+
? "project"
|
|
43
|
+
: filePath.includes(process.env.HOME || "")
|
|
44
|
+
? "global"
|
|
45
|
+
: "legacy";
|
|
46
|
+
return `[Read from ${locationLabel}: ${filePath}]\n\n${content}`;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
// Continue to next location if file not found
|
|
49
|
+
if (
|
|
50
|
+
error instanceof Error &&
|
|
51
|
+
"code" in error &&
|
|
52
|
+
error.code === "ENOENT"
|
|
53
|
+
) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Other errors should be reported
|
|
57
|
+
if (error instanceof Error) {
|
|
58
|
+
return `Error reading memory from ${filePath}: ${error.message}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
// No file found in any location
|
|
64
|
+
return `Memory file '${normalizedFile}.md' not found in any location.\nSearched:\n- ${locations.join("\n- ")}\n\nStructure:\n- handoffs/YYYY-MM-DD-phase (phase transitions)\n- research/YYYY-MM-DD-topic (research findings)\n- _templates/ (prd, spec, review, research, handoff)`;
|
|
65
|
+
},
|
|
66
66
|
});
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import { tool } from "@opencode-ai/plugin";
|
|
2
3
|
import fs from "fs/promises";
|
|
3
|
-
import path from "path";
|
|
4
4
|
|
|
5
5
|
export default tool({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
6
|
+
description:
|
|
7
|
+
"Update memory files with new learnings, progress, or context. Appends or replaces content based on mode. Supports subdirectories for organization (e.g., 'research/opencode-sessions' creates .opencode/memory/research/opencode-sessions.md).",
|
|
8
|
+
args: {
|
|
9
|
+
file: tool.schema
|
|
10
|
+
.string()
|
|
11
|
+
.describe(
|
|
12
|
+
"Memory file to update: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic. Use _templates/ for reference only.",
|
|
13
|
+
),
|
|
14
|
+
content: tool.schema
|
|
15
|
+
.string()
|
|
16
|
+
.describe("Content to write or append to the memory file"),
|
|
17
|
+
mode: tool.schema
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.default("replace")
|
|
21
|
+
.describe(
|
|
22
|
+
"Update mode: 'replace' (overwrite file) or 'append' (add to end).",
|
|
23
|
+
),
|
|
24
|
+
},
|
|
25
|
+
execute: async (args: { file: string; content: string; mode?: string }) => {
|
|
26
|
+
// Always write to project memory (.opencode/memory/)
|
|
27
|
+
const memoryDir = path.join(process.cwd(), ".opencode/memory");
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
// Normalize file path: strip existing .md extension, handle subdirectories
|
|
30
|
+
const normalizedFile = args.file.replace(/\.md$/i, ""); // Remove .md if present
|
|
31
|
+
const filePath = path.join(memoryDir, `${normalizedFile}.md`);
|
|
32
|
+
const mode = args.mode || "replace";
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
try {
|
|
35
|
+
// Ensure parent directory exists (handles subdirectories)
|
|
36
|
+
const fileDir = path.dirname(filePath);
|
|
37
|
+
await fs.mkdir(fileDir, { recursive: true });
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
if (mode === "append") {
|
|
40
|
+
const timestamp = new Date().toISOString();
|
|
41
|
+
const appendContent = `\n\n---\n**Updated:** ${timestamp}\n\n${args.content}`;
|
|
42
|
+
await fs.appendFile(filePath, appendContent, "utf-8");
|
|
43
|
+
return `Successfully appended to ${normalizedFile}.md\n[Written to: ${filePath}]`;
|
|
44
|
+
} else {
|
|
45
|
+
// Replace mode - update timestamp
|
|
46
|
+
const timestamp = new Date().toISOString();
|
|
47
|
+
const updatedContent = args.content.replace(
|
|
48
|
+
/\*\*Last Updated:\*\* \[Timestamp\]/,
|
|
49
|
+
`**Last Updated:** ${timestamp}`,
|
|
50
|
+
);
|
|
51
|
+
await fs.writeFile(filePath, updatedContent, "utf-8");
|
|
52
|
+
return `Successfully updated ${normalizedFile}.md\n[Written to: ${filePath}]`;
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof Error) {
|
|
56
|
+
return `Error updating memory: ${error.message}`;
|
|
57
|
+
}
|
|
58
|
+
return `Unknown error updating memory file`;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
61
|
});
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"strict": false,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"outDir": "./dist",
|
|
13
|
+
"rootDir": "./",
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"types": ["node"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["plugin/**/*.ts", "tool/**/*.ts", "agent/**/*.ts", "*.ts"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "**/*.js", "**/*.test.ts"]
|
|
21
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencodekit",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.7",
|
|
4
4
|
"description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -14,10 +14,7 @@
|
|
|
14
14
|
"bin": {
|
|
15
15
|
"ock": "dist/index.js"
|
|
16
16
|
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md"
|
|
20
|
-
],
|
|
17
|
+
"files": ["dist", "README.md"],
|
|
21
18
|
"scripts": {
|
|
22
19
|
"dev": "bun run src/index.ts",
|
|
23
20
|
"build": "bun build src/index.ts --outdir dist --target node && mkdir -p dist/template && rsync -av --exclude=node_modules --exclude=dist --exclude=.git --exclude=coverage --exclude=.next --exclude=.turbo --exclude=logs --exclude=package-lock.json .opencode/ dist/template/.opencode/",
|
|
@@ -29,14 +26,7 @@
|
|
|
29
26
|
"lint": "biome check .",
|
|
30
27
|
"lint:fix": "biome check --fix ."
|
|
31
28
|
},
|
|
32
|
-
"keywords": [
|
|
33
|
-
"cli",
|
|
34
|
-
"opencodekit",
|
|
35
|
-
"template",
|
|
36
|
-
"agents",
|
|
37
|
-
"mcp",
|
|
38
|
-
"opencode"
|
|
39
|
-
],
|
|
29
|
+
"keywords": ["cli", "opencodekit", "template", "agents", "mcp", "opencode"],
|
|
40
30
|
"author": "OpenCodeKit",
|
|
41
31
|
"license": "MIT",
|
|
42
32
|
"engines": {
|
|
@@ -59,7 +49,5 @@
|
|
|
59
49
|
"@types/node": "^22.10.1",
|
|
60
50
|
"typescript": "^5.7.2"
|
|
61
51
|
},
|
|
62
|
-
"trustedDependencies": [
|
|
63
|
-
"@beads/bd"
|
|
64
|
-
]
|
|
52
|
+
"trustedDependencies": ["@beads/bd"]
|
|
65
53
|
}
|