@steipete/oracle 1.0.2 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,6 +32,9 @@ npx -y @steipete/oracle --engine browser -p "Summarize the risk register" --file
32
32
  # Globs/exclusions
33
33
  npx -y @steipete/oracle -p "Review the TS data layer" --file "src/**/*.ts" --file "!src/**/*.test.ts"
34
34
 
35
+ # Mixed glob + single file
36
+ npx -y @steipete/oracle -p "Audit data layer" --file "src/**/*.ts" --file README.md
37
+
35
38
  # Inspect past sessions
36
39
  oracle status --clear --hours 168 # prune a week of cached runs
37
40
  oracle status # list runs; grab an ID
@@ -82,4 +85,5 @@ pnpm test:coverage
82
85
  ---
83
86
 
84
87
  If you’re looking for an even more powerful context-management tool, check out https://repoprompt.com
88
+
85
89
  Name inspired by: https://ampcode.com/news/oracle
@@ -39,7 +39,10 @@ program.hook('preAction', (thisCommand) => {
39
39
  thisCommand.setOptionValue('prompt', positional);
40
40
  }
41
41
  if (shouldRequirePrompt(rawCliArgs, opts)) {
42
- throw new Error('Prompt is required. Provide it via --prompt "<text>".');
42
+ console.log(chalk.yellow('Prompt is required. Provide it via --prompt "<text>" or positional [prompt].'));
43
+ thisCommand.help({ error: false });
44
+ process.exitCode = 1;
45
+ return;
43
46
  }
44
47
  });
45
48
  program
@@ -47,7 +47,7 @@ function renderHelpFooter(program, colors) {
47
47
  `${colors.bullet('•')} The model has no built-in knowledge of your project—open with the architecture, key components, and why you’re asking.`,
48
48
  `${colors.bullet('•')} Run ${colors.accent('--files-report')} to inspect token spend before hitting the API.`,
49
49
  `${colors.bullet('•')} Non-preview runs spawn detached sessions so they keep streaming even if your terminal closes — reattach anytime via ${colors.accent('pnpm oracle session <slug>')}.`,
50
- `${colors.bullet('•')} Ask the model for a memorable 3–5 word slug and pass it via ${colors.accent('--slug "<words>"')} to keep session IDs tidy.`,
50
+ `${colors.bullet('•')} Set a memorable 3–5 word slug via ${colors.accent('--slug "<words>"')} to keep session IDs tidy.`,
51
51
  `${colors.bullet('•')} Need hidden flags? Run ${colors.accent(`${program.name()} --help --verbose`)} to list search/token/browser overrides.`,
52
52
  ].join('\n');
53
53
  const formatExample = (command, description) => `${colors.command(` ${command}`)}\n${colors.muted(` ${description}`)}`;
@@ -51,7 +51,6 @@ export async function attachSession(sessionId, options) {
51
51
  }
52
52
  const initialStatus = metadata.status;
