@monoes/monomindcli 1.10.30 → 1.10.31

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 (48) hide show
  1. package/.claude/helpers/handlers/adr-draft-handler.cjs +64 -0
  2. package/.claude/helpers/handlers/agent-start-handler.cjs +99 -0
  3. package/.claude/helpers/handlers/graph-status-handler.cjs +38 -0
  4. package/.claude/helpers/handlers/session-restore-handler.cjs +45 -40
  5. package/.claude/helpers/hook-handler.cjs +6 -158
  6. package/dist/src/browser/actions.d.ts +15 -0
  7. package/dist/src/browser/actions.d.ts.map +1 -1
  8. package/dist/src/browser/actions.js +91 -0
  9. package/dist/src/browser/actions.js.map +1 -1
  10. package/dist/src/browser/batch.d.ts +13 -0
  11. package/dist/src/browser/batch.d.ts.map +1 -0
  12. package/dist/src/browser/batch.js +11 -0
  13. package/dist/src/browser/batch.js.map +1 -0
  14. package/dist/src/browser/console-log.d.ts +22 -0
  15. package/dist/src/browser/console-log.d.ts.map +1 -0
  16. package/dist/src/browser/console-log.js +55 -0
  17. package/dist/src/browser/console-log.js.map +1 -0
  18. package/dist/src/browser/dialog.d.ts +11 -0
  19. package/dist/src/browser/dialog.d.ts.map +1 -0
  20. package/dist/src/browser/dialog.js +36 -0
  21. package/dist/src/browser/dialog.js.map +1 -0
  22. package/dist/src/browser/emulation.d.ts +15 -0
  23. package/dist/src/browser/emulation.d.ts.map +1 -0
  24. package/dist/src/browser/emulation.js +62 -0
  25. package/dist/src/browser/emulation.js.map +1 -0
  26. package/dist/src/browser/find.d.ts +21 -0
  27. package/dist/src/browser/find.d.ts.map +1 -0
  28. package/dist/src/browser/find.js +118 -0
  29. package/dist/src/browser/find.js.map +1 -0
  30. package/dist/src/browser/index.d.ts +7 -0
  31. package/dist/src/browser/index.d.ts.map +1 -1
  32. package/dist/src/browser/index.js +7 -0
  33. package/dist/src/browser/index.js.map +1 -1
  34. package/dist/src/browser/pdf.d.ts +15 -0
  35. package/dist/src/browser/pdf.d.ts.map +1 -0
  36. package/dist/src/browser/pdf.js +27 -0
  37. package/dist/src/browser/pdf.js.map +1 -0
  38. package/dist/src/browser/storage.d.ts +11 -0
  39. package/dist/src/browser/storage.d.ts.map +1 -0
  40. package/dist/src/browser/storage.js +43 -0
  41. package/dist/src/browser/storage.js.map +1 -0
  42. package/dist/src/commands/browse.d.ts.map +1 -1
  43. package/dist/src/commands/browse.js +939 -18
  44. package/dist/src/commands/browse.js.map +1 -1
  45. package/dist/src/ui/dashboard-v2.html +182 -17
  46. package/dist/src/ui/server.mjs +56 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+ // Extracted from hook-handler.cjs — handles 'adr-draft' command.
