fixo-cli 1.0.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.
- package/LICENSE +201 -0
- package/README.md +530 -0
- package/dist/agent/agent-client.d.ts +108 -0
- package/dist/agent/agent-client.d.ts.map +1 -0
- package/dist/agent/agent-client.js +1247 -0
- package/dist/agent/agent-client.js.map +1 -0
- package/dist/agent/agent-pool.d.ts +20 -0
- package/dist/agent/agent-pool.d.ts.map +1 -0
- package/dist/agent/agent-pool.js +217 -0
- package/dist/agent/agent-pool.js.map +1 -0
- package/dist/agent/background-awareness.d.ts +55 -0
- package/dist/agent/background-awareness.d.ts.map +1 -0
- package/dist/agent/background-awareness.js +104 -0
- package/dist/agent/background-awareness.js.map +1 -0
- package/dist/agent/command-parser.d.ts +33 -0
- package/dist/agent/command-parser.d.ts.map +1 -0
- package/dist/agent/command-parser.js +120 -0
- package/dist/agent/command-parser.js.map +1 -0
- package/dist/agent/context-budget.d.ts +91 -0
- package/dist/agent/context-budget.d.ts.map +1 -0
- package/dist/agent/context-budget.js +219 -0
- package/dist/agent/context-budget.js.map +1 -0
- package/dist/agent/conversation.d.ts +190 -0
- package/dist/agent/conversation.d.ts.map +1 -0
- package/dist/agent/conversation.js +547 -0
- package/dist/agent/conversation.js.map +1 -0
- package/dist/agent/hooks.d.ts +72 -0
- package/dist/agent/hooks.d.ts.map +1 -0
- package/dist/agent/hooks.js +214 -0
- package/dist/agent/hooks.js.map +1 -0
- package/dist/agent/mcp-bridge.d.ts +13 -0
- package/dist/agent/mcp-bridge.d.ts.map +1 -0
- package/dist/agent/mcp-bridge.js +86 -0
- package/dist/agent/mcp-bridge.js.map +1 -0
- package/dist/agent/mcp-client.d.ts +24 -0
- package/dist/agent/mcp-client.d.ts.map +1 -0
- package/dist/agent/mcp-client.js +146 -0
- package/dist/agent/mcp-client.js.map +1 -0
- package/dist/agent/mcp-manager.d.ts +13 -0
- package/dist/agent/mcp-manager.d.ts.map +1 -0
- package/dist/agent/mcp-manager.js +84 -0
- package/dist/agent/mcp-manager.js.map +1 -0
- package/dist/agent/mcp-registry.d.ts +45 -0
- package/dist/agent/mcp-registry.d.ts.map +1 -0
- package/dist/agent/mcp-registry.js +98 -0
- package/dist/agent/mcp-registry.js.map +1 -0
- package/dist/agent/orchestrator.d.ts +14 -0
- package/dist/agent/orchestrator.d.ts.map +1 -0
- package/dist/agent/orchestrator.js +118 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/parser-adapter.d.ts +120 -0
- package/dist/agent/parser-adapter.d.ts.map +1 -0
- package/dist/agent/parser-adapter.js +265 -0
- package/dist/agent/parser-adapter.js.map +1 -0
- package/dist/agent/parsers/imports.d.ts +11 -0
- package/dist/agent/parsers/imports.d.ts.map +1 -0
- package/dist/agent/parsers/imports.js +94 -0
- package/dist/agent/parsers/imports.js.map +1 -0
- package/dist/agent/parsers/shell.d.ts +23 -0
- package/dist/agent/parsers/shell.d.ts.map +1 -0
- package/dist/agent/parsers/shell.js +200 -0
- package/dist/agent/parsers/shell.js.map +1 -0
- package/dist/agent/parsers/symbols.d.ts +17 -0
- package/dist/agent/parsers/symbols.d.ts.map +1 -0
- package/dist/agent/parsers/symbols.js +103 -0
- package/dist/agent/parsers/symbols.js.map +1 -0
- package/dist/agent/permissions.d.ts +65 -0
- package/dist/agent/permissions.d.ts.map +1 -0
- package/dist/agent/permissions.js +219 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/agent/predictive-gate.d.ts +69 -0
- package/dist/agent/predictive-gate.d.ts.map +1 -0
- package/dist/agent/predictive-gate.js +128 -0
- package/dist/agent/predictive-gate.js.map +1 -0
- package/dist/agent/provider-cooldown.d.ts +144 -0
- package/dist/agent/provider-cooldown.d.ts.map +1 -0
- package/dist/agent/provider-cooldown.js +300 -0
- package/dist/agent/provider-cooldown.js.map +1 -0
- package/dist/agent/providers-manager.d.ts +109 -0
- package/dist/agent/providers-manager.d.ts.map +1 -0
- package/dist/agent/providers-manager.js +464 -0
- package/dist/agent/providers-manager.js.map +1 -0
- package/dist/agent/repo-map.d.ts +6 -0
- package/dist/agent/repo-map.d.ts.map +1 -0
- package/dist/agent/repo-map.js +221 -0
- package/dist/agent/repo-map.js.map +1 -0
- package/dist/agent/retry.d.ts +103 -0
- package/dist/agent/retry.d.ts.map +1 -0
- package/dist/agent/retry.js +276 -0
- package/dist/agent/retry.js.map +1 -0
- package/dist/agent/search/index.d.ts +61 -0
- package/dist/agent/search/index.d.ts.map +1 -0
- package/dist/agent/search/index.js +314 -0
- package/dist/agent/search/index.js.map +1 -0
- package/dist/agent/single-agent.d.ts +76 -0
- package/dist/agent/single-agent.d.ts.map +1 -0
- package/dist/agent/single-agent.js +697 -0
- package/dist/agent/single-agent.js.map +1 -0
- package/dist/agent/skills.d.ts +22 -0
- package/dist/agent/skills.d.ts.map +1 -0
- package/dist/agent/skills.js +139 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/stream-glue.d.ts +85 -0
- package/dist/agent/stream-glue.d.ts.map +1 -0
- package/dist/agent/stream-glue.js +120 -0
- package/dist/agent/stream-glue.js.map +1 -0
- package/dist/agent/subagent.d.ts +72 -0
- package/dist/agent/subagent.d.ts.map +1 -0
- package/dist/agent/subagent.js +193 -0
- package/dist/agent/subagent.js.map +1 -0
- package/dist/agent/telemetry.d.ts +192 -0
- package/dist/agent/telemetry.d.ts.map +1 -0
- package/dist/agent/telemetry.js +400 -0
- package/dist/agent/telemetry.js.map +1 -0
- package/dist/agent/tokenizer.d.ts +42 -0
- package/dist/agent/tokenizer.d.ts.map +1 -0
- package/dist/agent/tokenizer.js +107 -0
- package/dist/agent/tokenizer.js.map +1 -0
- package/dist/agent/tool-executor.d.ts +289 -0
- package/dist/agent/tool-executor.d.ts.map +1 -0
- package/dist/agent/tool-executor.js +2519 -0
- package/dist/agent/tool-executor.js.map +1 -0
- package/dist/agent/web-impl.d.ts +2 -0
- package/dist/agent/web-impl.d.ts.map +1 -0
- package/dist/agent/web-impl.js +34 -0
- package/dist/agent/web-impl.js.map +1 -0
- package/dist/agent/web.d.ts +8 -0
- package/dist/agent/web.d.ts.map +1 -0
- package/dist/agent/web.js +8 -0
- package/dist/agent/web.js.map +1 -0
- package/dist/agent/worker-agent.d.ts +27 -0
- package/dist/agent/worker-agent.d.ts.map +1 -0
- package/dist/agent/worker-agent.js +503 -0
- package/dist/agent/worker-agent.js.map +1 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +138 -0
- package/dist/config.js.map +1 -0
- package/dist/context/fixo-md-watcher.d.ts +42 -0
- package/dist/context/fixo-md-watcher.d.ts.map +1 -0
- package/dist/context/fixo-md-watcher.js +126 -0
- package/dist/context/fixo-md-watcher.js.map +1 -0
- package/dist/context/fixo-md.d.ts +50 -0
- package/dist/context/fixo-md.d.ts.map +1 -0
- package/dist/context/fixo-md.js +118 -0
- package/dist/context/fixo-md.js.map +1 -0
- package/dist/context/todo.d.ts +65 -0
- package/dist/context/todo.d.ts.map +1 -0
- package/dist/context/todo.js +194 -0
- package/dist/context/todo.js.map +1 -0
- package/dist/git/git-manager.d.ts +33 -0
- package/dist/git/git-manager.d.ts.map +1 -0
- package/dist/git/git-manager.js +293 -0
- package/dist/git/git-manager.js.map +1 -0
- package/dist/git/git-ops.d.ts +10 -0
- package/dist/git/git-ops.d.ts.map +1 -0
- package/dist/git/git-ops.js +131 -0
- package/dist/git/git-ops.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +352 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer.d.ts +30 -0
- package/dist/indexer.d.ts.map +1 -0
- package/dist/indexer.js +273 -0
- package/dist/indexer.js.map +1 -0
- package/dist/lsp/lsp-client.d.ts +24 -0
- package/dist/lsp/lsp-client.d.ts.map +1 -0
- package/dist/lsp/lsp-client.js +205 -0
- package/dist/lsp/lsp-client.js.map +1 -0
- package/dist/lsp/lsp-manager.d.ts +17 -0
- package/dist/lsp/lsp-manager.d.ts.map +1 -0
- package/dist/lsp/lsp-manager.js +154 -0
- package/dist/lsp/lsp-manager.js.map +1 -0
- package/dist/lsp/lsp-pre-save.d.ts +137 -0
- package/dist/lsp/lsp-pre-save.d.ts.map +1 -0
- package/dist/lsp/lsp-pre-save.js +245 -0
- package/dist/lsp/lsp-pre-save.js.map +1 -0
- package/dist/lsp/syntax-fallback.d.ts +83 -0
- package/dist/lsp/syntax-fallback.d.ts.map +1 -0
- package/dist/lsp/syntax-fallback.js +275 -0
- package/dist/lsp/syntax-fallback.js.map +1 -0
- package/dist/model-outcomes.d.ts +12 -0
- package/dist/model-outcomes.d.ts.map +1 -0
- package/dist/model-outcomes.js +46 -0
- package/dist/model-outcomes.js.map +1 -0
- package/dist/planner.d.ts +32 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +163 -0
- package/dist/planner.js.map +1 -0
- package/dist/project-memory.d.ts +29 -0
- package/dist/project-memory.d.ts.map +1 -0
- package/dist/project-memory.js +349 -0
- package/dist/project-memory.js.map +1 -0
- package/dist/review.d.ts +2 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +61 -0
- package/dist/review.js.map +1 -0
- package/dist/runtime/background-jobs.d.ts +97 -0
- package/dist/runtime/background-jobs.d.ts.map +1 -0
- package/dist/runtime/background-jobs.js +331 -0
- package/dist/runtime/background-jobs.js.map +1 -0
- package/dist/runtime/credential-vault.d.ts +124 -0
- package/dist/runtime/credential-vault.d.ts.map +1 -0
- package/dist/runtime/credential-vault.js +184 -0
- package/dist/runtime/credential-vault.js.map +1 -0
- package/dist/runtime/loop-trap.d.ts +197 -0
- package/dist/runtime/loop-trap.d.ts.map +1 -0
- package/dist/runtime/loop-trap.js +420 -0
- package/dist/runtime/loop-trap.js.map +1 -0
- package/dist/runtime/policy.d.ts +15 -0
- package/dist/runtime/policy.d.ts.map +1 -0
- package/dist/runtime/policy.js +60 -0
- package/dist/runtime/policy.js.map +1 -0
- package/dist/runtime/redaction.d.ts +66 -0
- package/dist/runtime/redaction.d.ts.map +1 -0
- package/dist/runtime/redaction.js +155 -0
- package/dist/runtime/redaction.js.map +1 -0
- package/dist/runtime/session-snapshots.d.ts +76 -0
- package/dist/runtime/session-snapshots.d.ts.map +1 -0
- package/dist/runtime/session-snapshots.js +166 -0
- package/dist/runtime/session-snapshots.js.map +1 -0
- package/dist/runtime/staging.d.ts +205 -0
- package/dist/runtime/staging.d.ts.map +1 -0
- package/dist/runtime/staging.js +526 -0
- package/dist/runtime/staging.js.map +1 -0
- package/dist/runtime/task-session.d.ts +95 -0
- package/dist/runtime/task-session.d.ts.map +1 -0
- package/dist/runtime/task-session.js +263 -0
- package/dist/runtime/task-session.js.map +1 -0
- package/dist/runtime/worktree.d.ts +55 -0
- package/dist/runtime/worktree.d.ts.map +1 -0
- package/dist/runtime/worktree.js +175 -0
- package/dist/runtime/worktree.js.map +1 -0
- package/dist/setup-wizard.d.ts +8 -0
- package/dist/setup-wizard.d.ts.map +1 -0
- package/dist/setup-wizard.js +73 -0
- package/dist/setup-wizard.js.map +1 -0
- package/dist/shared/content.d.ts +43 -0
- package/dist/shared/content.d.ts.map +1 -0
- package/dist/shared/content.js +61 -0
- package/dist/shared/content.js.map +1 -0
- package/dist/shared/types.d.ts +217 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +3 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/test-runner.d.ts +5 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +42 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/ascii.d.ts +23 -0
- package/dist/ui/ascii.d.ts.map +1 -0
- package/dist/ui/ascii.js +45 -0
- package/dist/ui/ascii.js.map +1 -0
- package/dist/ui/colors.d.ts +111 -0
- package/dist/ui/colors.d.ts.map +1 -0
- package/dist/ui/colors.js +166 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/ui/image-attach.d.ts +27 -0
- package/dist/ui/image-attach.d.ts.map +1 -0
- package/dist/ui/image-attach.js +100 -0
- package/dist/ui/image-attach.js.map +1 -0
- package/dist/ui/index.d.ts +18 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +18 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/markdown-stream.d.ts +91 -0
- package/dist/ui/markdown-stream.d.ts.map +1 -0
- package/dist/ui/markdown-stream.js +524 -0
- package/dist/ui/markdown-stream.js.map +1 -0
- package/dist/ui/plan-renderer.d.ts +36 -0
- package/dist/ui/plan-renderer.d.ts.map +1 -0
- package/dist/ui/plan-renderer.js +79 -0
- package/dist/ui/plan-renderer.js.map +1 -0
- package/dist/ui/prompt.d.ts +11 -0
- package/dist/ui/prompt.d.ts.map +1 -0
- package/dist/ui/prompt.js +1960 -0
- package/dist/ui/prompt.js.map +1 -0
- package/dist/ui/render-primitives.d.ts +117 -0
- package/dist/ui/render-primitives.d.ts.map +1 -0
- package/dist/ui/render-primitives.js +322 -0
- package/dist/ui/render-primitives.js.map +1 -0
- package/dist/ui/render.d.ts +133 -0
- package/dist/ui/render.d.ts.map +1 -0
- package/dist/ui/render.js +547 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/session-header.d.ts +30 -0
- package/dist/ui/session-header.d.ts.map +1 -0
- package/dist/ui/session-header.js +74 -0
- package/dist/ui/session-header.js.map +1 -0
- package/dist/workspace-guard.d.ts +68 -0
- package/dist/workspace-guard.d.ts.map +1 -0
- package/dist/workspace-guard.js +168 -0
- package/dist/workspace-guard.js.map +1 -0
- package/dist/workspace-lock.d.ts +27 -0
- package/dist/workspace-lock.d.ts.map +1 -0
- package/dist/workspace-lock.js +95 -0
- package/dist/workspace-lock.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const SAFE_COMMANDS = [
|
|
2
|
+
/^npm\s+(run\s+)?(test|build|lint|typecheck|check)(\s|$)/,
|
|
3
|
+
/^npm\s+run\s+build:cli(\s|$)/,
|
|
4
|
+
/^git\s+(status|diff|log|show)(\s|$)/,
|
|
5
|
+
/^node\s+--version$/,
|
|
6
|
+
];
|
|
7
|
+
export const DANGEROUS_COMMANDS = [
|
|
8
|
+
/\brm\s+-rf\b/,
|
|
9
|
+
/\bsudo\b/,
|
|
10
|
+
/\bchmod\s+-R\b/,
|
|
11
|
+
/\bchown\b/,
|
|
12
|
+
/\bdd\s+if=/,
|
|
13
|
+
/\bmkfs\b/,
|
|
14
|
+
/\bcurl\b.*\|\s*(sh|bash)/,
|
|
15
|
+
/\bwget\b.*\|\s*(sh|bash)/,
|
|
16
|
+
/(^|\s)env(\s|$)/,
|
|
17
|
+
/(^|\s)printenv(\s|$)/,
|
|
18
|
+
/\b(?:cat|less|more|tail|head)\s+.*(\.env|id_rsa|credentials|passwd|shadow)/,
|
|
19
|
+
/[;&|`$<>]/,
|
|
20
|
+
];
|
|
21
|
+
export function classifyCommand(command) {
|
|
22
|
+
const trimmed = command.trim();
|
|
23
|
+
if (!trimmed)
|
|
24
|
+
return 'blocked';
|
|
25
|
+
if (DANGEROUS_COMMANDS.some(pattern => pattern.test(trimmed)))
|
|
26
|
+
return 'high';
|
|
27
|
+
if (SAFE_COMMANDS.some(pattern => pattern.test(trimmed)))
|
|
28
|
+
return 'low';
|
|
29
|
+
if (/^(npm|pnpm|yarn)\s+(install|add|remove|update)\b/.test(trimmed))
|
|
30
|
+
return 'high';
|
|
31
|
+
if (/^git\s+(add|commit|reset|checkout|clean|push|pull|merge|rebase)\b/.test(trimmed))
|
|
32
|
+
return 'high';
|
|
33
|
+
return 'medium';
|
|
34
|
+
}
|
|
35
|
+
export function decidePolicy(profile, action, detail = '', allowRules = { commands: [] }) {
|
|
36
|
+
if (profile === 'dangerous-deny') {
|
|
37
|
+
return { allowed: false, needsConfirmation: false, risk: 'blocked', reason: 'Dangerous actions are denied by policy.' };
|
|
38
|
+
}
|
|
39
|
+
if (profile === 'read-only' && action !== 'read') {
|
|
40
|
+
return { allowed: false, needsConfirmation: false, risk: 'blocked', reason: 'Read-only policy blocks mutations and commands.' };
|
|
41
|
+
}
|
|
42
|
+
if (action === 'command') {
|
|
43
|
+
const risk = classifyCommand(detail);
|
|
44
|
+
if (allowRules.commands.includes(detail.trim()) && risk === 'low') {
|
|
45
|
+
return { allowed: true, needsConfirmation: false, risk, reason: 'Command allowed by project policy.' };
|
|
46
|
+
}
|
|
47
|
+
if (risk === 'high' && profile !== 'trusted-project') {
|
|
48
|
+
return { allowed: true, needsConfirmation: true, risk, reason: 'High-risk command requires explicit confirmation.' };
|
|
49
|
+
}
|
|
50
|
+
if (risk === 'low' && profile === 'trusted-project') {
|
|
51
|
+
return { allowed: true, needsConfirmation: false, risk, reason: 'Safe command allowed by trusted project policy.' };
|
|
52
|
+
}
|
|
53
|
+
return { allowed: true, needsConfirmation: true, risk, reason: 'Shell command requires confirmation.' };
|
|
54
|
+
}
|
|
55
|
+
if (action === 'write' || action === 'delete') {
|
|
56
|
+
return { allowed: true, needsConfirmation: profile !== 'trusted-project', risk: 'medium', reason: 'Workspace mutation requires confirmation unless trusted.' };
|
|
57
|
+
}
|
|
58
|
+
return { allowed: true, needsConfirmation: false, risk: 'low', reason: 'Read action allowed.' };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/runtime/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redaction & credential-scrubbing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Pillar 4 of the Phase 2 safety refactor expanded the pattern
|
|
5
|
+
* catalogue to cover every major LLM provider's credential
|
|
6
|
+
* shape. The new public API is {@link scrubForLlm} — used by
|
|
7
|
+
* the {@link ProviderKeyVault} and by every tool that pipes
|
|
8
|
+
* external output (command results, HTTP responses, file
|
|
9
|
+
* contents) back into a model prompt.
|
|
10
|
+
*
|
|
11
|
+
* The legacy {@link redactSecrets} and {@link redactedEnv}
|
|
12
|
+
* functions are preserved as thin wrappers that delegate to the
|
|
13
|
+
* new implementation, so existing callers keep working and
|
|
14
|
+
* automatically inherit the expanded pattern set.
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripAnsi(value: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Replace every ANSI escape sequence with its printable form so
|
|
19
|
+
* the bytes survive a log write / telemetry upload without
|
|
20
|
+
* accidentally injecting terminal control codes downstream.
|
|
21
|
+
*
|
|
22
|
+
* Use this in places where the *content* matters (file paths,
|
|
23
|
+
* error messages) and the colour information is incidental. The
|
|
24
|
+
* default `stripAnsi` is the right choice when the consumer is
|
|
25
|
+
* another tool that doesn't care about colour.
|
|
26
|
+
*/
|
|
27
|
+
export declare function redactAnsi(value: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Comprehensive secret-detection pattern catalogue, covering
|
|
30
|
+
* OpenAI, Anthropic, OpenRouter, GitHub, Google, AWS, JWT-style
|
|
31
|
+
* tokens, and generic env-style assignments.
|
|
32
|
+
*
|
|
33
|
+
* Each pattern is `RegExp` with the `g` flag. They are
|
|
34
|
+
* deliberately conservative — they err on the side of false
|
|
35
|
+
* positives (a Base64-looking blob gets redacted) over false
|
|
36
|
+
* negatives (a real key leaks through). The downstream cost of
|
|
37
|
+
* a false positive is a string of `[REDACTED]` in a tool
|
|
38
|
+
* result; the downstream cost of a false negative is a leaked
|
|
39
|
+
* credential.
|
|
40
|
+
*/
|
|
41
|
+
export declare const SCRUB_PATTERNS: ReadonlyArray<RegExp>;
|
|
42
|
+
/**
|
|
43
|
+
* Scrub a string of every recognised secret pattern. Used by
|
|
44
|
+
* the credential vault and by every tool that pipes external
|
|
45
|
+
* output into a model prompt. Strips ANSI escapes first so a
|
|
46
|
+
* colourised `Bearer <token>` cannot dodge the redaction.
|
|
47
|
+
*/
|
|
48
|
+
export declare function scrubForLlm(value: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Legacy alias for {@link scrubForLlm}. Kept for backward
|
|
51
|
+
* compatibility with the 163 tests that exercise this API.
|
|
52
|
+
* New code should call `scrubForLlm` directly.
|
|
53
|
+
*
|
|
54
|
+
* @deprecated Use {@link scrubForLlm} for clarity. This alias
|
|
55
|
+
* remains in place so existing callers automatically inherit
|
|
56
|
+
* the expanded pattern catalogue.
|
|
57
|
+
*/
|
|
58
|
+
export declare function redactSecrets(value: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Return a copy of `source` with secret-bearing environment
|
|
61
|
+
* variables removed. Used by `executeRunCommand` so child
|
|
62
|
+
* processes (npm install, test runners) never inherit a leaked
|
|
63
|
+
* key.
|
|
64
|
+
*/
|
|
65
|
+
export declare function redactedEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
66
|
+
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../src/runtime/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAID;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,MAAM,CA6DhD,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,UAAU,CAuBtF"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redaction & credential-scrubbing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Pillar 4 of the Phase 2 safety refactor expanded the pattern
|
|
5
|
+
* catalogue to cover every major LLM provider's credential
|
|
6
|
+
* shape. The new public API is {@link scrubForLlm} — used by
|
|
7
|
+
* the {@link ProviderKeyVault} and by every tool that pipes
|
|
8
|
+
* external output (command results, HTTP responses, file
|
|
9
|
+
* contents) back into a model prompt.
|
|
10
|
+
*
|
|
11
|
+
* The legacy {@link redactSecrets} and {@link redactedEnv}
|
|
12
|
+
* functions are preserved as thin wrappers that delegate to the
|
|
13
|
+
* new implementation, so existing callers keep working and
|
|
14
|
+
* automatically inherit the expanded pattern set.
|
|
15
|
+
*/
|
|
16
|
+
const ANSI_PATTERN = /\x1b\[[0-9;]*[a-zA-Z]/g;
|
|
17
|
+
export function stripAnsi(value) {
|
|
18
|
+
return value.replace(ANSI_PATTERN, '');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Replace every ANSI escape sequence with its printable form so
|
|
22
|
+
* the bytes survive a log write / telemetry upload without
|
|
23
|
+
* accidentally injecting terminal control codes downstream.
|
|
24
|
+
*
|
|
25
|
+
* Use this in places where the *content* matters (file paths,
|
|
26
|
+
* error messages) and the colour information is incidental. The
|
|
27
|
+
* default `stripAnsi` is the right choice when the consumer is
|
|
28
|
+
* another tool that doesn't care about colour.
|
|
29
|
+
*/
|
|
30
|
+
export function redactAnsi(value) {
|
|
31
|
+
return value.replace(/\x1b/g, '\\x1b');
|
|
32
|
+
}
|
|
33
|
+
/* ──────────────────────── Pattern catalogue ──────────────────────── */
|
|
34
|
+
/**
|
|
35
|
+
* Comprehensive secret-detection pattern catalogue, covering
|
|
36
|
+
* OpenAI, Anthropic, OpenRouter, GitHub, Google, AWS, JWT-style
|
|
37
|
+
* tokens, and generic env-style assignments.
|
|
38
|
+
*
|
|
39
|
+
* Each pattern is `RegExp` with the `g` flag. They are
|
|
40
|
+
* deliberately conservative — they err on the side of false
|
|
41
|
+
* positives (a Base64-looking blob gets redacted) over false
|
|
42
|
+
* negatives (a real key leaks through). The downstream cost of
|
|
43
|
+
* a false positive is a string of `[REDACTED]` in a tool
|
|
44
|
+
* result; the downstream cost of a false negative is a leaked
|
|
45
|
+
* credential.
|
|
46
|
+
*/
|
|
47
|
+
export const SCRUB_PATTERNS = [
|
|
48
|
+
// ── OpenAI ──────────────────────────────────────────────────
|
|
49
|
+
// sk-... (legacy), sk-proj-... (project keys), sk-svcacct-... (service accounts)
|
|
50
|
+
/sk-[A-Za-z0-9._-]{16,}/g,
|
|
51
|
+
/sk-proj-[A-Za-z0-9._-]{16,}/g,
|
|
52
|
+
/sk-svcacct-[A-Za-z0-9._-]{16,}/g,
|
|
53
|
+
// ── Anthropic ───────────────────────────────────────────────
|
|
54
|
+
// sk-ant-api03-... and legacy sk-ant-...
|
|
55
|
+
/sk-ant-api03-[A-Za-z0-9._-]{16,}/g,
|
|
56
|
+
/sk-ant-[A-Za-z0-9._-]{16,}/g,
|
|
57
|
+
// ── OpenRouter ──────────────────────────────────────────────
|
|
58
|
+
// sk-or-v1-... and sk-or-...
|
|
59
|
+
/sk-or-v1-[A-Za-z0-9._-]{16,}/g,
|
|
60
|
+
/sk-or-[A-Za-z0-9._-]{16,}/g,
|
|
61
|
+
// ── Google (AI Studio, GCP service accounts) ────────────────
|
|
62
|
+
// AIzaSy... (Gemini/AI Studio)
|
|
63
|
+
/AIza[A-Za-z0-9_-]{35}/g,
|
|
64
|
+
// GCP service account private_key
|
|
65
|
+
/"private_key"\s*:\s*"-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----"/g,
|
|
66
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
67
|
+
// ── AWS ─────────────────────────────────────────────────────
|
|
68
|
+
// Access key ID: 20 chars, all-caps alphanumeric
|
|
69
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
70
|
+
// ASIA prefix (temporary STS credentials)
|
|
71
|
+
/ASIA[0-9A-Z]{16}/g,
|
|
72
|
+
// Secret access key in env/ini/json form
|
|
73
|
+
/(?:aws_secret_access_key|aws_session_token|secret_access_key)\s*[=:]\s*["']?([A-Za-z0-9/+=]{40})["']?/gi,
|
|
74
|
+
// ── GitHub ──────────────────────────────────────────────────
|
|
75
|
+
/ghp_[A-Za-z0-9]{20,}/g,
|
|
76
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
77
|
+
/gho_[A-Za-z0-9]{20,}/g,
|
|
78
|
+
/ghu_[A-Za-z0-9]{20,}/g,
|
|
79
|
+
/ghs_[A-Za-z0-9]{20,}/g,
|
|
80
|
+
/ghr_[A-Za-z0-9]{20,}/g,
|
|
81
|
+
// ── Slack ───────────────────────────────────────────────────
|
|
82
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
83
|
+
// ── Stripe ──────────────────────────────────────────────────
|
|
84
|
+
/sk_live_[A-Za-z0-9]{20,}/g,
|
|
85
|
+
/rk_live_[A-Za-z0-9]{20,}/g,
|
|
86
|
+
// ── Generic JWT (header.payload.signature) ─────────────────
|
|
87
|
+
/eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,
|
|
88
|
+
// ── Bearer token in Authorization header ────────────────────
|
|
89
|
+
/(?:Bearer|Token)\s+([A-Za-z0-9._~+/=-]{20,})/g,
|
|
90
|
+
// ── freellmapi proxy keys ──────────────────────────────────
|
|
91
|
+
/freellmapi-[A-Za-z0-9._-]{16,}/g,
|
|
92
|
+
// ── Generic env-style assignments (covers any provider's
|
|
93
|
+
// *_KEY / *_SECRET / *_TOKEN env var serialised to text).
|
|
94
|
+
// Look-behind is supported in Node 24's V8 build, so we use
|
|
95
|
+
// a non-anchored form for max compatibility.
|
|
96
|
+
/(?<=(api[_-]?key|apikey|secret|token|password|passwd|pwd)\s*["':=]{1,3}\s*)[A-Za-z0-9._/+=-]{16,}/gi,
|
|
97
|
+
];
|
|
98
|
+
/* ──────────────────────── Public API ──────────────────────── */
|
|
99
|
+
/**
|
|
100
|
+
* Scrub a string of every recognised secret pattern. Used by
|
|
101
|
+
* the credential vault and by every tool that pipes external
|
|
102
|
+
* output into a model prompt. Strips ANSI escapes first so a
|
|
103
|
+
* colourised `Bearer <token>` cannot dodge the redaction.
|
|
104
|
+
*/
|
|
105
|
+
export function scrubForLlm(value) {
|
|
106
|
+
let scrubbed = stripAnsi(value);
|
|
107
|
+
for (const pattern of SCRUB_PATTERNS) {
|
|
108
|
+
scrubbed = scrubbed.replace(pattern, '[REDACTED]');
|
|
109
|
+
}
|
|
110
|
+
return scrubbed;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Legacy alias for {@link scrubForLlm}. Kept for backward
|
|
114
|
+
* compatibility with the 163 tests that exercise this API.
|
|
115
|
+
* New code should call `scrubForLlm` directly.
|
|
116
|
+
*
|
|
117
|
+
* @deprecated Use {@link scrubForLlm} for clarity. This alias
|
|
118
|
+
* remains in place so existing callers automatically inherit
|
|
119
|
+
* the expanded pattern catalogue.
|
|
120
|
+
*/
|
|
121
|
+
export function redactSecrets(value) {
|
|
122
|
+
return scrubForLlm(value);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Return a copy of `source` with secret-bearing environment
|
|
126
|
+
* variables removed. Used by `executeRunCommand` so child
|
|
127
|
+
* processes (npm install, test runners) never inherit a leaked
|
|
128
|
+
* key.
|
|
129
|
+
*/
|
|
130
|
+
export function redactedEnv(source = process.env) {
|
|
131
|
+
const blocked = [
|
|
132
|
+
/^freellmapi_/i,
|
|
133
|
+
/^fixo_/i,
|
|
134
|
+
/^opencode_/i,
|
|
135
|
+
/_secret$/i,
|
|
136
|
+
/_key$/i,
|
|
137
|
+
/_password$/i,
|
|
138
|
+
/_token$/i,
|
|
139
|
+
/^api_key$/i,
|
|
140
|
+
/^anthropic_/i,
|
|
141
|
+
/^openai_/i,
|
|
142
|
+
/^google_/i,
|
|
143
|
+
/^aws_/i,
|
|
144
|
+
/^openrouter_/i,
|
|
145
|
+
/^github_/i,
|
|
146
|
+
];
|
|
147
|
+
const env = {};
|
|
148
|
+
for (const [key, value] of Object.entries(source)) {
|
|
149
|
+
if (blocked.some(pattern => pattern.test(key)))
|
|
150
|
+
continue;
|
|
151
|
+
env[key] = value;
|
|
152
|
+
}
|
|
153
|
+
return env;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../src/runtime/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,yEAAyE;AAEzE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,+DAA+D;IAC/D,iFAAiF;IACjF,yBAAyB;IACzB,8BAA8B;IAC9B,iCAAiC;IAEjC,+DAA+D;IAC/D,yCAAyC;IACzC,mCAAmC;IACnC,6BAA6B;IAE7B,+DAA+D;IAC/D,6BAA6B;IAC7B,+BAA+B;IAC/B,4BAA4B;IAE5B,+DAA+D;IAC/D,+BAA+B;IAC/B,wBAAwB;IACxB,kCAAkC;IAClC,mGAAmG;IACnG,6EAA6E;IAE7E,+DAA+D;IAC/D,iDAAiD;IACjD,mBAAmB;IACnB,0CAA0C;IAC1C,mBAAmB;IACnB,yCAAyC;IACzC,yGAAyG;IAEzG,+DAA+D;IAC/D,uBAAuB;IACvB,+BAA+B;IAC/B,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IAEvB,+DAA+D;IAC/D,+BAA+B;IAE/B,+DAA+D;IAC/D,2BAA2B;IAC3B,2BAA2B;IAE3B,8DAA8D;IAC9D,gEAAgE;IAEhE,+DAA+D;IAC/D,+CAA+C;IAE/C,8DAA8D;IAC9D,iCAAiC;IAEjC,0DAA0D;IAC1D,6DAA6D;IAC7D,+DAA+D;IAC/D,gDAAgD;IAChD,qGAAqG;CACtG,CAAC;AAEF,kEAAkE;AAElE;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,SAA4B,OAAO,CAAC,GAAG;IACjE,MAAM,OAAO,GAAG;QACd,eAAe;QACf,SAAS;QACT,aAAa;QACb,WAAW;QACX,QAAQ;QACR,aAAa;QACb,UAAU;QACV,YAAY;QACZ,cAAc;QACd,WAAW;QACX,WAAW;QACX,QAAQ;QACR,eAAe;QACf,WAAW;KACZ,CAAC;IACF,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QACzD,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type TodoList } from '../context/todo.js';
|
|
2
|
+
export declare const SNAPSHOT_VERSION: 1;
|
|
3
|
+
export declare const SNAPSHOT_KIND: "fixo-cli-session";
|
|
4
|
+
export type AgentMode = 'PLAN' | 'BUILD' | 'EXPLORE' | 'SCOUT';
|
|
5
|
+
export interface SessionMessage {
|
|
6
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
7
|
+
content: string;
|
|
8
|
+
/** Tool name for `role === 'tool'` messages. */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** Monotonic per-conversation index. */
|
|
11
|
+
index: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionSnapshot {
|
|
14
|
+
version: typeof SNAPSHOT_VERSION;
|
|
15
|
+
kind: typeof SNAPSHOT_KIND;
|
|
16
|
+
/** Snapshot id = file basename without `.json`. */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Absolute cwd captured at save time. */
|
|
19
|
+
cwd: string;
|
|
20
|
+
/** ISO-8601 timestamp. */
|
|
21
|
+
createdAt: string;
|
|
22
|
+
/** Conversation log. */
|
|
23
|
+
conversation: SessionMessage[];
|
|
24
|
+
/** Estimated prompt tokens (approximate, for UI display). */
|
|
25
|
+
tokens: number;
|
|
26
|
+
/** Active model at save time. */
|
|
27
|
+
model: string;
|
|
28
|
+
/** Agent mode at save time. */
|
|
29
|
+
mode: AgentMode;
|
|
30
|
+
/** Files the user had selected (e.g. via `--files` or the file picker). */
|
|
31
|
+
selectedFiles: string[];
|
|
32
|
+
/** Optional user-supplied session summary. */
|
|
33
|
+
summary?: string;
|
|
34
|
+
/** Optional system-prompt override (FIXO.md block stripped, but
|
|
35
|
+
* the caller's original override preserved). */
|
|
36
|
+
fixedInstructions?: string;
|
|
37
|
+
/** Persisted todo list at save time. */
|
|
38
|
+
todo: TodoList;
|
|
39
|
+
}
|
|
40
|
+
export declare function makeSnapshotId(now?: Date): string;
|
|
41
|
+
export declare function snapshotPath(cwd: string, id: string): string;
|
|
42
|
+
export interface SaveInput {
|
|
43
|
+
cwd: string;
|
|
44
|
+
conversation: SessionMessage[];
|
|
45
|
+
tokens: number;
|
|
46
|
+
model: string;
|
|
47
|
+
mode: AgentMode;
|
|
48
|
+
selectedFiles: string[];
|
|
49
|
+
summary?: string;
|
|
50
|
+
fixedInstructions?: string;
|
|
51
|
+
/** If omitted, the todo list is reloaded from disk. */
|
|
52
|
+
todo?: TodoList;
|
|
53
|
+
}
|
|
54
|
+
export interface SaveResult {
|
|
55
|
+
ok: boolean;
|
|
56
|
+
id: string;
|
|
57
|
+
path: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
export declare function saveSnapshot(input: SaveInput, now?: Date): SaveResult;
|
|
61
|
+
export interface LoadResult {
|
|
62
|
+
ok: boolean;
|
|
63
|
+
snapshot: SessionSnapshot | null;
|
|
64
|
+
error?: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function loadSnapshot(cwd: string, id: string): LoadResult;
|
|
67
|
+
export interface SnapshotListEntry {
|
|
68
|
+
id: string;
|
|
69
|
+
path: string;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
tokens: number;
|
|
72
|
+
items: number;
|
|
73
|
+
summary?: string;
|
|
74
|
+
}
|
|
75
|
+
export declare function listSnapshots(cwd: string): SnapshotListEntry[];
|
|
76
|
+
//# sourceMappingURL=session-snapshots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-snapshots.d.ts","sourceRoot":"","sources":["../../src/runtime/session-snapshots.ts"],"names":[],"mappings":"AA4BA,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,oBAAoB,CAAC;AAM5B,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAC3C,eAAO,MAAM,aAAa,EAAG,kBAA2B,CAAC;AAEzD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,gBAAgB,CAAC;IACjC,IAAI,EAAE,OAAO,aAAa,CAAC;IAC3B,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;qDACiD;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wCAAwC;IACxC,IAAI,EAAE,QAAQ,CAAC;CAChB;AAoBD,wBAAgB,cAAc,CAAC,GAAG,GAAE,IAAiB,GAAG,MAAM,CAG7D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5D;AAID,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uDAAuD;IACvD,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAE,IAAiB,GAAG,UAAU,CAyCjF;AAID,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CA4BhE;AAID,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAmC9D"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-snapshots.ts — Persistence layer for `--resume <id>`.
|
|
3
|
+
*
|
|
4
|
+
* A snapshot is a single JSON file under
|
|
5
|
+
* `~/.fixocli/sessions/<sha256(cwd)>/<iso-ts>_<short-uuid>.json`
|
|
6
|
+
* capturing the exact state the REPL needs to rehydrate a
|
|
7
|
+
* previous conversation: the message log, the todo list, the
|
|
8
|
+
* selected files, the model, the user-supplied summary, the
|
|
9
|
+
* agent mode, and the system-prompt override.
|
|
10
|
+
*
|
|
11
|
+
* The directory layout is keyed by `sha256(cwd)` so two
|
|
12
|
+
* different working directories never collide. The snapshot id
|
|
13
|
+
* is the file's basename (without `.json`) — short enough to
|
|
14
|
+
* copy/paste, deterministic when re-derived.
|
|
15
|
+
*
|
|
16
|
+
* Atomicity: writes go to `<file>.tmp` first, then `renameSync`
|
|
17
|
+
* over the final path, matching the pattern used by todo
|
|
18
|
+
* persistence and the staging manager.
|
|
19
|
+
*
|
|
20
|
+
* Stability: every snapshot is *self-describing* — it carries a
|
|
21
|
+
* `version` field and a `kind: 'fixo-cli-session'` discriminator
|
|
22
|
+
* so a future change to the on-disk format can be migrated
|
|
23
|
+
* rather than orphaned.
|
|
24
|
+
*/
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
import os from 'node:os';
|
|
28
|
+
import crypto from 'node:crypto';
|
|
29
|
+
import { loadTodoList, saveTodoList, } from '../context/todo.js';
|
|
30
|
+
import { recordTelemetry, telemetry, } from '../agent/telemetry.js';
|
|
31
|
+
export const SNAPSHOT_VERSION = 1;
|
|
32
|
+
export const SNAPSHOT_KIND = 'fixo-cli-session';
|
|
33
|
+
/* ──────────────────────── path helpers ──────────────────────── */
|
|
34
|
+
function sessionsRoot() {
|
|
35
|
+
return path.join(os.homedir(), '.fixocli', 'sessions');
|
|
36
|
+
}
|
|
37
|
+
function hashCwd(cwd) {
|
|
38
|
+
return crypto.createHash('sha256').update(cwd).digest('hex').slice(0, 32);
|
|
39
|
+
}
|
|
40
|
+
function dirForCwd(cwd) {
|
|
41
|
+
return path.join(sessionsRoot(), hashCwd(cwd));
|
|
42
|
+
}
|
|
43
|
+
function shortUuid() {
|
|
44
|
+
return crypto.randomBytes(6).toString('base64url');
|
|
45
|
+
}
|
|
46
|
+
export function makeSnapshotId(now = new Date()) {
|
|
47
|
+
const iso = now.toISOString().replace(/[:.]/g, '-');
|
|
48
|
+
return `${iso}_${shortUuid()}`;
|
|
49
|
+
}
|
|
50
|
+
export function snapshotPath(cwd, id) {
|
|
51
|
+
return path.join(dirForCwd(cwd), `${id}.json`);
|
|
52
|
+
}
|
|
53
|
+
export function saveSnapshot(input, now = new Date()) {
|
|
54
|
+
const id = makeSnapshotId(now);
|
|
55
|
+
const file = snapshotPath(input.cwd, id);
|
|
56
|
+
const dir = path.dirname(file);
|
|
57
|
+
try {
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
return { ok: false, id, path: file, error: err.message };
|
|
62
|
+
}
|
|
63
|
+
const todo = input.todo ?? loadTodoList(input.cwd);
|
|
64
|
+
const snapshot = {
|
|
65
|
+
version: SNAPSHOT_VERSION,
|
|
66
|
+
kind: SNAPSHOT_KIND,
|
|
67
|
+
id,
|
|
68
|
+
cwd: input.cwd,
|
|
69
|
+
createdAt: now.toISOString(),
|
|
70
|
+
conversation: input.conversation,
|
|
71
|
+
tokens: input.tokens,
|
|
72
|
+
model: input.model,
|
|
73
|
+
mode: input.mode,
|
|
74
|
+
selectedFiles: input.selectedFiles,
|
|
75
|
+
summary: input.summary,
|
|
76
|
+
fixedInstructions: input.fixedInstructions,
|
|
77
|
+
todo,
|
|
78
|
+
};
|
|
79
|
+
const tmp = `${file}.tmp`;
|
|
80
|
+
try {
|
|
81
|
+
fs.writeFileSync(tmp, JSON.stringify(snapshot, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
82
|
+
fs.renameSync(tmp, file);
|
|
83
|
+
recordTelemetry(telemetry.sessionSnapshot({ id, op: 'save', tokens: input.tokens, items: todo.items.length }));
|
|
84
|
+
// Best-effort: mirror the todo list to its on-disk location so
|
|
85
|
+
// a stale-snapshot resume still gets a sensible todo list
|
|
86
|
+
// *if* the caller didn't supply one. This keeps
|
|
87
|
+
// `loadTodoList(cwd)` consistent with what the user saw.
|
|
88
|
+
if (!input.todo)
|
|
89
|
+
saveTodoList(input.cwd, todo);
|
|
90
|
+
return { ok: true, id, path: file };
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
return { ok: false, id, path: file, error: err.message };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function loadSnapshot(cwd, id) {
|
|
97
|
+
const file = snapshotPath(cwd, id);
|
|
98
|
+
let raw;
|
|
99
|
+
try {
|
|
100
|
+
raw = fs.readFileSync(file, 'utf-8');
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return { ok: false, snapshot: null, error: err.message };
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(raw);
|
|
107
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
108
|
+
return { ok: false, snapshot: null, error: 'snapshot is not an object' };
|
|
109
|
+
}
|
|
110
|
+
const obj = parsed;
|
|
111
|
+
if (obj.kind !== SNAPSHOT_KIND) {
|
|
112
|
+
return { ok: false, snapshot: null, error: `unexpected snapshot kind: ${String(obj.kind)}` };
|
|
113
|
+
}
|
|
114
|
+
if (obj.version !== SNAPSHOT_VERSION) {
|
|
115
|
+
return { ok: false, snapshot: null, error: `unsupported snapshot version: ${String(obj.version)}` };
|
|
116
|
+
}
|
|
117
|
+
const snap = obj;
|
|
118
|
+
recordTelemetry(telemetry.sessionSnapshot({ id, op: 'load', tokens: snap.tokens, items: snap.todo.items.length }));
|
|
119
|
+
return { ok: true, snapshot: snap };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return { ok: false, snapshot: null, error: err.message };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function listSnapshots(cwd) {
|
|
126
|
+
const dir = dirForCwd(cwd);
|
|
127
|
+
if (!fs.existsSync(dir))
|
|
128
|
+
return [];
|
|
129
|
+
let entries;
|
|
130
|
+
try {
|
|
131
|
+
entries = fs.readdirSync(dir).filter((n) => n.endsWith('.json'));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const out = [];
|
|
137
|
+
for (const name of entries) {
|
|
138
|
+
const file = path.join(dir, name);
|
|
139
|
+
try {
|
|
140
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
141
|
+
const parsed = JSON.parse(raw);
|
|
142
|
+
if (!parsed || typeof parsed !== 'object')
|
|
143
|
+
continue;
|
|
144
|
+
const obj = parsed;
|
|
145
|
+
if (obj.kind !== SNAPSHOT_KIND)
|
|
146
|
+
continue;
|
|
147
|
+
const conv = Array.isArray(obj.conversation) ? obj.conversation : [];
|
|
148
|
+
const todo = (obj.todo && typeof obj.todo === 'object') ? obj.todo : {};
|
|
149
|
+
const items = Array.isArray(todo.items) ? todo.items.length : 0;
|
|
150
|
+
out.push({
|
|
151
|
+
id: name.slice(0, -'.json'.length),
|
|
152
|
+
path: file,
|
|
153
|
+
createdAt: typeof obj.createdAt === 'string' ? obj.createdAt : '',
|
|
154
|
+
tokens: typeof obj.tokens === 'number' ? obj.tokens : 0,
|
|
155
|
+
items,
|
|
156
|
+
summary: typeof obj.summary === 'string' ? obj.summary : undefined,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// skip unreadable
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=session-snapshots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-snapshots.js","sourceRoot":"","sources":["../../src/runtime/session-snapshots.ts"],"names":[],"mappings":"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"}
|