imprint-mcp 0.6.0 → 0.6.2

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 (43) hide show
  1. package/README.md +2 -0
  2. package/package.json +4 -2
  3. package/prompts/audit-agent.md +4 -2
  4. package/prompts/auth-compile-agent.md +149 -158
  5. package/prompts/build-planning.md +14 -9
  6. package/prompts/compile-agent.md +46 -23
  7. package/prompts/live-verifier-agent.md +101 -0
  8. package/prompts/playbook-compilation.md +8 -1
  9. package/prompts/tool-candidate-detection.md +9 -29
  10. package/src/cli.ts +83 -1
  11. package/src/imprint/audit.ts +219 -20
  12. package/src/imprint/auth-compile-agent.ts +215 -155
  13. package/src/imprint/auth-compile-tools.ts +300 -118
  14. package/src/imprint/auth-verifier.ts +167 -180
  15. package/src/imprint/backend-cache.ts +18 -11
  16. package/src/imprint/backend-ladder.ts +225 -177
  17. package/src/imprint/build-plan.ts +3 -8
  18. package/src/imprint/cdp-browser-fetch.ts +930 -83
  19. package/src/imprint/claude-cli-compile.ts +46 -20
  20. package/src/imprint/codex-cli-compile.ts +436 -139
  21. package/src/imprint/compile-agent-types.ts +15 -10
  22. package/src/imprint/compile-agent.ts +88 -28
  23. package/src/imprint/compile-tools.ts +228 -39
  24. package/src/imprint/compile-verification.ts +187 -0
  25. package/src/imprint/compile.ts +71 -2
  26. package/src/imprint/credential-store.ts +57 -44
  27. package/src/imprint/emit.ts +3 -1
  28. package/src/imprint/freeform-redact.ts +27 -6
  29. package/src/imprint/live-verifier.ts +1665 -0
  30. package/src/imprint/llm.ts +22 -3
  31. package/src/imprint/login.ts +107 -25
  32. package/src/imprint/mcp-compile-server.ts +447 -114
  33. package/src/imprint/mcp-live-verifier-server.ts +359 -0
  34. package/src/imprint/mcp-server.ts +116 -35
  35. package/src/imprint/probe-backends.ts +88 -7
  36. package/src/imprint/recording-request.ts +36 -0
  37. package/src/imprint/request-capture.ts +40 -17
  38. package/src/imprint/runtime.ts +490 -337
  39. package/src/imprint/teach-state.ts +36 -2
  40. package/src/imprint/teach.ts +302 -146
  41. package/src/imprint/tool-candidates.ts +8 -10
  42. package/src/imprint/tool-loader.ts +12 -4
  43. package/src/imprint/types.ts +137 -68
@@ -39,7 +39,7 @@ import type {
39
39
  import { formatCandidateContext, formatToolPlan } from './compile-agent-types.ts';
40
40
  import { preferredAgentModel } from './llm.ts';
41
41
  import { createLog } from './log.ts';
42
- import { COMPILE_SENTINELS } from './mcp-compile-server.ts';
42
+ import { COMPILE_SENTINELS, compileDeadlineAfterVerification } from './mcp-compile-server.ts';
43
43
  import type { SharedCompileContext, ToolCandidate } from './tool-candidates.ts';
44
44
  import {
45
45
  endTraceSpan,
@@ -60,6 +60,12 @@ const CLI_PATH = pathJoin(REPO_ROOT, 'src', 'cli.ts');
60
60
  const MCP_SERVER_NAME = 'imprint-compile';
61
61
  const MAX_VERIFICATION_CYCLES = 5;
62
62
 
63
+ function formatRevisionMode(enabled: boolean | undefined): string {
64
+ return enabled
65
+ ? 'REVISION MODE: inspect read_session_summary.revisionContext and the listed existing artifacts/diagnostics first. Preserve proven behavior; repair or honestly narrow only what evidence contradicts.'
66
+ : '';
67
+ }
68
+
63
69
  /**
64
70
  * Thinking effort for the compile agent. Deliberately `high`, not `max`:
65
71
  * empirically, max-effort thinking generates a large volume of reasoning tokens
@@ -110,6 +116,8 @@ interface CompileViaClaudeCliOptions {
110
116
  sharedModules?: SharedModuleManifestEntry[];
111
117
  /** Per-tool implementation plan injected into the agent's initial message. */
112
118
  toolPlan?: string;
119
+ /** Revise existing generated artifacts from durable verification feedback. */
120
+ revisionMode?: boolean;
113
121
  /** Present → drive an auth compile rather than a data compile. */
114
122
  authMode?: AuthCliCompileMode;
115
123
  /** Auth segments only: resume a prior segment's claude session with a new user
@@ -117,6 +125,8 @@ interface CompileViaClaudeCliOptions {
117
125
  * When set, `--resume <sessionId>` is used and `message` replaces the initial
118
126
  * prompt. Requires session persistence (auth mode keeps it on). */
119
127
  resume?: { sessionId: string; message: string };
128
+ /** Explicit model selected by the caller. Defaults to the provider preference. */
129
+ model?: string;
120
130
  }
121
131
 
122
132
  /** Options for the auth-compile entry point. A strict subset of the data
@@ -133,6 +143,7 @@ interface AuthCompileViaClaudeCliOptions {
133
143
  authMode: AuthCliCompileMode;
134
144
  /** Resume a prior segment (see CompileViaClaudeCliOptions.resume). */
135
145
  resume?: { sessionId: string; message: string };
146
+ model?: string;
136
147
  }