3
+ // Drafts an ADR from accumulated decision markers in .monomind/decisions.jsonl.
4
+ // Receives hCtx from dispatcher. See route-handler.cjs for hCtx field docs.
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ module.exports = {
10
+ handle: function(hCtx) {
11
+ var CWD = hCtx.CWD;
12
+
13
+ var jsonl = path.join(CWD, '.monomind', 'decisions.jsonl');
14
+ if (!fs.existsSync(jsonl)) {
15
+ console.log('[ADR] No decisions recorded yet. Type prompts containing markers like "let\'s go with X", "we chose Y", "decision: Z" to populate the log.');
16
+ return;
17
+ }
18
+ var lines = fs.readFileSync(jsonl, 'utf-8').trim().split('\n').filter(Boolean);
19
+ if (lines.length === 0) {
20
+ console.log('[ADR] decisions.jsonl is empty.');
21
+ return;
22
+ }
23
+ // Group decisions captured in the last 7 days.
24
+ var cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000;
25
+ var recent = lines
26
+ .map(function(l) { try { return JSON.parse(l); } catch (_) { return null; } })
27
+ .filter(function(d) { return d && d.ts >= cutoff; });
28
+ if (recent.length === 0) {
29
+ console.log('[ADR] No decisions in the last 7 days. Older entries: ' + lines.length + '.');
30
+ return;
31
+ }
32
+
33
+ var adrsDir = path.join(CWD, 'docs', 'adrs');
34
+ try { fs.mkdirSync(adrsDir, { recursive: true }); } catch (_) {}
35
+ var existing = [];
36
+ try { existing = fs.readdirSync(adrsDir).filter(function(f) { return /^ADR-\d{4}/.test(f); }); } catch (_) {}
37
+ var nextNum = existing.length + 1;
38
+ var num = String(nextNum).padStart(4, '0');
39
+ var stamp = new Date().toISOString().slice(0, 10);
40
+ var fname = 'ADR-' + num + '-' + stamp + '-session-decisions.md';
41
+ var outPath = path.join(adrsDir, fname);
42
+
43
+ var body = '# ADR-' + num + ': Session decisions (' + stamp + ')\n\n' +
44
+ '**Status:** Proposed\n**Date:** ' + stamp + '\n\n' +
45
+ '## Context\n\n' +
46
+ 'During recent sessions, the following decision markers were captured ' +
47
+ 'from user prompts. Each excerpt is the surrounding sentence at the time.\n\n' +
48
+ '## Decisions\n\n';
49
+ for (var i = 0; i < recent.length; i++) {
50
+ var d = recent[i];
51
+ var date = new Date(d.ts).toISOString().slice(0, 16).replace('T', ' ');
52
+ body += '### ' + (i + 1) + '. ' + date + '\n\n';
53
+ for (var j = 0; j < d.excerpts.length; j++) {
54
+ body += '> ' + d.excerpts[j].trim() + '\n\n';
55
+ }
56
+ if (d.prompt) body += '_Prompt:_ ' + d.prompt.slice(0, 200) + (d.prompt.length > 200 ? '…' : '') + '\n\n';
57
+ }
58
+ body += '## Consequences\n\n_(fill in after review)_\n\n' +
59
+ '## Status\n\nProposed — awaiting human review and refinement.\n';
60
+ fs.writeFileSync(outPath, body);
61
+ console.log('[ADR_DRAFT] Wrote ' + recent.length + ' decision(s) to ' + outPath);
62
+ console.log(' Edit the file to fill in Context and Consequences, then change Status to Accepted/Rejected.');
63
+ },
64
+ };
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+ // Extracted from hook-handler.cjs — handles 'agent-start' (SubagentStart) hook event.
3
+ // Receives hCtx from dispatcher. See route-handler.cjs for hCtx field docs.
4
+
5
+ const path = require('path');
6
+ const fs = require('fs');
7
+
8
+ module.exports = {
9
+ handle: function(hCtx) {
10
+ var hookInput = hCtx.hookInput;
11
+ var CWD = hCtx.CWD;
12
+ var _openMonographDb = hCtx._openMonographDb;
13
+ var getMonographSuggestions = hCtx.getMonographSuggestions;
14
+
15
+ // Register this agent so the statusline can count active agents.
16
+ const regDir = path.join(CWD, '.monomind', 'agents', 'registrations');
17
+ try {
18
+ fs.mkdirSync(regDir, { recursive: true });
19
+ const id = Date.now() + '-' + Math.random().toString(36).slice(2, 6);
20
+ const regFile = path.join(regDir, 'agent-' + id + '.json');
21
+ fs.writeFileSync(regFile, JSON.stringify({
22
+ agentId: id,
23
+ startedAt: new Date().toISOString(),
24
+ pid: process.pid,
25
+ }));
26
+ // Refresh swarm-activity.json within the 5-min staleness window.
27
+ const activityDir = path.join(CWD, '.monomind', 'metrics');
28
+ fs.mkdirSync(activityDir, { recursive: true });
29
+ const activityPath = path.join(activityDir, 'swarm-activity.json');
30
+ const active = fs.readdirSync(regDir).filter(f => f.endsWith('.json')).length;
31
+ // Preserve lastActive (peak) so statusline shows non-zero after completion.
32
+ let prevLastActive = 0;
33
+ try { prevLastActive = (JSON.parse(fs.readFileSync(activityPath, 'utf-8'))?.swarm?.lastActive) || 0; } catch { /* ignore */ }
34
+ fs.writeFileSync(activityPath, JSON.stringify({
35
+ timestamp: new Date().toISOString(),
36
+ swarm: {
37
+ active: active > 0,
38
+ agent_count: active,
39
+ coordination_active: active > 0,
40
+ lastActive: Math.max(active, prevLastActive),
41
+ },
42
+ }));
43
+
44
+ // Write last-dispatch.json so the route handler can suppress redundant
45
+ // suggestions on the next turn when the same agent type is recommended.
46
+ const agentType = hookInput.subagent_type || hookInput.agentType || hookInput.agent_type || hookInput.agentSlug || 'unknown';
47
+ const agentDesc = hookInput.description || hookInput.prompt_description || '';
48
+ fs.writeFileSync(
49
+ path.join(CWD, '.monomind', 'last-dispatch.json'),
50
+ JSON.stringify({
51
+ agentType: agentType,
52
+ description: agentDesc.substring(0, 120),
53
+ dispatchedAt: new Date().toISOString(),
54
+ }),
55
+ 'utf-8'
56
+ );
57
+ } catch (e) { /* non-fatal — never block a subagent from starting */ }
58
+
59
+ // Subagent context inheritance — inject graph god nodes + parent's last
60
+ // pre-resolved suggestions so the spawned agent inherits spatial map.
61
+ try {
62
+ var subDb = _openMonographDb();
63
+ if (subDb) {
64
+ try {
65
+ var godRows = subDb.prepare(
66
+ "SELECT n.name, n.label, n.file_path AS file, " +
67
+ "(SELECT COUNT(*) FROM edges WHERE source_id=n.id OR target_id=n.id) AS deg " +
68
+ "FROM nodes n " +
69
+ "WHERE n.label NOT IN ('Concept') AND n.file_path IS NOT NULL AND n.file_path != '' " +
70
+ "ORDER BY deg DESC LIMIT 5"
71
+ ).all();
72
+ if (godRows.length > 0) {
73
+ console.log('[MONOGRAPH_SUBAGENT_CTX] Graph map inherited from parent:');
74
+ for (var gi = 0; gi < godRows.length; gi++) {
75
+ var gr = godRows[gi];
76
+ console.log(' · ' + gr.name + ' [' + gr.label + '] — ' + (gr.file || '') + ' (deg ' + gr.deg + ')');
77
+ }
78
+ try {
79
+ var subAgentDesc = hookInput.description || hookInput.prompt_description || '';
80
+ if (subAgentDesc && subAgentDesc.length > 8) {
81
+ var subHints = getMonographSuggestions(subAgentDesc, 3);
82
+ if (subHints.length > 0) {
83
+ console.log(' Top files for this subagent task:');
84
+ for (var si2 = 0; si2 < subHints.length; si2++) {
85
+ var sh = subHints[si2];
86
+ console.log(' · ' + sh.name + ' [' + sh.label + '] — ' + (sh.file || ''));
87
+ }
88
+ }
89
+ }
90
+ } catch (_) {}
91
+ console.log(' Use mcp__monomind__monograph_suggest / monograph_query in this subagent before grepping.');
92
+ }
93
+ } catch (e) { /* non-fatal */ }
94
+ }
95
+ } catch (e) { /* non-fatal */ }
96
+
97
+ console.log('[OK] Agent registered');
98
+ },
99
+ };
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+ // Extracted from hook-handler.cjs — handles 'graph-status' command.
3
+ // Shows monograph node/edge counts and graph-vs-grep usage ratio.
4
+ // Receives hCtx from dispatcher. See route-handler.cjs for hCtx field docs.
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ module.exports = {
10
+ handle: function(hCtx) {
11
+ var CWD = hCtx.CWD;
12
+ var _openMonographDb = hCtx._openMonographDb;
13
+
14
+ var db = _openMonographDb();
15
+ if (!db) {
16
+ console.log('No monograph.db found. Run /monomind:understand to build.');
17
+ return;
18
+ }
19
+ try {
20
+ var n = db.prepare("SELECT COUNT(*) AS c FROM nodes").get().c;
21
+ var e = db.prepare("SELECT COUNT(*) AS c FROM edges").get().c;
22
+ var usage = (function() {
23
+ try { return JSON.parse(fs.readFileSync(path.join(CWD, '.monomind', 'metrics', 'graph-usage.json'), 'utf-8')); }
24
+ catch (_) { return {}; }
25
+ })();
26
+ var wins = (usage.monograph_call || 0) + (usage.preresolve_hit || 0)
27
+ + (usage.graph_assist_search || 0) + (usage.graph_assist_neighbors || 0);
28
+ var search = (usage.grep_call || 0) + (usage.glob_call || 0)
29
+ + (usage.bash_grep_call || 0) + (usage.bash_find_call || 0);
30
+ var pct = (wins + search) > 0 ? Math.round((wins / (wins + search)) * 100) : 0;
31
+ var saved = usage.dollars_saved || 0;
32
+ console.log('Monograph: ' + n.toLocaleString() + ' nodes · ' + e.toLocaleString() + ' edges');
33
+ console.log('Usage: ' + pct + '% graph · ' + (100 - pct) + '% grep · ' +
34
+ 'wins=' + wins + ' search=' + search +
35
+ (saved > 0 ? ' · saved $' + saved.toFixed(2) : ''));
36
+ } catch (err) { console.log('Error: ' + err.message); }
37
+ },
38
+ };
@@ -31,50 +31,55 @@ module.exports = {
31
31
  } catch (e) { console.log('[WARN] Session restore failed: ' + e.message); }
