pi-ui-extend 1.0.42 → 1.0.45
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 +41 -12
- package/dist/app/app.d.ts +10 -0
- package/dist/app/app.js +132 -8
- package/dist/app/cli/install.js +2 -2
- package/dist/app/commands/command-controller.d.ts +4 -0
- package/dist/app/commands/command-controller.js +11 -0
- package/dist/app/commands/command-git-actions.d.ts +25 -0
- package/dist/app/commands/command-git-actions.js +381 -0
- package/dist/app/commands/command-host.d.ts +3 -0
- package/dist/app/commands/command-host.js +5 -2
- package/dist/app/commands/command-model-actions.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +51 -34
- package/dist/app/commands/command-navigation-actions.d.ts +1 -0
- package/dist/app/commands/command-navigation-actions.js +16 -3
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +14 -0
- package/dist/app/commands/reload-context-inventory.js +12 -1
- package/dist/app/input/autocomplete-controller.js +61 -34
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/input/input-controller.d.ts +2 -1
- package/dist/app/input/input-controller.js +7 -2
- package/dist/app/input/prompt-enhancer-controller.js +53 -35
- package/dist/app/input/voice-controller.d.ts +41 -45
- package/dist/app/input/voice-controller.js +351 -419
- package/dist/app/model/model-usage-controller.js +17 -7
- package/dist/app/model/model-usage-status.d.ts +4 -1
- package/dist/app/model/model-usage-status.js +270 -46
- package/dist/app/popup/menu-items-controller.d.ts +13 -3
- package/dist/app/popup/menu-items-controller.js +37 -21
- package/dist/app/popup/popup-action-controller.d.ts +12 -2
- package/dist/app/popup/popup-action-controller.js +77 -24
- package/dist/app/popup/popup-menu-controller.d.ts +36 -14
- package/dist/app/popup/popup-menu-controller.js +239 -69
- package/dist/app/rendering/dcp-stats.d.ts +9 -4
- package/dist/app/rendering/dcp-stats.js +40 -425
- package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
- package/dist/app/rendering/popup-menu-renderer.js +42 -37
- package/dist/app/rendering/render-controller.js +23 -2
- package/dist/app/rendering/status-line-renderer.d.ts +5 -0
- package/dist/app/rendering/status-line-renderer.js +41 -5
- package/dist/app/rendering/tab-line-renderer.js +26 -20
- package/dist/app/runtime.d.ts +12 -1
- package/dist/app/runtime.js +120 -12
- package/dist/app/screen/mouse-controller.d.ts +2 -0
- package/dist/app/screen/mouse-controller.js +17 -7
- package/dist/app/screen/status-controller.d.ts +4 -0
- package/dist/app/screen/status-controller.js +5 -0
- package/dist/app/session/lazy-session-manager.js +34 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +10 -1
- package/dist/app/session/session-history.d.ts +1 -0
- package/dist/app/session/session-history.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
- package/dist/app/session/session-lifecycle-controller.js +10 -1
- package/dist/app/session/tabs-controller.d.ts +25 -1
- package/dist/app/session/tabs-controller.js +442 -153
- package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
- package/dist/app/subagents/subagents-widget-controller.js +6 -0
- package/dist/app/types.d.ts +11 -1
- package/dist/app/workspace/workspace-actions-controller.js +10 -2
- package/dist/app/workspace/workspace-undo.d.ts +1 -0
- package/dist/app/workspace/workspace-undo.js +1 -0
- package/dist/bundled-extensions/question/index.js +9 -1
- package/dist/bundled-extensions/question/remote.d.ts +4 -0
- package/dist/bundled-extensions/question/remote.js +33 -0
- package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
- package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
- package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
- package/dist/bundled-extensions/telegram-connector/config.js +87 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
- package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
- package/dist/bundled-extensions/telegram-connector/index.js +195 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
- package/dist/bundled-extensions/terminal-bell/index.js +0 -76
- package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
- package/dist/bundled-extensions/workspace-undo/index.js +191 -0
- package/dist/config.d.ts +21 -2
- package/dist/config.js +159 -32
- package/dist/default-pix-config.js +20 -10
- package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
- package/dist/schemas/pi-tools-suite-schema.js +11 -5
- package/dist/schemas/pix-schema.d.ts +12 -2
- package/dist/schemas/pix-schema.js +37 -9
- package/dist/schemas/tasks-schema.js +1 -1
- package/docs/concurrency.md +3 -1
- package/docs/desktop-mvp.md +10 -5
- package/docs/desktop-task-manager.md +81 -28
- package/docs/release.md +30 -6
- package/external/pi-tools-suite/README.md +165 -39
- package/external/pi-tools-suite/docs/session-recovery.md +7 -0
- package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
- package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
- package/external/pi-tools-suite/package.json +6 -1
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
- package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
- package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
- package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
- package/external/pi-tools-suite/src/config.ts +14 -0
- package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
- package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
- package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
- package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
- package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
- package/external/pi-tools-suite/src/dcp/config.ts +58 -4
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
- package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
- package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
- package/external/pi-tools-suite/src/dcp/index.ts +338 -66
- package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
- package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
- package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
- package/external/pi-tools-suite/src/dcp/state.ts +9 -0
- package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
- package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
- package/external/pi-tools-suite/src/lib/project.ts +36 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
- package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
- package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
- package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
- package/external/pi-tools-suite/src/todo/index.ts +21 -0
- package/external/pi-tools-suite/src/todo/todo.ts +19 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
- package/package.json +7 -8
- package/schemas/pi-tools-suite.json +44 -12
- package/schemas/pix.json +109 -15
- package/schemas/tasks.json +1 -2
- package/skills/simplify/SKILL.md +33 -5
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
- package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
- package/skills/playwright-cli/SKILL.md +0 -420
- package/skills/playwright-cli/references/element-attributes.md +0 -23
- package/skills/playwright-cli/references/playwright-tests.md +0 -50
- package/skills/playwright-cli/references/request-mocking.md +0 -87
- package/skills/playwright-cli/references/running-code.md +0 -241
- package/skills/playwright-cli/references/session-management.md +0 -273
- package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
- package/skills/playwright-cli/references/storage-state.md +0 -290
- package/skills/playwright-cli/references/test-generation.md +0 -142
- package/skills/playwright-cli/references/tracing.md +0 -154
- package/skills/playwright-cli/references/video-recording.md +0 -147
- package/skills/spec-wiki/SKILL.md +0 -55
- package/skills/spec-wiki/evals/evals.json +0 -132
- package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
- package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
- package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
- package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
- package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
- package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
- package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
- package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
- package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
- package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
- package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
- package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
- package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
- package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
- package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
- package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
- package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
- package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
- package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
- package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
- package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
- package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
- package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
- package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
- package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
- package/skills/spec-wiki/evals/trigger-evals.json +0 -94
- package/skills/spec-wiki/references/bootstrap.md +0 -100
- package/skills/spec-wiki/references/focused-spec.md +0 -117
- package/skills/spec-wiki/references/index-schema.md +0 -330
- package/skills/spec-wiki/references/maintenance.md +0 -134
- package/skills/spec-wiki/references/query.md +0 -74
- package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Shared, dependency-free presentation for the extension, TUI and ACP. Plain
|
|
2
|
+
// ESM is intentional: the compiled host can import the shipped extension source
|
|
3
|
+
// without loading TypeScript or bringing the extension runtime into the host.
|
|
4
|
+
|
|
5
|
+
/** @param {any} v */
|
|
6
|
+
const finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
7
|
+
/** @param {any} v */
|
|
8
|
+
const num = (v) => finite(v) ? Math.round(v).toLocaleString("en-US") : "unknown";
|
|
9
|
+
/** @param {any} n @param {any} d */
|
|
10
|
+
const percent = (n, d) => finite(n) && finite(d) && d > 0 ? `${(100 * n / d).toFixed(1)}%` : "unknown";
|
|
11
|
+
/** @param {any} v */
|
|
12
|
+
const mode = (v) => typeof v === "boolean" ? (v ? "on" : "off") : "unknown";
|
|
13
|
+
/** @param {any} m */
|
|
14
|
+
const modelRef = (m) => m?.provider && m?.id ? `${m.provider}/${m.id}` : undefined;
|
|
15
|
+
/** @param {any} v */
|
|
16
|
+
const record = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
17
|
+
|
|
18
|
+
/** Read-only diagnostic reducer. Never runs the pruner, a model, or a mutation.
|
|
19
|
+
* @param {import('./statistics.js').DcpStatisticsInput} input */
|
|
20
|
+
export function collectDcpStatistics(input) {
|
|
21
|
+
const entries = input.branch ?? [];
|
|
22
|
+
const blocks = new Map(), pruned = new Map(), operations = new Map(), measured = new Map();
|
|
23
|
+
let journal = "absent", previous = null, anchors = [], manualMode;
|
|
24
|
+
let epoch, snapshot, lastReminder, ignored, evidenceEpoch = false;
|
|
25
|
+
let projections = 0, attempts = 0, completed = 0, rejected = 0;
|
|
26
|
+
const publishedIds = new Set();
|
|
27
|
+
const attemptIds = new Set(), completionIds = new Set(), manualFailures = new Set();
|
|
28
|
+
const diagnostics = [];
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (entry?.type === "custom" && entry.customType === "dcp-journal") {
|
|
31
|
+
const op = entry.data;
|
|
32
|
+
if (!record(op) || op.schemaVersion !== 1 || !["init", "delta"].includes(op.kind) || typeof op.operationId !== "string") {
|
|
33
|
+
journal = "invalid/unsupported"; break;
|
|
34
|
+
}
|
|
35
|
+
if (operations.has(op.operationId)) {
|
|
36
|
+
if (operations.get(op.operationId) !== JSON.stringify(op)) { journal = "conflicting operations"; break; }
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if ((op.kind === "init" && (previous !== null || op.previousOperationId !== null)) ||
|
|
40
|
+
(op.kind === "delta" && (previous === null || op.previousOperationId !== previous))) {
|
|
41
|
+
journal = "incomplete/broken chain"; break;
|
|
42
|
+
}
|
|
43
|
+
previous = op.operationId;
|
|
44
|
+
operations.set(previous, JSON.stringify(op));
|
|
45
|
+
journal = "chain verified";
|
|
46
|
+
for (const b of op.blocks ?? []) {
|
|
47
|
+
if (!record(b) || !finite(b.id) || typeof b.active !== "boolean" || blocks.has(b.id)) { journal = "invalid blocks"; break; }
|
|
48
|
+
blocks.set(b.id, { ...b });
|
|
49
|
+
const m = b.commitMetrics;
|
|
50
|
+
if (record(m) && typeof m.operationId === "string" && finite(m.netGainTokens) && m.netGainTokens > 0 &&
|
|
51
|
+
finite(m.beforeTokens) && finite(m.afterTokens) && m.beforeTokens - m.afterTokens === m.netGainTokens) measured.set(m.operationId, m);
|
|
52
|
+
}
|
|
53
|
+
if (journal !== "chain verified") break;
|
|
54
|
+
for (const update of op.blockStates ?? []) {
|
|
55
|
+
const b = blocks.get(update.id);
|
|
56
|
+
if (!b || typeof update.active !== "boolean" || (!b.active && update.active)) { journal = "invalid block states"; break; }
|
|
57
|
+
b.active = update.active;
|
|
58
|
+
}
|
|
59
|
+
if (journal !== "chain verified") break;
|
|
60
|
+
for (const p of op.prunedTools ?? []) if (typeof p?.toolCallId === "string") pruned.set(p.toolCallId, p);
|
|
61
|
+
if (Array.isArray(op.nudgeAnchors)) {
|
|
62
|
+
anchors = op.nudgeAnchors;
|
|
63
|
+
for (const anchor of anchors) publishedIds.add(anchor.id);
|
|
64
|
+
}
|
|
65
|
+
if (typeof op.manualMode === "boolean") manualMode = op.manualMode;
|
|
66
|
+
}
|
|
67
|
+
if (entry?.type === "custom" && entry.customType === "dcp-nudge") {
|
|
68
|
+
const e = entry.data;
|
|
69
|
+
if (["emitted", "reapplied", "upgraded"].includes(e?.event)) { projections++; lastReminder = e; }
|
|
70
|
+
}
|
|
71
|
+
if (entry?.type === "custom" && entry.customType === "dcp-diagnostic" && entry.data?.version === 1) diagnostics.push(entry.data);
|
|
72
|
+
if (entry?.type === "message" && entry.message?.role === "toolResult" && entry.message.toolName === "compress" && entry.message.isError) {
|
|
73
|
+
manualFailures.add(entry.message.toolCallId ?? entry.id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Epoch markers invalidate live measurements/evidence, not durable history.
|
|
77
|
+
for (const d of diagnostics) {
|
|
78
|
+
if (d.event === "epoch") { epoch = d.epoch; snapshot = undefined; ignored = 0; evidenceEpoch = true; }
|
|
79
|
+
if (d.event === "request" && d.epoch === epoch) {
|
|
80
|
+
snapshot = d.snapshot;
|
|
81
|
+
if (finite(snapshot?.ignored)) ignored = snapshot.ignored;
|
|
82
|
+
if (d.reminder && !attemptIds.has(d.id)) { attempts++; attemptIds.add(d.id); }
|
|
83
|
+
}
|
|
84
|
+
if (d.event === "completion" && d.epoch === epoch && !completionIds.has(d.id) && (!d.reminder || attemptIds.has(d.id))) {
|
|
85
|
+
if (d.reminder) completed++;
|
|
86
|
+
completionIds.add(d.id); ignored = d.ignored;
|
|
87
|
+
}
|
|
88
|
+
if (d.event === "auto-rejected") rejected++;
|
|
89
|
+
}
|
|
90
|
+
const valid = journal === "chain verified" && input.historyStatus !== "unavailable";
|
|
91
|
+
const all = valid ? [...blocks.values()] : [];
|
|
92
|
+
const active = all.filter((b) => b.active);
|
|
93
|
+
const activity = { manual: new Set(), auto: new Set(), consolidation: new Set(), unknownBlocks: 0 };
|
|
94
|
+
for (const b of all) {
|
|
95
|
+
const kind = b.commitMetrics?.kind ?? (b.createdByToolCallId ? "manual" : b.autoSummaryRepresentation
|
|
96
|
+
? ((b.coveredBlockIds?.length ?? 0) >= 2 && b.sourceCoverage?.itemCount === b.coveredBlockIds.length ? "consolidation" : "auto") : undefined);
|
|
97
|
+
const bucket = kind === "manual" ? activity.manual : kind === "auto" ? activity.auto : kind === "consolidation" ? activity.consolidation : undefined;
|
|
98
|
+
if (bucket) bucket.add(b.commitMetrics?.operationId ?? (kind === "manual" ? `manual:${b.createdByToolCallId}` : `auto:${b.id}`));
|
|
99
|
+
else activity.unknownBlocks++;
|
|
100
|
+
}
|
|
101
|
+
const currentWindow = input.model?.contextWindow;
|
|
102
|
+
const snapshotMatchesModel = snapshot && modelRef(input.model) === snapshot.model &&
|
|
103
|
+
(!finite(currentWindow) || currentWindow === snapshot.contextWindow);
|
|
104
|
+
return { valid, journal, operations: operations.size, all, active, pruned: valid ? pruned.size : undefined,
|
|
105
|
+
summaryTokens: valid && active.every((b) => finite(b.summaryTokenEstimate)) ? active.reduce((s,b) => s + b.summaryTokenEstimate, 0) : undefined,
|
|
106
|
+
manualMode, activity, measured: valid ? measured.size : undefined,
|
|
107
|
+
measuredGain: valid && measured.size ? [...measured.values()].reduce((s,m) => s + m.netGainTokens, 0) : valid && all.length === 0 ? 0 : undefined,
|
|
108
|
+
snapshot: snapshotMatchesModel ? snapshot : undefined, snapshotStale: Boolean(snapshot && !snapshotMatchesModel),
|
|
109
|
+
published: publishedIds.size, projections, attempts: evidenceEpoch ? attempts : undefined, completed: evidenceEpoch ? completed : undefined,
|
|
110
|
+
ignored: snapshotMatchesModel ? ignored : undefined, anchors: valid ? anchors : [], lastReminder,
|
|
111
|
+
rejected: evidenceEpoch ? rejected : undefined, manualFailures: manualFailures.size };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** @param {import('./statistics.js').DcpStatisticsInput} input */
|
|
115
|
+
export function formatDcpStatistics(input) {
|
|
116
|
+
let s;
|
|
117
|
+
try { s = collectDcpStatistics(input); }
|
|
118
|
+
catch { return "DCP Session Statistics\n\nHistory unavailable: malformed diagnostic/journal records. No zero statistics inferred."; }
|
|
119
|
+
const usage = input.usage ?? {}, m = input.model, snap = s.snapshot;
|
|
120
|
+
const window = finite(m?.contextWindow) && m.contextWindow > 0 ? m.contextWindow : usage.contextWindow;
|
|
121
|
+
const lines = ["DCP Session Statistics:", "Context",
|
|
122
|
+
` Model: ${modelRef(m) ?? "unknown"}`,
|
|
123
|
+
` SDK usage: ${num(usage.tokens)} / ${num(window)} (${percent(usage.tokens, window)}; may lag)`,
|
|
124
|
+
];
|
|
125
|
+
if (snap) {
|
|
126
|
+
lines.push(` Last DCP request: ~${num(snap.projectedTokens)} tokens; ${snap.pressure} (${snap.reason})`,
|
|
127
|
+
` Input capacity: ${num(snap.inputCapacityTokens)}; reserved output: ${num(snap.reservedOutputTokens)}`,
|
|
128
|
+
` Resolved thresholds: routine ${percent(snap.routineTokens, snap.contextWindow)} / strong ${percent(snap.strongTokens, snap.contextWindow)} / hard ${percent(snap.hardTokens, snap.contextWindow)}`,
|
|
129
|
+
` Modes (last request): DCP ${mode(snap.enabled)}, manual ${mode(snap.manualMode)}, auto ${mode(snap.autoEnabled)}`,
|
|
130
|
+
` Snapshot: ${finite(snap.createdAt) && Math.abs(snap.createdAt) < 8.64e15 ? new Date(snap.createdAt).toISOString() : "unknown time"} (last request)`);
|
|
131
|
+
} else lines.push(` DCP budget/thresholds: ${s.snapshotStale ? "stale (model/window changed); awaiting projection" : "not recorded; awaiting projection"}`);
|
|
132
|
+
lines.push("History projection (active branch)");
|
|
133
|
+
if (!s.valid) {
|
|
134
|
+
lines.push(` Unavailable: ${input.historyStatus === "unavailable" ? "full history could not be read" : s.journal}`,
|
|
135
|
+
" Blocks, gains and reminders: unknown (not zero)");
|
|
136
|
+
return lines.join("\n");
|
|
137
|
+
}
|
|
138
|
+
lines.push(` Blocks: ${s.active.length} active / ${s.all.length - s.active.length} retired / ${s.all.length} total`,
|
|
139
|
+
` Active summaries: ~${num(s.summaryTokens)} tokens; result bodies pruned: ${num(s.pruned)}`);
|
|
140
|
+
if (snap) lines.push(` Input/projection: ~${num(snap.rawTokens)} -> ~${num(snap.projectedTokens)} (reduction ~${num(snap.rawTokens - snap.projectedTokens)})`);
|
|
141
|
+
lines.push("Compression activity",
|
|
142
|
+
` Commits: ${s.activity.manual.size} model/tool, ${s.activity.auto.size} auto, ${s.activity.consolidation.size} consolidations`);
|
|
143
|
+
if (s.activity.unknownBlocks) lines.push(` Provenance unknown: ${s.activity.unknownBlocks} blocks`);
|
|
144
|
+
lines.push(` Measured commit gain: ${num(s.measuredGain)} tokens (${num(s.measured)} measured commits)`,
|
|
145
|
+
` Rejections recorded: ${num(s.rejected)} auto; ${num(s.manualFailures)} failed compress results`,
|
|
146
|
+
"Reminder delivery",
|
|
147
|
+
` Anchors journaled: ${s.published}; projection events: ${s.projections} (not sends)`,
|
|
148
|
+
` Recorded provider attempts with reminder: ${num(s.attempts)}`,
|
|
149
|
+
` confirmed completed opportunities: ${num(s.completed)}`,
|
|
150
|
+
` Outstanding consecutive opportunities (last sample): ${num(s.ignored)}`,
|
|
151
|
+
` Active anchors: ${s.anchors.length}${s.anchors.length ? " (" + s.anchors.map((/** @type {any} */ a) => `${a.type}/${a.anchorRole ?? "unknown carrier"}`).join(", ") + ")" : ""}`,
|
|
152
|
+
` Last published/reapplied: ${s.lastReminder ? `${s.lastReminder.type} / ${s.lastReminder.anchorRole ?? "unknown carrier"}` : "none recorded"}`,
|
|
153
|
+
`Journal: ${s.journal} (${s.operations} records); full active branch`,
|
|
154
|
+
"Estimates, not billing. Old unmeasured gains/deliveries excluded.");
|
|
155
|
+
return lines.join("\n");
|
|
156
|
+
}
|
|
@@ -19,8 +19,10 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
19
19
|
"notify": true
|
|
20
20
|
},
|
|
21
21
|
// Context Gateway is off by default. observe is passive telemetry; enforce
|
|
22
|
-
//
|
|
23
|
-
//
|
|
22
|
+
// compacts recognised complete simple test/build output and over-budget
|
|
23
|
+
// structured web_search/web_fetch results whose raw details remain recoverable
|
|
24
|
+
// from the append-only session. Reads/repo and unsupported result shapes stay
|
|
25
|
+
// producer-owned passthrough/native-compact.
|
|
24
26
|
"contextGateway": {
|
|
25
27
|
"mode": "off",
|
|
26
28
|
"budgets": {
|
|
@@ -57,6 +59,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
57
59
|
// Vision-capable model used by the coding-discipline lookup tool for blind-model
|
|
58
60
|
// screenshot/image questions. Remove or set to null to disable lookup.
|
|
59
61
|
"lookupModel": "zai/glm-5.3-flash",
|
|
62
|
+
"lookupFallbackModels": [],
|
|
60
63
|
"terminalBell": { "sound": true },
|
|
61
64
|
// comment-checker: nudges the agent to remove AI-slop code comments it just
|
|
62
65
|
// added via write/edit/apply_patch. Net-new comments are classified and a
|
|
@@ -94,29 +97,43 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
94
97
|
}
|
|
95
98
|
},
|
|
96
99
|
"modelOverrides": {
|
|
100
|
+
// DCP policy reviewed 2026-09-14. Engineering starting points, not
|
|
101
|
+
// provider-certified optima. Keep candidate/message availability aligned
|
|
102
|
+
// with each model's routine compression threshold.
|
|
97
103
|
"openai-codex/gpt-5*": {
|
|
98
104
|
"compress": {
|
|
99
105
|
"minContextPercent": "26%",
|
|
100
|
-
"maxContextPercent": "46%"
|
|
106
|
+
"maxContextPercent": "46%",
|
|
107
|
+
"autoCandidates": { "minContextPercent": 0.26 },
|
|
108
|
+
"messageMode": { "minContextPercent": 0.26 }
|
|
101
109
|
}
|
|
102
110
|
},
|
|
103
111
|
"openai-codex/gpt-5.4-mini": {
|
|
104
112
|
"compress": {
|
|
105
113
|
"minContextPercent": "20%",
|
|
106
|
-
"maxContextPercent": "38%"
|
|
114
|
+
"maxContextPercent": "38%",
|
|
115
|
+
"autoCandidates": { "minContextPercent": 0.20 },
|
|
116
|
+
"messageMode": { "minContextPercent": 0.20 }
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"openai-codex/gpt-6-astra": {
|
|
120
|
+
"compress": {
|
|
121
|
+
"minContextPercent": "26%",
|
|
122
|
+
"maxContextPercent": "46%",
|
|
123
|
+
"autoCandidates": { "minContextPercent": 0.26 },
|
|
124
|
+
"messageMode": { "minContextPercent": 0.26 }
|
|
107
125
|
}
|
|
108
126
|
},
|
|
109
127
|
"zai/*": {
|
|
110
128
|
"compress": {
|
|
111
129
|
"minContextPercent": "16%",
|
|
112
|
-
"maxContextPercent": "30%"
|
|
130
|
+
"maxContextPercent": "30%",
|
|
131
|
+
"autoCandidates": { "minContextPercent": 0.16 },
|
|
132
|
+
"messageMode": { "minContextPercent": 0.16 }
|
|
113
133
|
}
|
|
114
134
|
},
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
// observed 14h/273K-token session never crossed 16%. Lower ONLY glm-5.3
|
|
118
|
-
// within the zai family: 8%/15% (~80K/150K) so nudging starts early and
|
|
119
|
-
// auto-compress fires at the observed degradation point. Other zai/*
|
|
135
|
+
// GLM-5.3 and GLM-5.3-Flash expose ~1M-token windows. Use 8%/15%
|
|
136
|
+
// (~80K/~150K) as a conservative long-session policy while other zai/*
|
|
120
137
|
// models keep 16%/30%.
|
|
121
138
|
"zai/glm-5.3": {
|
|
122
139
|
"compress": {
|
|
@@ -126,34 +143,68 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
126
143
|
"messageMode": { "minContextPercent": 0.08 }
|
|
127
144
|
}
|
|
128
145
|
},
|
|
146
|
+
"zai/glm-5.3-flash": {
|
|
147
|
+
"compress": {
|
|
148
|
+
"minContextPercent": "8%",
|
|
149
|
+
"maxContextPercent": "15%",
|
|
150
|
+
"autoCandidates": { "minContextPercent": 0.08 },
|
|
151
|
+
"messageMode": { "minContextPercent": 0.08 }
|
|
152
|
+
}
|
|
153
|
+
},
|
|
129
154
|
"antigravity/*sonnet*": {
|
|
130
155
|
"compress": {
|
|
131
156
|
"minContextPercent": "22%",
|
|
132
|
-
"maxContextPercent": "40%"
|
|
157
|
+
"maxContextPercent": "40%",
|
|
158
|
+
"autoCandidates": { "minContextPercent": 0.22 },
|
|
159
|
+
"messageMode": { "minContextPercent": 0.22 }
|
|
133
160
|
}
|
|
134
161
|
},
|
|
135
162
|
"antigravity/gemini-3.1-pro*": {
|
|
136
163
|
"compress": {
|
|
137
164
|
"minContextPercent": "24%",
|
|
138
|
-
"maxContextPercent": "42%"
|
|
165
|
+
"maxContextPercent": "42%",
|
|
166
|
+
"autoCandidates": { "minContextPercent": 0.24 },
|
|
167
|
+
"messageMode": { "minContextPercent": 0.24 }
|
|
139
168
|
}
|
|
140
169
|
},
|
|
141
170
|
"antigravity/gemini-3-flash*": {
|
|
142
171
|
"compress": {
|
|
143
172
|
"minContextPercent": "18%",
|
|
144
|
-
"maxContextPercent": "34%"
|
|
173
|
+
"maxContextPercent": "34%",
|
|
174
|
+
"autoCandidates": { "minContextPercent": 0.18 },
|
|
175
|
+
"messageMode": { "minContextPercent": 0.18 }
|
|
145
176
|
}
|
|
146
177
|
},
|
|
147
178
|
"antigravity/gemini-2.5-flash*": {
|
|
148
179
|
"compress": {
|
|
149
180
|
"minContextPercent": "18%",
|
|
150
|
-
"maxContextPercent": "32%"
|
|
181
|
+
"maxContextPercent": "32%",
|
|
182
|
+
"autoCandidates": { "minContextPercent": 0.18 },
|
|
183
|
+
"messageMode": { "minContextPercent": 0.18 }
|
|
151
184
|
}
|
|
152
185
|
},
|
|
153
186
|
"antigravity/antigravity-claude-opus-4-6-thinking": {
|
|
154
187
|
"compress": {
|
|
155
188
|
"minContextPercent": "26%",
|
|
156
|
-
"maxContextPercent": "44%"
|
|
189
|
+
"maxContextPercent": "44%",
|
|
190
|
+
"autoCandidates": { "minContextPercent": 0.26 },
|
|
191
|
+
"messageMode": { "minContextPercent": 0.26 }
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"antigravity/antigravity-gemini-3.1-pro": {
|
|
195
|
+
"compress": {
|
|
196
|
+
"minContextPercent": "24%",
|
|
197
|
+
"maxContextPercent": "42%",
|
|
198
|
+
"autoCandidates": { "minContextPercent": 0.24 },
|
|
199
|
+
"messageMode": { "minContextPercent": 0.24 }
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"antigravity/antigravity-gemini-3.8-flash": {
|
|
203
|
+
"compress": {
|
|
204
|
+
"minContextPercent": "18%",
|
|
205
|
+
"maxContextPercent": "34%",
|
|
206
|
+
"autoCandidates": { "minContextPercent": 0.18 },
|
|
207
|
+
"messageMode": { "minContextPercent": 0.18 }
|
|
157
208
|
}
|
|
158
209
|
}
|
|
159
210
|
},
|
|
@@ -168,7 +219,8 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
168
219
|
"autoCompress": {
|
|
169
220
|
"enabled": false,
|
|
170
221
|
"patience": 2,
|
|
171
|
-
"summarizerModel": ["zai/glm-5-turbo"
|
|
222
|
+
"summarizerModel": ["zai/glm-5-turbo"],
|
|
223
|
+
"summarizerFallbackModels": ["openai-codex/gpt-5.6-luna"],
|
|
172
224
|
"timeoutMs": 20000
|
|
173
225
|
}
|
|
174
226
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, statSync } from "node:fs";
|
|
1
|
+
import { accessSync, constants, existsSync, statSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
4
|
export function directoryExists(file: string): boolean {
|
|
@@ -40,3 +40,38 @@ export function findIndexedProjectRoot(cwd: string): string | undefined {
|
|
|
40
40
|
export function hasIndexedProjectRoot(cwd: string = process.cwd()): boolean {
|
|
41
41
|
return findIndexedProjectRoot(cwd) !== undefined;
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
export function commandAvailable(command: string, env: NodeJS.ProcessEnv = process.env): boolean {
|
|
45
|
+
const value = command.trim();
|
|
46
|
+
if (!value || value.includes("/") || value.includes("\\")) return false;
|
|
47
|
+
const pathValue = env.PATH ?? "";
|
|
48
|
+
const candidates = process.platform === "win32"
|
|
49
|
+
? [
|
|
50
|
+
value,
|
|
51
|
+
...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
|
|
52
|
+
.split(";")
|
|
53
|
+
.map((extension) => extension.trim())
|
|
54
|
+
.filter(Boolean)
|
|
55
|
+
.map((extension) => `${value}${extension.startsWith(".") ? extension : `.${extension}`}`),
|
|
56
|
+
]
|
|
57
|
+
: [value];
|
|
58
|
+
for (const directory of pathValue.split(path.delimiter)) {
|
|
59
|
+
if (!directory) continue;
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
try {
|
|
62
|
+
accessSync(path.join(directory, candidate), constants.X_OK);
|
|
63
|
+
return true;
|
|
64
|
+
} catch {
|
|
65
|
+
// Continue through PATH without spawning a process or blocking on shell lookup.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function hasAvailableIndexedProjectRoot(
|
|
73
|
+
cwd: string = process.cwd(),
|
|
74
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
75
|
+
): boolean {
|
|
76
|
+
return hasIndexedProjectRoot(cwd) && commandAvailable("idx", env);
|
|
77
|
+
}
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
import { realpath } from "node:fs/promises";
|
|
16
16
|
import { resolve } from "node:path";
|
|
17
17
|
import { Type, type TSchema } from "typebox";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
18
|
+
import { REPO_DISCOVERY_TOOL_NAMES, claudeAliasToolDescriptions, codexAliasToolDescriptions } from "../tool-descriptions";
|
|
19
|
+
import { hasAvailableIndexedProjectRoot } from "../lib/project.js";
|
|
20
20
|
import { applyPatch } from "./apply-patch";
|
|
21
21
|
import { isPathInside } from "./path-utils";
|
|
22
22
|
import {
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from "./tool-args";
|
|
33
33
|
|
|
34
34
|
const CLAUDE_ALIAS_TOOL_DESCRIPTIONS = claudeAliasToolDescriptions(false);
|
|
35
|
+
const CODEX_ALIAS_TOOL_DESCRIPTIONS = codexAliasToolDescriptions(false);
|
|
35
36
|
const CLAUDE_ALIAS_TOOLS = Object.values(CLAUDE_ALIAS_TOOL_DESCRIPTIONS).map((tool) => tool.name);
|
|
36
37
|
const CODEX_ALIAS_TOOLS = ["read", ...Object.values(CODEX_ALIAS_TOOL_DESCRIPTIONS).map((tool) => tool.name)];
|
|
37
38
|
const BUILTIN_TOOLS = ["read", "bash", "edit", "write", "grep", "find", "ls"] as const;
|
|
@@ -379,7 +380,8 @@ async function runShellAlias(
|
|
|
379
380
|
return tool.execute(id, { command, timeout: timeoutSeconds(input) }, signal, onUpdate, ctx);
|
|
380
381
|
}
|
|
381
382
|
|
|
382
|
-
function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): void {
|
|
383
|
+
function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI, repoDiscovery: boolean): void {
|
|
384
|
+
const descriptions = codexAliasToolDescriptions(repoDiscovery);
|
|
383
385
|
const shellParameters = Type.Object({
|
|
384
386
|
command: Type.String({ description: "The shell script to execute in the user's default shell" }),
|
|
385
387
|
workdir: Type.Optional(Type.String({ description: "Working directory" })),
|
|
@@ -390,7 +392,7 @@ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): voi
|
|
|
390
392
|
|
|
391
393
|
pi.registerTool(
|
|
392
394
|
defineTool({
|
|
393
|
-
...
|
|
395
|
+
...descriptions.shellCommand,
|
|
394
396
|
parameters: shellParameters,
|
|
395
397
|
renderCall: (args, theme, context) => renderShellAliasCall(runtime, args, theme, context),
|
|
396
398
|
renderResult: (result, options, theme, context) => renderShellAliasResult(runtime, result, options, theme, context),
|
|
@@ -402,7 +404,7 @@ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): voi
|
|
|
402
404
|
|
|
403
405
|
pi.registerTool(
|
|
404
406
|
defineTool({
|
|
405
|
-
...
|
|
407
|
+
...descriptions.applyPatch,
|
|
406
408
|
parameters: Type.Object({
|
|
407
409
|
input: Type.String({ description: "Complete patch text: either a unified diff or a Begin Patch block" }),
|
|
408
410
|
}),
|
|
@@ -457,8 +459,9 @@ function shouldPreserveSelection(env: NodeJS.ProcessEnv = process.env): boolean
|
|
|
457
459
|
|
|
458
460
|
export default function modelTools(pi: ExtensionAPI, dependencies: Partial<ModelToolsDependencies> = {}): void {
|
|
459
461
|
const runtime = createModelToolsRuntime(dependencies);
|
|
460
|
-
|
|
461
|
-
|
|
462
|
+
const repoDiscovery = hasAvailableIndexedProjectRoot();
|
|
463
|
+
registerClaudeAliases(runtime, pi, repoDiscovery);
|
|
464
|
+
registerCodexAliases(runtime, pi, repoDiscovery);
|
|
462
465
|
|
|
463
466
|
let baseTools: string[] = [];
|
|
464
467
|
|