53
53
  if (!options?.suppressMetadata) {
54
- console.log(chalk.bold(`Session: ${sessionId}`));
55
54
  const reattachLine = buildReattachLine(metadata);
56
55
  if (reattachLine) {
57
56
  console.log(chalk.blue(reattachLine));
@@ -26,6 +26,15 @@ const defaultWait = (ms) => new Promise((resolve) => {
26
26
  });
27
27
  export async function runOracle(options, deps = {}) {
28
28
  const { apiKey = options.apiKey ?? process.env.OPENAI_API_KEY, cwd = process.cwd(), fs: fsModule = createFsAdapter(fs), log = console.log, write = (text) => process.stdout.write(text), now = () => performance.now(), clientFactory = createDefaultClientFactory(), client, wait = defaultWait, } = deps;
29
+ const maskApiKey = (key) => {
30
+ if (!key)
31
+ return null;
32
+ if (key.length <= 8)
33
+ return `${key[0] ?? ''}***${key[key.length - 1] ?? ''}`;
34
+ const prefix = key.slice(0, 4);
35
+ const suffix = key.slice(-4);
36
+ return `${prefix}****${suffix}`;
37
+ };
29
38
  const logVerbose = (message) => {
30
39
  if (options.verbose) {
31
40
  log(dim(`[verbose] ${message}`));
@@ -38,6 +47,10 @@ export async function runOracle(options, deps = {}) {
38
47
  env: 'OPENAI_API_KEY',
39
48
  });
40
49
  }
50
+ const maskedKey = maskApiKey(apiKey);
51
+ if (maskedKey) {
52
+ log(dim(`Using OPENAI_API_KEY=${maskedKey}`));
53
+ }
41
54
  const modelConfig = MODEL_CONFIGS[options.model];
42
55
  if (!modelConfig) {
43
56
  throw new PromptValidationError(`Unsupported model "${options.model}". Choose one of: ${Object.keys(MODEL_CONFIGS).join(', ')}`, { model: options.model });
@@ -57,6 +70,9 @@ export async function runOracle(options, deps = {}) {
57
70
  }
58
71
  else {
59
72
  logVerbose('No files attached.');
73
+ if (!isPreview) {
74
+ log(dim('Tip: no files attached — Oracle works best with project context. Add files via --file path/to/code or docs.'));
75
+ }
60
76
  }
61
77
  const fileTokenInfo = getFileTokenStats(files, {
62
78
  cwd,
@@ -76,7 +92,11 @@ export async function runOracle(options, deps = {}) {
76
92
  logVerbose(`Estimated tokens (prompt + files): ${estimatedInputTokens.toLocaleString()}`);
77
93
  const fileCount = files.length;
78
94
  const cliVersion = getCliVersion();
79
- const headerLine = `Oracle (${cliVersion}) consulting ${modelConfig.model}'s crystal ball with ${estimatedInputTokens.toLocaleString()} tokens and ${fileCount} files...`;
95
+ const richTty = process.stdout.isTTY && chalk.level > 0;
96
+ const headerModelLabel = richTty ? chalk.cyan(modelConfig.model) : modelConfig.model;
97
+ const tokenLabel = richTty ? chalk.green(estimatedInputTokens.toLocaleString()) : estimatedInputTokens.toLocaleString();
98
+ const fileLabel = richTty ? chalk.magenta(fileCount.toString()) : fileCount.toString();
99
+ const headerLine = `Oracle (${cliVersion}) consulting ${headerModelLabel}'s crystal ball with ${tokenLabel} tokens and ${fileLabel} files...`;
80
100
  const shouldReportFiles = (options.filesReport || fileTokenInfo.totalTokens > inputTokenBudget) && fileTokenInfo.stats.length > 0;
81
101
  if (!isPreview) {
82
102
  log(headerLine);
@@ -129,6 +149,7 @@ export async function runOracle(options, deps = {}) {
129
149
  let answerHeaderPrinted = false;
130
150
  const ensureAnswerHeader = () => {
131
151
  if (!options.silent && !answerHeaderPrinted) {
152
+ log('');
132
153
  log(chalk.bold('Answer:'));
133
154
  answerHeaderPrinted = true;
134
155
  }
@@ -309,7 +330,7 @@ async function executeBackgroundResponse(params) {
309
330
  isActive: () => heartbeatActive,
310
331
  makeMessage: (elapsedMs) => {
311
332
  const elapsedText = formatElapsed(elapsedMs);
312
- return `OpenAI background run still in progress — ${elapsedText} elapsed (id=${responseId}).`;
333
+ return `OpenAI background run still in progress — ${elapsedText} elapsed.`;
313
334
  },
314
335
  });
315
336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steipete/oracle",
3
- "version": "1.0.2",
3
+ "version": "1.0.6",
4
4
  "description": "CLI wrapper around OpenAI Responses API with GPT-5 Pro and GPT-5.1 high reasoning modes.",
5
5
  "type": "module",
6
6
  "main": "dist/bin/oracle-cli.js",