@brianli/kimaki 0.4.72-brianli.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +2 -0
- package/dist/ai-tool-to-genai.js +233 -0
- package/dist/ai-tool-to-genai.test.js +267 -0
- package/dist/ai-tool.js +6 -0
- package/dist/bin.js +87 -0
- package/dist/bot-token.js +121 -0
- package/dist/bot-token.test.js +134 -0
- package/dist/channel-management.js +101 -0
- package/dist/cli-parsing.test.js +89 -0
- package/dist/cli.js +2529 -0
- package/dist/commands/abort.js +82 -0
- package/dist/commands/action-buttons.js +257 -0
- package/dist/commands/add-project.js +114 -0
- package/dist/commands/agent.js +291 -0
- package/dist/commands/ask-question.js +223 -0
- package/dist/commands/compact.js +120 -0
- package/dist/commands/context-usage.js +140 -0
- package/dist/commands/create-new-project.js +118 -0
- package/dist/commands/diff.js +128 -0
- package/dist/commands/file-upload.js +275 -0
- package/dist/commands/fork.js +217 -0
- package/dist/commands/gemini-apikey.js +70 -0
- package/dist/commands/login.js +490 -0
- package/dist/commands/mention-mode.js +51 -0
- package/dist/commands/merge-worktree.js +124 -0
- package/dist/commands/model.js +694 -0
- package/dist/commands/permissions.js +163 -0
- package/dist/commands/queue.js +217 -0
- package/dist/commands/remove-project.js +115 -0
- package/dist/commands/restart-opencode-server.js +116 -0
- package/dist/commands/resume.js +159 -0
- package/dist/commands/run-command.js +79 -0
- package/dist/commands/session-id.js +78 -0
- package/dist/commands/session.js +192 -0
- package/dist/commands/share.js +80 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/undo-redo.js +159 -0
- package/dist/commands/unset-model.js +152 -0
- package/dist/commands/upgrade.js +42 -0
- package/dist/commands/user-command.js +148 -0
- package/dist/commands/verbosity.js +60 -0
- package/dist/commands/worktree-settings.js +50 -0
- package/dist/commands/worktree.js +299 -0
- package/dist/condense-memory.js +33 -0
- package/dist/config.js +110 -0
- package/dist/database.js +1050 -0
- package/dist/db.js +159 -0
- package/dist/db.test.js +49 -0
- package/dist/discord-api.js +28 -0
- package/dist/discord-auth.js +231 -0
- package/dist/discord-auth.test.js +80 -0
- package/dist/discord-bot.js +997 -0
- package/dist/discord-utils.js +560 -0
- package/dist/discord-utils.test.js +115 -0
- package/dist/errors.js +167 -0
- package/dist/escape-backticks.test.js +429 -0
- package/dist/format-tables.js +122 -0
- package/dist/format-tables.test.js +199 -0
- package/dist/forum-sync/config.js +79 -0
- package/dist/forum-sync/discord-operations.js +154 -0
- package/dist/forum-sync/index.js +5 -0
- package/dist/forum-sync/markdown.js +117 -0
- package/dist/forum-sync/sync-to-discord.js +417 -0
- package/dist/forum-sync/sync-to-files.js +190 -0
- package/dist/forum-sync/types.js +53 -0
- package/dist/forum-sync/watchers.js +307 -0
- package/dist/gateway-consumer.js +232 -0
- package/dist/gateway-consumer.test.js +18 -0
- package/dist/genai-worker-wrapper.js +111 -0
- package/dist/genai-worker.js +311 -0
- package/dist/genai.js +232 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.js +35 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.js +30 -0
- package/dist/generated/internal/class.js +41 -0
- package/dist/generated/internal/prismaNamespace.js +239 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +209 -0
- package/dist/generated/models/bot_api_keys.js +1 -0
- package/dist/generated/models/bot_tokens.js +1 -0
- package/dist/generated/models/channel_agents.js +1 -0
- package/dist/generated/models/channel_directories.js +1 -0
- package/dist/generated/models/channel_mention_mode.js +1 -0
- package/dist/generated/models/channel_models.js +1 -0
- package/dist/generated/models/channel_verbosity.js +1 -0
- package/dist/generated/models/channel_worktrees.js +1 -0
- package/dist/generated/models/forum_sync_configs.js +1 -0
- package/dist/generated/models/global_models.js +1 -0
- package/dist/generated/models/ipc_requests.js +1 -0
- package/dist/generated/models/part_messages.js +1 -0
- package/dist/generated/models/scheduled_tasks.js +1 -0
- package/dist/generated/models/session_agents.js +1 -0
- package/dist/generated/models/session_models.js +1 -0
- package/dist/generated/models/session_start_sources.js +1 -0
- package/dist/generated/models/thread_sessions.js +1 -0
- package/dist/generated/models/thread_worktrees.js +1 -0
- package/dist/generated/models.js +1 -0
- package/dist/heap-monitor.js +95 -0
- package/dist/hrana-server.js +416 -0
- package/dist/hrana-server.test.js +368 -0
- package/dist/image-utils.js +112 -0
- package/dist/interaction-handler.js +327 -0
- package/dist/ipc-polling.js +251 -0
- package/dist/kimaki-digital-twin.e2e.test.js +165 -0
- package/dist/limit-heading-depth.js +25 -0
- package/dist/limit-heading-depth.test.js +105 -0
- package/dist/logger.js +160 -0
- package/dist/markdown.js +342 -0
- package/dist/markdown.test.js +253 -0
- package/dist/message-formatting.js +433 -0
- package/dist/message-formatting.test.js +73 -0
- package/dist/openai-realtime.js +228 -0
- package/dist/opencode-plugin-loading.e2e.test.js +91 -0
- package/dist/opencode-plugin.js +536 -0
- package/dist/opencode-plugin.test.js +98 -0
- package/dist/opencode.js +409 -0
- package/dist/privacy-sanitizer.js +105 -0
- package/dist/runtime-mode.js +51 -0
- package/dist/runtime-mode.test.js +115 -0
- package/dist/sentry.js +127 -0
- package/dist/session-handler/state.js +151 -0
- package/dist/session-handler.js +1874 -0
- package/dist/session-search.js +100 -0
- package/dist/session-search.test.js +40 -0
- package/dist/startup-service.js +153 -0
- package/dist/system-message.js +499 -0
- package/dist/task-runner.js +282 -0
- package/dist/task-schedule.js +191 -0
- package/dist/task-schedule.test.js +71 -0
- package/dist/thinking-utils.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +781 -0
- package/dist/tools.js +359 -0
- package/dist/unnest-code-blocks.js +136 -0
- package/dist/unnest-code-blocks.test.js +641 -0
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +109 -0
- package/dist/voice-handler.js +606 -0
- package/dist/voice.js +304 -0
- package/dist/voice.test.js +187 -0
- package/dist/wait-session.js +94 -0
- package/dist/worker-types.js +4 -0
- package/dist/worktree-utils.js +727 -0
- package/dist/xml.js +92 -0
- package/dist/xml.test.js +32 -0
- package/package.json +82 -0
- package/schema.prisma +246 -0
- package/skills/batch/SKILL.md +87 -0
- package/skills/critique/SKILL.md +129 -0
- package/skills/errore/SKILL.md +589 -0
- package/skills/goke/.prettierrc +5 -0
- package/skills/goke/CHANGELOG.md +40 -0
- package/skills/goke/LICENSE +21 -0
- package/skills/goke/README.md +666 -0
- package/skills/goke/SKILL.md +458 -0
- package/skills/goke/package.json +43 -0
- package/skills/goke/src/__test__/coerce.test.ts +411 -0
- package/skills/goke/src/__test__/index.test.ts +1798 -0
- package/skills/goke/src/__test__/types.test-d.ts +111 -0
- package/skills/goke/src/coerce.ts +547 -0
- package/skills/goke/src/goke.ts +1362 -0
- package/skills/goke/src/index.ts +16 -0
- package/skills/goke/src/mri.ts +164 -0
- package/skills/goke/tsconfig.json +15 -0
- package/skills/jitter/EDITOR.md +219 -0
- package/skills/jitter/EXPORT-INTERNALS.md +309 -0
- package/skills/jitter/SKILL.md +158 -0
- package/skills/jitter/jitter-clipboard.json +1042 -0
- package/skills/jitter/package.json +14 -0
- package/skills/jitter/tsconfig.json +15 -0
- package/skills/jitter/utils/actions.ts +212 -0
- package/skills/jitter/utils/export.ts +114 -0
- package/skills/jitter/utils/index.ts +141 -0
- package/skills/jitter/utils/snapshot.ts +154 -0
- package/skills/jitter/utils/traverse.ts +246 -0
- package/skills/jitter/utils/types.ts +279 -0
- package/skills/jitter/utils/wait.ts +133 -0
- package/skills/playwriter/SKILL.md +31 -0
- package/skills/security-review/SKILL.md +208 -0
- package/skills/simplify/SKILL.md +58 -0
- package/skills/termcast/SKILL.md +945 -0
- package/skills/tuistory/SKILL.md +250 -0
- package/skills/zustand-centralized-state/SKILL.md +582 -0
- package/src/__snapshots__/compact-session-context-no-system.md +35 -0
- package/src/__snapshots__/compact-session-context.md +41 -0
- package/src/__snapshots__/first-session-no-info.md +17 -0
- package/src/__snapshots__/first-session-with-info.md +23 -0
- package/src/__snapshots__/session-1.md +17 -0
- package/src/__snapshots__/session-2.md +5871 -0
- package/src/__snapshots__/session-3.md +17 -0
- package/src/__snapshots__/session-with-tools.md +5871 -0
- package/src/ai-tool-to-genai.test.ts +296 -0
- package/src/ai-tool-to-genai.ts +282 -0
- package/src/ai-tool.ts +39 -0
- package/src/bin.ts +108 -0
- package/src/bot-token.test.ts +171 -0
- package/src/bot-token.ts +159 -0
- package/src/channel-management.ts +172 -0
- package/src/cli-parsing.test.ts +132 -0
- package/src/cli.ts +3605 -0
- package/src/commands/abort.ts +112 -0
- package/src/commands/action-buttons.ts +376 -0
- package/src/commands/add-project.ts +152 -0
- package/src/commands/agent.ts +404 -0
- package/src/commands/ask-question.ts +330 -0
- package/src/commands/compact.ts +157 -0
- package/src/commands/context-usage.ts +199 -0
- package/src/commands/create-new-project.ts +179 -0
- package/src/commands/diff.ts +165 -0
- package/src/commands/file-upload.ts +389 -0
- package/src/commands/fork.ts +320 -0
- package/src/commands/gemini-apikey.ts +104 -0
- package/src/commands/login.ts +634 -0
- package/src/commands/mention-mode.ts +77 -0
- package/src/commands/merge-worktree.ts +177 -0
- package/src/commands/model.ts +961 -0
- package/src/commands/permissions.ts +261 -0
- package/src/commands/queue.ts +296 -0
- package/src/commands/remove-project.ts +155 -0
- package/src/commands/restart-opencode-server.ts +162 -0
- package/src/commands/resume.ts +242 -0
- package/src/commands/run-command.ts +123 -0
- package/src/commands/session-id.ts +109 -0
- package/src/commands/session.ts +250 -0
- package/src/commands/share.ts +106 -0
- package/src/commands/types.ts +25 -0
- package/src/commands/undo-redo.ts +221 -0
- package/src/commands/unset-model.ts +189 -0
- package/src/commands/upgrade.ts +52 -0
- package/src/commands/user-command.ts +193 -0
- package/src/commands/verbosity.ts +88 -0
- package/src/commands/worktree-settings.ts +79 -0
- package/src/commands/worktree.ts +431 -0
- package/src/condense-memory.ts +36 -0
- package/src/config.ts +148 -0
- package/src/database.ts +1530 -0
- package/src/db.test.ts +60 -0
- package/src/db.ts +190 -0
- package/src/discord-api.ts +35 -0
- package/src/discord-bot.ts +1316 -0
- package/src/discord-utils.test.ts +132 -0
- package/src/discord-utils.ts +767 -0
- package/src/errors.ts +213 -0
- package/src/escape-backticks.test.ts +469 -0
- package/src/format-tables.test.ts +223 -0
- package/src/format-tables.ts +145 -0
- package/src/forum-sync/config.ts +92 -0
- package/src/forum-sync/discord-operations.ts +241 -0
- package/src/forum-sync/index.ts +9 -0
- package/src/forum-sync/markdown.ts +176 -0
- package/src/forum-sync/sync-to-discord.ts +595 -0
- package/src/forum-sync/sync-to-files.ts +294 -0
- package/src/forum-sync/types.ts +175 -0
- package/src/forum-sync/watchers.ts +454 -0
- package/src/genai-worker-wrapper.ts +164 -0
- package/src/genai-worker.ts +386 -0
- package/src/genai.ts +321 -0
- package/src/generated/browser.ts +109 -0
- package/src/generated/client.ts +131 -0
- package/src/generated/commonInputTypes.ts +512 -0
- package/src/generated/enums.ts +46 -0
- package/src/generated/internal/class.ts +362 -0
- package/src/generated/internal/prismaNamespace.ts +2251 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +308 -0
- package/src/generated/models/bot_api_keys.ts +1288 -0
- package/src/generated/models/bot_tokens.ts +1577 -0
- package/src/generated/models/channel_agents.ts +1256 -0
- package/src/generated/models/channel_directories.ts +2104 -0
- package/src/generated/models/channel_mention_mode.ts +1300 -0
- package/src/generated/models/channel_models.ts +1288 -0
- package/src/generated/models/channel_verbosity.ts +1224 -0
- package/src/generated/models/channel_worktrees.ts +1308 -0
- package/src/generated/models/forum_sync_configs.ts +1452 -0
- package/src/generated/models/global_models.ts +1288 -0
- package/src/generated/models/ipc_requests.ts +1485 -0
- package/src/generated/models/part_messages.ts +1302 -0
- package/src/generated/models/scheduled_tasks.ts +2320 -0
- package/src/generated/models/session_agents.ts +1086 -0
- package/src/generated/models/session_models.ts +1114 -0
- package/src/generated/models/session_start_sources.ts +1408 -0
- package/src/generated/models/thread_sessions.ts +1599 -0
- package/src/generated/models/thread_worktrees.ts +1352 -0
- package/src/generated/models.ts +29 -0
- package/src/heap-monitor.ts +121 -0
- package/src/hrana-server.test.ts +428 -0
- package/src/hrana-server.ts +547 -0
- package/src/image-utils.ts +149 -0
- package/src/interaction-handler.ts +461 -0
- package/src/ipc-polling.ts +325 -0
- package/src/kimaki-digital-twin.e2e.test.ts +201 -0
- package/src/limit-heading-depth.test.ts +116 -0
- package/src/limit-heading-depth.ts +26 -0
- package/src/logger.ts +203 -0
- package/src/markdown.test.ts +360 -0
- package/src/markdown.ts +410 -0
- package/src/message-formatting.test.ts +81 -0
- package/src/message-formatting.ts +549 -0
- package/src/openai-realtime.ts +362 -0
- package/src/opencode-plugin-loading.e2e.test.ts +112 -0
- package/src/opencode-plugin.test.ts +108 -0
- package/src/opencode-plugin.ts +652 -0
- package/src/opencode.ts +554 -0
- package/src/privacy-sanitizer.ts +142 -0
- package/src/schema.sql +158 -0
- package/src/sentry.ts +137 -0
- package/src/session-handler/state.ts +232 -0
- package/src/session-handler.ts +2668 -0
- package/src/session-search.test.ts +50 -0
- package/src/session-search.ts +148 -0
- package/src/startup-service.ts +200 -0
- package/src/system-message.ts +568 -0
- package/src/task-runner.ts +425 -0
- package/src/task-schedule.test.ts +84 -0
- package/src/task-schedule.ts +287 -0
- package/src/thinking-utils.ts +61 -0
- package/src/thread-message-queue.e2e.test.ts +997 -0
- package/src/tools.ts +432 -0
- package/src/unnest-code-blocks.test.ts +679 -0
- package/src/unnest-code-blocks.ts +168 -0
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +145 -0
- package/src/voice-handler.ts +852 -0
- package/src/voice.test.ts +219 -0
- package/src/voice.ts +444 -0
- package/src/wait-session.ts +147 -0
- package/src/worker-types.ts +64 -0
- package/src/worktree-utils.ts +988 -0
- package/src/xml.test.ts +38 -0
- package/src/xml.ts +121 -0
package/dist/xml.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// XML/HTML tag content extractor.
|
|
2
|
+
// Parses XML-like tags from strings (e.g., channel topics) to extract
|
|
3
|
+
// Kimaki configuration like directory paths and app IDs.
|
|
4
|
+
import { DomHandler, Parser, ElementType } from 'htmlparser2';
|
|
5
|
+
import { createLogger, LogPrefix } from './logger.js';
|
|
6
|
+
const xmlLogger = createLogger(LogPrefix.XML);
|
|
7
|
+
export function extractTagsArrays({ xml, tags, }) {
|
|
8
|
+
const result = {
|
|
9
|
+
others: [],
|
|
10
|
+
};
|
|
11
|
+
// Initialize arrays for each tag
|
|
12
|
+
tags.forEach((tag) => {
|
|
13
|
+
result[tag] = [];
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const handler = new DomHandler((error, dom) => {
|
|
17
|
+
if (error) {
|
|
18
|
+
xmlLogger.error('Error parsing XML:', error);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const findTags = (nodes, path = []) => {
|
|
22
|
+
nodes.forEach((node) => {
|
|
23
|
+
if (node.type === ElementType.Tag) {
|
|
24
|
+
const element = node;
|
|
25
|
+
const currentPath = [...path, element.name];
|
|
26
|
+
const pathString = currentPath.join('.');
|
|
27
|
+
// Extract content using original string positions
|
|
28
|
+
const extractContent = () => {
|
|
29
|
+
// Use element's own indices but exclude the tags
|
|
30
|
+
if (element.startIndex !== null &&
|
|
31
|
+
element.endIndex !== null) {
|
|
32
|
+
// Extract the full element including tags
|
|
33
|
+
const fullElement = xml.substring(element.startIndex, element.endIndex + 1);
|
|
34
|
+
// Find where content starts (after opening tag)
|
|
35
|
+
const contentStart = fullElement.indexOf('>') + 1;
|
|
36
|
+
// Find where content ends (before this element's closing tag)
|
|
37
|
+
const closingTag = `</${element.name}>`;
|
|
38
|
+
const contentEnd = fullElement.lastIndexOf(closingTag);
|
|
39
|
+
if (contentStart > 0 && contentEnd > contentStart) {
|
|
40
|
+
return fullElement.substring(contentStart, contentEnd);
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
}
|
|
44
|
+
return '';
|
|
45
|
+
};
|
|
46
|
+
// Check both single tag names and nested paths
|
|
47
|
+
if (tags.includes(element.name)) {
|
|
48
|
+
const content = extractContent();
|
|
49
|
+
result[element.name]?.push(content);
|
|
50
|
+
}
|
|
51
|
+
// Check for nested path matches
|
|
52
|
+
if (tags.includes(pathString)) {
|
|
53
|
+
const content = extractContent();
|
|
54
|
+
result[pathString]?.push(content);
|
|
55
|
+
}
|
|
56
|
+
if (element.children) {
|
|
57
|
+
findTags(element.children, currentPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (node.type === ElementType.Text &&
|
|
61
|
+
node.parent?.type === ElementType.Root) {
|
|
62
|
+
const textNode = node;
|
|
63
|
+
if (textNode.data.trim()) {
|
|
64
|
+
// console.log('node.parent',node.parent)
|
|
65
|
+
result.others?.push(textNode.data.trim());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
findTags(dom);
|
|
71
|
+
}
|
|
72
|
+
}, {
|
|
73
|
+
withStartIndices: true,
|
|
74
|
+
withEndIndices: true,
|
|
75
|
+
xmlMode: true,
|
|
76
|
+
});
|
|
77
|
+
const parser = new Parser(handler, {
|
|
78
|
+
xmlMode: true,
|
|
79
|
+
decodeEntities: false,
|
|
80
|
+
});
|
|
81
|
+
parser.write(xml);
|
|
82
|
+
parser.end();
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
xmlLogger.error('Unexpected error in extractTags:', error);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
export function extractNonXmlContent(xml) {
|
|
90
|
+
const result = extractTagsArrays({ xml, tags: [] });
|
|
91
|
+
return result.others.join('\n');
|
|
92
|
+
}
|
package/dist/xml.test.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
|
2
|
+
import { extractNonXmlContent } from './xml.js';
|
|
3
|
+
describe('extractNonXmlContent', () => {
|
|
4
|
+
test('removes xml tags and returns only text content', () => {
|
|
5
|
+
const xml = 'Hello <tag>content</tag> world <nested><inner>deep</inner></nested> end';
|
|
6
|
+
expect(extractNonXmlContent(xml)).toMatchInlineSnapshot(`
|
|
7
|
+
"Hello
|
|
8
|
+
world
|
|
9
|
+
end"
|
|
10
|
+
`);
|
|
11
|
+
});
|
|
12
|
+
test('handles multiple text segments', () => {
|
|
13
|
+
const xml = 'Start <a>tag1</a> middle <b>tag2</b> finish';
|
|
14
|
+
expect(extractNonXmlContent(xml)).toMatchInlineSnapshot(`
|
|
15
|
+
"Start
|
|
16
|
+
middle
|
|
17
|
+
finish"
|
|
18
|
+
`);
|
|
19
|
+
});
|
|
20
|
+
test('handles only xml without text', () => {
|
|
21
|
+
const xml = '<root><child>content</child></root>';
|
|
22
|
+
expect(extractNonXmlContent(xml)).toMatchInlineSnapshot(`""`);
|
|
23
|
+
});
|
|
24
|
+
test('handles only text without xml', () => {
|
|
25
|
+
const xml = 'Just plain text';
|
|
26
|
+
expect(extractNonXmlContent(xml)).toMatchInlineSnapshot(`"Just plain text"`);
|
|
27
|
+
});
|
|
28
|
+
test('handles empty string', () => {
|
|
29
|
+
const xml = '';
|
|
30
|
+
expect(extractNonXmlContent(xml)).toMatchInlineSnapshot(`""`);
|
|
31
|
+
});
|
|
32
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brianli/kimaki",
|
|
3
|
+
"module": "index.ts",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.4.72-brianli.1",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsx --env-file .env src/cli.ts",
|
|
8
|
+
"prepublishOnly": "pnpm generate && pnpm tsc",
|
|
9
|
+
"dev:bun": "DEBUG=1 bun --env-file .env src/cli.ts",
|
|
10
|
+
"watch": "tsx scripts/watch-session.ts",
|
|
11
|
+
"generate": "prisma generate && pnpm generate:sql",
|
|
12
|
+
"generate:sql": "rm -f dev.db && prisma db push --url 'file:dev.db' --accept-data-loss && echo '-- This file is generated by pnpm generate:sql. Do not edit manually.' > src/schema.sql && sqlite3 dev.db '.schema' >> src/schema.sql",
|
|
13
|
+
"pcm-to-mp3": "bun scripts/pcm-to-mp3",
|
|
14
|
+
"test": "vitest",
|
|
15
|
+
"test:send": "tsx send-test-message.ts",
|
|
16
|
+
"register-commands": "tsx scripts/register-commands.ts",
|
|
17
|
+
"format": "oxfmt src",
|
|
18
|
+
"sync-skills": "tsx scripts/sync-skills.ts"
|
|
19
|
+
},
|
|
20
|
+
"repository": "https://github.com/remorses/kimaki",
|
|
21
|
+
"bin": "bin.js",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src",
|
|
25
|
+
"skills",
|
|
26
|
+
"schema.prisma",
|
|
27
|
+
"bin.js"
|
|
28
|
+
],
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/bun": "latest",
|
|
31
|
+
"@types/heic-convert": "^2.1.0",
|
|
32
|
+
"@types/js-yaml": "^4.0.9",
|
|
33
|
+
"@types/json-schema": "^7.0.15",
|
|
34
|
+
"@types/ms": "^2.1.0",
|
|
35
|
+
"@types/node": "^24.3.0",
|
|
36
|
+
"discord-digital-twin": "workspace:^",
|
|
37
|
+
"opencode-cached-provider": "workspace:^",
|
|
38
|
+
"opencode-deterministic-provider": "workspace:^",
|
|
39
|
+
"prisma": "7.3.0",
|
|
40
|
+
"tsx": "^4.20.5"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@ai-sdk/google": "^3.0.30",
|
|
44
|
+
"@ai-sdk/openai": "^3.0.31",
|
|
45
|
+
"@ai-sdk/provider": "^3.0.8",
|
|
46
|
+
"@clack/prompts": "^1.0.0",
|
|
47
|
+
"@discordjs/voice": "^0.19.0",
|
|
48
|
+
"@google/genai": "^1.34.0",
|
|
49
|
+
"@libsql/client": "^0.15.15",
|
|
50
|
+
"@opencode-ai/plugin": "^1.1.53",
|
|
51
|
+
"@opencode-ai/sdk": "^1.1.53",
|
|
52
|
+
"@parcel/watcher": "^2.5.6",
|
|
53
|
+
"@prisma/adapter-libsql": "7.3.0",
|
|
54
|
+
"@prisma/client": "7.3.0",
|
|
55
|
+
"@purinton/resampler": "^1.0.4",
|
|
56
|
+
"@sentry/node": "^10.40.0",
|
|
57
|
+
"cron-parser": "^5.5.0",
|
|
58
|
+
"discord.js": "^14.25.1",
|
|
59
|
+
"domhandler": "^5.0.3",
|
|
60
|
+
"errore": "workspace:^",
|
|
61
|
+
"goke": "^6.1.2",
|
|
62
|
+
"htmlparser2": "^10.0.0",
|
|
63
|
+
"js-yaml": "^4.1.0",
|
|
64
|
+
"libsql": "^0.5.22",
|
|
65
|
+
"marked": "^16.3.0",
|
|
66
|
+
"mime": "^4.1.0",
|
|
67
|
+
"picocolors": "^1.1.1",
|
|
68
|
+
"pretty-ms": "^9.3.0",
|
|
69
|
+
"string-dedent": "^3.0.2",
|
|
70
|
+
"traforo": "workspace:^",
|
|
71
|
+
"undici": "^7.16.0",
|
|
72
|
+
"xdg-basedir": "^5.1.0",
|
|
73
|
+
"zod": "^4.3.6",
|
|
74
|
+
"zustand": "^5.0.11"
|
|
75
|
+
},
|
|
76
|
+
"optionalDependencies": {
|
|
77
|
+
"@discordjs/opus": "^0.10.0",
|
|
78
|
+
"heic-convert": "^2.1.0",
|
|
79
|
+
"prism-media": "^1.3.5",
|
|
80
|
+
"sharp": "^0.34.5"
|
|
81
|
+
}
|
|
82
|
+
}
|
package/schema.prisma
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client"
|
|
3
|
+
output = "./src/generated"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
datasource db {
|
|
7
|
+
provider = "sqlite"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
model thread_sessions {
|
|
11
|
+
thread_id String @id
|
|
12
|
+
session_id String
|
|
13
|
+
created_at DateTime? @default(now())
|
|
14
|
+
|
|
15
|
+
part_messages part_messages[]
|
|
16
|
+
scheduled_tasks scheduled_tasks[]
|
|
17
|
+
thread_worktree thread_worktrees?
|
|
18
|
+
ipc_requests ipc_requests[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
model part_messages {
|
|
22
|
+
part_id String @id
|
|
23
|
+
message_id String
|
|
24
|
+
thread_id String
|
|
25
|
+
created_at DateTime? @default(now())
|
|
26
|
+
|
|
27
|
+
thread thread_sessions @relation(fields: [thread_id], references: [thread_id])
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
model bot_tokens {
|
|
31
|
+
app_id String @id
|
|
32
|
+
token String
|
|
33
|
+
created_at DateTime? @default(now())
|
|
34
|
+
|
|
35
|
+
api_keys bot_api_keys?
|
|
36
|
+
channels channel_directories[]
|
|
37
|
+
forum_sync_configs forum_sync_configs[]
|
|
38
|
+
global_model global_models?
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
model channel_directories {
|
|
42
|
+
channel_id String @id
|
|
43
|
+
directory String
|
|
44
|
+
channel_type String
|
|
45
|
+
app_id String?
|
|
46
|
+
created_at DateTime? @default(now())
|
|
47
|
+
|
|
48
|
+
bot bot_tokens? @relation(fields: [app_id], references: [app_id])
|
|
49
|
+
channel_model channel_models?
|
|
50
|
+
channel_agent channel_agents?
|
|
51
|
+
channel_worktree channel_worktrees?
|
|
52
|
+
channel_verbosity channel_verbosity?
|
|
53
|
+
channel_mention_mode channel_mention_mode?
|
|
54
|
+
scheduled_tasks scheduled_tasks[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
model bot_api_keys {
|
|
58
|
+
app_id String @id
|
|
59
|
+
gemini_api_key String?
|
|
60
|
+
openai_api_key String?
|
|
61
|
+
xai_api_key String?
|
|
62
|
+
created_at DateTime? @default(now())
|
|
63
|
+
|
|
64
|
+
bot bot_tokens @relation(fields: [app_id], references: [app_id])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// status: 'pending' while creating, 'ready' when done, 'error' if failed
|
|
68
|
+
model thread_worktrees {
|
|
69
|
+
thread_id String @id
|
|
70
|
+
worktree_name String
|
|
71
|
+
worktree_directory String?
|
|
72
|
+
project_directory String
|
|
73
|
+
status String? @default("pending")
|
|
74
|
+
error_message String?
|
|
75
|
+
created_at DateTime? @default(now())
|
|
76
|
+
|
|
77
|
+
thread thread_sessions @relation(fields: [thread_id], references: [thread_id])
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
model channel_models {
|
|
81
|
+
channel_id String @id
|
|
82
|
+
model_id String
|
|
83
|
+
variant String?
|
|
84
|
+
created_at DateTime? @default(now())
|
|
85
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
86
|
+
|
|
87
|
+
channel channel_directories @relation(fields: [channel_id], references: [channel_id])
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
model session_models {
|
|
91
|
+
session_id String @id
|
|
92
|
+
model_id String
|
|
93
|
+
variant String?
|
|
94
|
+
created_at DateTime? @default(now())
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
model channel_agents {
|
|
98
|
+
channel_id String @id
|
|
99
|
+
agent_name String
|
|
100
|
+
created_at DateTime? @default(now())
|
|
101
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
102
|
+
|
|
103
|
+
channel channel_directories @relation(fields: [channel_id], references: [channel_id])
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
model session_agents {
|
|
107
|
+
session_id String @id
|
|
108
|
+
agent_name String
|
|
109
|
+
created_at DateTime? @default(now())
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
model channel_worktrees {
|
|
113
|
+
channel_id String @id
|
|
114
|
+
enabled Int @default(0)
|
|
115
|
+
created_at DateTime? @default(now())
|
|
116
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
117
|
+
|
|
118
|
+
channel channel_directories @relation(fields: [channel_id], references: [channel_id])
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
model channel_verbosity {
|
|
122
|
+
channel_id String @id
|
|
123
|
+
verbosity String @default("tools-and-text")
|
|
124
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
125
|
+
|
|
126
|
+
channel channel_directories @relation(fields: [channel_id], references: [channel_id])
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
model channel_mention_mode {
|
|
130
|
+
channel_id String @id
|
|
131
|
+
enabled Int @default(0)
|
|
132
|
+
created_at DateTime? @default(now())
|
|
133
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
134
|
+
|
|
135
|
+
channel channel_directories @relation(fields: [channel_id], references: [channel_id])
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
model global_models {
|
|
139
|
+
app_id String @id
|
|
140
|
+
model_id String
|
|
141
|
+
variant String?
|
|
142
|
+
created_at DateTime? @default(now())
|
|
143
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
144
|
+
|
|
145
|
+
bot bot_tokens @relation(fields: [app_id], references: [app_id])
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
enum task_status {
|
|
149
|
+
planned
|
|
150
|
+
running
|
|
151
|
+
completed
|
|
152
|
+
cancelled
|
|
153
|
+
failed
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
enum task_schedule_kind {
|
|
157
|
+
at
|
|
158
|
+
cron
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
model scheduled_tasks {
|
|
162
|
+
id Int @id @default(autoincrement())
|
|
163
|
+
status task_status @default(planned)
|
|
164
|
+
schedule_kind task_schedule_kind
|
|
165
|
+
run_at DateTime?
|
|
166
|
+
cron_expr String?
|
|
167
|
+
timezone String?
|
|
168
|
+
next_run_at DateTime
|
|
169
|
+
running_started_at DateTime?
|
|
170
|
+
last_run_at DateTime?
|
|
171
|
+
last_error String?
|
|
172
|
+
attempts Int @default(0)
|
|
173
|
+
payload_json String
|
|
174
|
+
prompt_preview String
|
|
175
|
+
channel_id String?
|
|
176
|
+
thread_id String?
|
|
177
|
+
session_id String?
|
|
178
|
+
project_directory String?
|
|
179
|
+
created_at DateTime? @default(now())
|
|
180
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
181
|
+
|
|
182
|
+
channel channel_directories? @relation(fields: [channel_id], references: [channel_id], onDelete: SetNull, onUpdate: Cascade)
|
|
183
|
+
thread thread_sessions? @relation(fields: [thread_id], references: [thread_id], onDelete: SetNull, onUpdate: Cascade)
|
|
184
|
+
session_start_sources session_start_sources[]
|
|
185
|
+
|
|
186
|
+
@@index([status, next_run_at])
|
|
187
|
+
@@index([channel_id, status])
|
|
188
|
+
@@index([thread_id, status])
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
model session_start_sources {
|
|
192
|
+
session_id String @id
|
|
193
|
+
schedule_kind task_schedule_kind
|
|
194
|
+
scheduled_task_id Int?
|
|
195
|
+
created_at DateTime? @default(now())
|
|
196
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
197
|
+
|
|
198
|
+
scheduled_task scheduled_tasks? @relation(fields: [scheduled_task_id], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
199
|
+
|
|
200
|
+
@@index([scheduled_task_id])
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
model forum_sync_configs {
|
|
204
|
+
id Int @id @default(autoincrement())
|
|
205
|
+
app_id String
|
|
206
|
+
forum_channel_id String
|
|
207
|
+
output_dir String
|
|
208
|
+
direction String @default("bidirectional")
|
|
209
|
+
created_at DateTime? @default(now())
|
|
210
|
+
updated_at DateTime? @default(now()) @updatedAt
|
|
211
|
+
|
|
212
|
+
bot bot_tokens @relation(fields: [app_id], references: [app_id], onDelete: Cascade, onUpdate: Cascade)
|
|
213
|
+
|
|
214
|
+
@@unique([app_id, forum_channel_id])
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
enum ipc_request_type {
|
|
218
|
+
file_upload
|
|
219
|
+
action_buttons
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
enum ipc_request_status {
|
|
223
|
+
pending
|
|
224
|
+
processing
|
|
225
|
+
completed
|
|
226
|
+
cancelled
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// IPC bridge between the opencode plugin process and the Discord bot process.
|
|
230
|
+
// Replaces the old HTTP lock server for file-upload and action-buttons requests.
|
|
231
|
+
// Plugin inserts a pending row, bot polls and dispatches, then writes the response.
|
|
232
|
+
model ipc_requests {
|
|
233
|
+
id String @id @default(uuid())
|
|
234
|
+
type ipc_request_type
|
|
235
|
+
session_id String
|
|
236
|
+
thread_id String
|
|
237
|
+
payload String // JSON-encoded request data
|
|
238
|
+
response String? // JSON-encoded response, null while pending
|
|
239
|
+
status ipc_request_status @default(pending)
|
|
240
|
+
created_at DateTime @default(now())
|
|
241
|
+
updated_at DateTime @default(now()) @updatedAt
|
|
242
|
+
|
|
243
|
+
thread thread_sessions @relation(fields: [thread_id], references: [thread_id])
|
|
244
|
+
|
|
245
|
+
@@index([status, created_at])
|
|
246
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: batch
|
|
3
|
+
description: >
|
|
4
|
+
Research and plan a large-scale change, then execute it in parallel across
|
|
5
|
+
5-30 isolated worktree agents that each open a PR. Use when the user wants
|
|
6
|
+
to make a sweeping, mechanical change across many files (migrations,
|
|
7
|
+
refactors, bulk renames) that can be decomposed into independent parallel
|
|
8
|
+
units.
|
|
9
|
+
argument-hint: "<instruction>"
|
|
10
|
+
source-path: cli.js (line 7359, function mGz)
|
|
11
|
+
source-package: "@anthropic-ai/claude-code@2.1.63"
|
|
12
|
+
source-date: 2026-02-28
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Batch: Parallel Work Orchestration
|
|
16
|
+
|
|
17
|
+
You are orchestrating a large, parallelizable change across this codebase.
|
|
18
|
+
|
|
19
|
+
## User Instruction
|
|
20
|
+
|
|
21
|
+
$instruction
|
|
22
|
+
|
|
23
|
+
## Phase 1: Research and Plan (Plan Mode)
|
|
24
|
+
|
|
25
|
+
Enter plan mode, then:
|
|
26
|
+
|
|
27
|
+
1. **Understand the scope.** Launch one or more Explore agents (in the foreground — you need their results) to deeply research what this instruction touches. Find all the files, patterns, and call sites that need to change. Understand the existing conventions so the migration is consistent.
|
|
28
|
+
|
|
29
|
+
2. **Decompose into independent units.** Break the work into 5–30 self-contained units. Each unit must:
|
|
30
|
+
- Be independently implementable in an isolated git worktree (no shared state with sibling units)
|
|
31
|
+
- Be mergeable on its own without depending on another unit's PR landing first
|
|
32
|
+
- Be roughly uniform in size (split large units, merge trivial ones)
|
|
33
|
+
|
|
34
|
+
Scale the count to the actual work: few files → closer to 5; hundreds of files → closer to 30. Prefer per-directory or per-module slicing over arbitrary file lists.
|
|
35
|
+
|
|
36
|
+
3. **Determine the e2e test recipe.** Figure out how a worker can verify its change actually works end-to-end — not just that unit tests pass. Look for:
|
|
37
|
+
- A browser-automation tool (for UI changes: click through the affected flow, screenshot the result)
|
|
38
|
+
- A tmux or CLI-verifier skill (for CLI changes: launch the app interactively, exercise the changed behavior)
|
|
39
|
+
- A dev-server + curl pattern (for API changes: start the server, hit the affected endpoints)
|
|
40
|
+
- An existing e2e/integration test suite the worker can run
|
|
41
|
+
|
|
42
|
+
If you cannot find a concrete e2e path, ask the user how to verify this change end-to-end. Offer 2–3 specific options based on what you found (e.g., "Screenshot via chrome extension", "Run `bun run dev` and curl the endpoint", "No e2e — unit tests are sufficient"). Do not skip this — the workers cannot ask the user themselves.
|
|
43
|
+
|
|
44
|
+
Write the recipe as a short, concrete set of steps that a worker can execute autonomously. Include any setup (start a dev server, build first) and the exact command/interaction to verify.
|
|
45
|
+
|
|
46
|
+
4. **Write the plan.** In your plan file, include:
|
|
47
|
+
- A summary of what you found during research
|
|
48
|
+
- A numbered list of work units — for each: a short title, the list of files/directories it covers, and a one-line description of the change
|
|
49
|
+
- The e2e test recipe (or "skip e2e because …" if the user chose that)
|
|
50
|
+
- The exact worker instructions you will give each agent (the shared template)
|
|
51
|
+
|
|
52
|
+
5. Present the plan for approval.
|
|
53
|
+
|
|
54
|
+
## Phase 2: Spawn Workers (After Plan Approval)
|
|
55
|
+
|
|
56
|
+
Once the plan is approved, spawn one background agent per work unit using the Task tool. **All agents must use `isolation: "worktree"` and `run_in_background: true`.** Launch them all in a single message block so they run in parallel.
|
|
57
|
+
|
|
58
|
+
For each agent, the prompt must be fully self-contained. Include:
|
|
59
|
+
- The overall goal (the user's instruction)
|
|
60
|
+
- This unit's specific task (title, file list, change description — copied verbatim from your plan)
|
|
61
|
+
- Any codebase conventions you discovered that the worker needs to follow
|
|
62
|
+
- The e2e test recipe from your plan (or "skip e2e because …")
|
|
63
|
+
- The worker instructions below, copied verbatim:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
After you finish implementing the change:
|
|
67
|
+
1. **Simplify** — Invoke the simplify skill to review and clean up your changes.
|
|
68
|
+
2. **Run unit tests** — Run the project's test suite (check for package.json scripts, Makefile targets, or common commands like `npm test`, `bun test`, `pytest`, `go test`). If tests fail, fix them.
|
|
69
|
+
3. **Test end-to-end** — Follow the e2e test recipe from the coordinator's prompt (below). If the recipe says to skip e2e for this unit, skip it.
|
|
70
|
+
4. **Commit and push** — Commit all changes with a clear message, push the branch, and create a PR with `gh pr create`. Use a descriptive title. If `gh` is not available or the push fails, note it in your final message.
|
|
71
|
+
5. **Report** — End with a single line: `PR: <url>` so the coordinator can track it. If no PR was created, end with `PR: none — <reason>`.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Use `subagent_type: "general-purpose"` unless a more specific agent type fits.
|
|
75
|
+
|
|
76
|
+
## Phase 3: Track Progress
|
|
77
|
+
|
|
78
|
+
After launching all workers, render an initial status table:
|
|
79
|
+
|
|
80
|
+
| # | Unit | Status | PR |
|
|
81
|
+
|---|------|--------|----|
|
|
82
|
+
| 1 | <title> | running | — |
|
|
83
|
+
| 2 | <title> | running | — |
|
|
84
|
+
|
|
85
|
+
As background-agent completion notifications arrive, parse the `PR: <url>` line from each agent's result and re-render the table with updated status (`done` / `failed`) and PR links. Keep a brief failure note for any agent that did not produce a PR.
|
|
86
|
+
|
|
87
|
+
When all agents have reported, render the final table and a one-line summary (e.g., "22/24 units landed as PRs").
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: critique
|
|
3
|
+
description: >
|
|
4
|
+
Git diff viewer and AI reviewer. Renders diffs as web pages, images, and PDFs
|
|
5
|
+
with syntax highlighting. Also provides AI-powered diff reviews via
|
|
6
|
+
`critique review --web`. Use this skill when working with critique for showing
|
|
7
|
+
diffs, generating diff URLs, selective hunk staging, or AI code reviews.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# critique
|
|
11
|
+
|
|
12
|
+
Git diff viewer that renders diffs as **web pages**, **images**, and **PDFs** with syntax highlighting.
|
|
13
|
+
|
|
14
|
+
Agents running in headless environments (kimaki on Discord, openclaw on Slack/Telegram) have no terminal to show diffs. critique uploads diffs to critique.work and returns a shareable URL you can paste into chat. Users click the link and see a syntax-highlighted split-view diff with mobile support and dark/light mode — no install needed.
|
|
15
|
+
|
|
16
|
+
**Always run `critique --help` first** to see the latest flags and commands. The help output is the source of truth.
|
|
17
|
+
|
|
18
|
+
## Web — shareable diff URLs
|
|
19
|
+
|
|
20
|
+
Always pass a title to describe what the diff contains.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Working tree changes
|
|
24
|
+
critique --web "Add retry logic to database connections"
|
|
25
|
+
|
|
26
|
+
# Staged changes
|
|
27
|
+
critique --staged --web "Refactor auth middleware"
|
|
28
|
+
|
|
29
|
+
# Branch diff (three-dot: changes since diverging from base)
|
|
30
|
+
critique main...HEAD --web "Feature branch changes"
|
|
31
|
+
critique main...feature-branch --web "Compare branches"
|
|
32
|
+
|
|
33
|
+
# Last N commits
|
|
34
|
+
critique HEAD~3 --web "Recent changes"
|
|
35
|
+
|
|
36
|
+
# Specific commit
|
|
37
|
+
critique --commit HEAD --web "Latest commit"
|
|
38
|
+
critique --commit abc1234 --web "Fix race condition"
|
|
39
|
+
|
|
40
|
+
# Filter to specific files
|
|
41
|
+
critique --web "API changes" --filter "src/api.ts" --filter "src/utils.ts"
|
|
42
|
+
|
|
43
|
+
# JSON output for programmatic use (returns {url, id, files})
|
|
44
|
+
critique --web "Deploy changes" --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Share the returned URL with the user so they can see the diff.
|
|
48
|
+
|
|
49
|
+
## PDF
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
critique --pdf # working tree to PDF
|
|
53
|
+
critique --staged --pdf # staged changes
|
|
54
|
+
critique main...HEAD --pdf # branch diff
|
|
55
|
+
critique --commit HEAD --pdf # single commit
|
|
56
|
+
critique --pdf output.pdf # custom filename
|
|
57
|
+
critique --pdf --pdf-page-size a4-portrait # page size options
|
|
58
|
+
critique main...HEAD --pdf --open # open in viewer
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Image
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
critique --image # renders to /tmp as WebP
|
|
65
|
+
critique main...HEAD --image # branch diff as images
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Selective hunk staging
|
|
69
|
+
|
|
70
|
+
When multiple agents work on the same repo, each agent should only commit its own changes. `critique hunks` lets you stage individual hunks instead of whole files — like a scriptable `git add -p`.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# List hunks with stable IDs
|
|
74
|
+
critique hunks list
|
|
75
|
+
critique hunks list --filter "src/**/*.ts"
|
|
76
|
+
|
|
77
|
+
# Stage specific hunks by ID
|
|
78
|
+
critique hunks add 'src/main.ts:@-10,6+10,7'
|
|
79
|
+
critique hunks add 'src/main.ts:@-10,6+10,7' 'src/utils.ts:@-5,3+5,4'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Hunk ID format: `file:@-oldStart,oldLines+newStart,newLines` — derived from the `@@` diff header, stable across runs.
|
|
83
|
+
|
|
84
|
+
**Typical workflow:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
critique hunks list # see all unstaged hunks
|
|
88
|
+
critique hunks add 'file:@-10,6+10,7' # stage only your hunks
|
|
89
|
+
git commit -m "your changes" # commit separately
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## AI-powered diff review
|
|
93
|
+
|
|
94
|
+
`critique review --web` spawns a separate opencode session that analyzes a diff, groups related
|
|
95
|
+
changes, and produces a structured review with explanations, diagrams, and suggestions. Uploads
|
|
96
|
+
the result as a shareable URL — much richer than a plain diff link.
|
|
97
|
+
|
|
98
|
+
**This command is very slow (up to 20 minutes for large diffs).** Only run when the user
|
|
99
|
+
explicitly asks for a code review or diff explanation. Warn the user it will take a while.
|
|
100
|
+
Set Bash tool timeout to at least 25 minutes (`timeout: 1_500_000`).
|
|
101
|
+
|
|
102
|
+
Always pass `--agent opencode` and `--session <current_session_id>` so the reviewer has context
|
|
103
|
+
about why the changes were made. If you know other session IDs that produced the diff, pass them
|
|
104
|
+
too with additional `--session` flags.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Review working tree changes
|
|
108
|
+
critique review --web --agent opencode --session <session_id>
|
|
109
|
+
|
|
110
|
+
# Review a specific commit
|
|
111
|
+
critique review --commit HEAD --web --agent opencode --session <session_id>
|
|
112
|
+
|
|
113
|
+
# Review branch changes compared to main
|
|
114
|
+
critique review main...HEAD --web --agent opencode --session <session_id>
|
|
115
|
+
|
|
116
|
+
# Review with multiple session contexts
|
|
117
|
+
critique review --commit abc1234 --web --agent opencode --session <session_id> --session <other_session_id>
|
|
118
|
+
|
|
119
|
+
# Review only specific files
|
|
120
|
+
critique review --web --agent opencode --session <session_id> --filter "src/**/*.ts"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The command prints a preview URL when done — share that URL with the user.
|
|
124
|
+
|
|
125
|
+
## Notes
|
|
126
|
+
|
|
127
|
+
- Requires **Bun** — use `bunx critique` or global `critique`
|
|
128
|
+
- Lock files and diffs >6000 lines are auto-hidden
|
|
129
|
+
- `--web` URLs expire after 7 days (content-hashed, same diff = same URL)
|