@pugi/cli 0.1.0-beta.5 → 0.1.0-beta.51
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/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-mascot.ansi +15 -25
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +15 -0
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash-classifier.js +400 -4
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/diff-capture.js +112 -3
- package/dist/core/context/index.js +7 -0
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +86 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/dispatch.js +218 -2
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +115 -5
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +155 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +897 -211
- package/dist/core/engine/prompts.js +88 -2
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1045 -36
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/hooks/events.js +44 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +213 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +776 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/mcp/client.js +75 -6
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +24 -2
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory-sync/queue.js +158 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +284 -2
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/history.js +11 -1
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/session.js +1897 -37
- package/dist/core/repl/slash-commands.js +430 -15
- package/dist/core/repl/store/session-store.js +31 -2
- package/dist/core/repl/workspace-context.js +22 -0
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +80 -0
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +113 -24
- package/dist/core/subagents/index.js +18 -5
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +28 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +3241 -343
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +242 -11
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +412 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +184 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +508 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +17 -2
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +32 -0
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/version.js +65 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +213 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +203 -4
- package/dist/tools/file-tools.js +85 -14
- package/dist/tools/lsp-tools.js +189 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +51 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/web-fetch.js +147 -2
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +10 -0
- package/dist/tui/ask-modal.js +2 -2
- package/dist/tui/ask-user-question-prompt.js +192 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +82 -8
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +218 -3
- package/dist/tui/markdown-render.js +4 -4
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +35 -0
- package/dist/tui/repl-render.js +313 -35
- package/dist/tui/repl-splash-art.js +1 -1
- package/dist/tui/repl-splash-mascot.js +32 -8
- package/dist/tui/repl-splash.js +2 -2
- package/dist/tui/repl.js +85 -5
- package/dist/tui/splash.js +1 -1
- package/dist/tui/status-bar.js +94 -16
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +52 -3
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +13 -7
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +11 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +11 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getJobRegistry, summarizeJobsForPrompt, } from '../jobs/registry.js';
|
|
2
|
+
import { compileStyleBlock } from '../output-style/presets.js';
|
|
3
|
+
import { resolveOutputStyle } from '../output-style/state.js';
|
|
2
4
|
/**
|
|
3
5
|
* System prompts for each engine command. Each prompt:
|
|
4
6
|
* - Anchors the model in Pugi's local-first contract (ADR-0037).
|
|
@@ -22,10 +24,62 @@ import { getJobRegistry, summarizeJobsForPrompt, } from '../jobs/registry.js';
|
|
|
22
24
|
const COMMON_LOCAL_FIRST_PREAMBLE = [
|
|
23
25
|
'You are the Pugi CLI agent running locally inside the operator\'s repository.',
|
|
24
26
|
'The local filesystem is the source of truth. Every change you make is committed locally; nothing is uploaded by default (ADR-0037 local-first).',
|
|
27
|
+
// R1 fix (2026-05-26, PR #413 r1, Fix 5 Option B): only advertise the
|
|
28
|
+
// tools currently wired in `tool-bridge.ts::WIRED_TOOLS`. α7.7 ships
|
|
29
|
+
// apply_patch / lsp_* / worktree_* as CLI-only surfaces (`pugi patch`,
|
|
30
|
+
// `pugi lsp`, `pugi worktree`); wiring them into the engine loop is
|
|
31
|
+
// deferred to β2 (apply_patch), β4 (LSP tools), β7 (worktree tools)
|
|
32
|
+
// per the consolidated sprint plan. Advertising them in the system
|
|
33
|
+
// prompt without a matching executor entry caused Mira to attempt
|
|
34
|
+
// calls that returned `unknown_tool` — broken eval surface.
|
|
25
35
|
'You have a tool registry: read, write, edit, grep, glob, bash. Call tools to inspect and modify the workspace.',
|
|
26
36
|
'Cite file paths relative to the workspace root. Keep edits minimal and reversible.',
|
|
27
37
|
'When you are done, return a single final text answer that the operator can read on the CLI.',
|
|
28
38
|
].join(' ');
|
|
39
|
+
/**
|
|
40
|
+
* β5a P1+P6 (2026-05-26): prompt v2 — intent marker contract +
|
|
41
|
+
* definitional examples + jargon ban. Fixes the dominant Pugi loss
|
|
42
|
+
* mode in the α7.X Phase 2 comparative eval: tool-use on pure
|
|
43
|
+
* knowledge questions ("What is grep?" → bash man grep).
|
|
44
|
+
*
|
|
45
|
+
* The CLI-side `classifyIntent` (apps/pugi-cli/src/core/engine/intent.ts)
|
|
46
|
+
* wraps definitional questions with `<intent kind="definitional">` on
|
|
47
|
+
* the user message before send. The rules below teach the model what
|
|
48
|
+
* to do with that marker.
|
|
49
|
+
*
|
|
50
|
+
* Voice constraint: same banned-jargon list as the cabinet Mira
|
|
51
|
+
* persona (брифую / диспатчу / шипаю and the English jargon list
|
|
52
|
+
* from BANNED_WORDS in mira.system-prompt.ts). Repeated here verbatim
|
|
53
|
+
* so the CLI surface has its own enforcement copy; the cabinet copy
|
|
54
|
+
* is the source of truth and ships through the runtime persona
|
|
55
|
+
* prompt for the cabinet UI. CLI runs DO NOT load the cabinet
|
|
56
|
+
* persona prompt — engine prompts are the only place to enforce
|
|
57
|
+
* voice for `pugi explain` / `pugi code` callers.
|
|
58
|
+
*/
|
|
59
|
+
const INTENT_MARKER_CONTRACT = [
|
|
60
|
+
'# Intent contract',
|
|
61
|
+
'When the operator\'s message starts with `<intent kind="definitional">`, treat it as a knowledge question:',
|
|
62
|
+
' - Answer in prose. Do NOT call any tools.',
|
|
63
|
+
' - Cite a file from the repo only when it directly supports the explanation.',
|
|
64
|
+
' - Keep the answer to one short paragraph unless the operator asked for depth.',
|
|
65
|
+
'When no intent marker is present OR the marker is operational, use tools as needed.',
|
|
66
|
+
'',
|
|
67
|
+
'# Definitional examples',
|
|
68
|
+
'Operator: `<intent kind="definitional">What is grep?</intent>`',
|
|
69
|
+
'You: `grep is a Unix command-line tool that searches plain text for lines matching a regular expression. It reads stdin or files and prints matching lines to stdout.`',
|
|
70
|
+
'(No tool calls. One paragraph. No file paths because grep is a generic Unix tool, not a repo artefact.)',
|
|
71
|
+
'',
|
|
72
|
+
'Operator: `<intent kind="definitional">что такое pgvector?</intent>`',
|
|
73
|
+
'You: `pgvector - это расширение PostgreSQL для хранения и поиска векторных эмбеддингов. Поддерживает ivfflat и hnsw индексы; используется для RAG и semantic search.`',
|
|
74
|
+
'(One short paragraph. No tools.)',
|
|
75
|
+
].join('\n');
|
|
76
|
+
const JARGON_BAN = [
|
|
77
|
+
'# Voice',
|
|
78
|
+
'Brand voice: terse, operator-grade, English in code paths / Russian-Ukrainian permitted in chat answers.',
|
|
79
|
+
'Banned words (CLI customer-facing output): "брифую", "диспатчу", "шипаю", "journey", "explore", "delight", "magical", "friendly", "let me help", "I\'d be happy to", "pug-tastic". Use neutral verbs instead: brief / dispatch / ship / build / read / write.',
|
|
80
|
+
'No em-dashes. No emoji. No "AI assistant" framing.',
|
|
81
|
+
].join('\n');
|
|
82
|
+
const PROMPT_V2_APPENDIX = [INTENT_MARKER_CONTRACT, JARGON_BAN].join('\n\n');
|
|
29
83
|
const PLAN_TOOLS_NOTE = 'PLAN MODE IS READ-ONLY. You may call read, grep, glob. Calls to write, edit, or bash will be refused and end the run. Produce a written plan, not changes.';
|
|
30
84
|
const EDIT_FLOW_RULES = [
|
|
31
85
|
'Before calling edit on a file you have not yet read this session, call read first — the edit tool fails otherwise.',
|
|
@@ -34,10 +88,42 @@ const EDIT_FLOW_RULES = [
|
|
|
34
88
|
].join(' ');
|
|
35
89
|
export function systemPromptFor(kind) {
|
|
36
90
|
const base = baseSystemPromptFor(kind);
|
|
91
|
+
// β5a P1+P6: append the prompt-v2 intent-marker contract +
|
|
92
|
+
// definitional examples + jargon ban to every command kind. The
|
|
93
|
+
// appendix is shared across kinds because the marker contract +
|
|
94
|
+
// voice gate are command-agnostic — a definitional question lands
|
|
95
|
+
// the same way under `pugi explain` and `pugi code`.
|
|
96
|
+
const withV2 = `${base}\n\n${PROMPT_V2_APPENDIX}`;
|
|
97
|
+
// Leak L18 (2026-05-27): output-style preset block. Compiled from
|
|
98
|
+
// workspace > user > default precedence. The `default` preset
|
|
99
|
+
// returns an empty block (no override over the base voice), so the
|
|
100
|
+
// injection is a no-op for the most-common case. Wrapped in
|
|
101
|
+
// try/catch — every IO failure inside `resolveOutputStyle` already
|
|
102
|
+
// degrades to the default slug, but defence in depth keeps the
|
|
103
|
+
// engine prompt assembly from ever crashing on a hand-edited
|
|
104
|
+
// config.json.
|
|
105
|
+
const styleBlock = formatOutputStyleBlock();
|
|
106
|
+
const withStyle = styleBlock ? `${withV2}\n\n${styleBlock}` : withV2;
|
|
37
107
|
const snapshot = formatBackgroundJobsSnapshot(getJobRegistrySafely());
|
|
38
108
|
if (!snapshot)
|
|
39
|
-
return
|
|
40
|
-
return `${
|
|
109
|
+
return withStyle;
|
|
110
|
+
return `${withStyle}\n\n${snapshot}`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Resolve the active output-style preset for the current process
|
|
114
|
+
* and compile it into a prompt block. Returns empty string for the
|
|
115
|
+
* default preset OR for any unexpected IO failure so the engine
|
|
116
|
+
* prompt assembly path is unaffected by a missing / malformed
|
|
117
|
+
* config.json.
|
|
118
|
+
*/
|
|
119
|
+
function formatOutputStyleBlock() {
|
|
120
|
+
try {
|
|
121
|
+
const resolved = resolveOutputStyle({ workspaceRoot: process.cwd() });
|
|
122
|
+
return compileStyleBlock(resolved.slug);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
41
127
|
}
|
|
42
128
|
function baseSystemPromptFor(kind) {
|
|
43
129
|
switch (kind) {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* α7 L3 (2026-05-27) — leak-parity: underscore-prefix internal-fields filter.
|
|
3
|
+
*
|
|
4
|
+
* The convention (observed in the leaked Claude Code BashTool surface and
|
|
5
|
+
* codified in `docs/research/2026-05-27-pugi-gap-analysis-3-repos.md` §1)
|
|
6
|
+
* is that tool-argument fields whose names start with a leading underscore
|
|
7
|
+
* are INTERNAL — populated by the dispatcher at call time (sessionId,
|
|
8
|
+
* tenantId, correlation handles, hook context, ask-modal bridge handles)
|
|
9
|
+
* but never advertised to the model. The model schema MUST omit them so:
|
|
10
|
+
*
|
|
11
|
+
* 1. No token cost — internal context never burns model budget.
|
|
12
|
+
* 2. No fabrication risk — the model cannot hallucinate values for
|
|
13
|
+
* sessionId / tenantId / etc. because the field is invisible.
|
|
14
|
+
* 3. No leak surface — implementation detail stays implementation detail.
|
|
15
|
+
*
|
|
16
|
+
* The dispatcher (see `tool-bridge.ts::buildExecutor`) does NOT strip these
|
|
17
|
+
* fields at call time. It passes the full args record (including any
|
|
18
|
+
* `_internal*` keys an upstream layer injected) straight to the tool
|
|
19
|
+
* handler. Only the schema surface that the engine adapter ships to the
|
|
20
|
+
* model is filtered.
|
|
21
|
+
*
|
|
22
|
+
* This module is intentionally narrow: it accepts a JSON Schema fragment
|
|
23
|
+
* and returns a deep clone with `_`-prefixed keys removed from every
|
|
24
|
+
* `properties` map encountered while walking, and with `required` filtered
|
|
25
|
+
* to drop any references to those keys. It descends into nested object
|
|
26
|
+
* schemas and into the `items` schema of arrays. It is JSON-Schema-version
|
|
27
|
+
* agnostic (works on draft-07, 2019-09, 2020-12 alike) because it only
|
|
28
|
+
* inspects `properties`/`required`/`items` and leaves the rest of the
|
|
29
|
+
* fragment alone.
|
|
30
|
+
*
|
|
31
|
+
* Edge cases handled:
|
|
32
|
+
* - `_` alone (single underscore) is treated as internal and stripped.
|
|
33
|
+
* - Nested object schemas inside `properties` get the same treatment
|
|
34
|
+
* (a sub-property whose name starts with `_` is removed too).
|
|
35
|
+
* - Array `items` are walked. Tuple schemas (`items` as array) are
|
|
36
|
+
* walked element-by-element.
|
|
37
|
+
* - `oneOf`/`anyOf`/`allOf` branches are walked.
|
|
38
|
+
* - Non-object inputs (null, primitives, arrays passed as the root)
|
|
39
|
+
* are returned as-is — defensive no-op, never throws.
|
|
40
|
+
*
|
|
41
|
+
* Contract notes:
|
|
42
|
+
* - Pure function. Input is never mutated.
|
|
43
|
+
* - Output is a deep clone — every nested object/array is freshly
|
|
44
|
+
* allocated so callers can mutate safely.
|
|
45
|
+
* - JSON-only — does not preserve symbols, getters, or class instances
|
|
46
|
+
* because JSON Schema is plain-data by spec.
|
|
47
|
+
*/
|
|
48
|
+
const INTERNAL_PREFIX = '_';
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when the field name should be stripped from the model-
|
|
51
|
+
* facing schema. Leading underscore is the contract — single `_` is also
|
|
52
|
+
* stripped (no escape hatch). Empty-string keys (which are technically
|
|
53
|
+
* valid JSON) are left alone so we do not silently drop them.
|
|
54
|
+
*/
|
|
55
|
+
export function isInternalFieldName(name) {
|
|
56
|
+
return name.length > 0 && name.startsWith(INTERNAL_PREFIX);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Strip `_`-prefixed properties from a JSON Schema fragment. Recursively
|
|
60
|
+
* walks nested object schemas and array `items`. Returns a deep clone;
|
|
61
|
+
* the input is never mutated.
|
|
62
|
+
*
|
|
63
|
+
* Pass-through behaviour:
|
|
64
|
+
* - Non-object / null / array inputs round-trip unchanged (as deep
|
|
65
|
+
* clones where applicable).
|
|
66
|
+
* - Fragments with no `properties` key are returned as deep clones
|
|
67
|
+
* after walking `items`/`oneOf`/`anyOf`/`allOf`.
|
|
68
|
+
*/
|
|
69
|
+
export function stripInternalFields(schema) {
|
|
70
|
+
if (schema === null || typeof schema !== 'object')
|
|
71
|
+
return schema;
|
|
72
|
+
if (Array.isArray(schema)) {
|
|
73
|
+
return schema.map((item) => stripInternalFields(item));
|
|
74
|
+
}
|
|
75
|
+
return walkObject(schema);
|
|
76
|
+
}
|
|
77
|
+
function walkObject(node) {
|
|
78
|
+
const out = {};
|
|
79
|
+
for (const [key, value] of Object.entries(node)) {
|
|
80
|
+
if (key === 'properties' && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
81
|
+
out[key] = walkProperties(value);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (key === 'required' && Array.isArray(value)) {
|
|
85
|
+
out[key] = value.filter((entry) => typeof entry === 'string' && !isInternalFieldName(entry));
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (key === 'items') {
|
|
89
|
+
out[key] = stripInternalFields(value);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (key === 'oneOf' || key === 'anyOf' || key === 'allOf') {
|
|
93
|
+
if (Array.isArray(value)) {
|
|
94
|
+
out[key] = value.map((branch) => stripInternalFields(branch));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Default: deep-clone any nested objects/arrays so the caller can
|
|
99
|
+
// mutate freely without touching the input. Primitives pass through.
|
|
100
|
+
out[key] = cloneJson(value);
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
function walkProperties(props) {
|
|
105
|
+
const out = {};
|
|
106
|
+
for (const [propName, propSchema] of Object.entries(props)) {
|
|
107
|
+
if (isInternalFieldName(propName))
|
|
108
|
+
continue;
|
|
109
|
+
out[propName] = stripInternalFields(propSchema);
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function cloneJson(value) {
|
|
114
|
+
if (value === null || typeof value !== 'object')
|
|
115
|
+
return value;
|
|
116
|
+
if (Array.isArray(value))
|
|
117
|
+
return value.map((item) => cloneJson(item));
|
|
118
|
+
const out = {};
|
|
119
|
+
for (const [key, val] of Object.entries(value)) {
|
|
120
|
+
out[key] = cloneJson(val);
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=strip-internal-fields.js.map
|