imprint-mcp 0.6.1 → 0.6.3
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 +2 -0
- package/package.json +3 -2
- package/prompts/audit-agent.md +10 -7
- package/prompts/build-planning.md +2 -2
- package/prompts/compile-agent.md +49 -24
- package/prompts/live-verifier-agent.md +114 -0
- package/prompts/playbook-compilation.md +8 -1
- package/src/cli.ts +121 -4
- package/src/imprint/agent.ts +7 -2
- package/src/imprint/audit.ts +430 -39
- package/src/imprint/auth-compile-tools.ts +64 -13
- package/src/imprint/backend-cache.ts +18 -11
- package/src/imprint/backend-ladder.ts +48 -34
- package/src/imprint/cdp-browser-fetch.ts +135 -42
- package/src/imprint/claude-cli-compile.ts +38 -16
- package/src/imprint/codex-cli-compile.ts +120 -21
- package/src/imprint/compile-agent-types.ts +25 -2
- package/src/imprint/compile-agent.ts +238 -36
- package/src/imprint/compile-tools.ts +331 -58
- package/src/imprint/compile-verification.ts +187 -0
- package/src/imprint/compile.ts +71 -2
- package/src/imprint/freeform-redact.ts +27 -6
- package/src/imprint/live-verifier.ts +1826 -0
- package/src/imprint/llm.ts +20 -0
- package/src/imprint/mcp-compile-server.ts +488 -84
- package/src/imprint/mcp-live-verifier-server.ts +359 -0
- package/src/imprint/mcp-server.ts +28 -3
- package/src/imprint/probe-backends.ts +147 -31
- package/src/imprint/runtime.ts +61 -11
- package/src/imprint/teach-state.ts +70 -3
- package/src/imprint/teach.ts +171 -88
- package/src/imprint/types.ts +39 -2
package/src/cli.ts
CHANGED
|
@@ -25,7 +25,6 @@ function loadDotenv(): void {
|
|
|
25
25
|
if (!(key in process.env)) process.env[key] = value;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
|
|
29
28
|
loadDotenv();
|
|
30
29
|
|
|
31
30
|
/** Parse a duration string: "5m" → 300000, "1h" → 3600000, "30s" → 30000, "5000" → 5000.
|
|
@@ -113,7 +112,7 @@ export const VERB_HELP: Record<string, VerbHelp> = {
|
|
|
113
112
|
summary:
|
|
114
113
|
'Record a workflow, compile both artifacts, emit the tool, and connect to your AI platform — all in one interactive flow. Supports resuming incomplete runs and multiple workflows per site.',
|
|
115
114
|
usage: [
|
|
116
|
-
'imprint teach <site> [--url <url>] [--from-session <path>] [--persist-profile] [--no-interactive] [--all-tools] [--provider <name>] [--model <name>] [--timeout <duration>] [--keep-test] [--skip-replay] [--from-step <step>] [--to-step <step>] [--only <step>]',
|
|
115
|
+
'imprint teach <site> [--url <url>] [--from-session <path>] [--persist-profile] [--no-interactive] [--all-tools] [--tool <toolName>] [--provider <name>] [--model <name>] [--timeout <duration>] [--keep-test] [--skip-replay] [--from-step <step>] [--to-step <step>] [--only <step>]',
|
|
117
116
|
],
|
|
118
117
|
flags: [
|
|
119
118
|
{ name: '--url <url>', description: 'Starting URL (else about:blank).' },
|
|
@@ -132,6 +131,11 @@ export const VERB_HELP: Record<string, VerbHelp> = {
|
|
|
132
131
|
description:
|
|
133
132
|
'With --no-interactive, compile every detected candidate tool instead of only the primary.',
|
|
134
133
|
},
|
|
134
|
+
{
|
|
135
|
+
name: '--tool <toolName>',
|
|
136
|
+
description:
|
|
137
|
+
'With --from-step/--only, resume exactly one persisted tool from the retained recording.',
|
|
138
|
+
},
|
|
135
139
|
{
|
|
136
140
|
name: '--provider <name>',
|
|
137
141
|
description:
|
|
@@ -406,10 +410,14 @@ export const VERB_HELP: Record<string, VerbHelp> = {
|
|
|
406
410
|
},
|
|
407
411
|
'mcp-server': {
|
|
408
412
|
summary: "Serve one site's generated tools as MCP (stdio default).",
|
|
409
|
-
usage: ['imprint mcp-server <site> [--http] [--port <num>]'],
|
|
413
|
+
usage: ['imprint mcp-server <site> [--http] [--port <num>] [--include-tools <names>]'],
|
|
410
414
|
flags: [
|
|
411
415
|
{ name: '--http', description: 'Use Streamable HTTP transport instead of stdio.' },
|
|
412
416
|
{ name: '--port <num>', description: 'Port for HTTP transport (default 8765).' },
|
|
417
|
+
{
|
|
418
|
+
name: '--include-tools <names>',
|
|
419
|
+
description: 'Expose only these comma-separated generated tool names.',
|
|
420
|
+
},
|
|
413
421
|
],
|
|
414
422
|
example: 'imprint mcp-server southwest',
|
|
415
423
|
},
|
|
@@ -1118,6 +1126,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1118
1126
|
options: {
|
|
1119
1127
|
http: { type: 'boolean' },
|
|
1120
1128
|
port: { type: 'string' },
|
|
1129
|
+
'include-tools': { type: 'string' },
|
|
1121
1130
|
},
|
|
1122
1131
|
allowPositionals: false,
|
|
1123
1132
|
});
|
|
@@ -1126,6 +1135,10 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1126
1135
|
site,
|
|
1127
1136
|
http: values.http,
|
|
1128
1137
|
port: values.port ? Number(values.port) : undefined,
|
|
1138
|
+
includeToolNames: values['include-tools']
|
|
1139
|
+
?.split(',')
|
|
1140
|
+
.map((name) => name.trim())
|
|
1141
|
+
.filter(Boolean),
|
|
1129
1142
|
});
|
|
1130
1143
|
return 0;
|
|
1131
1144
|
}
|
|
@@ -1410,6 +1423,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1410
1423
|
'persist-profile': { type: 'boolean' },
|
|
1411
1424
|
'no-interactive': { type: 'boolean' },
|
|
1412
1425
|
'all-tools': { type: 'boolean' },
|
|
1426
|
+
tool: { type: 'string' },
|
|
1413
1427
|
provider: { type: 'string' },
|
|
1414
1428
|
model: { type: 'string' },
|
|
1415
1429
|
timeout: { type: 'string' },
|
|
@@ -1428,7 +1442,9 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1428
1442
|
// mutual exclusion with --from-session, and --to-step ≥ redact when
|
|
1429
1443
|
// --from-session enters the chain at redact), returning the resolved window
|
|
1430
1444
|
// or the exact error message to print. Extracted for unit-testing.
|
|
1431
|
-
const { resolveTeachPhaseWindow } = await import(
|
|
1445
|
+
const { resolveTeachPhaseWindow, validateToolScopedResumeStep } = await import(
|
|
1446
|
+
'./imprint/teach-state.ts'
|
|
1447
|
+
);
|
|
1432
1448
|
const phaseWindow = resolveTeachPhaseWindow(values);
|
|
1433
1449
|
if ('error' in phaseWindow) {
|
|
1434
1450
|
console.error(phaseWindow.error);
|
|
@@ -1437,6 +1453,22 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1437
1453
|
const fromStepArg = phaseWindow.fromStep;
|
|
1438
1454
|
const toStepArg = phaseWindow.toStep;
|
|
1439
1455
|
|
|
1456
|
+
if (values.tool && !fromStepArg) {
|
|
1457
|
+
console.error('error: --tool requires --from-step or --only');
|
|
1458
|
+
return 2;
|
|
1459
|
+
}
|
|
1460
|
+
if (values.tool) {
|
|
1461
|
+
const toolWindowError = validateToolScopedResumeStep(fromStepArg);
|
|
1462
|
+
if (toolWindowError) {
|
|
1463
|
+
console.error(toolWindowError);
|
|
1464
|
+
return 2;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
if (values.tool && values['all-tools']) {
|
|
1468
|
+
console.error('error: --tool cannot be combined with --all-tools');
|
|
1469
|
+
return 2;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1440
1472
|
if (!site && values['no-interactive']) {
|
|
1441
1473
|
console.error(
|
|
1442
1474
|
'error: `imprint teach` requires a <site> argument in --no-interactive mode.\n <site> is a label you choose — it names the output folder under ~/.imprint/.\n\n example: imprint teach google-flights --url https://flights.google.com\n→ run `imprint teach --help` for usage.',
|
|
@@ -1482,6 +1514,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1482
1514
|
'imprint.model': values.model ?? 'auto',
|
|
1483
1515
|
'imprint.timeout_ms': teachTimeoutMs ?? 'default',
|
|
1484
1516
|
'imprint.all_tools': values['all-tools'] ?? false,
|
|
1517
|
+
'imprint.tool': values.tool,
|
|
1485
1518
|
'imprint.no_interactive': values['no-interactive'] ?? false,
|
|
1486
1519
|
'imprint.skip_replay': values['skip-replay'] ?? false,
|
|
1487
1520
|
},
|
|
@@ -1498,6 +1531,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1498
1531
|
maxDurationMs: teachTimeoutMs,
|
|
1499
1532
|
keepTest: values['keep-test'] || process.env.IMPRINT_KEEP_TEST === '1',
|
|
1500
1533
|
allTools: values['all-tools'],
|
|
1534
|
+
tool: values.tool,
|
|
1501
1535
|
skipReplay: values['skip-replay'],
|
|
1502
1536
|
fromStep: fromStepArg,
|
|
1503
1537
|
toStep: toStepArg,
|
|
@@ -1533,6 +1567,8 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1533
1567
|
'build-plan-path': { type: 'string' },
|
|
1534
1568
|
'shared-modules-json': { type: 'string' },
|
|
1535
1569
|
'auth-plan-json': { type: 'string' },
|
|
1570
|
+
'revision-mode': { type: 'boolean' },
|
|
1571
|
+
provider: { type: 'string' },
|
|
1536
1572
|
site: { type: 'string' },
|
|
1537
1573
|
},
|
|
1538
1574
|
allowPositionals: false,
|
|
@@ -1571,11 +1607,92 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1571
1607
|
buildPlanPath: values['build-plan-path'],
|
|
1572
1608
|
sharedModules,
|
|
1573
1609
|
authToolPlan: authToolPlan ?? undefined,
|
|
1610
|
+
revisionMode: values['revision-mode'],
|
|
1611
|
+
provider: values.provider as
|
|
1612
|
+
| 'anthropic-api'
|
|
1613
|
+
| 'claude-cli'
|
|
1614
|
+
| 'codex-cli'
|
|
1615
|
+
| 'cursor-cli'
|
|
1616
|
+
| undefined,
|
|
1574
1617
|
site: values.site,
|
|
1575
1618
|
});
|
|
1576
1619
|
return 0;
|
|
1577
1620
|
}
|
|
1578
1621
|
|
|
1622
|
+
// Hidden semantic-verifier MCP server. It exposes backend preparation,
|
|
1623
|
+
// verifier-owned suite/targeted calls, and structured report submission.
|
|
1624
|
+
case '__mcp-live-verifier-server': {
|
|
1625
|
+
const { values } = parseArgs({
|
|
1626
|
+
args: argv.slice(1),
|
|
1627
|
+
options: {
|
|
1628
|
+
'workflow-path': { type: 'string' },
|
|
1629
|
+
'report-path': { type: 'string' },
|
|
1630
|
+
'log-path': { type: 'string' },
|
|
1631
|
+
attempt: { type: 'string' },
|
|
1632
|
+
'session-label': { type: 'string' },
|
|
1633
|
+
},
|
|
1634
|
+
allowPositionals: false,
|
|
1635
|
+
});
|
|
1636
|
+
if (!values['workflow-path'] || !values['report-path'] || !values['session-label']) {
|
|
1637
|
+
console.error(
|
|
1638
|
+
'error: __mcp-live-verifier-server requires --workflow-path <path>, --report-path <path>, and --session-label <label>',
|
|
1639
|
+
);
|
|
1640
|
+
return 2;
|
|
1641
|
+
}
|
|
1642
|
+
const { runLiveVerifierMcpServer } = await import('./imprint/mcp-live-verifier-server.ts');
|
|
1643
|
+
await runLiveVerifierMcpServer({
|
|
1644
|
+
workflowPath: values['workflow-path'],
|
|
1645
|
+
reportPath: values['report-path'],
|
|
1646
|
+
sessionLabel: values['session-label'],
|
|
1647
|
+
logPath: values['log-path'],
|
|
1648
|
+
attempt: values.attempt ? Number.parseInt(values.attempt, 10) : undefined,
|
|
1649
|
+
});
|
|
1650
|
+
return 0;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
// Hidden one-shot worker for compile-time live verification. The MCP
|
|
1654
|
+
// verifier owns this worker as a detached process group, so a wedged
|
|
1655
|
+
// browser-backed probe can be terminated without killing the verifier that
|
|
1656
|
+
// must still write an inconclusive/changes-required report.
|
|
1657
|
+
case '__probe-live-verification-backends': {
|
|
1658
|
+
const { values } = parseArgs({
|
|
1659
|
+
args: argv.slice(1),
|
|
1660
|
+
options: {
|
|
1661
|
+
'workflow-path': { type: 'string' },
|
|
1662
|
+
'out-path': { type: 'string' },
|
|
1663
|
+
},
|
|
1664
|
+
allowPositionals: false,
|
|
1665
|
+
});
|
|
1666
|
+
if (!values['workflow-path'] || !values['out-path']) {
|
|
1667
|
+
console.error(
|
|
1668
|
+
'error: __probe-live-verification-backends requires --workflow-path <path> and --out-path <path>',
|
|
1669
|
+
);
|
|
1670
|
+
return 2;
|
|
1671
|
+
}
|
|
1672
|
+
const rawParams = await Bun.stdin.text();
|
|
1673
|
+
const params = rawParams.trim()
|
|
1674
|
+
? (JSON.parse(rawParams) as Record<string, string | number | boolean>)
|
|
1675
|
+
: {};
|
|
1676
|
+
const { resolveWorkflowTool } = await import('./imprint/backend-ladder.ts');
|
|
1677
|
+
const { probeResolvedTool } = await import('./imprint/probe-backends.ts');
|
|
1678
|
+
const workflowPath = values['workflow-path'];
|
|
1679
|
+
const tool = resolveWorkflowTool(workflowPath);
|
|
1680
|
+
const assetRoot = resolve(dirname(workflowPath), '..', '..');
|
|
1681
|
+
const result = await probeResolvedTool(
|
|
1682
|
+
{ site: tool.site, paramOverrides: params },
|
|
1683
|
+
assetRoot,
|
|
1684
|
+
tool,
|
|
1685
|
+
values['out-path'],
|
|
1686
|
+
);
|
|
1687
|
+
console.log(
|
|
1688
|
+
JSON.stringify({
|
|
1689
|
+
outPath: result.outPath,
|
|
1690
|
+
preferredBackend: result.cache.preferredOrder[0],
|
|
1691
|
+
}),
|
|
1692
|
+
);
|
|
1693
|
+
return 0;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1579
1696
|
case 'update': {
|
|
1580
1697
|
const { checkForUpdate, performUpdate } = await import('./imprint/update.ts');
|
|
1581
1698
|
const checkOnly = argv.slice(1).includes('--check');
|
package/src/imprint/agent.ts
CHANGED
|
@@ -49,6 +49,10 @@ export type OnDeadlineReached = () => Promise<number | null>;
|
|
|
49
49
|
export interface AgentResult {
|
|
50
50
|
outcome: 'done' | 'give_up' | 'timeout' | 'soft_cap' | 'error';
|
|
51
51
|
doneSummary?: string;
|
|
52
|
+
/** Raw arguments supplied to the reserved done tool. Callers with a richer
|
|
53
|
+
* done contract can make a post-verification decision without teaching the
|
|
54
|
+
* generic agent loop about that contract. */
|
|
55
|
+
doneInput?: Record<string, unknown>;
|
|
52
56
|
giveUpReason?: string;
|
|
53
57
|
giveUpDetail?: string;
|
|
54
58
|
errorMessage?: string;
|
|
@@ -294,12 +298,13 @@ export async function runAgentLoop(opts: AgentLoopOptions): Promise<AgentResult>
|
|
|
294
298
|
// Check for done() or give_up() first
|
|
295
299
|
for (const block of toolUseBlocks) {
|
|
296
300
|
if (block.name === 'done') {
|
|
297
|
-
const input = block.input as
|
|
301
|
+
const input = block.input as Record<string, unknown>;
|
|
298
302
|
return {
|
|
299
303
|
action: 'return',
|
|
300
304
|
result: {
|
|
301
305
|
outcome: 'done',
|
|
302
|
-
doneSummary: input.summary
|
|
306
|
+
doneSummary: typeof input.summary === 'string' ? input.summary : 'Task completed',
|
|
307
|
+
doneInput: input,
|
|
303
308
|
turns: turn,
|
|
304
309
|
durationMs: Date.now() - startTime,
|
|
305
310
|
inputTokens,
|