@horizon-ai-dev/shokunin 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +236 -0
  3. package/dist/agents/sn-code-reviewer.d.ts +13 -0
  4. package/dist/agents/sn-code-reviewer.d.ts.map +1 -0
  5. package/dist/agents/sn-code-reviewer.js +75 -0
  6. package/dist/agents/sn-code-reviewer.js.map +1 -0
  7. package/dist/agents/sn-code-simplifier.d.ts +13 -0
  8. package/dist/agents/sn-code-simplifier.d.ts.map +1 -0
  9. package/dist/agents/sn-code-simplifier.js +70 -0
  10. package/dist/agents/sn-code-simplifier.js.map +1 -0
  11. package/dist/agents/sn-comment-analyzer.d.ts +12 -0
  12. package/dist/agents/sn-comment-analyzer.d.ts.map +1 -0
  13. package/dist/agents/sn-comment-analyzer.js +65 -0
  14. package/dist/agents/sn-comment-analyzer.js.map +1 -0
  15. package/dist/agents/sn-pr-test-analyzer.d.ts +12 -0
  16. package/dist/agents/sn-pr-test-analyzer.d.ts.map +1 -0
  17. package/dist/agents/sn-pr-test-analyzer.js +78 -0
  18. package/dist/agents/sn-pr-test-analyzer.js.map +1 -0
  19. package/dist/agents/sn-silent-failure-hunter.d.ts +12 -0
  20. package/dist/agents/sn-silent-failure-hunter.d.ts.map +1 -0
  21. package/dist/agents/sn-silent-failure-hunter.js +84 -0
  22. package/dist/agents/sn-silent-failure-hunter.js.map +1 -0
  23. package/dist/agents/sn-skill-reviewer.d.ts +12 -0
  24. package/dist/agents/sn-skill-reviewer.d.ts.map +1 -0
  25. package/dist/agents/sn-skill-reviewer.js +93 -0
  26. package/dist/agents/sn-skill-reviewer.js.map +1 -0
  27. package/dist/agents/sn-type-design-analyzer.d.ts +12 -0
  28. package/dist/agents/sn-type-design-analyzer.d.ts.map +1 -0
  29. package/dist/agents/sn-type-design-analyzer.js +109 -0
  30. package/dist/agents/sn-type-design-analyzer.js.map +1 -0
  31. package/dist/commands/sn-check-config.d.ts +23 -0
  32. package/dist/commands/sn-check-config.d.ts.map +1 -0
  33. package/dist/commands/sn-check-config.js +230 -0
  34. package/dist/commands/sn-check-config.js.map +1 -0
  35. package/dist/commands/sn-configure.d.ts +27 -0
  36. package/dist/commands/sn-configure.d.ts.map +1 -0
  37. package/dist/commands/sn-configure.js +273 -0
  38. package/dist/commands/sn-configure.js.map +1 -0
  39. package/dist/commands/sn-review-pr.d.ts +16 -0
  40. package/dist/commands/sn-review-pr.d.ts.map +1 -0
  41. package/dist/commands/sn-review-pr.js +113 -0
  42. package/dist/commands/sn-review-pr.js.map +1 -0
  43. package/dist/commands/sn-update.d.ts +23 -0
  44. package/dist/commands/sn-update.d.ts.map +1 -0
  45. package/dist/commands/sn-update.js +202 -0
  46. package/dist/commands/sn-update.js.map +1 -0
  47. package/dist/context/shokunin-rules.d.ts +26 -0
  48. package/dist/context/shokunin-rules.d.ts.map +1 -0
  49. package/dist/context/shokunin-rules.js +59 -0
  50. package/dist/context/shokunin-rules.js.map +1 -0
  51. package/dist/index.d.ts +8 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +8 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lib/logger.d.ts +50 -0
  56. package/dist/lib/logger.d.ts.map +1 -0
  57. package/dist/lib/logger.js +52 -0
  58. package/dist/lib/logger.js.map +1 -0
  59. package/dist/lib/smart-merge.d.ts +130 -0
  60. package/dist/lib/smart-merge.d.ts.map +1 -0
  61. package/dist/lib/smart-merge.js +368 -0
  62. package/dist/lib/smart-merge.js.map +1 -0
  63. package/dist/plugin.d.ts +30 -0
  64. package/dist/plugin.d.ts.map +1 -0
  65. package/dist/plugin.js +133 -0
  66. package/dist/plugin.js.map +1 -0
  67. package/dist/tools/emergency-stop.d.ts +15 -0
  68. package/dist/tools/emergency-stop.d.ts.map +1 -0
  69. package/dist/tools/emergency-stop.js +97 -0
  70. package/dist/tools/emergency-stop.js.map +1 -0
  71. package/package.json +46 -0
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Smart-merge utilities for config files.
3
+ *
4
+ * Provides functions for merging plugin configuration into user's
5
+ * opencode.json without overwriting existing settings.
6
+ *
7
+ * Used by /sn-configure and /sn-update commands.
8
+ */
9
+ // ============================================================================
10
+ // Internal helpers
11
+ // ============================================================================
12
+ /**
13
+ * Check if a value is a plain object (not array, null, etc.)
14
+ */
15
+ function isPlainObject(value) {
16
+ return (typeof value === "object" &&
17
+ value !== null &&
18
+ !Array.isArray(value) &&
19
+ Object.prototype.toString.call(value) === "[object Object]");
20
+ }
21
+ /**
22
+ * Stringify a value for comparison purposes.
23
+ */
24
+ function stringify(value) {
25
+ if (value === null || value === undefined) {
26
+ return JSON.stringify(value);
27
+ }
28
+ if (typeof value !== "object") {
29
+ return JSON.stringify(value);
30
+ }
31
+ return JSON.stringify(value, Object.keys(value).sort());
32
+ }
33
+ /**
34
+ * Deep equality check for two values.
35
+ */
36
+ function deepEqual(a, b) {
37
+ return stringify(a) === stringify(b);
38
+ }
39
+ /**
40
+ * Deep clone a value using JSON serialization.
41
+ */
42
+ function deepClone(value) {
43
+ return JSON.parse(JSON.stringify(value));
44
+ }
45
+ /**
46
+ * Build a path string from parent and key.
47
+ */
48
+ function buildPath(parentPath, key) {
49
+ return parentPath ? `${parentPath}.${key}` : key;
50
+ }
51
+ // ============================================================================
52
+ // Array merge
53
+ // ============================================================================
54
+ /**
55
+ * Merge arrays, adding only unique items from additions.
56
+ *
57
+ * Uses JSON.stringify for deep equality comparison of objects.
58
+ *
59
+ * @param existing - The existing array
60
+ * @param additions - Items to potentially add
61
+ * @returns New array with unique items from both
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * mergeArrayUnique([1, 2, 3], [2, 3, 4]);
66
+ * // => [1, 2, 3, 4]
67
+ *
68
+ * mergeArrayUnique([{ a: 1 }], [{ a: 1 }, { b: 2 }]);
69
+ * // => [{ a: 1 }, { b: 2 }]
70
+ * ```
71
+ */
72
+ export function mergeArrayUnique(existing, additions) {
73
+ const result = [...existing];
74
+ const existingSet = new Set(existing.map((item) => stringify(item)));
75
+ for (const item of additions) {
76
+ const key = stringify(item);
77
+ if (!existingSet.has(key)) {
78
+ result.push(item);
79
+ existingSet.add(key);
80
+ }
81
+ }
82
+ return result;
83
+ }
84
+ /**
85
+ * Handle the case when a key doesn't exist in existing object.
86
+ */
87
+ function handleNewKey(ctx, key, newValue) {
88
+ ctx.merged[key] = deepClone(newValue);
89
+ ctx.hasChanges = true;
90
+ }
91
+ /**
92
+ * Handle merging two arrays.
93
+ */
94
+ function handleArrayMerge(ctx, key, existingArray, newArray) {
95
+ const mergedArray = mergeArrayUnique(existingArray, newArray);
96
+ if (mergedArray.length !== existingArray.length) {
97
+ ctx.hasChanges = true;
98
+ }
99
+ ctx.merged[key] = mergedArray;
100
+ }
101
+ /**
102
+ * Handle merging two nested objects.
103
+ */
104
+ function handleNestedObjectMerge(params) {
105
+ const { ctx, key, path, existingObj, newObj } = params;
106
+ const nestedResult = mergeObjectInternal(existingObj, newObj, path);
107
+ ctx.merged[key] = nestedResult.merged;
108
+ ctx.conflicts.push(...nestedResult.conflicts);
109
+ if (nestedResult.hasChanges) {
110
+ ctx.hasChanges = true;
111
+ }
112
+ }
113
+ /**
114
+ * Handle value conflicts (different primitive values).
115
+ */
116
+ function handleConflict(ctx, path, existingValue, newValue) {
117
+ ctx.conflicts.push({
118
+ path,
119
+ existingValue,
120
+ newValue,
121
+ });
122
+ // Keep existing value on conflict
123
+ }
124
+ /**
125
+ * Internal merge implementation with lower complexity.
126
+ */
127
+ function mergeObjectInternal(existing, additions, parentPath) {
128
+ const ctx = {
129
+ merged: { ...existing },
130
+ conflicts: [],
131
+ hasChanges: false,
132
+ };
133
+ for (const key of Object.keys(additions)) {
134
+ const path = buildPath(parentPath, key);
135
+ const existingValue = existing[key];
136
+ const newValue = additions[key];
137
+ if (!(key in existing)) {
138
+ handleNewKey(ctx, key, newValue);
139
+ continue;
140
+ }
141
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
142
+ handleArrayMerge(ctx, key, existingValue, newValue);
143
+ continue;
144
+ }
145
+ const bothObjects = isPlainObject(existingValue) && isPlainObject(newValue);
146
+ if (bothObjects) {
147
+ handleNestedObjectMerge({
148
+ ctx,
149
+ key,
150
+ path,
151
+ existingObj: existingValue,
152
+ newObj: newValue,
153
+ });
154
+ continue;
155
+ }
156
+ if (!deepEqual(existingValue, newValue)) {
157
+ handleConflict(ctx, path, existingValue, newValue);
158
+ }
159
+ }
160
+ return ctx;
161
+ }
162
+ /**
163
+ * Deep merge two objects, detecting value conflicts.
164
+ *
165
+ * - For arrays: merges using mergeArrayUnique
166
+ * - For objects: recursively merges nested objects
167
+ * - For primitives: detects conflicts when values differ
168
+ *
169
+ * @param existing - The existing object
170
+ * @param additions - Object with values to merge in
171
+ * @returns Merged object and any conflicts detected
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * mergeObject(
176
+ * { a: 1, b: { c: 2 } },
177
+ * { b: { d: 3 }, e: 4 }
178
+ * );
179
+ * // => { merged: { a: 1, b: { c: 2, d: 3 }, e: 4 }, conflicts: [] }
180
+ *
181
+ * mergeObject({ a: 1 }, { a: 2 });
182
+ * // => { merged: { a: 1 }, conflicts: [{ path: 'a', existingValue: 1, newValue: 2 }] }
183
+ * ```
184
+ */
185
+ export function mergeObject(existing, additions) {
186
+ return mergeObjectInternal(existing, additions, "");
187
+ }
188
+ // ============================================================================
189
+ // Change collection - helpers for reduced complexity
190
+ // ============================================================================
191
+ /**
192
+ * Handle new key addition in change collection.
193
+ */
194
+ function recordAddition(changes, path, newValue) {
195
+ changes.push({ type: "added", path, value: newValue });
196
+ }
197
+ /**
198
+ * Handle array modification in change collection.
199
+ */
200
+ function recordArrayChange(changes, path, existingArray, newArray) {
201
+ const existingSet = new Set(existingArray.map((item) => stringify(item)));
202
+ const newItems = newArray.filter((item) => !existingSet.has(stringify(item)));
203
+ if (newItems.length > 0) {
204
+ changes.push({
205
+ type: "modified",
206
+ path,
207
+ value: newItems,
208
+ previousValue: `(array with ${existingArray.length} items)`,
209
+ });
210
+ }
211
+ }
212
+ /**
213
+ * Record a value conflict in change collection.
214
+ */
215
+ function recordConflict(changes, path, existingValue, newValue) {
216
+ changes.push({
217
+ type: "conflict",
218
+ path,
219
+ value: newValue,
220
+ previousValue: existingValue,
221
+ });
222
+ }
223
+ /**
224
+ * Recursively collect changes between original and additions.
225
+ */
226
+ function collectChanges(original, additions, parentPath, changes) {
227
+ for (const key of Object.keys(additions)) {
228
+ const path = buildPath(parentPath, key);
229
+ const existingValue = original[key];
230
+ const newValue = additions[key];
231
+ if (!(key in original)) {
232
+ recordAddition(changes, path, newValue);
233
+ continue;
234
+ }
235
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
236
+ recordArrayChange(changes, path, existingValue, newValue);
237
+ continue;
238
+ }
239
+ const bothObjects = isPlainObject(existingValue) && isPlainObject(newValue);
240
+ if (bothObjects) {
241
+ collectChanges(existingValue, newValue, path, changes);
242
+ continue;
243
+ }
244
+ if (!deepEqual(existingValue, newValue)) {
245
+ recordConflict(changes, path, existingValue, newValue);
246
+ }
247
+ }
248
+ }
249
+ // ============================================================================
250
+ // Summary formatting - helpers for reduced complexity
251
+ // ============================================================================
252
+ /**
253
+ * Format added changes for summary.
254
+ */
255
+ function formatAddedChanges(added) {
256
+ if (added.length === 0) {
257
+ return "";
258
+ }
259
+ let result = "Added:\n";
260
+ for (const change of added) {
261
+ result += ` + ${change.path}\n`;
262
+ }
263
+ return result;
264
+ }
265
+ /**
266
+ * Format modified changes for summary.
267
+ */
268
+ function formatModifiedChanges(modified) {
269
+ if (modified.length === 0) {
270
+ return "";
271
+ }
272
+ let result = "Modified:\n";
273
+ for (const change of modified) {
274
+ result += ` ~ ${change.path}\n`;
275
+ }
276
+ return result;
277
+ }
278
+ /**
279
+ * Format conflict changes for summary.
280
+ */
281
+ function formatConflictChanges(conflicts) {
282
+ if (conflicts.length === 0) {
283
+ return "";
284
+ }
285
+ let result = "Conflicts (existing value kept):\n";
286
+ for (const change of conflicts) {
287
+ const existing = JSON.stringify(change.previousValue);
288
+ const newVal = JSON.stringify(change.value);
289
+ result += ` ! ${change.path}: existing=${existing}, new=${newVal}\n`;
290
+ }
291
+ return result;
292
+ }
293
+ /**
294
+ * Build summary header with counts.
295
+ */
296
+ function buildSummaryHeader(added, modified, conflicts) {
297
+ const parts = [];
298
+ if (added.length > 0) {
299
+ parts.push(`${added.length} addition${added.length > 1 ? "s" : ""}`);
300
+ }
301
+ if (modified.length > 0) {
302
+ parts.push(`${modified.length} modification${modified.length > 1 ? "s" : ""}`);
303
+ }
304
+ if (conflicts.length > 0) {
305
+ parts.push(`${conflicts.length} conflict${conflicts.length > 1 ? "s" : ""}`);
306
+ }
307
+ return `Changes: ${parts.join(", ")}.\n\n`;
308
+ }
309
+ /**
310
+ * Format changes into a human-readable summary.
311
+ */
312
+ function formatChangesSummary(changes) {
313
+ if (changes.length === 0) {
314
+ return "No changes needed.";
315
+ }
316
+ const added = changes.filter((c) => c.type === "added");
317
+ const modified = changes.filter((c) => c.type === "modified");
318
+ const conflicts = changes.filter((c) => c.type === "conflict");
319
+ let summary = buildSummaryHeader(added, modified, conflicts);
320
+ summary += formatAddedChanges(added);
321
+ summary += formatModifiedChanges(modified);
322
+ summary += formatConflictChanges(conflicts);
323
+ return summary.trim();
324
+ }
325
+ // ============================================================================
326
+ // Public API - preview and dry run
327
+ // ============================================================================
328
+ /**
329
+ * Preview the changes that would be made by merging additions into existing.
330
+ *
331
+ * @param original - The original object
332
+ * @param additions - Object with values to merge in
333
+ * @returns Preview with list of changes and human-readable summary
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * const preview = previewChanges(
338
+ * { a: 1, b: 2 },
339
+ * { b: 3, c: 4 }
340
+ * );
341
+ * // preview.changes = [
342
+ * // { type: 'conflict', path: 'b', value: 3, previousValue: 2 },
343
+ * // { type: 'added', path: 'c', value: 4 }
344
+ * // ]
345
+ * ```
346
+ */
347
+ export function previewChanges(original, additions) {
348
+ const changes = [];
349
+ collectChanges(original, additions, "", changes);
350
+ const summary = formatChangesSummary(changes);
351
+ return { changes, summary };
352
+ }
353
+ /**
354
+ * Perform a merge operation in dry-run mode.
355
+ *
356
+ * Returns the merge result without modifying anything,
357
+ * along with a preview of what would change.
358
+ *
359
+ * @param original - The original object
360
+ * @param additions - Object with values to merge in
361
+ * @returns Merge result and preview
362
+ */
363
+ export function dryRunMerge(original, additions) {
364
+ const result = mergeObject(original, additions);
365
+ const preview = previewChanges(original, additions);
366
+ return { result, preview };
367
+ }
368
+ //# sourceMappingURL=smart-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-merge.js","sourceRoot":"","sources":["../../src/lib/smart-merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shokunin Plugin
3
+ *
4
+ * Wraps and extends the opencode-beads plugin with additional
5
+ * Shokunin-specific functionality.
6
+ *
7
+ * Inherited from opencode-beads:
8
+ * - Context injection via `bd prime` on session start and after compaction
9
+ * - Commands parsed from beads command definitions
10
+ * - beads-task-agent for autonomous issue completion
11
+ *
12
+ * Shokunin agents (sn- prefix):
13
+ * - sn-code-reviewer (primary) - Comprehensive code review
14
+ * - sn-code-simplifier (subagent) - Code simplification
15
+ * - sn-comment-analyzer (subagent) - Comment quality analysis
16
+ * - sn-pr-test-analyzer (subagent) - Test coverage analysis
17
+ * - sn-silent-failure-hunter (subagent) - Error handling analysis
18
+ * - sn-type-design-analyzer (subagent) - TypeScript type design
19
+ * - sn-skill-reviewer (subagent) - OpenCode skill review
20
+ */
21
+ import type { Plugin } from "@opencode-ai/plugin";
22
+ /**
23
+ * The main Shokunin plugin export.
24
+ *
25
+ * Wraps BeadsPlugin and merges any additional Shokunin-specific hooks.
26
+ * This allows extending the plugin functionality while maintaining
27
+ * full compatibility with opencode-beads.
28
+ */
29
+ export declare const ShokuninPlugin: Plugin;
30
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAS,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAkDzD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,MA4E5B,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Shokunin Plugin
3
+ *
4
+ * Wraps and extends the opencode-beads plugin with additional
5
+ * Shokunin-specific functionality.
6
+ *
7
+ * Inherited from opencode-beads:
8
+ * - Context injection via `bd prime` on session start and after compaction
9
+ * - Commands parsed from beads command definitions
10
+ * - beads-task-agent for autonomous issue completion
11
+ *
12
+ * Shokunin agents (sn- prefix):
13
+ * - sn-code-reviewer (primary) - Comprehensive code review
14
+ * - sn-code-simplifier (subagent) - Code simplification
15
+ * - sn-comment-analyzer (subagent) - Comment quality analysis
16
+ * - sn-pr-test-analyzer (subagent) - Test coverage analysis
17
+ * - sn-silent-failure-hunter (subagent) - Error handling analysis
18
+ * - sn-type-design-analyzer (subagent) - TypeScript type design
19
+ * - sn-skill-reviewer (subagent) - OpenCode skill review
20
+ */
21
+ import { BeadsPlugin } from "opencode-beads";
22
+ // Shokunin agents
23
+ import { snCodeReviewerAgent } from "./agents/sn-code-reviewer.js";
24
+ import { snCodeSimplifierAgent } from "./agents/sn-code-simplifier.js";
25
+ import { snCommentAnalyzerAgent } from "./agents/sn-comment-analyzer.js";
26
+ import { snPrTestAnalyzerAgent } from "./agents/sn-pr-test-analyzer.js";
27
+ import { snSilentFailureHunterAgent } from "./agents/sn-silent-failure-hunter.js";
28
+ import { snSkillReviewerAgent } from "./agents/sn-skill-reviewer.js";
29
+ import { snTypeDesignAnalyzerAgent } from "./agents/sn-type-design-analyzer.js";
30
+ // Shokunin commands
31
+ import { snCheckConfigCommand } from "./commands/sn-check-config.js";
32
+ import { snConfigureCommand } from "./commands/sn-configure.js";
33
+ import { snReviewPrCommand } from "./commands/sn-review-pr.js";
34
+ import { snUpdateCommand } from "./commands/sn-update.js";
35
+ // Shokunin context
36
+ import { looksLikeCompaction, SHOKUNIN_RULES, } from "./context/shokunin-rules.js";
37
+ // Shokunin tools
38
+ import { shokuninTools } from "./tools/emergency-stop.js";
39
+ /**
40
+ * All Shokunin commands merged together.
41
+ */
42
+ const shokuninCommands = {
43
+ ...snCheckConfigCommand,
44
+ ...snConfigureCommand,
45
+ ...snReviewPrCommand,
46
+ ...snUpdateCommand,
47
+ };
48
+ /**
49
+ * All Shokunin agents merged together.
50
+ */
51
+ const shokuninAgents = {
52
+ ...snCodeReviewerAgent,
53
+ ...snCodeSimplifierAgent,
54
+ ...snCommentAnalyzerAgent,
55
+ ...snPrTestAnalyzerAgent,
56
+ ...snSilentFailureHunterAgent,
57
+ ...snTypeDesignAnalyzerAgent,
58
+ ...snSkillReviewerAgent,
59
+ };
60
+ /**
61
+ * The main Shokunin plugin export.
62
+ *
63
+ * Wraps BeadsPlugin and merges any additional Shokunin-specific hooks.
64
+ * This allows extending the plugin functionality while maintaining
65
+ * full compatibility with opencode-beads.
66
+ */
67
+ export const ShokuninPlugin = async (input) => {
68
+ const { client } = input;
69
+ // Get hooks from BeadsPlugin
70
+ const beadsHooks = await BeadsPlugin(input);
71
+ // Track sessions that have received shokunin-rules context
72
+ const injectedSessions = new Set();
73
+ // Shokunin-specific hooks
74
+ const shokuninHooks = {
75
+ config: async (config) => {
76
+ // Inject Shokunin agents
77
+ config.agent = {
78
+ ...config.agent,
79
+ ...shokuninAgents,
80
+ };
81
+ // Inject Shokunin commands
82
+ config.command = {
83
+ ...config.command,
84
+ ...shokuninCommands,
85
+ };
86
+ // Call beads config hook if it exists
87
+ if (beadsHooks.config) {
88
+ await beadsHooks.config(config);
89
+ }
90
+ },
91
+ // Register Shokunin tools
92
+ tool: shokuninTools,
93
+ // Inject shokunin-rules context on first message and after compaction
94
+ "chat.message": async (hookInput, output) => {
95
+ const sessionID = hookInput.sessionID;
96
+ // Get the first text part from the message
97
+ const textPart = output.parts.find((p) => p.type === "text");
98
+ const messageText = textPart?.type === "text" ? textPart.text : "";
99
+ // Check if this is a new session or post-compaction
100
+ const isNewSession = !injectedSessions.has(sessionID);
101
+ const isPostCompaction = looksLikeCompaction(messageText);
102
+ // Inject context if needed
103
+ if (isNewSession || isPostCompaction) {
104
+ try {
105
+ await client.session.prompt({
106
+ path: { id: sessionID },
107
+ body: {
108
+ noReply: true,
109
+ model: hookInput.model,
110
+ agent: hookInput.agent,
111
+ parts: [{ type: "text", text: SHOKUNIN_RULES, synthetic: true }],
112
+ },
113
+ });
114
+ injectedSessions.add(sessionID);
115
+ }
116
+ catch {
117
+ // Silent skip if injection fails
118
+ }
119
+ }
120
+ // Call beads chat.message hook if it exists
121
+ if (beadsHooks["chat.message"]) {
122
+ await beadsHooks["chat.message"](hookInput, output);
123
+ }
124
+ },
125
+ };
126
+ // Merge hooks - shokunin hooks override beads hooks when both exist
127
+ // This ensures our config hook runs and then calls beads' config hook
128
+ return {
129
+ ...beadsHooks,
130
+ ...shokuninHooks,
131
+ };
132
+ };
133
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Emergency Stop Tool
3
+ *
4
+ * Plays terminal bell to alert users when the LLM needs human input.
5
+ * Works through SSH and VS Code Remote by using the terminal bell character.
6
+ */
7
+ import type { Hooks } from "@opencode-ai/plugin";
8
+ /**
9
+ * Emergency stop tool for the Shokunin plugin.
10
+ *
11
+ * Plays terminal bell to alert users when human input is required.
12
+ * Returns the tool definition directly - TypeScript will infer the Hooks["tool"] type.
13
+ */
14
+ export declare const shokuninTools: Hooks["tool"];
15
+ //# sourceMappingURL=emergency-stop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emergency-stop.d.ts","sourceRoot":"","sources":["../../src/tools/emergency-stop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AA2DjD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,MAAM,CAkDvC,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Emergency Stop Tool
3
+ *
4
+ * Plays terminal bell to alert users when the LLM needs human input.
5
+ * Works through SSH and VS Code Remote by using the terminal bell character.
6
+ */
7
+ import { tool } from "@opencode-ai/plugin";
8
+ /**
9
+ * Number of bells to play based on urgency level.
10
+ */
11
+ const URGENCY_BELLS = {
12
+ low: 1,
13
+ medium: 3,
14
+ high: 5,
15
+ };
16
+ /**
17
+ * Plays the terminal bell character the specified number of times.
18
+ * The bell character (\x07) works through SSH and VS Code Remote.
19
+ */
20
+ function playBells(count) {
21
+ for (let i = 0; i < count; i++) {
22
+ process.stdout.write("\x07");
23
+ }
24
+ }
25
+ /**
26
+ * Formats the alert message for the LLM context window.
27
+ */
28
+ function formatAlertMessage(reason, urgency, context) {
29
+ const timestamp = new Date().toISOString();
30
+ const urgencyLabel = urgency.toUpperCase();
31
+ const bellCount = URGENCY_BELLS[urgency];
32
+ let message = `
33
+ ## EMERGENCY STOP ALERT
34
+
35
+ **Timestamp:** ${timestamp}
36
+ **Urgency:** ${urgencyLabel} (${bellCount} bell${bellCount > 1 ? "s" : ""})
37
+ **Reason:** ${reason}
38
+ `;
39
+ if (context) {
40
+ message += `
41
+ **Context:**
42
+ ${context}
43
+ `;
44
+ }
45
+ message += `
46
+ ---
47
+ *Alert sound played. Waiting for human input.*
48
+ `;
49
+ return message.trim();
50
+ }
51
+ /**
52
+ * Emergency stop tool for the Shokunin plugin.
53
+ *
54
+ * Plays terminal bell to alert users when human input is required.
55
+ * Returns the tool definition directly - TypeScript will infer the Hooks["tool"] type.
56
+ */
57
+ export const shokuninTools = {
58
+ emergency_stop: tool({
59
+ description: "Play an alert sound (terminal bell) to notify the user that their attention is required. " +
60
+ "Use when: (1) you encounter a critical decision that requires human judgment, " +
61
+ "(2) you find a potential security issue that needs review, " +
62
+ "(3) you're blocked and cannot proceed without clarification, " +
63
+ "(4) you've completed a significant milestone and need review, or " +
64
+ "(5) you encounter an error you cannot resolve autonomously.",
65
+ args: {
66
+ reason: tool.schema
67
+ .string()
68
+ .describe("The reason why human input is needed"),
69
+ urgency: tool.schema
70
+ .enum(["low", "medium", "high"])
71
+ .optional()
72
+ .default("medium")
73
+ .describe("Urgency level: low (1 bell), medium (3 bells), high (5 bells). Defaults to medium."),
74
+ context: tool.schema
75
+ .string()
76
+ .optional()
77
+ .describe("Additional context about the situation"),
78
+ repeat_interval_seconds: tool.schema
79
+ .number()
80
+ .optional()
81
+ .describe("If provided, repeat the alert at this interval until user responds (not implemented in initial version)"),
82
+ max_repeats: tool.schema
83
+ .number()
84
+ .optional()
85
+ .describe("Maximum number of times to repeat the alert (not implemented in initial version)"),
86
+ },
87
+ execute(args, _context) {
88
+ const urgency = (args.urgency ?? "medium");
89
+ const bellCount = URGENCY_BELLS[urgency];
90
+ // Play terminal bells
91
+ playBells(bellCount);
92
+ // Return formatted message for LLM context
93
+ return Promise.resolve(formatAlertMessage(args.reason, urgency, args.context));
94
+ },
95
+ }),
96
+ };
97
+ //# sourceMappingURL=emergency-stop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emergency-stop.js","sourceRoot":"","sources":["../../src/tools/emergency-stop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C;;GAEG;AACH,MAAM,aAAa,GAAG;IACpB,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;CACC,CAAC;AAIX;;;GAGG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CACzB,MAAc,EACd,OAAqB,EACrB,OAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,OAAO,GAAG;;;iBAGC,SAAS;eACX,YAAY,KAAK,SAAS,QAAQ,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;cAC3D,MAAM;CACnB,CAAC;IAEA,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,IAAI;;EAEb,OAAO;CACR,CAAC;IACA,CAAC;IAED,OAAO,IAAI;;;CAGZ,CAAC;IAEA,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,cAAc,EAAE,IAAI,CAAC;QACnB,WAAW,EACT,2FAA2F;YAC3F,gFAAgF;YAChF,6DAA6D;YAC7D,+DAA+D;YAC/D,mEAAmE;YACnE,6DAA6D;QAC/D,IAAI,EAAE;YACJ,MAAM,EAAE,IAAI,CAAC,MAAM;iBAChB,MAAM,EAAE;iBACR,QAAQ,CAAC,sCAAsC,CAAC;YACnD,OAAO,EAAE,IAAI,CAAC,MAAM;iBACjB,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;iBAC/B,QAAQ,EAAE;iBACV,OAAO,CAAC,QAAQ,CAAC;iBACjB,QAAQ,CACP,oFAAoF,CACrF;YACH,OAAO,EAAE,IAAI,CAAC,MAAM;iBACjB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,wCAAwC,CAAC;YACrD,uBAAuB,EAAE,IAAI,CAAC,MAAM;iBACjC,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,yGAAyG,CAC1G;YACH,WAAW,EAAE,IAAI,CAAC,MAAM;iBACrB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,kFAAkF,CACnF;SACJ;QACD,OAAO,CAAC,IAAI,EAAE,QAAQ;YACpB,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAiB,CAAC;YAC3D,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YAEzC,sBAAsB;YACtB,SAAS,CAAC,SAAS,CAAC,CAAC;YAErB,2CAA2C;YAC3C,OAAO,OAAO,CAAC,OAAO,CACpB,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CACvD,CAAC;QACJ,CAAC;KACF,CAAC;CACH,CAAC"}