@steipete/oracle 0.9.0 → 0.10.0

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 (177) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -48
  3. package/dist/bin/oracle-cli.js +455 -402
  4. package/dist/bin/oracle-mcp.js +2 -2
  5. package/dist/bin/oracle.js +165 -279
  6. package/dist/scripts/agent-send.js +31 -31
  7. package/dist/scripts/check.js +6 -6
  8. package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
  9. package/dist/scripts/docs-list.js +30 -30
  10. package/dist/scripts/git-policy.js +25 -23
  11. package/dist/scripts/run-cli.js +8 -8
  12. package/dist/scripts/runner.js +203 -195
  13. package/dist/scripts/test-browser.js +21 -18
  14. package/dist/scripts/test-remote-chrome.js +20 -20
  15. package/dist/src/bridge/connection.js +18 -18
  16. package/dist/src/bridge/userConfigFile.js +7 -7
  17. package/dist/src/browser/actions/assistantResponse.js +149 -101
  18. package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
  19. package/dist/src/browser/actions/attachments.js +246 -150
  20. package/dist/src/browser/actions/domEvents.js +2 -2
  21. package/dist/src/browser/actions/modelSelection.js +275 -117
  22. package/dist/src/browser/actions/navigation.js +161 -137
  23. package/dist/src/browser/actions/promptComposer.js +100 -64
  24. package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
  25. package/dist/src/browser/actions/thinkingTime.js +207 -110
  26. package/dist/src/browser/chromeLifecycle.js +62 -60
  27. package/dist/src/browser/config.js +34 -15
  28. package/dist/src/browser/constants.js +17 -12
  29. package/dist/src/browser/cookies.js +19 -19
  30. package/dist/src/browser/detect.js +62 -62
  31. package/dist/src/browser/domDebug.js +1 -1
  32. package/dist/src/browser/index.js +390 -295
  33. package/dist/src/browser/modelStrategy.js +1 -1
  34. package/dist/src/browser/pageActions.js +5 -5
  35. package/dist/src/browser/policies.js +16 -13
  36. package/dist/src/browser/profileState.js +44 -39
  37. package/dist/src/browser/prompt.js +72 -42
  38. package/dist/src/browser/promptSummary.js +5 -5
  39. package/dist/src/browser/providerDomFlow.js +1 -1
  40. package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
  41. package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
  42. package/dist/src/browser/providers/index.js +2 -2
  43. package/dist/src/browser/reattach.js +67 -34
  44. package/dist/src/browser/reattachHelpers.js +31 -26
  45. package/dist/src/browser/sessionRunner.js +37 -25
  46. package/dist/src/browser/utils.js +9 -9
  47. package/dist/src/browserMode.js +1 -1
  48. package/dist/src/cli/bridge/claudeConfig.js +16 -16
  49. package/dist/src/cli/bridge/client.js +28 -20
  50. package/dist/src/cli/bridge/codexConfig.js +16 -16
  51. package/dist/src/cli/bridge/doctor.js +47 -39
  52. package/dist/src/cli/bridge/host.js +58 -56
  53. package/dist/src/cli/browserConfig.js +62 -48
  54. package/dist/src/cli/browserDefaults.js +27 -26
  55. package/dist/src/cli/bundleWarnings.js +1 -1
  56. package/dist/src/cli/clipboard.js +11 -2
  57. package/dist/src/cli/detach.js +2 -2
  58. package/dist/src/cli/dryRun.js +29 -25
  59. package/dist/src/cli/duplicatePromptGuard.js +3 -3
  60. package/dist/src/cli/engine.js +9 -9
  61. package/dist/src/cli/errorUtils.js +1 -1
  62. package/dist/src/cli/fileSize.js +3 -3
  63. package/dist/src/cli/format.js +2 -2
  64. package/dist/src/cli/help.js +28 -28
  65. package/dist/src/cli/hiddenAliases.js +3 -3
  66. package/dist/src/cli/markdownBundle.js +7 -7
  67. package/dist/src/cli/markdownRenderer.js +15 -15
  68. package/dist/src/cli/notifier.js +77 -67
  69. package/dist/src/cli/options.js +127 -106
  70. package/dist/src/cli/oscUtils.js +1 -1
  71. package/dist/src/cli/promptRequirement.js +2 -2
  72. package/dist/src/cli/renderOutput.js +1 -1
  73. package/dist/src/cli/rootAlias.js +1 -1
  74. package/dist/src/cli/runOptions.js +32 -28
  75. package/dist/src/cli/sessionCommand.js +31 -21
  76. package/dist/src/cli/sessionDisplay.js +95 -81
  77. package/dist/src/cli/sessionLineage.js +6 -2
  78. package/dist/src/cli/sessionRunner.js +103 -93
  79. package/dist/src/cli/sessionTable.js +26 -23
  80. package/dist/src/cli/stdin.js +22 -0
  81. package/dist/src/cli/tagline.js +121 -124
  82. package/dist/src/cli/tui/index.js +139 -128
  83. package/dist/src/cli/writeOutputPath.js +5 -5
  84. package/dist/src/config.js +7 -7
  85. package/dist/src/gemini-web/browserSessionManager.js +19 -15
  86. package/dist/src/gemini-web/client.js +76 -70
  87. package/dist/src/gemini-web/executionMode.js +6 -8
  88. package/dist/src/gemini-web/executor.js +98 -93
  89. package/dist/src/gemini-web/index.js +1 -1
  90. package/dist/src/mcp/server.js +16 -12
  91. package/dist/src/mcp/tools/consult.js +51 -47
  92. package/dist/src/mcp/tools/sessionResources.js +12 -12
  93. package/dist/src/mcp/tools/sessions.js +26 -17
  94. package/dist/src/mcp/types.js +5 -5
  95. package/dist/src/mcp/utils.js +15 -7
  96. package/dist/src/oracle/background.js +15 -15
  97. package/dist/src/oracle/claude.js +53 -25
  98. package/dist/src/oracle/client.js +50 -41
  99. package/dist/src/oracle/config.js +96 -66
  100. package/dist/src/oracle/errors.js +38 -38
  101. package/dist/src/oracle/files.js +55 -46
  102. package/dist/src/oracle/finishLine.js +10 -8
  103. package/dist/src/oracle/format.js +3 -3
  104. package/dist/src/oracle/gemini.js +37 -33
  105. package/dist/src/oracle/logging.js +7 -7
  106. package/dist/src/oracle/markdown.js +28 -28
  107. package/dist/src/oracle/modelResolver.js +16 -16
  108. package/dist/src/oracle/multiModelRunner.js +12 -12
  109. package/dist/src/oracle/oscProgress.js +8 -8
  110. package/dist/src/oracle/promptAssembly.js +6 -3
  111. package/dist/src/oracle/request.js +16 -13
  112. package/dist/src/oracle/run.js +156 -134
  113. package/dist/src/oracle/runUtils.js +8 -5
  114. package/dist/src/oracle/tokenEstimate.js +6 -6
  115. package/dist/src/oracle/tokenStats.js +5 -5
  116. package/dist/src/oracle/tokenStringifier.js +5 -5
  117. package/dist/src/oracle.js +12 -12
  118. package/dist/src/oracleHome.js +3 -3
  119. package/dist/src/remote/client.js +25 -25
  120. package/dist/src/remote/health.js +20 -20
  121. package/dist/src/remote/remoteServiceConfig.js +9 -9
  122. package/dist/src/remote/server.js +129 -118
  123. package/dist/src/sessionManager.js +77 -75
  124. package/dist/src/sessionStore.js +3 -3
  125. package/dist/src/version.js +10 -10
  126. package/dist/vendor/oracle-notifier/README.md +2 -0
  127. package/package.json +66 -62
  128. package/vendor/oracle-notifier/README.md +2 -0
  129. package/dist/markdansi/types/index.js +0 -4
  130. package/dist/oracle/bin/oracle-cli.js +0 -472
  131. package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
  132. package/dist/oracle/src/browser/actions/attachments.js +0 -82
  133. package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
  134. package/dist/oracle/src/browser/actions/navigation.js +0 -75
  135. package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
  136. package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
  137. package/dist/oracle/src/browser/config.js +0 -33
  138. package/dist/oracle/src/browser/constants.js +0 -40
  139. package/dist/oracle/src/browser/cookies.js +0 -210
  140. package/dist/oracle/src/browser/domDebug.js +0 -36
  141. package/dist/oracle/src/browser/index.js +0 -331
  142. package/dist/oracle/src/browser/pageActions.js +0 -5
  143. package/dist/oracle/src/browser/prompt.js +0 -88
  144. package/dist/oracle/src/browser/promptSummary.js +0 -20
  145. package/dist/oracle/src/browser/sessionRunner.js +0 -80
  146. package/dist/oracle/src/browser/types.js +0 -1
  147. package/dist/oracle/src/browser/utils.js +0 -62
  148. package/dist/oracle/src/browserMode.js +0 -1
  149. package/dist/oracle/src/cli/browserConfig.js +0 -44
  150. package/dist/oracle/src/cli/dryRun.js +0 -59
  151. package/dist/oracle/src/cli/engine.js +0 -17
  152. package/dist/oracle/src/cli/errorUtils.js +0 -9
  153. package/dist/oracle/src/cli/help.js +0 -70
  154. package/dist/oracle/src/cli/markdownRenderer.js +0 -15
  155. package/dist/oracle/src/cli/options.js +0 -103
  156. package/dist/oracle/src/cli/promptRequirement.js +0 -14
  157. package/dist/oracle/src/cli/rootAlias.js +0 -30
  158. package/dist/oracle/src/cli/sessionCommand.js +0 -77
  159. package/dist/oracle/src/cli/sessionDisplay.js +0 -270
  160. package/dist/oracle/src/cli/sessionRunner.js +0 -94
  161. package/dist/oracle/src/heartbeat.js +0 -43
  162. package/dist/oracle/src/oracle/client.js +0 -48
  163. package/dist/oracle/src/oracle/config.js +0 -29
  164. package/dist/oracle/src/oracle/errors.js +0 -101
  165. package/dist/oracle/src/oracle/files.js +0 -220
  166. package/dist/oracle/src/oracle/format.js +0 -33
  167. package/dist/oracle/src/oracle/fsAdapter.js +0 -7
  168. package/dist/oracle/src/oracle/oscProgress.js +0 -60
  169. package/dist/oracle/src/oracle/request.js +0 -48
  170. package/dist/oracle/src/oracle/run.js +0 -444
  171. package/dist/oracle/src/oracle/tokenStats.js +0 -39
  172. package/dist/oracle/src/oracle/types.js +0 -1
  173. package/dist/oracle/src/oracle.js +0 -9
  174. package/dist/oracle/src/sessionManager.js +0 -205
  175. package/dist/oracle/src/version.js +0 -39
  176. package/dist/scripts/chrome/browser-tools.js +0 -295
  177. package/dist/src/browser/profileSync.js +0 -141