32
32
 
33
33
  // Stale helper detection — warn when project helpers drift from the bundled npm copy.
34
+ // Skip when running inside the monomind dev repo itself: local helpers ARE the
35
+ // source of truth there, so any diff vs. the npm global install is expected.
34
36
  try {
35
- var crypto = require('crypto');
36
- function _findBundledHelpers() {
37
- var helperPaths = [
38
- path.join(helpersDir),
39
- path.join(CWD, 'node_modules', 'monomind', '.claude', 'helpers'),
40
- path.join(CWD, 'node_modules', '@monoes', 'monomindcli', '.claude', 'helpers'),
41
- ];
42
- try {
43
- var globalRoot = require('child_process')
44
- .execSync('npm root -g 2>/dev/null', { encoding: 'utf-8', timeout: 2000 })
45
- .trim();
46
- if (globalRoot) {
47
- helperPaths.push(path.join(globalRoot, 'monomind', '.claude', 'helpers'));
48
- helperPaths.push(path.join(globalRoot, '@monoes', 'monomindcli', '.claude', 'helpers'));
49
- }
50
- } catch (_) {}
51
- for (var i = 0; i < helperPaths.length; i++) {
52
- if (fs.existsSync(path.join(helperPaths[i], 'hook-handler.cjs')) &&
53
- helperPaths[i] !== path.join(CWD, '.claude', 'helpers')) {
54
- return helperPaths[i];
55
- }
56
- }
57
- return null;
58
- }
59
-
60
- var bundledDir = _findBundledHelpers();
61
- if (bundledDir) {
62
- var helpersToCheck = ['hook-handler.cjs', 'statusline.cjs'];
63
- var stale = [];
64
- for (var hi = 0; hi < helpersToCheck.length; hi++) {
65
- var hName = helpersToCheck[hi];
66
- var localF = path.join(CWD, '.claude', 'helpers', hName);
67
- var bundledF = path.join(bundledDir, hName);
68
- if (!fs.existsSync(localF) || !fs.existsSync(bundledF)) continue;
37
+ var _isDevRepo = fs.existsSync(path.join(CWD, 'packages', '@monomind', 'cli', 'package.json'));
38
+ if (!_isDevRepo) {
39
+ var crypto = require('crypto');
40
+ function _findBundledHelpers() {
41
+ var helperPaths = [
42
+ path.join(helpersDir),
43
+ path.join(CWD, 'node_modules', 'monomind', '.claude', 'helpers'),
44
+ path.join(CWD, 'node_modules', '@monoes', 'monomindcli', '.claude', 'helpers'),
45
+ ];
69
46
  try {
70
- var hashL = crypto.createHash('sha256').update(fs.readFileSync(localF)).digest('hex');
71
- var hashB = crypto.createHash('sha256').update(fs.readFileSync(bundledF)).digest('hex');
72
- if (hashL !== hashB) stale.push(hName);
47
+ var globalRoot = require('child_process')
48
+ .execSync('npm root -g 2>/dev/null', { encoding: 'utf-8', timeout: 2000 })
49
+ .trim();
50
+ if (globalRoot) {
51
+ helperPaths.push(path.join(globalRoot, 'monomind', '.claude', 'helpers'));
52
+ helperPaths.push(path.join(globalRoot, '@monoes', 'monomindcli', '.claude', 'helpers'));
53
+ }
73
54
  } catch (_) {}
55
+ for (var i = 0; i < helperPaths.length; i++) {
56
+ if (fs.existsSync(path.join(helperPaths[i], 'hook-handler.cjs')) &&
57
+ helperPaths[i] !== path.join(CWD, '.claude', 'helpers')) {
58
+ return helperPaths[i];
59
+ }
60
+ }
61
+ return null;
74
62
  }
75
- if (stale.length > 0) {
76
- console.log('[STALE_HELPERS] Project helpers differ from bundled version: ' + stale.join(', '));
77
- console.log(' Run `npx monomind@latest init upgrade` to refresh and pick up the latest features.');
63
+
64
+ var bundledDir = _findBundledHelpers();
65
+ if (bundledDir) {
66
+ var helpersToCheck = ['hook-handler.cjs', 'statusline.cjs'];
67
+ var stale = [];
68
+ for (var hi = 0; hi < helpersToCheck.length; hi++) {
69
+ var hName = helpersToCheck[hi];
70
+ var localF = path.join(CWD, '.claude', 'helpers', hName);
71
+ var bundledF = path.join(bundledDir, hName);
72
+ if (!fs.existsSync(localF) || !fs.existsSync(bundledF)) continue;
73
+ try {
74
+ var hashL = crypto.createHash('sha256').update(fs.readFileSync(localF)).digest('hex');
75
+ var hashB = crypto.createHash('sha256').update(fs.readFileSync(bundledF)).digest('hex');
76
+ if (hashL !== hashB) stale.push(hName);
77
+ } catch (_) {}
78
+ }
79
+ if (stale.length > 0) {
80
+ console.log('[STALE_HELPERS] Project helpers differ from bundled version: ' + stale.join(', '));
81
+ console.log(' Run `npx monomind@latest init upgrade` to refresh and pick up the latest features.');
82
+ }
78
83
  }
79
84
  }
80
85
  } catch (e) { /* non-fatal */ }
@@ -279,170 +279,18 @@ const handlers = {
279
279
  },
280
280
 
281
281
  'agent-start': () => {
282
- // Called by SubagentStart hook — register this agent so the statusline can count it
283
- const regDir = path.join(CWD, '.monomind', 'agents', 'registrations');
284
- try {
285
- fs.mkdirSync(regDir, { recursive: true });
286
- const id = Date.now() + '-' + Math.random().toString(36).slice(2, 6);
287
- const regFile = path.join(regDir, 'agent-' + id + '.json');
288
- fs.writeFileSync(regFile, JSON.stringify({
289
- agentId: id,
290
- startedAt: new Date().toISOString(),
291
- pid: process.pid,
292
- }));
293
- // Also refresh swarm-activity.json so it's within the 5-min staleness window
294
- const activityDir = path.join(CWD, '.monomind', 'metrics');
295
- fs.mkdirSync(activityDir, { recursive: true });
296
- const activityPath = path.join(activityDir, 'swarm-activity.json');
297
- const active = fs.readdirSync(regDir).filter(f => f.endsWith('.json')).length;
298
- // Preserve lastActive (peak) across agent lifecycle so statusline shows non-zero after completion
299
- let prevLastActive = 0;
300
- try { prevLastActive = (JSON.parse(fs.readFileSync(activityPath, 'utf-8'))?.swarm?.lastActive) || 0; } catch { /* ignore */ }
301
- fs.writeFileSync(activityPath, JSON.stringify({
302
- timestamp: new Date().toISOString(),
303
- swarm: {
304
- active: active > 0,
305
- agent_count: active,
306
- coordination_active: active > 0,
307
- lastActive: Math.max(active, prevLastActive),
308
- },
309
- }));
310
-
311
- // Write last-dispatch.json so the route handler can suppress redundant suggestions
312
- // on the next turn when the same type of agent is recommended.
313
- const agentType = hookInput.subagent_type || hookInput.agentType || hookInput.agent_type || hookInput.agentSlug || 'unknown';
314
- const agentDesc = hookInput.description || hookInput.prompt_description || '';
315
- fs.writeFileSync(
316
- path.join(CWD, '.monomind', 'last-dispatch.json'),
317
- JSON.stringify({
318
- agentType: agentType,
319
- description: agentDesc.substring(0, 120),
320
- dispatchedAt: new Date().toISOString(),
321
- }),
322
- 'utf-8'
323
- );
324
- } catch (e) { /* non-fatal — never block a subagent from starting */ }
325
-
326
- // Subagent context inheritance — inject graph god nodes + parent's last
327
- // pre-resolved suggestions so the spawned agent inherits spatial map
328
- // instead of starting blind.
329
- try {
330
- var subDb = _openMonographDb();
331
- if (subDb) {
332
- try {
333
- var godRows = subDb.prepare(
334
- "SELECT n.name, n.label, n.file_path AS file, " +
335
- "(SELECT COUNT(*) FROM edges WHERE source_id=n.id OR target_id=n.id) AS deg " +
336
- "FROM nodes n " +
337
- "WHERE n.label NOT IN ('Concept') AND n.file_path IS NOT NULL AND n.file_path != '' " +
338
- "ORDER BY deg DESC LIMIT 5"
339
- ).all();
340
- if (godRows.length > 0) {
341
- console.log('[MONOGRAPH_SUBAGENT_CTX] Graph map inherited from parent:');
342
- for (var gi = 0; gi < godRows.length; gi++) {
343
- var gr = godRows[gi];
344
- console.log(' · ' + gr.name + ' [' + gr.label + '] — ' + (gr.file || '') + ' (deg ' + gr.deg + ')');
345
- }
346
- // Also forward parent's last routing suggestion text if any
347
- try {
348
- var subAgentDesc = hookInput.description || hookInput.prompt_description || '';
349
- if (subAgentDesc && subAgentDesc.length > 8) {
350
- var subHints = getMonographSuggestions(subAgentDesc, 3);
351
- if (subHints.length > 0) {
352
- console.log(' Top files for this subagent task:');
353
- for (var si2 = 0; si2 < subHints.length; si2++) {
354
- var sh = subHints[si2];
355
- console.log(' · ' + sh.name + ' [' + sh.label + '] — ' + (sh.file || ''));
356
- }
357
- }
358
- }
359
- } catch (_) {}
360
- console.log(' Use mcp__monomind__monograph_suggest / monograph_query in this subagent before grepping.');
361
- }
362
- } catch (e) { /* non-fatal */ }
363
- }
364
- } catch (e) { /* non-fatal */ }
365
-
366
- console.log('[OK] Agent registered');
282
+ const h = require('./handlers/agent-start-handler.cjs');
283
+ h.handle(hCtx);
367
284
  },
368
285
 
369
- // Draft an ADR from accumulated decision markers in .monomind/decisions.jsonl.
370
- // Usage: node hook-handler.cjs adr-draft (or via /adr slash command)
371
286
  'adr-draft': () => {
372
- var jsonl = path.join(CWD, '.monomind', 'decisions.jsonl');
373
- if (!fs.existsSync(jsonl)) {
374
- console.log('[ADR] No decisions recorded yet. Type prompts containing markers like "let\'s go with X", "we chose Y", "decision: Z" to populate the log.');
375
- return;
376
- }
377
- var lines = fs.readFileSync(jsonl, 'utf-8').trim().split('\n').filter(Boolean);
378
- if (lines.length === 0) {
379
- console.log('[ADR] decisions.jsonl is empty.');
380
- return;
381
- }
382
- // Group decisions captured in the last 7 days
383
- var cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000;
384
- var recent = lines.map(function(l) { try { return JSON.parse(l); } catch (_) { return null; } })
385
- .filter(function(d) { return d && d.ts >= cutoff; });
386
- if (recent.length === 0) {
387
- console.log('[ADR] No decisions in the last 7 days. Older entries: ' + lines.length + '.');
388
- return;
389
- }
390
-
391
- var adrsDir = path.join(CWD, 'docs', 'adrs');
392
- try { fs.mkdirSync(adrsDir, { recursive: true }); } catch (_) {}
393
- // Pick next ADR number
394
- var existing = [];
395
- try { existing = fs.readdirSync(adrsDir).filter(function(f) { return /^ADR-\d{4}/.test(f); }); } catch (_) {}
396
- var nextNum = existing.length + 1;
397
- var num = String(nextNum).padStart(4, '0');
398
- var stamp = new Date().toISOString().slice(0,10);
399
- var slug = 'session-decisions';
400
- var fname = 'ADR-' + num + '-' + stamp + '-' + slug + '.md';
401
- var outPath = path.join(adrsDir, fname);
402
-
403
- var body = '# ADR-' + num + ': Session decisions (' + stamp + ')\n\n' +
404
- '**Status:** Proposed\n**Date:** ' + stamp + '\n\n' +
405
- '## Context\n\n' +
406
- 'During recent sessions, the following decision markers were captured ' +
407
- 'from user prompts. Each excerpt is the surrounding sentence at the time.\n\n' +
408
- '## Decisions\n\n';
409
- for (var i = 0; i < recent.length; i++) {
410
- var d = recent[i];
411
- var date = new Date(d.ts).toISOString().slice(0,16).replace('T',' ');
412
- body += '### ' + (i + 1) + '. ' + date + '\n\n';
413
- for (var j = 0; j < d.excerpts.length; j++) {
414
- body += '> ' + d.excerpts[j].trim() + '\n\n';
415
- }
416
- if (d.prompt) body += '_Prompt:_ ' + d.prompt.slice(0, 200) + (d.prompt.length > 200 ? '…' : '') + '\n\n';
417
- }
418
- body += '## Consequences\n\n_(fill in after review)_\n\n' +
419
- '## Status\n\nProposed — awaiting human review and refinement.\n';
420
- fs.writeFileSync(outPath, body);
421
- console.log('[ADR_DRAFT] Wrote ' + recent.length + ' decision(s) to ' + outPath);
422
- console.log(' Edit the file to fill in Context and Consequences, then change Status to Accepted/Rejected.');
287
+ const h = require('./handlers/adr-draft-handler.cjs');
288
+ h.handle(hCtx);
423
289
  },
424
290
 
425
291
  'graph-status': () => {
426
- var db = _openMonographDb();
427
- if (!db) { console.log('No monograph.db found. Run /monomind:understand to build.'); return; }
428
- try {
429
- var n = db.prepare("SELECT COUNT(*) AS c FROM nodes").get().c;
430
- var e = db.prepare("SELECT COUNT(*) AS c FROM edges").get().c;
431
- var usage = (function() {
432
- try { return JSON.parse(fs.readFileSync(path.join(CWD, '.monomind', 'metrics', 'graph-usage.json'), 'utf-8')); }
433
- catch (_) { return {}; }
434
- })();
435
- var wins = (usage.monograph_call || 0) + (usage.preresolve_hit || 0)
436
- + (usage.graph_assist_search || 0) + (usage.graph_assist_neighbors || 0);
437
- var search = (usage.grep_call || 0) + (usage.glob_call || 0)
438
- + (usage.bash_grep_call || 0) + (usage.bash_find_call || 0);
439
- var pct = (wins + search) > 0 ? Math.round((wins / (wins + search)) * 100) : 0;
440
- var saved = usage.dollars_saved || 0;
441
- console.log('Monograph: ' + n.toLocaleString() + ' nodes · ' + e.toLocaleString() + ' edges');
442
- console.log('Usage: ' + pct + '% graph · ' + (100 - pct) + '% grep · ' +
443
- 'wins=' + wins + ' search=' + search +
444
- (saved > 0 ? ' · saved $' + saved.toFixed(2) : ''));
445
- } catch (err) { console.log('Error: ' + err.message); }
292
+ const h = require('./handlers/graph-status-handler.cjs');
293
+ h.handle(hCtx);
446
294
  },
447
295
 
448
296
  'budget-status': () => {
@@ -9,5 +9,20 @@ export declare function scrollElement(client: CdpClient, sessionId: string, dire
9
9
  export declare function hoverElement(client: CdpClient, sessionId: string, ref: ElementRef): Promise<void>;
10
10
  export declare function selectOption(client: CdpClient, sessionId: string, ref: ElementRef, value: string): Promise<void>;
11
11
  export declare function checkElement(client: CdpClient, sessionId: string, ref: ElementRef, checked?: boolean): Promise<void>;
12
+ export declare function focusElement(client: CdpClient, sessionId: string, ref: ElementRef): Promise<void>;
13
+ export declare function typeIntoElement(client: CdpClient, sessionId: string, ref: ElementRef, text: string): Promise<void>;
14
+ export declare function keyDown(client: CdpClient, sessionId: string, key: string): Promise<void>;
15
+ export declare function keyUp(client: CdpClient, sessionId: string, key: string): Promise<void>;
16
+ export declare function mouseMove(client: CdpClient, sessionId: string, x: number, y: number): Promise<void>;
17
+ export declare function mouseDown(client: CdpClient, sessionId: string, x: number, y: number, button?: 'left' | 'right' | 'middle'): Promise<void>;
18
+ export declare function mouseUp(client: CdpClient, sessionId: string, x: number, y: number, button?: 'left' | 'right' | 'middle'): Promise<void>;
19
+ export declare function mouseWheel(client: CdpClient, sessionId: string, x: number, y: number, deltaY: number, deltaX?: number): Promise<void>;
20
+ export declare function dragAndDrop(client: CdpClient, sessionId: string, src: ElementRef, tgt: ElementRef): Promise<void>;
21
+ export declare function uploadFile(client: CdpClient, sessionId: string, ref: ElementRef, filePaths: string[]): Promise<void>;
22
+ export declare function readClipboard(client: CdpClient, sessionId: string): Promise<string>;
23
+ export declare function writeClipboard(client: CdpClient, sessionId: string, text: string): Promise<void>;
24
+ export declare function pushState(client: CdpClient, sessionId: string, url: string): Promise<void>;
25
+ export declare function addInitScript(client: CdpClient, sessionId: string, script: string): Promise<string>;
26
+ export declare function removeInitScript(client: CdpClient, sessionId: string, identifier: string): Promise<void>;
12
27
  export declare function evaluateJs(client: CdpClient, sessionId: string, expression: string): Promise<unknown>;
13
28
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/browser/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG3D,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhG;AAED,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAmBf;AA+BD,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC3C,MAAM,SAAM,EACZ,GAAG,CAAC,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,OAAO,UAAO,GACb,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAelB"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/browser/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG3D,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhG;AAED,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAmBf;AA+BD,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC3C,MAAM,SAAM,EACZ,GAAG,CAAC,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,OAAO,UAAO,GACb,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvG;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9F;AAED,wBAAsB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5F;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzG;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAM,GAAG,OAAO,GAAG,QAAiB,GAC3C,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,MAAM,GAAG,OAAO,GAAG,QAAiB,GAC3C,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,EAAE,MAAM,EACd,MAAM,SAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzF;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtG;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAahG;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKzG;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9G;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAelB"}
@@ -187,6 +187,97 @@ export async function checkElement(client, sessionId, ref, checked = true) {
187
187
  arguments: [{ value: checked }],
188
188
  }, sessionId);
189
189
  }
190
+ export async function focusElement(client, sessionId, ref) {
191
+ const objectId = await getObjectIdForRef(client, sessionId, ref);
192
+ if (objectId) {
193
+ await client.send('Runtime.callFunctionOn', {
194
+ functionDeclaration: 'function() { this.focus(); }',
195
+ objectId,
196
+ }, sessionId);
197
+ return;
198
+ }
199
+ const box = await getElementBox(client, sessionId, ref);
200
+ if (box)
201
+ await clickPoint(client, sessionId, box.x, box.y);
202
+ }
203
+ export async function typeIntoElement(client, sessionId, ref, text) {
204
+ await focusElement(client, sessionId, ref);
205
+ await typeText(client, sessionId, text);
206
+ }
207
+ export async function keyDown(client, sessionId, key) {
208
+ const keyInfo = resolveKey(key);
209
+ await client.send('Input.dispatchKeyEvent', { type: 'keyDown', ...keyInfo }, sessionId);
210
+ }
211
+ export async function keyUp(client, sessionId, key) {
212
+ const keyInfo = resolveKey(key);
213
+ await client.send('Input.dispatchKeyEvent', { type: 'keyUp', ...keyInfo }, sessionId);
214
+ }
215
+ export async function mouseMove(client, sessionId, x, y) {
216
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y }, sessionId);
217
+ }
218
+ export async function mouseDown(client, sessionId, x, y, button = 'left') {
219
+ await client.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button, buttons: 1, clickCount: 1 }, sessionId);
220
+ }
221
+ export async function mouseUp(client, sessionId, x, y, button = 'left') {
222
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button, buttons: 0, clickCount: 1 }, sessionId);
223
+ }
224
+ export async function mouseWheel(client, sessionId, x, y, deltaY, deltaX = 0) {
225
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseWheel', x, y, deltaX, deltaY }, sessionId);
226
+ }
227
+ export async function dragAndDrop(client, sessionId, src, tgt) {
228
+ const srcBox = await getElementBox(client, sessionId, src);
229
+ const tgtBox = await getElementBox(client, sessionId, tgt);
230
+ if (!srcBox || !tgtBox)
231
+ throw new Error('Cannot drag: one or both elements not found in DOM');
232
+ await client.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1, clickCount: 1 }, sessionId);
233
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: srcBox.x, y: srcBox.y, button: 'left', buttons: 1 }, sessionId);
234
+ // Move in steps for smooth drag
235
+ const steps = 10;
236
+ for (let i = 1; i <= steps; i++) {
237
+ const x = srcBox.x + (tgtBox.x - srcBox.x) * (i / steps);
238
+ const y = srcBox.y + (tgtBox.y - srcBox.y) * (i / steps);
239
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y, button: 'left', buttons: 1 }, sessionId);
240
+ }
241
+ await client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x: tgtBox.x, y: tgtBox.y, button: 'left', buttons: 0, clickCount: 1 }, sessionId);
242
+ }
243
+ export async function uploadFile(client, sessionId, ref, filePaths) {
244
+ if (!ref.backendDOMNodeId)
245
+ throw new Error(`Cannot upload: ref @${ref.ref} has no DOM node`);
246
+ await client.send('DOM.setFileInputFiles', {
247
+ files: filePaths,
248
+ backendNodeId: ref.backendDOMNodeId,
249
+ }, sessionId);
250
+ }
251
+ export async function readClipboard(client, sessionId) {
252
+ const result = await evaluateJs(client, sessionId, 'navigator.clipboard.readText()');
253
+ return result;
254
+ }
255
+ export async function writeClipboard(client, sessionId, text) {
256
+ await evaluateJs(client, sessionId, `navigator.clipboard.writeText(${JSON.stringify(text)})`);
257
+ }
258
+ export async function pushState(client, sessionId, url) {
259
+ // Try Next.js router first, then fallback to history.pushState
260
+ await evaluateJs(client, sessionId, `
261
+ (function() {
262
+ const url = ${JSON.stringify(url)};
263
+ if (window.next && window.next.router) {
264
+ window.next.router.push(url);
265
+ } else {
266
+ history.pushState({}, '', url);
267
+ window.dispatchEvent(new PopStateEvent('popstate'));
268
+ }
269
+ })()
270
+ `);
271
+ }
272
+ export async function addInitScript(client, sessionId, script) {
273
+ const result = await client.send('Page.addScriptToEvaluateOnNewDocument', {
274
+ source: script,
275
+ }, sessionId);
276
+ return result.identifier;
277
+ }
278
+ export async function removeInitScript(client, sessionId, identifier) {
279
+ await client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier }, sessionId);
280
+ }
190
281
  export async function evaluateJs(client, sessionId, expression) {
191
282
  const result = await client.send('Runtime.evaluate', {
192
283
  expression,