137
148
 
138
149
  /** Auth-compile entry point for claude-cli. Delegates to the same trace +
@@ -153,6 +164,7 @@ export function compileAuthViaClaudeCli(
153
164
  onDeadlineReached: opts.onDeadlineReached,
154
165
  authMode: opts.authMode,
155
166
  resume: opts.resume,
167
+ model: opts.model,
156
168
  });
157
169
  }
158
170
 
@@ -196,7 +208,7 @@ export async function compileViaClaudeCli(
196
208
  'imprint.site': opts.session.site,
197
209
  'imprint.tool_dir': opts.absoluteToolDir,
198
210
  'imprint.provider': 'claude-cli',
199
- 'imprint.model': preferredAgentModel('claude-cli'),
211
+ 'imprint.model': opts.model ?? preferredAgentModel('claude-cli'),
200
212
  },
201
213
  async (span) => {
202
214
  const result = await compileViaClaudeCliImpl(opts);
@@ -210,7 +222,7 @@ export async function compileViaClaudeCli(
210
222
  'imprint.compile.cache_creation_input_tokens': result.cacheCreationInputTokens,
211
223
  ...llmSpanAttributes({
212
224
  provider: 'claude-cli',
213
- model: preferredAgentModel('claude-cli'),
225
+ model: opts.model ?? preferredAgentModel('claude-cli'),
214
226
  // TOTAL prompt (uncached + cache); the cache split is passed separately
215
227
  // for cost. `result.inputTokens` alone is the uncached delta (often a
216
228
  // few hundred), which would mislabel `llm.token_count.prompt`.
@@ -271,6 +283,7 @@ async function runClaudeCliAttempt(opts: CompileViaClaudeCliOptions): Promise<Co
271
283
  COMPILE_SENTINELS.done,
272
284
  COMPILE_SENTINELS.giveUp,
273
285
  COMPILE_SENTINELS.checkpoint,
286
+ COMPILE_SENTINELS.verificationState,
274
287
  ]) {
275
288
  const p = pathJoin(opts.absoluteToolDir, name);
276
289
  if (existsSync(p)) {
@@ -321,10 +334,13 @@ async function runClaudeCliAttempt(opts: CompileViaClaudeCliOptions): Promise<Co
321
334
  sessionPathAbs,
322
335
  '--tool-dir',
323
336
  opts.absoluteToolDir,
337
+ '--provider',
338
+ 'claude-cli',
324
339
  ...(opts.candidate ? ['--candidate-json', JSON.stringify(opts.candidate)] : []),
325
340
  ...(opts.sharedContext ? ['--shared-context-json', JSON.stringify(opts.sharedContext)] : []),
326
341
  ...(opts.buildPlanPath ? ['--build-plan-path', opts.buildPlanPath] : []),
327
342
  ...(opts.sharedModules ? ['--shared-modules-json', JSON.stringify(opts.sharedModules)] : []),
343
+ ...(opts.revisionMode ? ['--revision-mode'] : []),
328
344
  ];
329
345
  allowedToolNames = [
330
346
  'read_session_summary',
@@ -351,6 +367,7 @@ Tool directory: ${opts.absoluteToolDir}
351
367
  You will write artifacts into the tool directory.
352
368
  ${formatCandidateContext(opts.candidate, opts.sharedContext, assignedSharedModules)}
353
369
  ${formatToolPlan(opts.toolPlan)}
370
+ ${formatRevisionMode(opts.revisionMode)}
354
371
 
355
372
  Begin by calling read_session_summary to orient yourself, then proceed per the system prompt.`;
356
373
  }
@@ -408,7 +425,7 @@ Begin by calling read_session_summary to orient yourself, then proceed per the s
408
425
  '--effort',
409
426
  COMPILE_EFFORT_LEVEL,
410
427
  '--model',
411
- preferredAgentModel('claude-cli'),
428
+ opts.model ?? preferredAgentModel('claude-cli'),
412
429
  promptArg,
413
430
  ];
414
431
 
@@ -421,19 +438,14 @@ Begin by calling read_session_summary to orient yourself, then proceed per the s
421
438
  child = spawn('claude', args, {
422
439
  cwd: REPO_ROOT,
423
440
  // Claude CLI's default MCP_TOOL_TIMEOUT is 60s. The compile MCP
424
- // server's `done` tool runs external verification inline — bun test
425
- // (up to 60s × 3 retries for the integration suite + 120s for the
426
- // parser suite) plus typechecking. On bot-protected sites where the
427
- // integration test escalates fetch → fetch-bootstrap → stealth-fetch
428
- // for every assertion, a single bun test pass can run 30s × 3
429
- // rungs × N tests = 10-15 min before the outer wrapper kills it,
430
- // and 3 retries push the total well past 30 min. A 10-min cap was
431
- // not enough — set 30 min so the worst-case verification can
432
- // actually complete and the agent receives the failure feedback
433
- // (and ships with `liveVerified: false` via the waiver path)
434
- // rather than getting `-32000: Connection closed` mid-call and
435
- // wasting the rest of its turn budget. Honor user-set env so an
436
- // operator on a fast network can tighten without editing source.
441
+ // server's `done` tool runs external verification inline: one live
442
+ // integration suite, parser tests, typechecking, and a fresh semantic
443
+ // verifier agent that may make a narrowly targeted follow-up call. On
444
+ // bot-protected sites one suite can still take 10-15 minutes as each
445
+ // assertion escalates fetch → fetch-bootstrap → stealth-fetch. Keep the
446
+ // 30-minute cap so the agent receives semantic feedback rather than an
447
+ // MCP connection-close midway through review. Honor user-set env so an
448
+ // operator on a fast network can tighten it without editing source.
437
449
  // Connection-startup timeout stays at 60s for cold Playwright boot.
438
450
  env: {
439
451
  ...process.env,
@@ -491,7 +503,7 @@ async function driveStreamJson(
491
503
  inputTokens,
492
504
  outputTokens,
493
505
  verificationCycle: 1,
494
- maxVerificationCycles: MAX_VERIFICATION_CYCLES,
506
+ maxVerificationCycles: opts.authMode ? undefined : MAX_VERIFICATION_CYCLES,
495
507
  });
496
508
  };
497
509
 
@@ -512,9 +524,19 @@ async function driveStreamJson(
512
524
  };
513
525
 
514
526
  const scheduleDeadlineCheck = (): ReturnType<typeof setTimeout> => {
515
- const remaining = Math.max(0, currentDeadlineMs - Date.now());
527
+ const effectiveDeadlineMs = compileDeadlineAfterVerification(
528
+ opts.absoluteToolDir,
529
+ currentDeadlineMs,
530
+ );
531
+ const remaining = Math.max(0, effectiveDeadlineMs - Date.now());
516
532
  return setTimeout(async () => {
517
533
  if (childExited) return;
534
+ // done() verification runs in the MCP child. Re-read its lifecycle clock
535
+ // before killing the compiler so only reasoning time counts here.
536
+ if (Date.now() < compileDeadlineAfterVerification(opts.absoluteToolDir, currentDeadlineMs)) {
537
+ deadlineTimer = scheduleDeadlineCheck();
538
+ return;
539
+ }
518
540
  if (opts.onDeadlineReached) {
519
541
  const extensionMs = await opts.onDeadlineReached();
520
542
  if (childExited) return;
@@ -744,7 +766,11 @@ async function driveStreamJson(
744
766
  }
745
767
 
746
768
  // Wall-clock deadline exceeded?
747
- if (Date.now() > currentDeadlineMs && !existsSync(doneSentinel) && !existsSync(giveUpSentinel)) {
769
+ if (
770
+ Date.now() > compileDeadlineAfterVerification(opts.absoluteToolDir, currentDeadlineMs) &&
771
+ !existsSync(doneSentinel) &&
772
+ !existsSync(giveUpSentinel)
773
+ ) {
748
774
  return {
749
775
  success: false,
750
776
  outcome: 'timeout',