@@ -12,8 +12,8 @@
12
12
  * --escape Send ESC before typing (to interrupt/resume)
13
13
  * --wait-ms N Extra wait (ms) after typing before Enter
14
14
  */
15
- import { spawnSync } from 'node:child_process';
16
- import { sleepSync } from 'bun';
15
+ import { spawnSync } from "node:child_process";
16
+ import { sleepSync } from "bun";
17
17
  function usage(message) {
18
18
  if (message) {
19
19
  console.error(`Error: ${message}`);
@@ -29,44 +29,44 @@ Examples:
29
29
  }
30
30
  function parseArgs(argv) {
31
31
  let session;
32
- let entry = 'single';
32
+ let entry = "single";
33
33
  let shouldEscape = false;
34
34
  let waitMs = 400;
35
- const literalSeparator = argv.indexOf('--');
35
+ const literalSeparator = argv.indexOf("--");
36
36
  const optionPart = literalSeparator === -1 ? argv : argv.slice(0, literalSeparator);
37
37
  const literalPart = literalSeparator === -1 ? [] : argv.slice(literalSeparator + 1);
38
38
  for (let i = 0; i < optionPart.length; i += 1) {
39
39
  const token = optionPart[i];
40
- if (!token.startsWith('--')) {
40
+ if (!token.startsWith("--")) {
41
41
  usage(`Unexpected argument: ${token}`);
42
42
  }
43
43
  const key = token.slice(2);
44
44
  switch (key) {
45
- case 'session': {
45
+ case "session": {
46
46
  const value = optionPart[i + 1];
47
47
  if (!value)
48
- usage('--session requires a value');
48
+ usage("--session requires a value");
49
49
  session = value;
50
50
  i += 1;
51
51
  break;
52
52
  }
53
- case 'entry': {
53
+ case "entry": {
54
54
  const value = optionPart[i + 1];
55
- if (value !== 'single' && value !== 'double' && value !== 'none') {
55
+ if (value !== "single" && value !== "double" && value !== "none") {
56
56
  usage(`Unknown entry mode: ${value}`);
57
57
  }
58
58
  entry = value;
59
59
  i += 1;
60
60
  break;
61
61
  }
62
- case 'escape': {
62
+ case "escape": {
63
63
  shouldEscape = true;
64
64
  break;
65
65
  }
66
- case 'wait-ms': {
66
+ case "wait-ms": {
67
67
  const value = optionPart[i + 1];
68
68
  if (!value || Number.isNaN(Number.parseInt(value, 10))) {
69
- usage('--wait-ms requires an integer value');
69
+ usage("--wait-ms requires an integer value");
70
70
  }
71
71
  waitMs = Number.parseInt(value, 10);
72
72
  i += 1;
@@ -76,30 +76,30 @@ function parseArgs(argv) {
76
76
  usage(`Unknown option: --${key}`);
77
77
  }
78
78
  }
79
- const message = literalPart.join(' ').trim();
79
+ const message = literalPart.join(" ").trim();
80
80
  if (!session)
81
- usage('Missing --session');
81
+ usage("Missing --session");
82
82
  if (!message)
83
- usage('Missing message (provide text after -- separator)');
83
+ usage("Missing message (provide text after -- separator)");
84
84
  return { session, entry, escape: shouldEscape, waitMs, message };
85
85
  }
86
86
  function runTmux(args, allowFailure = false) {
87
- const result = spawnSync('tmux', args, { encoding: 'utf8' });
87
+ const result = spawnSync("tmux", args, { encoding: "utf8" });
88
88
  if (result.error) {
89
89
  if (allowFailure)
90
- return '';
90
+ return "";
91
91
  throw result.error;
92
92
  }
93
93
  if (result.status !== 0) {
94
94
  if (allowFailure)
95
- return result.stderr?.trim() ?? '';
96
- throw new Error(`tmux ${args.join(' ')} failed: ${result.stderr?.trim()}`);
95
+ return result.stderr?.trim() ?? "";
96
+ throw new Error(`tmux ${args.join(" ")} failed: ${result.stderr?.trim()}`);
97
97
  }
98
- return result.stdout?.trimEnd() ?? '';
98
+ return result.stdout?.trimEnd() ?? "";
99
99
  }
100
100
  function ensureSession(target) {
101
- const session = target.split(':')[0] ?? target;
102
- const result = spawnSync('tmux', ['has-session', '-t', session]);
101
+ const session = target.split(":")[0] ?? target;
102
+ const result = spawnSync("tmux", ["has-session", "-t", session]);
103
103
  if (result.status !== 0) {
104
104
  usage(`tmux session '${session}' not found. Start it first (e.g., tmux new-session -s ${session} ...)`);
105
105
  }
@@ -107,35 +107,35 @@ function ensureSession(target) {
107
107
  function sendMessage(options) {
108
108
  ensureSession(options.session);
109
109
  if (options.escape) {
110
- runTmux(['send-keys', '-t', options.session, 'Escape'], true);
110
+ runTmux(["send-keys", "-t", options.session, "Escape"], true);
111
111
  sleepSync(200);
112
112
  }
113
113
  // Clear existing prompt
114
- runTmux(['send-keys', '-t', options.session, 'Escape'], true);
114
+ runTmux(["send-keys", "-t", options.session, "Escape"], true);
115
115
  sleepSync(120);
116
- runTmux(['send-keys', '-t', options.session, 'C-u'], true);
116
+ runTmux(["send-keys", "-t", options.session, "C-u"], true);
117
117
  sleepSync(120);
118
118
  // Type the message
119
- runTmux(['send-keys', '-t', options.session, '-l', options.message], true);
119
+ runTmux(["send-keys", "-t", options.session, "-l", options.message], true);
120
120
  sleepSync(Math.max(120, options.waitMs));
121
121
  // Send Enter(s)
122
- const pressEnter = () => runTmux(['send-keys', '-t', options.session, 'C-m'], true);
122
+ const pressEnter = () => runTmux(["send-keys", "-t", options.session, "C-m"], true);
123
123
  switch (options.entry) {
124
- case 'single':
124
+ case "single":
125
125
  pressEnter();
126
126
  break;
127
- case 'double':
127
+ case "double":
128
128
  pressEnter();
129
129
  sleepSync(200);
130
130
  pressEnter();
131
131
  break;
132
- case 'none':
132
+ case "none":
133
133
  break;
134
134
  default:
135
135
  usage(`Unsupported entry mode: ${options.entry}`);
136
136
  }
137
137
  sleepSync(600);
138
- const tail = runTmux(['capture-pane', '-pt', options.session, '-S', '-6'], true);
138
+ const tail = runTmux(["capture-pane", "-pt", options.session, "-S", "-6"], true);
139
139
  console.log(tail);
140
140
  }
141
141
  try {
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env bun
2
- import process from 'node:process';
2
+ import process from "node:process";
3
3
  const buildConfig = {
4
- entrypoints: ['./bin/oracle-cli.js'],
5
- outdir: './.bun-check',
6
- target: 'bun',
4
+ entrypoints: ["./bin/oracle-cli.js"],
5
+ outdir: "./.bun-check",
6
+ target: "bun",
7
7
  minify: false,
8
8
  write: false,
9
9
  };
10
10
  const result = await Bun.build(buildConfig);
11
11
  if (!result.success) {
12
- console.error('Build failed while checking syntax:');
12
+ console.error("Build failed while checking syntax:");
13
13
  for (const log of result.logs) {
14
14
  console.error(log.message);
15
15
  if (log.position) {
@@ -18,4 +18,4 @@ if (!result.success) {
18
18
  }
19
19
  process.exit(1);
20
20
  }
21
- console.log('Syntax OK');
21
+ console.log("Syntax OK");
@@ -1,5 +1,5 @@
1
- import puppeteer from 'puppeteer-core';
2
- const port = parseInt(process.argv[2] || '52990', 10);
1
+ import puppeteer from "puppeteer-core";
2
+ const port = parseInt(process.argv[2] || "52990", 10);
3
3
  async function main() {
4
4
  const browser = await puppeteer.connect({
5
5
  browserURL: `http://127.0.0.1:${port}`,
@@ -9,24 +9,24 @@ async function main() {
9
9
  let targetPage = null;
10
10
  for (const page of pages) {
11
11
  const url = page.url();
12
- if (url.includes('chatgpt.com/c/')) {
12
+ if (url.includes("chatgpt.com/c/")) {
13
13
  targetPage = page;
14
14
  break;
15
15
  }
16
16
  }
17
17
  if (!targetPage) {
18
- console.error('ChatGPT conversation page not found');
18
+ console.error("ChatGPT conversation page not found");
19
19
  process.exit(1);
20
20
  }
21
- console.error('Found page:', await targetPage.url());
21
+ console.error("Found page:", await targetPage.url());
22
22
  // Extract the last assistant message
23
23
  const content = (await targetPage.evaluate(() => {
24
24
  // Try multiple selectors for ChatGPT's assistant messages
25
25
  const selectors = [
26
26
  '[data-message-author-role="assistant"] .markdown',
27
27
  '[data-message-author-role="assistant"]',
28
- '.agent-turn .markdown',
29
- '.agent-turn',
28
+ ".agent-turn .markdown",
29
+ ".agent-turn",
30
30
  ];
31
31
  for (const selector of selectors) {
32
32
  const elements = document.querySelectorAll(selector);
@@ -41,10 +41,10 @@ async function main() {
41
41
  }
42
42
  // Debug: show what's on the page
43
43
  const body = document.body.innerHTML;
44
- return { error: 'No messages found', bodyLength: body.length, sample: body.slice(0, 2000) };
44
+ return { error: "No messages found", bodyLength: body.length, sample: body.slice(0, 2000) };
45
45
  }));
46
- if ('error' in content) {
47
- console.error('Error:', JSON.stringify(content, null, 2));
46
+ if ("error" in content) {
47
+ console.error("Error:", JSON.stringify(content, null, 2));
48
48
  process.exit(1);
49
49
  }
50
50
  console.log(content.text);
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env tsx
2
- import { readdirSync, readFileSync } from 'node:fs';
3
- import { dirname, join, relative } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { compact } from 'es-toolkit';
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ import { dirname, join, relative } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { compact } from "es-toolkit";
6
6
  const docsListFile = fileURLToPath(import.meta.url);
7
7
  const docsListDir = dirname(docsListFile);
8
- const DOCS_DIR = join(docsListDir, '..', 'docs');
9
- const EXCLUDED_DIRS = new Set(['archive', 'research']);
8
+ const DOCS_DIR = join(docsListDir, "..", "docs");
9
+ const EXCLUDED_DIRS = new Set(["archive", "research"]);
10
10
  function walkMarkdownFiles(dir, base = dir) {
11
11
  const entries = readdirSync(dir, { withFileTypes: true });
12
12
  const files = [];
13
13
  for (const entry of entries) {
14
- if (entry.name.startsWith('.')) {
14
+ if (entry.name.startsWith(".")) {
15
15
  continue;
16
16
  }
17
17
  const fullPath = join(dir, entry.name);
@@ -21,37 +21,37 @@ function walkMarkdownFiles(dir, base = dir) {
21
21
  }
22
22
  files.push(...walkMarkdownFiles(fullPath, base));
23
23
  }
24
- else if (entry.isFile() && entry.name.endsWith('.md')) {
24
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
25
25
  files.push(relative(base, fullPath));
26
26
  }
27
27
  }
28
28
  return files.sort((a, b) => a.localeCompare(b));
29
29
  }
30
30
  function extractMetadata(fullPath) {
31
- const content = readFileSync(fullPath, 'utf8');
32
- if (!content.startsWith('---')) {
33
- return { summary: null, readWhen: [], error: 'missing front matter' };
31
+ const content = readFileSync(fullPath, "utf8");
32
+ if (!content.startsWith("---")) {
33
+ return { summary: null, readWhen: [], error: "missing front matter" };
34
34
  }
35
- const endIndex = content.indexOf('\n---', 3);
35
+ const endIndex = content.indexOf("\n---", 3);
36
36
  if (endIndex === -1) {
37
- return { summary: null, readWhen: [], error: 'unterminated front matter' };
37
+ return { summary: null, readWhen: [], error: "unterminated front matter" };
38
38
  }
39
39
  const frontMatter = content.slice(3, endIndex).trim();
40
- const lines = frontMatter.split('\n');
40
+ const lines = frontMatter.split("\n");
41
41
  let summaryLine = null;
42
42
  const readWhen = [];
43
43
  let collectingField = null;
44
44
  for (const rawLine of lines) {
45
45
  const line = rawLine.trim();
46
- if (line.startsWith('summary:')) {
46
+ if (line.startsWith("summary:")) {
47
47
  summaryLine = line;
48
48
  collectingField = null;
49
49
  continue;
50
50
  }
51
- if (line.startsWith('read_when:')) {
52
- collectingField = 'read_when';
53
- const inline = line.slice('read_when:'.length).trim();
54
- if (inline.startsWith('[') && inline.endsWith(']')) {
51
+ if (line.startsWith("read_when:")) {
52
+ collectingField = "read_when";
53
+ const inline = line.slice("read_when:".length).trim();
54
+ if (inline.startsWith("[") && inline.endsWith("]")) {
55
55
  try {
56
56
  const parsed = JSON.parse(inline.replace(/'/g, '"'));
57
57
  if (Array.isArray(parsed)) {
@@ -64,14 +64,14 @@ function extractMetadata(fullPath) {
64
64
  }
65
65
  continue;
66
66
  }
67
- if (collectingField === 'read_when') {
68
- if (line.startsWith('- ')) {
67
+ if (collectingField === "read_when") {
68
+ if (line.startsWith("- ")) {
69
69
  const hint = line.slice(2).trim();
70
70
  if (hint) {
71
71
  readWhen.push(hint);
72
72
  }
73
73
  }
74
- else if (line === '') {
74
+ else if (line === "") {
75
75
  }
76
76
  else {
77
77
  collectingField = null;
@@ -79,19 +79,19 @@ function extractMetadata(fullPath) {
79
79
  }
80
80
  }
81
81
  if (!summaryLine) {
82
- return { summary: null, readWhen, error: 'summary key missing' };
82
+ return { summary: null, readWhen, error: "summary key missing" };
83
83
  }
84
- const summaryValue = summaryLine.slice('summary:'.length).trim();
84
+ const summaryValue = summaryLine.slice("summary:".length).trim();
85
85
  const normalized = summaryValue
86
- .replace(/^['"]|['"]$/g, '')
87
- .replace(/\s+/g, ' ')
86
+ .replace(/^['"]|['"]$/g, "")
87
+ .replace(/\s+/g, " ")
88
88
  .trim();
89
89
  if (!normalized) {
90
- return { summary: null, readWhen, error: 'summary is empty' };
90
+ return { summary: null, readWhen, error: "summary is empty" };
91
91
  }
92
92
  return { summary: normalized, readWhen };
93
93
  }
94
- console.log('Listing all markdown files in docs folder:');
94
+ console.log("Listing all markdown files in docs folder:");
95
95
  const markdownFiles = walkMarkdownFiles(DOCS_DIR);
96
96
  for (const relativePath of markdownFiles) {
97
97
  const fullPath = join(DOCS_DIR, relativePath);
@@ -99,11 +99,11 @@ for (const relativePath of markdownFiles) {
99
99
  if (summary) {
100
100
  console.log(`${relativePath} - ${summary}`);
101
101
  if (readWhen.length > 0) {
102
- console.log(` Read when: ${readWhen.join('; ')}`);
102
+ console.log(` Read when: ${readWhen.join("; ")}`);
103
103
  }
104
104
  }
105
105
  else {
106
- const reason = error ? ` - [${error}]` : '';
106
+ const reason = error ? ` - [${error}]` : "";
107
107
  console.log(`${relativePath}${reason}`);
108
108
  }
109
109
  }
@@ -1,20 +1,20 @@
1
- import { resolve } from 'node:path';
2
- const COMMIT_HELPER_SUBCOMMANDS = new Set(['add', 'commit']);
3
- const GUARDED_SUBCOMMANDS = new Set(['push', 'pull', 'merge', 'rebase', 'cherry-pick']);
1
+ import { resolve } from "node:path";
2
+ const COMMIT_HELPER_SUBCOMMANDS = new Set(["add", "commit"]);
3
+ const GUARDED_SUBCOMMANDS = new Set(["push", "pull", "merge", "rebase", "cherry-pick"]);
4
4
  const DESTRUCTIVE_SUBCOMMANDS = new Set([
5
- 'reset',
6
- 'checkout',
7
- 'clean',
8
- 'restore',
9
- 'switch',
10
- 'stash',
11
- 'branch',
12
- 'filter-branch',
13
- 'fast-import',
5
+ "reset",
6
+ "checkout",
7
+ "clean",
8
+ "restore",
9
+ "switch",
10
+ "stash",
11
+ "branch",
12
+ "filter-branch",
13
+ "fast-import",
14
14
  ]);
15
15
  export function extractGitInvocation(commandArgs) {
16
16
  for (const [index, token] of commandArgs.entries()) {
17
- if (token === 'git' || token.endsWith('/git')) {
17
+ if (token === "git" || token.endsWith("/git")) {
18
18
  return { index, argv: commandArgs.slice(index) };
19
19
  }
20
20
  }
@@ -24,21 +24,21 @@ export function findGitSubcommand(commandArgs) {
24
24
  if (commandArgs.length <= 1) {
25
25
  return null;
26
26
  }
27
- const optionsWithValue = new Set(['-C', '--git-dir', '--work-tree', '-c']);
27
+ const optionsWithValue = new Set(["-C", "--git-dir", "--work-tree", "-c"]);
28
28
  let index = 1;
29
29
  while (index < commandArgs.length) {
30
30
  const token = commandArgs[index];
31
31
  if (token === undefined) {
32
32
  break;
33
33
  }
34
- if (token === '--') {
34
+ if (token === "--") {
35
35
  const next = commandArgs[index + 1];
36
36
  return next ? { name: next, index: index + 1 } : null;
37
37
  }
38
- if (!token.startsWith('-')) {
38
+ if (!token.startsWith("-")) {
39
39
  return { name: token, index };
40
40
  }
41
- if (token.includes('=')) {
41
+ if (token.includes("=")) {
42
42
  index += 1;
43
43
  continue;
44
44
  }
@@ -59,7 +59,7 @@ export function determineGitWorkdir(baseDir, gitArgs, command) {
59
59
  if (token === undefined) {
60
60
  break;
61
61
  }
62
- if (token === '-C') {
62
+ if (token === "-C") {
63
63
  const next = gitArgs[index + 1];
64
64
  if (next) {
65
65
  workDir = resolve(workDir, next);
@@ -67,7 +67,7 @@ export function determineGitWorkdir(baseDir, gitArgs, command) {
67
67
  index += 2;
68
68
  continue;
69
69
  }
70
- if (token.startsWith('-C')) {
70
+ if (token.startsWith("-C")) {
71
71
  const pathSegment = token.slice(2);
72
72
  if (pathSegment.length > 0) {
73
73
  workDir = resolve(workDir, pathSegment);
@@ -80,7 +80,9 @@ export function determineGitWorkdir(baseDir, gitArgs, command) {
80
80
  export function analyzeGitExecution(commandArgs, workspaceDir) {
81
81
  const invocation = extractGitInvocation(commandArgs);
82
82
  const command = invocation ? findGitSubcommand(invocation.argv) : null;
83
- const workDir = invocation ? determineGitWorkdir(workspaceDir, invocation.argv, command) : workspaceDir;
83
+ const workDir = invocation
84
+ ? determineGitWorkdir(workspaceDir, invocation.argv, command)
85
+ : workspaceDir;
84
86
  return {
85
87
  invocation,
86
88
  command,
@@ -108,9 +110,9 @@ export function isDestructiveGitSubcommand(command, gitArgv) {
108
110
  if (DESTRUCTIVE_SUBCOMMANDS.has(subcommand)) {
109
111
  return true;
110
112
  }
111
- if (subcommand === 'bisect') {
112
- const action = gitArgv[command.index + 1] ?? '';
113
- return action === 'reset';
113
+ if (subcommand === "bisect") {
114
+ const action = gitArgv[command.index + 1] ?? "";
115
+ return action === "reset";
114
116
  }
115
117
  return false;
116
118
  }
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from 'node:child_process';
3
- import path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
2
+ import { spawn } from "node:child_process";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
5
  const rawArgs = process.argv.slice(2);
6
- const args = rawArgs[0] === '--' ? rawArgs.slice(1) : rawArgs;
6
+ const args = rawArgs[0] === "--" ? rawArgs.slice(1) : rawArgs;
7
7
  const here = path.dirname(fileURLToPath(import.meta.url));
8
- const cliEntry = path.join(here, '../bin/oracle-cli.js');
9
- const child = spawn(process.execPath, ['--', cliEntry, ...args], {
10
- stdio: 'inherit',
8
+ const cliEntry = path.join(here, "../bin/oracle-cli.js");
9
+ const child = spawn(process.execPath, ["--", cliEntry, ...args], {
10
+ stdio: "inherit",
11
11
  });
12
- child.on('exit', (code) => {
12
+ child.on("exit", (code) => {
13
13
  process.exit(code ?? 0);
14
14
  });