@gaunt-sloth/core 2.0.0-alpha.9 → 2.0.0-beta.1
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/.gsloth.review.md +2 -0
- package/README.md +71 -20
- package/dist/config/colour.d.ts +38 -0
- package/dist/config/colour.js +36 -0
- package/dist/config/colour.js.map +1 -0
- package/dist/config/configDiscovery.d.ts +79 -0
- package/dist/config/configDiscovery.js +80 -0
- package/dist/config/configDiscovery.js.map +1 -0
- package/dist/config/defaults.d.ts +20 -20
- package/dist/config/defaults.js +10 -8
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/filesystem-tools.d.ts +41 -0
- package/dist/config/filesystem-tools.js +56 -0
- package/dist/config/filesystem-tools.js.map +1 -0
- package/dist/config/loader.d.ts +171 -19
- package/dist/config/loader.js +1054 -144
- package/dist/config/loader.js.map +1 -1
- package/dist/config/mouse.d.ts +50 -0
- package/dist/config/mouse.js +44 -0
- package/dist/config/mouse.js.map +1 -0
- package/dist/config/profiles.d.ts +68 -0
- package/dist/config/profiles.js +93 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/providerKeys.d.ts +69 -0
- package/dist/config/providerKeys.js +69 -0
- package/dist/config/providerKeys.js.map +1 -0
- package/dist/config/schema.d.ts +2671 -138
- package/dist/config/schema.js +1361 -85
- package/dist/config/schema.js.map +1 -1
- package/dist/config/shell-policy.d.ts +899 -111
- package/dist/config/shell-policy.js +800 -70
- package/dist/config/shell-policy.js.map +1 -1
- package/dist/config/tool-descriptions.d.ts +211 -0
- package/dist/config/tool-descriptions.js +272 -0
- package/dist/config/tool-descriptions.js.map +1 -0
- package/dist/config/types.d.ts +352 -41
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/config.d.ts +35 -1
- package/dist/config.js +16 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +28 -1
- package/dist/constants.js +28 -1
- package/dist/constants.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +166 -11
- package/dist/core/GthAbstractAgent.js +484 -45
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +543 -57
- package/dist/core/GthAgentRunner.js +1494 -140
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/GthLangChainAgent.d.ts +117 -2
- package/dist/core/GthLangChainAgent.js +602 -29
- package/dist/core/GthLangChainAgent.js.map +1 -1
- package/dist/core/approvals/annotations.d.ts +122 -0
- package/dist/core/approvals/annotations.js +137 -0
- package/dist/core/approvals/annotations.js.map +1 -0
- package/dist/core/approvals/grants.d.ts +216 -0
- package/dist/core/approvals/grants.js +469 -0
- package/dist/core/approvals/grants.js.map +1 -0
- package/dist/core/approvals/matcher.d.ts +202 -0
- package/dist/core/approvals/matcher.js +267 -0
- package/dist/core/approvals/matcher.js.map +1 -0
- package/dist/core/approvals/mcpSubjects.d.ts +40 -0
- package/dist/core/approvals/mcpSubjects.js +99 -0
- package/dist/core/approvals/mcpSubjects.js.map +1 -0
- package/dist/core/approvals/promptHeader.d.ts +28 -0
- package/dist/core/approvals/promptHeader.js +62 -0
- package/dist/core/approvals/promptHeader.js.map +1 -0
- package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
- package/dist/core/approvals/toolAnnotationSources.js +277 -0
- package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
- package/dist/core/approvals/toolHost.d.ts +46 -0
- package/dist/core/approvals/toolHost.js +108 -0
- package/dist/core/approvals/toolHost.js.map +1 -0
- package/dist/core/debugCapture.d.ts +74 -0
- package/dist/core/debugCapture.js +100 -0
- package/dist/core/debugCapture.js.map +1 -0
- package/dist/core/gthLeanAgentFactory.d.ts +4 -4
- package/dist/core/gthLeanAgentFactory.js +4 -4
- package/dist/core/launchBanner.d.ts +127 -0
- package/dist/core/launchBanner.js +414 -0
- package/dist/core/launchBanner.js.map +1 -0
- package/dist/core/modelLabel.d.ts +19 -0
- package/dist/core/modelLabel.js +26 -0
- package/dist/core/modelLabel.js.map +1 -0
- package/dist/core/plainToolIndication.d.ts +15 -0
- package/dist/core/plainToolIndication.js +174 -0
- package/dist/core/plainToolIndication.js.map +1 -0
- package/dist/core/reasoningBlocks.d.ts +65 -0
- package/dist/core/reasoningBlocks.js +103 -0
- package/dist/core/reasoningBlocks.js.map +1 -0
- package/dist/core/refusal.d.ts +53 -0
- package/dist/core/refusal.js +133 -0
- package/dist/core/refusal.js.map +1 -0
- package/dist/core/runHeader.d.ts +38 -0
- package/dist/core/runHeader.js +42 -0
- package/dist/core/runHeader.js.map +1 -0
- package/dist/core/runStats.d.ts +14 -3
- package/dist/core/runStats.js +48 -3
- package/dist/core/runStats.js.map +1 -1
- package/dist/core/shell/ShellCommandFailedError.d.ts +3 -4
- package/dist/core/shell/ShellCommandFailedError.js +3 -4
- package/dist/core/shell/ShellCommandFailedError.js.map +1 -1
- package/dist/core/shell/abstention.d.ts +88 -0
- package/dist/core/shell/abstention.js +184 -0
- package/dist/core/shell/abstention.js.map +1 -0
- package/dist/core/shell/approvalCapture.d.ts +271 -0
- package/dist/core/shell/approvalCapture.js +108 -0
- package/dist/core/shell/approvalCapture.js.map +1 -0
- package/dist/core/shell/approvalStop.d.ts +123 -0
- package/dist/core/shell/approvalStop.js +269 -0
- package/dist/core/shell/approvalStop.js.map +1 -0
- package/dist/core/shell/arity.d.ts +6 -0
- package/dist/core/shell/arity.js +20 -6
- package/dist/core/shell/arity.js.map +1 -1
- package/dist/core/shell/denylist.d.ts +11 -0
- package/dist/core/shell/denylist.js +37 -0
- package/dist/core/shell/denylist.js.map +1 -0
- package/dist/core/shell/escalationSeverity.d.ts +141 -0
- package/dist/core/shell/escalationSeverity.js +89 -0
- package/dist/core/shell/escalationSeverity.js.map +1 -0
- package/dist/core/shell/framing.d.ts +190 -0
- package/dist/core/shell/framing.js +633 -0
- package/dist/core/shell/framing.js.map +1 -0
- package/dist/core/shell/hardline.d.ts +103 -0
- package/dist/core/shell/hardline.js +780 -0
- package/dist/core/shell/hardline.js.map +1 -0
- package/dist/core/shell/negotiation.d.ts +328 -0
- package/dist/core/shell/negotiation.js +488 -0
- package/dist/core/shell/negotiation.js.map +1 -0
- package/dist/core/shell/normalize.d.ts +44 -4
- package/dist/core/shell/normalize.js +61 -7
- package/dist/core/shell/normalize.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +263 -0
- package/dist/core/shell/openWorld.js +1188 -0
- package/dist/core/shell/openWorld.js.map +1 -0
- package/dist/core/shell/rater.d.ts +873 -0
- package/dist/core/shell/rater.js +1454 -0
- package/dist/core/shell/rater.js.map +1 -0
- package/dist/core/shell/raterModel.d.ts +41 -0
- package/dist/core/shell/raterModel.js +51 -0
- package/dist/core/shell/raterModel.js.map +1 -0
- package/dist/core/shell/raterVocabulary.d.ts +121 -0
- package/dist/core/shell/raterVocabulary.js +116 -0
- package/dist/core/shell/raterVocabulary.js.map +1 -0
- package/dist/core/shell/rejection.d.ts +69 -0
- package/dist/core/shell/rejection.js +38 -0
- package/dist/core/shell/rejection.js.map +1 -0
- package/dist/core/toolCallRepair/grammar.d.ts +41 -0
- package/dist/core/toolCallRepair/grammar.js +116 -0
- package/dist/core/toolCallRepair/grammar.js.map +1 -0
- package/dist/core/toolCallRepair/index.d.ts +2 -0
- package/dist/core/toolCallRepair/index.js +7 -0
- package/dist/core/toolCallRepair/index.js.map +1 -0
- package/dist/core/toolCallRepair/payload.d.ts +36 -0
- package/dist/core/toolCallRepair/payload.js +341 -0
- package/dist/core/toolCallRepair/payload.js.map +1 -0
- package/dist/core/toolCallRepair/promote.d.ts +45 -0
- package/dist/core/toolCallRepair/promote.js +90 -0
- package/dist/core/toolCallRepair/promote.js.map +1 -0
- package/dist/core/toolDisplay.d.ts +123 -0
- package/dist/core/toolDisplay.js +451 -0
- package/dist/core/toolDisplay.js.map +1 -0
- package/dist/core/toolOutputChannel.d.ts +95 -0
- package/dist/core/toolOutputChannel.js +165 -0
- package/dist/core/toolOutputChannel.js.map +1 -0
- package/dist/core/types.d.ts +349 -16
- package/dist/core/types.js.map +1 -1
- package/dist/history/historyFormat.d.ts +12 -3
- package/dist/history/historyFormat.js +50 -8
- package/dist/history/historyFormat.js.map +1 -1
- package/dist/history/historyStore.d.ts +77 -0
- package/dist/history/historyStore.js +173 -6
- package/dist/history/historyStore.js.map +1 -1
- package/dist/history/recordSession.d.ts +10 -1
- package/dist/history/recordSession.js +27 -0
- package/dist/history/recordSession.js.map +1 -1
- package/dist/providers/anthropic.js +12 -0
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/configurationPassthrough.d.ts +107 -0
- package/dist/providers/configurationPassthrough.js +148 -0
- package/dist/providers/configurationPassthrough.js.map +1 -0
- package/dist/providers/geminiSchemaSanitizer.d.ts +55 -0
- package/dist/providers/geminiSchemaSanitizer.js +347 -0
- package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
- package/dist/providers/geminiThinking.d.ts +60 -0
- package/dist/providers/geminiThinking.js +92 -0
- package/dist/providers/geminiThinking.js.map +1 -0
- package/dist/providers/google-genai.js +18 -1
- package/dist/providers/google-genai.js.map +1 -1
- package/dist/providers/groq.js +12 -0
- package/dist/providers/groq.js.map +1 -1
- package/dist/providers/huggingface.d.ts +25 -0
- package/dist/providers/huggingface.js +69 -0
- package/dist/providers/huggingface.js.map +1 -0
- package/dist/providers/modelCatalog.d.ts +109 -0
- package/dist/providers/modelCatalog.js +245 -0
- package/dist/providers/modelCatalog.js.map +1 -0
- package/dist/providers/modelDiscovery.d.ts +99 -5
- package/dist/providers/modelDiscovery.js +191 -35
- package/dist/providers/modelDiscovery.js.map +1 -1
- package/dist/providers/ollama.d.ts +18 -4
- package/dist/providers/ollama.js +67 -37
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.js +34 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +26 -4
- package/dist/providers/openrouter.js +83 -26
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/vertexai.js +19 -1
- package/dist/providers/vertexai.js.map +1 -1
- package/dist/providers/xai.js +20 -0
- package/dist/providers/xai.js.map +1 -1
- package/dist/runtime/askStructured.d.ts +105 -0
- package/dist/runtime/askStructured.js +120 -0
- package/dist/runtime/askStructured.js.map +1 -0
- package/dist/runtime/conversation.d.ts +64 -0
- package/dist/runtime/conversation.js +171 -0
- package/dist/runtime/conversation.js.map +1 -0
- package/dist/runtime/singleShot.d.ts +37 -6
- package/dist/runtime/singleShot.js +113 -67
- package/dist/runtime/singleShot.js.map +1 -1
- package/dist/runtime/structuredOutput.d.ts +104 -0
- package/dist/runtime/structuredOutput.js +393 -0
- package/dist/runtime/structuredOutput.js.map +1 -0
- package/dist/utils/ProgressIndicator.d.ts +21 -0
- package/dist/utils/ProgressIndicator.js +30 -3
- package/dist/utils/ProgressIndicator.js.map +1 -1
- package/dist/utils/aiignoreUtils.js.map +1 -1
- package/dist/utils/binaryOutputUtils.js.map +1 -1
- package/dist/utils/consoleUtils.d.ts +95 -0
- package/dist/utils/consoleUtils.js +112 -2
- package/dist/utils/consoleUtils.js.map +1 -1
- package/dist/utils/crashHandler.d.ts +87 -0
- package/dist/utils/crashHandler.js +128 -0
- package/dist/utils/crashHandler.js.map +1 -0
- package/dist/utils/debugDump.d.ts +134 -0
- package/dist/utils/debugDump.js +381 -0
- package/dist/utils/debugDump.js.map +1 -0
- package/dist/utils/debugUtils.d.ts +13 -4
- package/dist/utils/debugUtils.js +36 -13
- package/dist/utils/debugUtils.js.map +1 -1
- package/dist/utils/displayWidth.d.ts +53 -0
- package/dist/utils/displayWidth.js +195 -0
- package/dist/utils/displayWidth.js.map +1 -0
- package/dist/utils/fileUtils.js.map +1 -1
- package/dist/utils/globalConfigUtils.d.ts +14 -2
- package/dist/utils/globalConfigUtils.js +22 -4
- package/dist/utils/globalConfigUtils.js.map +1 -1
- package/dist/utils/llmUtils.d.ts +39 -8
- package/dist/utils/llmUtils.js +76 -8
- package/dist/utils/llmUtils.js.map +1 -1
- package/dist/utils/redactSecrets.d.ts +63 -0
- package/dist/utils/redactSecrets.js +286 -0
- package/dist/utils/redactSecrets.js.map +1 -0
- package/dist/utils/systemPromptNotes.d.ts +222 -0
- package/dist/utils/systemPromptNotes.js +338 -0
- package/dist/utils/systemPromptNotes.js.map +1 -0
- package/dist/utils/systemUtils.d.ts +18 -1
- package/dist/utils/systemUtils.js +38 -3
- package/dist/utils/systemUtils.js.map +1 -1
- package/dist/utils/toolMatching.d.ts +30 -0
- package/dist/utils/toolMatching.js +44 -0
- package/dist/utils/toolMatching.js.map +1 -0
- package/dist/utils/untrustedText.d.ts +86 -0
- package/dist/utils/untrustedText.js +101 -0
- package/dist/utils/untrustedText.js.map +1 -0
- package/package.json +21 -7
- package/schema/gsloth-config.schema.json +1921 -326
- package/dist/core/shell/allowlist.d.ts +0 -75
- package/dist/core/shell/allowlist.js +0 -187
- package/dist/core/shell/allowlist.js.map +0 -1
- package/dist/core/shell/judge.d.ts +0 -161
- package/dist/core/shell/judge.js +0 -261
- package/dist/core/shell/judge.js.map +0 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { inspect } from 'node:util';
|
|
5
|
+
import { ensureGlobalGslothDir } from '#src/utils/globalConfigUtils.js';
|
|
6
|
+
import { env, getSlothVersion } from '#src/utils/systemUtils.js';
|
|
7
|
+
import { getDebugLogBuffer } from '#src/utils/debugUtils.js';
|
|
8
|
+
import { REDACTED, collectSecretValues, redactText, redactValue, } from '#src/utils/redactSecrets.js';
|
|
9
|
+
/**
|
|
10
|
+
* Best-effort git repo state (branch/remote/dirty). Uses `execFileSync` — NOT the existing
|
|
11
|
+
* `execAsync` helper in systemUtils.ts (a promisified wrapper used elsewhere for `gh` calls) —
|
|
12
|
+
* because `SlashCommand.run()` is fully synchronous (no Promise support in the TUI's registry or
|
|
13
|
+
* dispatcher). Fails soft: any failure (not inside a repo, `git` missing, a detached/bare repo
|
|
14
|
+
* with no remote, etc.) returns `undefined` rather than throwing, so the command never errors —
|
|
15
|
+
* the git-state file is simply omitted from the archive.
|
|
16
|
+
*/
|
|
17
|
+
function collectGitState(cwd) {
|
|
18
|
+
try {
|
|
19
|
+
const run = (args) => execFileSync('git', args, {
|
|
20
|
+
cwd,
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
23
|
+
}).trim();
|
|
24
|
+
const branch = run(['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
25
|
+
let remote;
|
|
26
|
+
try {
|
|
27
|
+
remote = run(['remote', 'get-url', 'origin']);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
remote = undefined; // no `origin` remote configured — not fatal, just omit it
|
|
31
|
+
}
|
|
32
|
+
const status = run(['status', '--porcelain']);
|
|
33
|
+
return { branch, remote, dirty: status.length > 0 };
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined; // not inside a git repo (or git unavailable) — omit the file entirely
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Serialize a value as pretty JSON, tolerating the non-JSON-safe shapes real session state can
|
|
41
|
+
* contain (e.g. the resolved `GthConfig.llm` is a live LangChain client, not plain data):
|
|
42
|
+
* functions/bigints are stringified and circular references are broken rather than throwing.
|
|
43
|
+
* Falls back to `util.inspect` if `JSON.stringify` still fails for some other reason, so writing
|
|
44
|
+
* the dump can never throw partway through the archive.
|
|
45
|
+
*
|
|
46
|
+
* QA-6: `JSON.stringify` returns `undefined` (not a string) for a handful of top-level inputs —
|
|
47
|
+
* notably `undefined` itself, which `DebugDumpInput.config` legitimately is when the caller has
|
|
48
|
+
* no resolved config (verified live via the e2e fixture harness, which wires the real writer with
|
|
49
|
+
* `config` omitted). Passing `undefined` straight to `writeFileSync` throws
|
|
50
|
+
* `ERR_INVALID_ARG_TYPE`, defeating the "never throw partway through the archive" contract this
|
|
51
|
+
* function documents. Fall back to the literal `'null'` in that case, same as `JSON.stringify`
|
|
52
|
+
* would for a *nested* `undefined` value.
|
|
53
|
+
*/
|
|
54
|
+
function safeStringify(value) {
|
|
55
|
+
const seen = new WeakSet();
|
|
56
|
+
try {
|
|
57
|
+
const json = JSON.stringify(value, (_key, val) => {
|
|
58
|
+
if (typeof val === 'function')
|
|
59
|
+
return `[Function: ${val.name || 'anonymous'}]`;
|
|
60
|
+
if (typeof val === 'bigint')
|
|
61
|
+
return val.toString();
|
|
62
|
+
if (val && typeof val === 'object') {
|
|
63
|
+
if (seen.has(val))
|
|
64
|
+
return '[Circular]';
|
|
65
|
+
seen.add(val);
|
|
66
|
+
}
|
|
67
|
+
return val;
|
|
68
|
+
}, 2);
|
|
69
|
+
return json ?? 'null';
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return inspect(value, { showHidden: false, depth: 5, colors: false });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The filesystem-safe directory-name segment for one dump: the ISO timestamp with `:` and `.`
|
|
77
|
+
* (illegal on Windows, noisy everywhere) replaced by `-`. This is the ONLY path component
|
|
78
|
+
* debugDump generates — and the only one it is responsible for sanitizing. The parent it is joined
|
|
79
|
+
* under (the global `~/.gsloth` dir) is supplied by the environment and may legitimately carry a
|
|
80
|
+
* drive-letter colon on Windows (`C:\…`), which is not ours to strip. Exported so the invariant
|
|
81
|
+
* "the generated segment is colon-free" is testable on any platform without asserting anything
|
|
82
|
+
* about the (platform-dependent) parent path (GS2-50).
|
|
83
|
+
*/
|
|
84
|
+
export function debugDumpDirName(date = new Date()) {
|
|
85
|
+
return date.toISOString().replace(/[:.]/g, '-');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* GS2-54 (gap 3) — a live LangChain chat model is detected structurally, NOT by field name: a real
|
|
89
|
+
* `BaseChatModel` exposes `_llmType()` and `invoke()` as functions. This duck-type is the LOAD-BEARING
|
|
90
|
+
* invariant that lets us strip a *live* model to a descriptor (below) WITHOUT also flattening a plain
|
|
91
|
+
* `{ type, model, apiKey }` config object — the latter must keep flowing through {@link redactValue}'s
|
|
92
|
+
* field-masking (key kept, value masked). Do NOT "simplify" this into an unconditional strip.
|
|
93
|
+
*/
|
|
94
|
+
function isLiveChatModel(llm) {
|
|
95
|
+
if (llm == null || typeof llm !== 'object')
|
|
96
|
+
return false;
|
|
97
|
+
const m = llm;
|
|
98
|
+
return typeof m._llmType === 'function' || typeof m.invoke === 'function';
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* GS2-54 (gap 3) — a short, secret-free descriptor for a live chat model, mirroring the spirit of
|
|
102
|
+
* `configCommand.ts`'s `redactConfigForPrint`. Never returns the live object or any of its internals
|
|
103
|
+
* (client instances, cached kwargs, inline keys) — only a `type` + `model` label. Each field probe
|
|
104
|
+
* is guarded so a hostile/exotic getter can't throw out of here.
|
|
105
|
+
*/
|
|
106
|
+
function describeLiveModel(config, llm) {
|
|
107
|
+
const m = llm;
|
|
108
|
+
let type = 'unknown';
|
|
109
|
+
try {
|
|
110
|
+
const t = (typeof m._llmType === 'function' ? m._llmType() : undefined) ??
|
|
111
|
+
(Array.isArray(m.lc_namespace) ? m.lc_namespace.join('/') : undefined) ??
|
|
112
|
+
(typeof config.type === 'string'
|
|
113
|
+
? config.type
|
|
114
|
+
: undefined) ??
|
|
115
|
+
m.constructor?.name;
|
|
116
|
+
if (typeof t === 'string' && t.length > 0)
|
|
117
|
+
type = t;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// keep 'unknown' — a throwing getter must not defeat the strip
|
|
121
|
+
}
|
|
122
|
+
let model = 'unknown';
|
|
123
|
+
try {
|
|
124
|
+
const md = config.modelDisplayName;
|
|
125
|
+
const mdl = (typeof md === 'string' && md.length > 0 ? md : undefined) ??
|
|
126
|
+
(typeof m.model === 'string' ? m.model : undefined) ??
|
|
127
|
+
(typeof m.modelName === 'string' ? m.modelName : undefined);
|
|
128
|
+
if (typeof mdl === 'string' && mdl.length > 0)
|
|
129
|
+
model = mdl;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// keep 'unknown'
|
|
133
|
+
}
|
|
134
|
+
return { type, model };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* GS2-54 (gap 3) + GS2-66 (residual 3) — defense-in-depth for the CONFIG artifact: return a shallow
|
|
138
|
+
* clone of `config` with the LIVE instances stripped to short descriptors so their large internal
|
|
139
|
+
* surface (client objects, cached kwargs, inline keys, and non-secret-NAMED opaque fields the
|
|
140
|
+
* `caCert` class that field-masking cannot catch) never reaches disk — rather than relying on
|
|
141
|
+
* {@link redactValue}'s field-masking alone. Mirrors `configCommand.ts`'s `redactConfigForPrint`:
|
|
142
|
+
* - a *live* `llm` (a `BaseChatModel`) → a `{ type, model }` descriptor;
|
|
143
|
+
* - a `tools` array → `[N tool instance(s)]`;
|
|
144
|
+
* - a `middleware` array → `[N middleware]`.
|
|
145
|
+
* PURE: never mutates the caller's config (a fresh clone is made only if something is stripped).
|
|
146
|
+
* FAIL-SAFE: on any error, or when a field is absent / not a live instance, that field is left as-is
|
|
147
|
+
* so {@link redactValue}'s existing GS2-47 masking still applies (never less-redacted). The `llm`,
|
|
148
|
+
* `tools` and `middleware` strips are independent — `tools`/`middleware` are stripped even when the
|
|
149
|
+
* config carries no live `llm`.
|
|
150
|
+
*/
|
|
151
|
+
function stripLiveInstancesForConfig(config) {
|
|
152
|
+
try {
|
|
153
|
+
if (config == null || typeof config !== 'object' || Array.isArray(config))
|
|
154
|
+
return config;
|
|
155
|
+
const record = config;
|
|
156
|
+
// Clone lazily: only spread into a new object once we know a field is actually being replaced,
|
|
157
|
+
// so a config with no live instances is returned untouched (===).
|
|
158
|
+
let out = record;
|
|
159
|
+
const clone = () => {
|
|
160
|
+
if (out === record)
|
|
161
|
+
out = { ...record };
|
|
162
|
+
return out;
|
|
163
|
+
};
|
|
164
|
+
if ('llm' in record && isLiveChatModel(record.llm)) {
|
|
165
|
+
clone().llm = describeLiveModel(record, record.llm);
|
|
166
|
+
}
|
|
167
|
+
// Hoist before the mutating clone() call so TS keeps the `Array` narrowing on `.length`.
|
|
168
|
+
const tools = record.tools;
|
|
169
|
+
if (Array.isArray(tools)) {
|
|
170
|
+
clone().tools = `[${tools.length} tool instance(s)]`;
|
|
171
|
+
}
|
|
172
|
+
const middleware = record.middleware;
|
|
173
|
+
if (Array.isArray(middleware)) {
|
|
174
|
+
clone().middleware = `[${middleware.length} middleware]`;
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return config; // fail safe: fall back to redactValue over the untouched config
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* GS2-47 — render the CONFIG artifact: {@link redactValue} applies sensitive-field masking (keys
|
|
184
|
+
* kept, values masked) plus literal/pattern string redaction, then {@link safeStringify}. Fail-safe:
|
|
185
|
+
* any throw yields the fully-withheld marker rather than raw content ("redact more on error, never
|
|
186
|
+
* write a raw artifact because redaction hiccuped").
|
|
187
|
+
*
|
|
188
|
+
* GS2-54 (gap 3) + GS2-66 (residual 3) — before redaction, {@link stripLiveInstancesForConfig} swaps
|
|
189
|
+
* a live `llm` for a `{ type, model }` descriptor and the `tools`/`middleware` arrays for count
|
|
190
|
+
* descriptors, so those live instances' internals never serialize. This runs on a fresh clone only;
|
|
191
|
+
* the caller's config (and the {@link collectSecretValues} harvest already taken from it) is
|
|
192
|
+
* untouched, so inline secrets inside those instances are still scrubbed from the OTHER artifacts.
|
|
193
|
+
*/
|
|
194
|
+
function renderConfig(config, redact, secrets) {
|
|
195
|
+
if (!redact)
|
|
196
|
+
return safeStringify(config);
|
|
197
|
+
try {
|
|
198
|
+
return safeStringify(redactValue(stripLiveInstancesForConfig(config), secrets));
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return REDACTED;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* GS2-47 — render a non-config STRUCTURED artifact (transcript, env, git-state): stringify (never
|
|
206
|
+
* throws), then literal/pattern-redact the text. Structural field-masking is intentionally NOT
|
|
207
|
+
* applied here (config-only, per the brief) so a legitimately `token`/`secret`-named field in tool
|
|
208
|
+
* output is not blanket-masked. {@link redactText} is itself fail-safe.
|
|
209
|
+
*/
|
|
210
|
+
function renderStructured(value, redact, secrets) {
|
|
211
|
+
const raw = safeStringify(value);
|
|
212
|
+
return redact ? redactText(raw, secrets) : raw;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Write one timestamped `/debug-dump` archive under the GLOBAL `~/.gsloth/debug-dumps/<timestamp>/`
|
|
216
|
+
* (via `ensureGlobalGslothDir()` — mirrors how `resolveHistoryDbPath()` builds its path under the
|
|
217
|
+
* same dir — NOT the per-project cwd-relative helper of the same name elsewhere in this codebase).
|
|
218
|
+
* Contains: the full transcript, the resolved config, env/version info, the in-memory debugLog
|
|
219
|
+
* ring buffer, and (best-effort) git repo state.
|
|
220
|
+
*
|
|
221
|
+
* GS2-47 — unless `input.redact === false`, the shared secret-redaction pass
|
|
222
|
+
* ({@link file://./redactSecrets.ts}) is applied to EVERY artifact before it is written: the literal
|
|
223
|
+
* values of secret-named env vars + inline config secrets are substituted everywhere, a tight set of
|
|
224
|
+
* provider-key/auth-header patterns is masked, and the config's sensitive fields are masked in place.
|
|
225
|
+
* On opt-out the archive is raw and the caller surfaces the loud "may contain secrets" warning.
|
|
226
|
+
*/
|
|
227
|
+
export function writeDebugDump(input) {
|
|
228
|
+
const redact = input.redact !== false; // default ON; only an explicit `false` opts out
|
|
229
|
+
const timestamp = debugDumpDirName();
|
|
230
|
+
const archiveDir = resolve(ensureGlobalGslothDir(), 'debug-dumps', timestamp);
|
|
231
|
+
mkdirSync(archiveDir, { recursive: true });
|
|
232
|
+
// Technique 1 (load-bearing): the literal secret values to scrub across ALL artifacts, gathered
|
|
233
|
+
// from env (by secret-named var) + the config (apiKeyEnvironmentVariable's target + inline
|
|
234
|
+
// secrets). `env` is the systemUtils accessor (process.env); collection is itself fail-safe.
|
|
235
|
+
const secrets = redact ? collectSecretValues(input.config, env) : [];
|
|
236
|
+
writeFileSync(resolve(archiveDir, 'transcript.json'), renderStructured(input.transcript, redact, secrets), 'utf8');
|
|
237
|
+
writeFileSync(resolve(archiveDir, 'config.json'), renderConfig(input.config, redact, secrets), 'utf8');
|
|
238
|
+
// GS2-56 — the always-on model-request snapshot: WHAT was actually fed to the model (the thing a
|
|
239
|
+
// bug report needs, previously omitted whenever the TUI `/debug` panel wasn't open). Written only
|
|
240
|
+
// when the caller threaded `agent.lastModelRequest` (a model call has happened), so before the
|
|
241
|
+
// first turn these files are simply absent. Both go through `renderStructured` (literal+pattern
|
|
242
|
+
// redaction, like transcript.json/env.json) rather than `renderConfig`'s field-masking, so a
|
|
243
|
+
// legitimately `token`/`secret`-named field inside a tool result or a schema isn't blanket-masked.
|
|
244
|
+
if (input.modelRequest) {
|
|
245
|
+
// model-request.json — the composed system prompt + tool defs (with JSON schema) + model params
|
|
246
|
+
// + tool-choice. `?? {}` keeps the artifact present-but-empty rather than serializing `undefined`.
|
|
247
|
+
writeFileSync(resolve(archiveDir, 'model-request.json'), renderStructured(input.modelRequest.extras ?? {}, redact, secrets), 'utf8');
|
|
248
|
+
// model-messages.json — the EXACT messages sent to the model for the last call (post-
|
|
249
|
+
// summarization / middleware), i.e. what the model actually saw. Deliberately a separate
|
|
250
|
+
// artifact from transcript.json (the conversation view): the two are distinct arrays.
|
|
251
|
+
writeFileSync(resolve(archiveDir, 'model-messages.json'), renderStructured(input.modelRequest.messages ?? [], redact, secrets), 'utf8');
|
|
252
|
+
}
|
|
253
|
+
// [[TUI-C27]] — approvals.json: the gate's own record of every gated decision, INCLUDING the
|
|
254
|
+
// approving branch, which previously left no trace anywhere in this archive. Each entry carries
|
|
255
|
+
// the exact prompt the rater was sent and its raw answer, so a reader can state what the rater was
|
|
256
|
+
// shown as well as what it said — specifically whether the user's own messages were in its view at
|
|
257
|
+
// round N, which is the first question anyone asks of a negotiation and the one no artifact here
|
|
258
|
+
// could answer. Same `renderStructured` pass as transcript.json (see `WriteDebugDumpInput`).
|
|
259
|
+
// Written only when there is something to write, so a session that gated nothing omits the file
|
|
260
|
+
// rather than shipping an empty array that reads as "the gate recorded nothing".
|
|
261
|
+
if (input.approvals && input.approvals.length > 0) {
|
|
262
|
+
writeFileSync(resolve(archiveDir, 'approvals.json'), renderStructured(input.approvals, redact, secrets), 'utf8');
|
|
263
|
+
}
|
|
264
|
+
// getSlothVersion() reads the installed package.json via the install dir set at CLI startup
|
|
265
|
+
// (setEntryPoint); guarded so a dump can never fail just because that wasn't wired (e.g. an
|
|
266
|
+
// unusual embedding), falling back to 'unknown'.
|
|
267
|
+
let gthVersion;
|
|
268
|
+
try {
|
|
269
|
+
gthVersion = getSlothVersion();
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
gthVersion = 'unknown';
|
|
273
|
+
}
|
|
274
|
+
const envInfo = {
|
|
275
|
+
gthVersion,
|
|
276
|
+
nodeVersion: process.version,
|
|
277
|
+
platform: process.platform,
|
|
278
|
+
model: input.modelDisplayName ?? 'unknown',
|
|
279
|
+
};
|
|
280
|
+
writeFileSync(resolve(archiveDir, 'env.json'), renderStructured(envInfo, redact, secrets), 'utf8');
|
|
281
|
+
writeFileSync(resolve(archiveDir, 'debug-log.txt'), redact ? redactText(getDebugLogBuffer().join('\n'), secrets) : getDebugLogBuffer().join('\n'), 'utf8');
|
|
282
|
+
const gitState = collectGitState(input.cwd ?? process.cwd());
|
|
283
|
+
if (gitState) {
|
|
284
|
+
writeFileSync(resolve(archiveDir, 'git-state.json'), renderStructured(gitState, redact, secrets), 'utf8');
|
|
285
|
+
}
|
|
286
|
+
return { archiveDir };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* GS2-48 — how many trailing lines of the always-on in-memory debugLog ring buffer
|
|
290
|
+
* ({@link file://./debugUtils.ts}, cap {@link DEBUG_LOG_BUFFER_MAX} = 1000) the crash snapshot keeps.
|
|
291
|
+
* The buffer itself is the "always-on capture" the crash handler relies on (nothing is written to
|
|
292
|
+
* disk until a crash — O(N) memory, zero steady-state I/O); the snapshot copies only this TAIL to
|
|
293
|
+
* stay MINIMAL (a crash file is a triage artifact, not the full session). 200 is enough to show what
|
|
294
|
+
* the agent was doing in the moments before death without bloating the file.
|
|
295
|
+
*/
|
|
296
|
+
const CRASH_DEBUG_LOG_TAIL_LINES = 200;
|
|
297
|
+
/**
|
|
298
|
+
* GS2-48 — flatten a thrown value (or a rejection reason, which need not be an `Error`) into a plain
|
|
299
|
+
* object BEFORE redaction. `Error.message`/`Error.stack` are NON-ENUMERABLE, so `Object.entries`
|
|
300
|
+
* (which {@link redactValue} walks with) would silently drop them — the crash file would carry no
|
|
301
|
+
* error and no stack. Explicitly copying them here is what makes the error survive the redaction pass.
|
|
302
|
+
* Tolerates a non-Error reason (string / number / object / undefined) without throwing.
|
|
303
|
+
*/
|
|
304
|
+
function normalizeError(error) {
|
|
305
|
+
if (error instanceof Error) {
|
|
306
|
+
return { name: error.name, message: error.message, stack: error.stack };
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
return {
|
|
310
|
+
name: 'NonError',
|
|
311
|
+
message: typeof error === 'string' ? error : safeStringify(error),
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return { name: 'NonError', message: String(error) };
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* GS2-48 — write a MINIMAL, ALWAYS-REDACTED crash snapshot to
|
|
320
|
+
* `~/.gsloth/debug-dumps/crash-<timestamp>/crash.json` and return its paths.
|
|
321
|
+
*
|
|
322
|
+
* This is the unattended sibling of {@link writeDebugDump}: it fires from the process-level crash
|
|
323
|
+
* handler ({@link file://./crashHandler.ts}) with no human present, so — unlike `/debug-dump` — it
|
|
324
|
+
* exposes NO `redact` opt-out. Redaction (GS2-47, hard-dep) is MANDATORY and applied to the whole
|
|
325
|
+
* snapshot. It reuses this module's location convention (`ensureGlobalGslothDir()` + `debug-dumps/`)
|
|
326
|
+
* and rendering helpers, but deliberately stays minimal and crash-safe:
|
|
327
|
+
* - a SINGLE `crash.json` (not the multi-file interactive archive);
|
|
328
|
+
* - it does NOT shell out for git state (a subprocess is unsafe/slow while the process is dying);
|
|
329
|
+
* - it keeps only the last {@link CRASH_DEBUG_LOG_TAIL_LINES} debugLog lines and the transcript TAIL.
|
|
330
|
+
*
|
|
331
|
+
* Redaction shape (conscious choice): the entire normalized snapshot is passed through
|
|
332
|
+
* {@link redactValue} in one pass. That is stricter than {@link writeDebugDump}, which uses
|
|
333
|
+
* {@link redactText} (literal+pattern only) for its non-config artifacts to avoid field-masking a
|
|
334
|
+
* legitimately `token`/`secret`-named field in tool output. For an unattended crash file the
|
|
335
|
+
* over-masking is the SAFE direction and buys uniform circular-ref / depth / function handling in
|
|
336
|
+
* one place, so it is intended, not an oversight. The config subtree is stripped of live instances
|
|
337
|
+
* first (as `writeDebugDump` does) so a live LLM client's internals never serialize.
|
|
338
|
+
*
|
|
339
|
+
* Callers wrap this in their own try/catch (see {@link file://./crashHandler.ts}); it does its best
|
|
340
|
+
* to be fail-safe internally (`redactValue`/`safeStringify` never throw), but the ONE unavoidably
|
|
341
|
+
* throwing operation is the `mkdirSync`/`writeFileSync` to disk — an unwritable `~/.gsloth` is what
|
|
342
|
+
* the handler's degraded path is for.
|
|
343
|
+
*/
|
|
344
|
+
export function writeCrashSnapshot(input) {
|
|
345
|
+
const crashDir = resolve(ensureGlobalGslothDir(), 'debug-dumps', `crash-${debugDumpDirName()}`);
|
|
346
|
+
mkdirSync(crashDir, { recursive: true });
|
|
347
|
+
// Redaction is unconditional here (no opt-out) — gather the literal secret values to scrub from
|
|
348
|
+
// env + config, exactly as writeDebugDump does. `env` is the systemUtils accessor (process.env).
|
|
349
|
+
const secrets = collectSecretValues(input.config, env);
|
|
350
|
+
let gthVersion;
|
|
351
|
+
try {
|
|
352
|
+
gthVersion = getSlothVersion();
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
gthVersion = 'unknown';
|
|
356
|
+
}
|
|
357
|
+
const snapshot = {
|
|
358
|
+
kind: 'crash',
|
|
359
|
+
origin: input.origin,
|
|
360
|
+
timestamp: new Date().toISOString(),
|
|
361
|
+
// Flattened to plain enumerable fields so message/stack survive the redaction walk.
|
|
362
|
+
error: normalizeError(input.error),
|
|
363
|
+
env: {
|
|
364
|
+
gthVersion,
|
|
365
|
+
nodeVersion: process.version,
|
|
366
|
+
platform: process.platform,
|
|
367
|
+
model: input.modelDisplayName ?? 'unknown',
|
|
368
|
+
},
|
|
369
|
+
// Strip live LLM/tool/middleware instances to short descriptors before redaction (as the
|
|
370
|
+
// interactive config artifact does), so their internals never reach disk. `?? null` so an
|
|
371
|
+
// absent config serializes as an explicit `null` (JSON drops an `undefined`-valued key).
|
|
372
|
+
config: stripLiveInstancesForConfig(input.config) ?? null,
|
|
373
|
+
debugLogTail: getDebugLogBuffer().slice(-CRASH_DEBUG_LOG_TAIL_LINES),
|
|
374
|
+
transcriptTail: input.transcriptTail ?? null,
|
|
375
|
+
};
|
|
376
|
+
// Single fail-safe redaction pass over the whole normalized snapshot (see doc above).
|
|
377
|
+
const crashFile = resolve(crashDir, 'crash.json');
|
|
378
|
+
writeFileSync(crashFile, safeStringify(redactValue(snapshot, secrets)), 'utf8');
|
|
379
|
+
return { crashDir, crashFile };
|
|
380
|
+
}
|
|
381
|
+
//# sourceMappingURL=debugDump.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugDump.js","sourceRoot":"","sources":["../../src/utils/debugDump.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GS2-46 — read the current debug-log ring buffer (oldest first). Returns a copy so callers
|
|
3
|
+
* (e.g. the `/debug-dump` writer) can't mutate the live buffer.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDebugLogBuffer(): string[];
|
|
1
6
|
/**
|
|
2
7
|
* Initialize debug logging based on config
|
|
3
8
|
*/
|
|
4
9
|
export declare function initDebugLogging(enabled: boolean): void;
|
|
5
10
|
/**
|
|
6
|
-
* Log a debug message
|
|
11
|
+
* Log a debug message. Always pushed into the in-memory ring buffer (GS2-46); only appended to
|
|
12
|
+
* the on-disk log file when debug logging is enabled.
|
|
7
13
|
*/
|
|
8
14
|
export declare function debugLog(message: string): void;
|
|
9
15
|
/**
|
|
10
|
-
* Log multiple lines with proper formatting
|
|
16
|
+
* Log multiple lines with proper formatting. Always buffered (GS2-46); delegates to `debugLog`
|
|
17
|
+
* for the on-disk gating.
|
|
11
18
|
*/
|
|
12
19
|
export declare function debugLogMultiline(title: string, content: string): void;
|
|
13
20
|
/**
|
|
14
|
-
* Log an object using Node.js inspect with reasonable depth
|
|
21
|
+
* Log an object using Node.js inspect with reasonable depth. Always buffered (GS2-46); delegates
|
|
22
|
+
* to `debugLogMultiline`/`debugLog` for the on-disk gating.
|
|
15
23
|
*/
|
|
16
24
|
export declare function debugLogObject(title: string, obj: unknown): void;
|
|
17
25
|
/**
|
|
18
|
-
* Log error with stack trace
|
|
26
|
+
* Log error with stack trace. Always buffered (GS2-46); delegates to `debugLog` for the on-disk
|
|
27
|
+
* gating.
|
|
19
28
|
*/
|
|
20
29
|
export declare function debugLogError(context: string, error: unknown): void;
|
package/dist/utils/debugUtils.js
CHANGED
|
@@ -3,6 +3,30 @@ import { dirname, resolve } from 'node:path';
|
|
|
3
3
|
import { inspect } from 'node:util';
|
|
4
4
|
const DEBUG_LOG_FILE = 'gaunt-sloth.log';
|
|
5
5
|
let debugEnabled = false;
|
|
6
|
+
/**
|
|
7
|
+
* GS2-46 — bounded in-memory ring buffer of debug-log lines, populated by every `debugLog*`
|
|
8
|
+
* variant UNCONDITIONALLY (independent of `debugEnabled`, which only gates the on-disk write
|
|
9
|
+
* below). This is deliberately always-on and forward-looking: GS2-48 (crash handler) expects
|
|
10
|
+
* "the last-N debugLog buffer lines already held in memory" to exist regardless of whether
|
|
11
|
+
* `config.debugLog` was ever turned on for the session, and `/debug-dump` (GS2-46) surfaces it
|
|
12
|
+
* verbatim. Capped so a long session can't grow this without bound.
|
|
13
|
+
*/
|
|
14
|
+
const DEBUG_LOG_BUFFER_MAX = 1000;
|
|
15
|
+
const debugLogBuffer = [];
|
|
16
|
+
/** Push one formatted line into the ring buffer, evicting the oldest entry once at capacity. */
|
|
17
|
+
function pushToDebugLogBuffer(entry) {
|
|
18
|
+
debugLogBuffer.push(entry);
|
|
19
|
+
if (debugLogBuffer.length > DEBUG_LOG_BUFFER_MAX) {
|
|
20
|
+
debugLogBuffer.shift();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* GS2-46 — read the current debug-log ring buffer (oldest first). Returns a copy so callers
|
|
25
|
+
* (e.g. the `/debug-dump` writer) can't mutate the live buffer.
|
|
26
|
+
*/
|
|
27
|
+
export function getDebugLogBuffer() {
|
|
28
|
+
return [...debugLogBuffer];
|
|
29
|
+
}
|
|
6
30
|
/**
|
|
7
31
|
* Initialize debug logging based on config
|
|
8
32
|
*/
|
|
@@ -27,15 +51,17 @@ export function initDebugLogging(enabled) {
|
|
|
27
51
|
}
|
|
28
52
|
}
|
|
29
53
|
/**
|
|
30
|
-
* Log a debug message
|
|
54
|
+
* Log a debug message. Always pushed into the in-memory ring buffer (GS2-46); only appended to
|
|
55
|
+
* the on-disk log file when debug logging is enabled.
|
|
31
56
|
*/
|
|
32
57
|
export function debugLog(message) {
|
|
58
|
+
const timestamp = new Date().toISOString();
|
|
59
|
+
const logEntry = `[${timestamp}] ${message}`;
|
|
60
|
+
pushToDebugLogBuffer(logEntry);
|
|
33
61
|
if (!debugEnabled)
|
|
34
62
|
return;
|
|
35
|
-
const timestamp = new Date().toISOString();
|
|
36
|
-
const logEntry = `[${timestamp}] ${message}\n`;
|
|
37
63
|
try {
|
|
38
|
-
appendFileSync(resolve(DEBUG_LOG_FILE), logEntry
|
|
64
|
+
appendFileSync(resolve(DEBUG_LOG_FILE), `${logEntry}\n`, 'utf8');
|
|
39
65
|
}
|
|
40
66
|
catch (error) {
|
|
41
67
|
// Ignore logging errors to prevent breaking the main flow
|
|
@@ -43,21 +69,19 @@ export function debugLog(message) {
|
|
|
43
69
|
}
|
|
44
70
|
}
|
|
45
71
|
/**
|
|
46
|
-
* Log multiple lines with proper formatting
|
|
72
|
+
* Log multiple lines with proper formatting. Always buffered (GS2-46); delegates to `debugLog`
|
|
73
|
+
* for the on-disk gating.
|
|
47
74
|
*/
|
|
48
75
|
export function debugLogMultiline(title, content) {
|
|
49
|
-
if (!debugEnabled)
|
|
50
|
-
return;
|
|
51
76
|
debugLog(`=== ${title} ===`);
|
|
52
77
|
debugLog(content);
|
|
53
78
|
debugLog(`=== End ${title} ===\n`);
|
|
54
79
|
}
|
|
55
80
|
/**
|
|
56
|
-
* Log an object using Node.js inspect with reasonable depth
|
|
81
|
+
* Log an object using Node.js inspect with reasonable depth. Always buffered (GS2-46); delegates
|
|
82
|
+
* to `debugLogMultiline`/`debugLog` for the on-disk gating.
|
|
57
83
|
*/
|
|
58
84
|
export function debugLogObject(title, obj) {
|
|
59
|
-
if (!debugEnabled)
|
|
60
|
-
return;
|
|
61
85
|
try {
|
|
62
86
|
// Use Node.js inspect with reasonable depth and no colors for log files
|
|
63
87
|
const formatted = inspect(obj, { showHidden: false, depth: 3, colors: false });
|
|
@@ -68,11 +92,10 @@ export function debugLogObject(title, obj) {
|
|
|
68
92
|
}
|
|
69
93
|
}
|
|
70
94
|
/**
|
|
71
|
-
* Log error with stack trace
|
|
95
|
+
* Log error with stack trace. Always buffered (GS2-46); delegates to `debugLog` for the on-disk
|
|
96
|
+
* gating.
|
|
72
97
|
*/
|
|
73
98
|
export function debugLogError(context, error) {
|
|
74
|
-
if (!debugEnabled)
|
|
75
|
-
return;
|
|
76
99
|
debugLog(`❌ Error in ${context}:`);
|
|
77
100
|
if (error instanceof Error) {
|
|
78
101
|
debugLog(` Message: ${error.message}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debugUtils.js","sourceRoot":"","sources":["../../src/utils/debugUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AACzC,IAAI,YAAY,GAAG,KAAK,CAAC;AAEzB;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,YAAY,GAAG,OAAO,CAAC;IACvB,IAAI,YAAY,EAAE,CAAC;QACjB,uCAAuC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC;YACH,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,6DAA6D;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8CAA8C;QAChD,CAAC;QAED,qBAAqB;QACrB,QAAQ,CAAC,mCAAmC,CAAC,CAAC;QAC9C,QAAQ,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACnD,QAAQ,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC;QACjC,QAAQ,CAAC,oCAAoC,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"debugUtils.js","sourceRoot":"","sources":["../../src/utils/debugUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal columns `text` occupies. Zero-width clusters (combining marks, default-ignorables)
|
|
3
|
+
* count 0, wide clusters (CJK, emoji, fullwidth forms) count 2, everything else 1. ANSI escape
|
|
4
|
+
* sequences are not counted, so a pre-coloured string measures as what the user sees — but the
|
|
5
|
+
* slices below do not share that awareness, so do not read this as a licence to feed them one.
|
|
6
|
+
*/
|
|
7
|
+
export declare function displayWidth(text: string): number;
|
|
8
|
+
/**
|
|
9
|
+
* Terminal columns `text` occupies **at most** — the same measurement as {@link displayWidth} but
|
|
10
|
+
* counting East-Asian Ambiguous characters as two columns rather than one, which is the widest any
|
|
11
|
+
* terminal will render them.
|
|
12
|
+
*
|
|
13
|
+
* For a budget that must hold on a terminal whose ambiguous-width policy is unknown, this is the
|
|
14
|
+
* only sound ruler: it is the supremum over the policies a terminal can be configured with, so a
|
|
15
|
+
* string that fits under it fits under all of them. See the module docblock for when to reach for
|
|
16
|
+
* this rather than {@link displayWidth}.
|
|
17
|
+
*/
|
|
18
|
+
export declare function maxDisplayWidth(text: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* The first grapheme cluster of `text`, or `''` when it is empty — i.e. the smallest piece a cut
|
|
21
|
+
* can leave behind, for a caller that has to make progress through a string one drawable glyph at
|
|
22
|
+
* a time.
|
|
23
|
+
*/
|
|
24
|
+
export declare function firstCluster(text: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* The longest LEADING run of whole clusters whose total width is at most `maxWidth` — i.e. keep
|
|
27
|
+
* the head, lose the tail. Total (never throws): a non-positive `maxWidth` yields `''`.
|
|
28
|
+
*
|
|
29
|
+
* A cluster is kept only if it fits ENTIRELY, so the result can come back one column short of
|
|
30
|
+
* `maxWidth` when the next cluster is two columns wide. That is the point: half a wide glyph
|
|
31
|
+
* cannot be drawn, and spending the column anyway is how text over-runs its budget.
|
|
32
|
+
*
|
|
33
|
+
* The clusters are produced one at a time and the walk stops at the budget, so the cost is the
|
|
34
|
+
* length of the RESULT rather than the length of the input — the input here is a whole tool-output
|
|
35
|
+
* line, which is unbounded.
|
|
36
|
+
*/
|
|
37
|
+
export declare function sliceToWidth(text: string, maxWidth: number): string;
|
|
38
|
+
/**
|
|
39
|
+
* {@link sliceToWidth} measured by {@link maxDisplayWidth} — the head that fits the budget on any
|
|
40
|
+
* terminal, whatever it does with Ambiguous characters. The cut for a budget that must hold rather
|
|
41
|
+
* than merely look right.
|
|
42
|
+
*/
|
|
43
|
+
export declare function sliceToMaxWidth(text: string, maxWidth: number): string;
|
|
44
|
+
/**
|
|
45
|
+
* The longest TRAILING run of whole clusters whose total width is at most `maxWidth` — i.e. keep
|
|
46
|
+
* the tail, lose the head. The mirror of {@link sliceToWidth}, for values whose end is the
|
|
47
|
+
* informative part (a path's leaf directory).
|
|
48
|
+
*
|
|
49
|
+
* This one materialises the clusters: it walks backwards, and cluster boundaries are only
|
|
50
|
+
* derivable from the front. Its callers pass a path or a model id, so the input is a line rather
|
|
51
|
+
* than a file.
|
|
52
|
+
*/
|
|
53
|
+
export declare function sliceEndToWidth(text: string, maxWidth: number): string;
|