token-goat 2.6.5 → 2.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/token-goat.mjs +260 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -328,9 +328,9 @@ This writes `.pi/extensions/token-goat.ts` in the current project only. Remove i
|
|
|
328
328
|
token-goat install --copilot
|
|
329
329
|
```
|
|
330
330
|
|
|
331
|
-
The `--copilot` flag patches Claude Code and registers a Copilot CLI hook config: `~/.copilot/hooks/token-goat.json` (a `{ version, hooks }` file registering `preToolUse`, `postToolUse`, `preCompact`, `agentStop`, and `
|
|
331
|
+
The `--copilot` flag patches Claude Code and registers a Copilot CLI hook config: `~/.copilot/hooks/token-goat.json` (a `{ version, hooks }` file registering `preToolUse`, `postToolUse`, `preCompact`, `agentStop`, `subagentStop`, and `userPromptSubmitted`, per Copilot's own [hooks reference](https://docs.github.com/en/copilot/reference/hooks-reference)) plus the shim script it points at, `~/.copilot/hooks/token-goat-shim.js`. Unlike Codex, Copilot's event names and response schema (`permissionDecision`/`modifiedArgs` for `preToolUse`, `modifiedResult`/`additionalContext` for `postToolUse`, `decision`/`reason` for `agentStop`/`subagentStop`) genuinely differ from Claude Code's, so the shim translates rather than passes through.
|
|
332
332
|
|
|
333
|
-
What works: **bash output compression and re-read denial** (`preToolUse` returns `modifiedArgs` or `permissionDecision: "deny"`), **image shrinking and post-edit indexing** (`postToolUse` returns `additionalContext`), and
|
|
333
|
+
What works: **bash output compression and re-read denial** (`preToolUse` returns `modifiedArgs` or `permissionDecision: "deny"`), **image shrinking and post-edit indexing** (`postToolUse` returns `additionalContext`), and **stop-hallucination logging** (`agentStop`/`subagentStop` map a token-goat `deny` onto `decision: "block"`, everything else onto `decision: "allow"`). `preCompact` and `userPromptSubmitted` are notification-only on real Copilot CLI, per its docs: Copilot never reads a response body for either, so token-goat's compaction manifest and prompt-context hints have no surfacing channel there. The shim still calls through for both so token-goat's internal side effects keep running, but nothing gets injected back into the agent. Copilot's built-in tool names (`shell`, `read`, `write`, `url`, `memory`, and MCP-server calls) are remapped onto token-goat's internal names where a clear match exists (`shell`→Bash, `read`→Read, `write`→Write, `url`→WebFetch); `memory` and MCP tool calls pass through unmapped and simply no-op.
|
|
334
334
|
|
|
335
335
|
No ambient environment variable documents "this process is running under Copilot CLI" the way Codex/opencode set one, so the shim sets `TOKEN_GOAT_HARNESS_OVERRIDE=copilot_cli` itself before calling `token-goat hook` (same workaround `--pi` uses). To install for one project instead of user scope: `token-goat install --copilot --local` (writes `.github/hooks/token-goat.json` in the current project). To remove: `token-goat uninstall --copilot`.
|
|
336
336
|
|
package/dist/token-goat.mjs
CHANGED
|
@@ -137045,7 +137045,7 @@ init_define_import_meta_env();
|
|
|
137045
137045
|
import { createRequire } from "node:module";
|
|
137046
137046
|
function resolveVersion() {
|
|
137047
137047
|
if (true) {
|
|
137048
|
-
return "2.6.
|
|
137048
|
+
return "2.6.6";
|
|
137049
137049
|
}
|
|
137050
137050
|
const require2 = createRequire(import.meta.url);
|
|
137051
137051
|
const pkg = require2("../package.json");
|
|
@@ -140157,29 +140157,85 @@ var COPILOT_CLI_HOOK_SCRIPT = `#!/usr/bin/env node
|
|
|
140157
140157
|
const { spawnSync } = require('node:child_process')
|
|
140158
140158
|
|
|
140159
140159
|
// Copilot event name -> token-goat internal HookEventName (src/types.ts's
|
|
140160
|
-
// HOOK_EVENTS). Only these
|
|
140161
|
-
// Copilot event (sessionEnd,
|
|
140162
|
-
//
|
|
140163
|
-
//
|
|
140164
|
-
//
|
|
140165
|
-
//
|
|
140166
|
-
//
|
|
140160
|
+
// HOOK_EVENTS). Only these six have a token-goat handler; every other real
|
|
140161
|
+
// Copilot event (sessionEnd, postToolUseFailure, subagentStart,
|
|
140162
|
+
// errorOccurred, notification, permissionRequest) is left unimplemented
|
|
140163
|
+
// rather than guessed at, and falls through to the default no-op below.
|
|
140164
|
+
// 'sessionStart' is handled as a permanent no-op even though it's a real
|
|
140165
|
+
// Copilot event, because token-goat has no internal session_start handler
|
|
140166
|
+
// (mirrors PI_EXTENSION_SCRIPT's documented precedent).
|
|
140167
140167
|
const COPILOT_TO_TG_EVENT = {
|
|
140168
140168
|
preToolUse: 'pre_tool_use',
|
|
140169
140169
|
postToolUse: 'post_tool_use',
|
|
140170
140170
|
preCompact: 'pre_compact',
|
|
140171
140171
|
agentStop: 'stop',
|
|
140172
140172
|
subagentStop: 'subagent_stop',
|
|
140173
|
+
userPromptSubmitted: 'user_prompt_submit',
|
|
140174
|
+
}
|
|
140175
|
+
|
|
140176
|
+
// Copilot built-in tool name -> token-goat internal tool name. Confirmed via
|
|
140177
|
+
// @github/copilot-sdk type definitions and multiple real GitHub issue payload
|
|
140178
|
+
// dumps -- supersedes an earlier docs-based guess (shell/read/write/url) that
|
|
140179
|
+
// didn't hold up in practice; 'write' in particular was never a real
|
|
140180
|
+
// toolName value, only a Copilot permission-pattern keyword. 'powershell'
|
|
140181
|
+
// maps to the same 'Bash' handler as 'bash' since both are shell-command
|
|
140182
|
+
// execution from token-goat's perspective (mirrors how hooks_bash.ts's own
|
|
140183
|
+
// filters already treat powershell-wrapped commands as part of the Bash
|
|
140184
|
+
// pipeline, not a separate tool). 'task', 'ask_user', 'memory', and
|
|
140185
|
+
// MCP-server tool invocations (<server-name>-<tool-name>) have no
|
|
140186
|
+
// token-goat equivalent and are passed through unmapped (safe no-op for
|
|
140187
|
+
// handlers that don't recognize the name).
|
|
140188
|
+
const TOOL_TO_TG = {
|
|
140189
|
+
bash: 'Bash',
|
|
140190
|
+
powershell: 'Bash',
|
|
140191
|
+
view: 'Read',
|
|
140192
|
+
create: 'Write',
|
|
140193
|
+
edit: 'Edit',
|
|
140194
|
+
web_fetch: 'WebFetch',
|
|
140195
|
+
grep: 'Grep',
|
|
140196
|
+
glob: 'Glob',
|
|
140197
|
+
}
|
|
140198
|
+
|
|
140199
|
+
// Confirmed via github/copilot-cli#3349 (open, unresolved as of writing): some
|
|
140200
|
+
// real Copilot CLI invocations send toolArgs as a JSON-*encoded string*
|
|
140201
|
+
// rather than a parsed object, contradicting the documented schema. Left
|
|
140202
|
+
// unhandled, canonical.tool_input would become a raw string and every
|
|
140203
|
+
// downstream event.toolInput[key] lookup in token-goat's handlers would
|
|
140204
|
+
// silently return undefined -- the deny/dedup mechanism would no-op with no
|
|
140205
|
+
// error surfaced. Parse it defensively; on a non-string, absent, or
|
|
140206
|
+
// unparsable value, fall back to {} rather than throwing (this shim's
|
|
140207
|
+
// convention throughout is fail-open, never crash on a malformed payload).
|
|
140208
|
+
function parseMaybeJsonObject(value) {
|
|
140209
|
+
if (value && typeof value === 'object') return value
|
|
140210
|
+
if (typeof value === 'string') {
|
|
140211
|
+
try {
|
|
140212
|
+
const parsed = JSON.parse(value)
|
|
140213
|
+
if (parsed && typeof parsed === 'object') return parsed
|
|
140214
|
+
} catch {
|
|
140215
|
+
// fall through to {}
|
|
140216
|
+
}
|
|
140217
|
+
}
|
|
140218
|
+
return {}
|
|
140173
140219
|
}
|
|
140174
140220
|
|
|
140175
|
-
//
|
|
140176
|
-
//
|
|
140177
|
-
//
|
|
140178
|
-
|
|
140179
|
-
|
|
140180
|
-
|
|
140181
|
-
|
|
140182
|
-
|
|
140221
|
+
// view/edit/create send the file path under 'path'; every token-goat handler these
|
|
140222
|
+
// three tools reach only ever looks for 'file_path' (getFilePath in hooks_common.ts).
|
|
140223
|
+
// Keyed by the ORIGINAL Copilot tool name (before TOOL_TO_TG renames it) since that's
|
|
140224
|
+
// the name toolArgs' shape is keyed to, not token-goat's internal tool name.
|
|
140225
|
+
const FILE_PATH_ARG_KEY = {
|
|
140226
|
+
view: 'path',
|
|
140227
|
+
edit: 'path',
|
|
140228
|
+
create: 'path',
|
|
140229
|
+
}
|
|
140230
|
+
|
|
140231
|
+
function remapToolInput(copilotToolName, input) {
|
|
140232
|
+
const pathKey = FILE_PATH_ARG_KEY[copilotToolName]
|
|
140233
|
+
if (pathKey === undefined || !input || typeof input !== 'object' || !(pathKey in input)) {
|
|
140234
|
+
return input
|
|
140235
|
+
}
|
|
140236
|
+
// Add file_path alongside the original key rather than renaming it, so nothing that
|
|
140237
|
+
// might read the original 'path' key elsewhere (e.g. a future handler) loses it.
|
|
140238
|
+
return Object.assign({}, input, { file_path: input[pathKey] })
|
|
140183
140239
|
}
|
|
140184
140240
|
|
|
140185
140241
|
function main() {
|
|
@@ -140219,7 +140275,25 @@ function main() {
|
|
|
140219
140275
|
}
|
|
140220
140276
|
if (toolName) {
|
|
140221
140277
|
canonical.tool_name = TOOL_TO_TG[toolName] || toolName
|
|
140222
|
-
canonical.tool_input = (payload && payload.toolArgs)
|
|
140278
|
+
canonical.tool_input = remapToolInput(toolName, parseMaybeJsonObject(payload && payload.toolArgs))
|
|
140279
|
+
}
|
|
140280
|
+
|
|
140281
|
+
// postToolUse only: confirmed via https://docs.github.com/en/copilot/reference/hooks-reference
|
|
140282
|
+
// that Copilot's toolResult is an object ({resultType, textResultForLlm}), not a bare string
|
|
140283
|
+
// or array. Without this, token-goat's tool_response consumers (hooks_read.ts's
|
|
140284
|
+
// extractReadOutput, hooks_bash.ts's extractBashOutput, etc. -- all of which check for a
|
|
140285
|
+
// string or an object keyed by output/content/text/body) never see any content, so
|
|
140286
|
+
// post-read/post-bash stats stay empty no matter how many tool calls happen. Extract the
|
|
140287
|
+
// LLM-facing text directly rather than forwarding the raw object, since textResultForLlm
|
|
140288
|
+
// isn't one of those recognized object keys.
|
|
140289
|
+
const rawResult = payload && payload.toolResult
|
|
140290
|
+
if (rawResult && typeof rawResult === 'object') {
|
|
140291
|
+
const tr = rawResult
|
|
140292
|
+
// text_result_for_llm: Copilot's docs also describe a "VS Code compatible" snake_case
|
|
140293
|
+
// wire format (tool_result.text_result_for_llm) alongside the camelCase one above; try
|
|
140294
|
+
// both rather than assuming only the camelCase shape ever reaches this shim.
|
|
140295
|
+
const text = typeof tr.textResultForLlm === 'string' ? tr.textResultForLlm : tr.text_result_for_llm
|
|
140296
|
+
if (typeof text === 'string') canonical.tool_response = text
|
|
140223
140297
|
}
|
|
140224
140298
|
|
|
140225
140299
|
// A single command string (not an args array) with shell: true, exactly like
|
|
@@ -140273,13 +140347,27 @@ function translate(copilotEvent, resp) {
|
|
|
140273
140347
|
return {}
|
|
140274
140348
|
}
|
|
140275
140349
|
|
|
140276
|
-
|
|
140277
|
-
|
|
140278
|
-
|
|
140279
|
-
|
|
140280
|
-
|
|
140281
|
-
|
|
140282
|
-
|
|
140350
|
+
if (copilotEvent === 'agentStop' || copilotEvent === 'subagentStop') {
|
|
140351
|
+
// Confirmed against the hooks reference doc: the only accepted response
|
|
140352
|
+
// shape for these two events is {decision, reason} -- additionalContext
|
|
140353
|
+
// is not part of their schema and Copilot silently ignores it there.
|
|
140354
|
+
// token-goat's internal 'stop'/'subagent_stop' handlers never return a
|
|
140355
|
+
// real deny today (subagentStopHandler only ever logs and passes), but a
|
|
140356
|
+
// future deny is mapped through here rather than silently dropped.
|
|
140357
|
+
if (resp && resp.decision === 'block') {
|
|
140358
|
+
const reason = (resp && resp.reason) || 'blocked by token-goat'
|
|
140359
|
+
return { decision: 'block', reason: reason }
|
|
140360
|
+
}
|
|
140361
|
+
return { decision: 'allow' }
|
|
140362
|
+
}
|
|
140363
|
+
|
|
140364
|
+
// preCompact / userPromptSubmitted: confirmed against the hooks reference
|
|
140365
|
+
// doc that both are notification-only -- Copilot never reads a response
|
|
140366
|
+
// body for either, so any additionalContext/systemMessage token-goat
|
|
140367
|
+
// produces has no surfacing channel here. This still routes through the
|
|
140368
|
+
// token-goat hook call above (unlike sessionStart's early no-op) so the
|
|
140369
|
+
// internal handler's own side effects keep running; only the response is
|
|
140370
|
+
// discarded.
|
|
140283
140371
|
return {}
|
|
140284
140372
|
}
|
|
140285
140373
|
|
|
@@ -140290,7 +140378,26 @@ function extractContext(resp) {
|
|
|
140290
140378
|
return undefined
|
|
140291
140379
|
}
|
|
140292
140380
|
|
|
140293
|
-
main()
|
|
140381
|
+
// Hard outer safety net, on top of main()'s own per-step try/catch fallbacks
|
|
140382
|
+
// (JSON.parse, readFileSync, spawnSync): a hook error must never itself cause
|
|
140383
|
+
// Copilot's fail-closed "(hook errored)" behavior, which denies EVERY tool
|
|
140384
|
+
// call unconditionally (the exact live-production failure mode behind
|
|
140385
|
+
// github/copilot-cli#4001). Any uncaught exception anywhere in this script --
|
|
140386
|
+
// including one a future code path adds that the existing per-step guards
|
|
140387
|
+
// don't anticipate -- still guarantees stdout gets valid JSON and the
|
|
140388
|
+
// process exits 0. process.exitCode is set explicitly and unconditionally at
|
|
140389
|
+
// the very end of every path so nothing upstream (e.g. an unhandled-rejection
|
|
140390
|
+
// warning in some Node versions nudging exit-code inference) can flip it.
|
|
140391
|
+
try {
|
|
140392
|
+
main()
|
|
140393
|
+
} catch {
|
|
140394
|
+
try {
|
|
140395
|
+
process.stdout.write('{}')
|
|
140396
|
+
} catch {
|
|
140397
|
+
// stdout itself is broken; nothing more can be done here.
|
|
140398
|
+
}
|
|
140399
|
+
}
|
|
140400
|
+
process.exitCode = 0
|
|
140294
140401
|
`;
|
|
140295
140402
|
|
|
140296
140403
|
// src/bridges/copilot_cli_install.ts
|
|
@@ -140298,7 +140405,14 @@ init_define_import_meta_env();
|
|
|
140298
140405
|
import * as fs6 from "node:fs";
|
|
140299
140406
|
import * as os4 from "node:os";
|
|
140300
140407
|
import * as path9 from "node:path";
|
|
140301
|
-
var COPILOT_CLI_HOOK_EVENTS = [
|
|
140408
|
+
var COPILOT_CLI_HOOK_EVENTS = [
|
|
140409
|
+
"preToolUse",
|
|
140410
|
+
"postToolUse",
|
|
140411
|
+
"preCompact",
|
|
140412
|
+
"agentStop",
|
|
140413
|
+
"subagentStop",
|
|
140414
|
+
"userPromptSubmitted"
|
|
140415
|
+
];
|
|
140302
140416
|
function copilotCliUserHooksDir() {
|
|
140303
140417
|
return path9.join(os4.homedir(), ".copilot", "hooks");
|
|
140304
140418
|
}
|
|
@@ -140315,7 +140429,7 @@ function copilotCliScriptPath(opts = {}) {
|
|
|
140315
140429
|
return path9.join(copilotCliHooksDir(opts), "token-goat-shim.js");
|
|
140316
140430
|
}
|
|
140317
140431
|
function hookCommandFor2(scriptPath, event) {
|
|
140318
|
-
return `
|
|
140432
|
+
return `"${process.execPath}" "${scriptPath}" ${event}`;
|
|
140319
140433
|
}
|
|
140320
140434
|
function buildConfig(scriptPath) {
|
|
140321
140435
|
const hooks = {};
|
|
@@ -140324,7 +140438,7 @@ function buildConfig(scriptPath) {
|
|
|
140324
140438
|
}
|
|
140325
140439
|
return { version: 1, hooks };
|
|
140326
140440
|
}
|
|
140327
|
-
function writeIfDifferent(p, content) {
|
|
140441
|
+
function writeIfDifferent(p, content, backup = false) {
|
|
140328
140442
|
let existing;
|
|
140329
140443
|
try {
|
|
140330
140444
|
existing = fs6.readFileSync(p, "utf8");
|
|
@@ -140332,6 +140446,7 @@ function writeIfDifferent(p, content) {
|
|
|
140332
140446
|
existing = void 0;
|
|
140333
140447
|
}
|
|
140334
140448
|
if (existing === content) return false;
|
|
140449
|
+
if (backup) backupFile(p);
|
|
140335
140450
|
ensureDirSync(path9.dirname(p));
|
|
140336
140451
|
atomicWriteText(p, content);
|
|
140337
140452
|
return true;
|
|
@@ -140341,7 +140456,7 @@ function installCopilotCli(opts = {}) {
|
|
|
140341
140456
|
const scriptPath = copilotCliScriptPath(opts);
|
|
140342
140457
|
const scriptChanged = writeIfDifferent(scriptPath, COPILOT_CLI_HOOK_SCRIPT);
|
|
140343
140458
|
const desiredText = JSON.stringify(buildConfig(scriptPath), null, 2) + "\n";
|
|
140344
|
-
const configChanged = writeIfDifferent(configPath2, desiredText);
|
|
140459
|
+
const configChanged = writeIfDifferent(configPath2, desiredText, true);
|
|
140345
140460
|
return { configPath: configPath2, scriptPath, alreadyInstalled: !scriptChanged && !configChanged };
|
|
140346
140461
|
}
|
|
140347
140462
|
function uninstallCopilotCli(opts = {}) {
|
|
@@ -141122,11 +141237,25 @@ function pressureRawTotal(cache) {
|
|
|
141122
141237
|
}
|
|
141123
141238
|
function getEffectiveAutoTriggerWindow() {
|
|
141124
141239
|
const ca = loadConfig().compact_assist;
|
|
141240
|
+
const isConfigDefault = !isAutoTriggerMultiplierExplicit();
|
|
141125
141241
|
const multiplier = getAutoTriggerMultiplier(
|
|
141126
|
-
ca.harness === "auto" ? { configExplicitMultiplier: ca.auto_trigger_multiplier } : { configExplicitMultiplier: ca.auto_trigger_multiplier, harness: ca.harness }
|
|
141242
|
+
ca.harness === "auto" ? { configExplicitMultiplier: ca.auto_trigger_multiplier, isConfigDefault } : { configExplicitMultiplier: ca.auto_trigger_multiplier, harness: ca.harness, isConfigDefault }
|
|
141127
141243
|
);
|
|
141128
141244
|
return CONTEXT_AUTOCOMPACT_TOKENS * multiplier;
|
|
141129
141245
|
}
|
|
141246
|
+
function isAutoTriggerMultiplierExplicit() {
|
|
141247
|
+
try {
|
|
141248
|
+
const text = fs10.readFileSync(configPath(), "utf8");
|
|
141249
|
+
const raw = parse(text);
|
|
141250
|
+
const ca_raw = raw["compact_assist"];
|
|
141251
|
+
if (ca_raw === null || typeof ca_raw !== "object" || Array.isArray(ca_raw)) {
|
|
141252
|
+
return false;
|
|
141253
|
+
}
|
|
141254
|
+
return ca_raw["auto_trigger_multiplier"] !== void 0;
|
|
141255
|
+
} catch {
|
|
141256
|
+
return false;
|
|
141257
|
+
}
|
|
141258
|
+
}
|
|
141130
141259
|
function getContextPressure(cache) {
|
|
141131
141260
|
try {
|
|
141132
141261
|
if (!cache) {
|
|
@@ -142122,8 +142251,15 @@ function stripCstyleComments(text, lineCommentRe) {
|
|
|
142122
142251
|
break;
|
|
142123
142252
|
}
|
|
142124
142253
|
result += line.slice(j, open);
|
|
142125
|
-
|
|
142126
|
-
|
|
142254
|
+
const close = line.indexOf("*/", open + 2);
|
|
142255
|
+
if (close === -1) {
|
|
142256
|
+
result += " ".repeat(line.length - open);
|
|
142257
|
+
inComment = true;
|
|
142258
|
+
break;
|
|
142259
|
+
}
|
|
142260
|
+
result += " ".repeat(close + 2 - open);
|
|
142261
|
+
j = close + 2;
|
|
142262
|
+
inComment = false;
|
|
142127
142263
|
} else {
|
|
142128
142264
|
const close = line.indexOf("*/", j);
|
|
142129
142265
|
if (close === -1) {
|
|
@@ -142196,12 +142332,16 @@ function stripBlockCommentSpan(line, inComment) {
|
|
|
142196
142332
|
}
|
|
142197
142333
|
return { code, inComment: comment };
|
|
142198
142334
|
}
|
|
142199
|
-
function stripLineComment(line) {
|
|
142200
|
-
let
|
|
142201
|
-
|
|
142202
|
-
idx = line.indexOf(
|
|
142335
|
+
function stripLineComment(line, markers = ["//"]) {
|
|
142336
|
+
let cutIdx = -1;
|
|
142337
|
+
for (const marker of markers) {
|
|
142338
|
+
let idx = line.indexOf(marker);
|
|
142339
|
+
while (idx !== -1 && isInsideStringLiteral(line, idx)) {
|
|
142340
|
+
idx = line.indexOf(marker, idx + 1);
|
|
142341
|
+
}
|
|
142342
|
+
if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
|
|
142203
142343
|
}
|
|
142204
|
-
return
|
|
142344
|
+
return cutIdx === -1 ? line : line.slice(0, cutIdx);
|
|
142205
142345
|
}
|
|
142206
142346
|
function stripStringLiterals(line) {
|
|
142207
142347
|
let out2 = "";
|
|
@@ -142367,7 +142507,7 @@ function extractCsharp(content, filePath) {
|
|
|
142367
142507
|
}
|
|
142368
142508
|
}
|
|
142369
142509
|
}
|
|
142370
|
-
const braceLine = stripStringLiterals(line);
|
|
142510
|
+
const braceLine = stripStringLiterals(stripLineComment(line));
|
|
142371
142511
|
const openBraces = (braceLine.match(/\{/g) ?? []).length;
|
|
142372
142512
|
const closeBraces = (braceLine.match(/\}/g) ?? []).length;
|
|
142373
142513
|
braceDepth += openBraces - closeBraces;
|
|
@@ -142435,7 +142575,7 @@ function extractPhp(content, filePath) {
|
|
|
142435
142575
|
const line = codeLine.trimEnd();
|
|
142436
142576
|
const stripped = line.trimStart();
|
|
142437
142577
|
if (!stripped || stripped.startsWith("//") || stripped.startsWith("#")) continue;
|
|
142438
|
-
const braceLine = stripStringLiterals(line);
|
|
142578
|
+
const braceLine = stripStringLiterals(stripLineComment(line, ["//", "#"]));
|
|
142439
142579
|
const openB = (braceLine.match(/\{/g) ?? []).length;
|
|
142440
142580
|
const closeB = (braceLine.match(/\}/g) ?? []).length;
|
|
142441
142581
|
braceDepth += openB - closeB;
|
|
@@ -143057,16 +143197,14 @@ function extractMakefile(content, filePath) {
|
|
|
143057
143197
|
init_define_import_meta_env();
|
|
143058
143198
|
var MAX_SYMBOLS4 = 500;
|
|
143059
143199
|
var MAX_HEADING_LEN5 = 120;
|
|
143060
|
-
var LINE_COMMENT_RE = /\/\/[^\n]*/g;
|
|
143061
143200
|
function stripComments2(text) {
|
|
143062
|
-
|
|
143063
|
-
|
|
143064
|
-
return out2;
|
|
143201
|
+
const out2 = stripCstyleComments(text);
|
|
143202
|
+
return out2.split("\n").map((line) => stripLineComment(line)).join("\n");
|
|
143065
143203
|
}
|
|
143066
143204
|
var TOP_LEVEL_RE = /^[ \t]*(?<keyword>message|enum|service)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)\s*\{/gm;
|
|
143067
143205
|
var EXTEND_RE = /^[ \t]*extend\s+(?<name>[A-Za-z_][A-Za-z0-9_.]*)\s*\{/gm;
|
|
143068
|
-
var RPC_RE =
|
|
143069
|
-
var ONEOF_RE =
|
|
143206
|
+
var RPC_RE = /^[ \t]+rpc\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/gm;
|
|
143207
|
+
var ONEOF_RE = /^[ \t]+oneof\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/gm;
|
|
143070
143208
|
var IMPORT_RE2 = /^import\s+(?:weak\s+|public\s+)?["']([^"']+)["']/gm;
|
|
143071
143209
|
var KIND_MAP2 = /* @__PURE__ */ new Map([
|
|
143072
143210
|
["message", "proto_message"],
|
|
@@ -143206,18 +143344,25 @@ function extractPowershell(content, filePath) {
|
|
|
143206
143344
|
const rawLine = lines[i] ?? "";
|
|
143207
143345
|
const lineNum = i + 1;
|
|
143208
143346
|
let line = rawLine;
|
|
143347
|
+
let openedBlockCommentThisLine = false;
|
|
143209
143348
|
if (!inBlockComment) {
|
|
143210
143349
|
const openIdx = findUnquoted(rawLine, "<#");
|
|
143211
143350
|
if (openIdx !== -1) {
|
|
143212
|
-
const
|
|
143213
|
-
|
|
143214
|
-
|
|
143215
|
-
|
|
143216
|
-
|
|
143351
|
+
const hashIdx2 = findUnquoted(rawLine, "#");
|
|
143352
|
+
const isRealOpener = hashIdx2 === -1 || hashIdx2 >= openIdx;
|
|
143353
|
+
if (isRealOpener) {
|
|
143354
|
+
const closeIdx = rawLine.indexOf("#>", openIdx + 2);
|
|
143355
|
+
if (closeIdx !== -1) {
|
|
143356
|
+
line = rawLine.slice(0, openIdx) + " ".repeat(closeIdx + 2 - openIdx) + rawLine.slice(closeIdx + 2);
|
|
143357
|
+
} else {
|
|
143358
|
+
inBlockComment = true;
|
|
143359
|
+
openedBlockCommentThisLine = true;
|
|
143360
|
+
line = rawLine.slice(0, openIdx);
|
|
143361
|
+
}
|
|
143217
143362
|
}
|
|
143218
143363
|
}
|
|
143219
143364
|
}
|
|
143220
|
-
if (inBlockComment) {
|
|
143365
|
+
if (inBlockComment && !openedBlockCommentThisLine) {
|
|
143221
143366
|
const closeMarkerIdx = rawLine.indexOf("#>");
|
|
143222
143367
|
if (closeMarkerIdx === -1) {
|
|
143223
143368
|
continue;
|
|
@@ -143332,7 +143477,7 @@ function loadGrammar(lang, filePath) {
|
|
|
143332
143477
|
} catch {
|
|
143333
143478
|
grammar = null;
|
|
143334
143479
|
}
|
|
143335
|
-
_grammarCache.set(
|
|
143480
|
+
_grammarCache.set(cacheKey, grammar);
|
|
143336
143481
|
return grammar;
|
|
143337
143482
|
}
|
|
143338
143483
|
function isTreeSitterAvailable(lang) {
|
|
@@ -143907,7 +144052,11 @@ function extractJsonSymbols(content, filePath) {
|
|
|
143907
144052
|
} else {
|
|
143908
144053
|
inString = false;
|
|
143909
144054
|
let k = i + 1;
|
|
143910
|
-
|
|
144055
|
+
let keyToColonNewlines = 0;
|
|
144056
|
+
while (k < content.length && /\s/.test(content[k] ?? "")) {
|
|
144057
|
+
if (content[k] === "\n") keyToColonNewlines++;
|
|
144058
|
+
k++;
|
|
144059
|
+
}
|
|
143911
144060
|
if (content[k] === ":" && depthWhenStringOpened === 1) {
|
|
143912
144061
|
let v = k + 1;
|
|
143913
144062
|
let gapNewlines = 0;
|
|
@@ -143918,7 +144067,7 @@ function extractJsonSymbols(content, filePath) {
|
|
|
143918
144067
|
let lineEnd = strStartLine;
|
|
143919
144068
|
let body = (lines[strStartLine - 1] ?? "").trim();
|
|
143920
144069
|
if (content[v] === '"') {
|
|
143921
|
-
let valueLine = line + gapNewlines;
|
|
144070
|
+
let valueLine = line + keyToColonNewlines + gapNewlines;
|
|
143922
144071
|
let valueEscaping = false;
|
|
143923
144072
|
for (let j = v + 1; j < content.length; j++) {
|
|
143924
144073
|
const vch = content[j];
|
|
@@ -155899,6 +156048,7 @@ var GoTestFilter = class extends ToolFilter {
|
|
|
155899
156048
|
continue;
|
|
155900
156049
|
}
|
|
155901
156050
|
if (TEST_RPC_RE.test(line)) {
|
|
156051
|
+
if (inFailBlock) inFailBlock = false;
|
|
155902
156052
|
lastRunLine = line;
|
|
155903
156053
|
droppedRun += 1;
|
|
155904
156054
|
continue;
|
|
@@ -162348,12 +162498,12 @@ var CdkFilter = class extends ToolFilter {
|
|
|
162348
162498
|
}
|
|
162349
162499
|
};
|
|
162350
162500
|
var cdkFilter = new CdkFilter();
|
|
162351
|
-
var _VAULT_TABLE_DIVIDER_RE = /^\s*-{3,}
|
|
162501
|
+
var _VAULT_TABLE_DIVIDER_RE = /^\s*-{3,}(?:\s+-{3,})?\s*$/;
|
|
162352
162502
|
var _VAULT_LEASE_META_RE = /^\s*(?:lease_(?:id|renewable|duration|accessor)|token_(?:policies|accessor|type|ttl|issue_time|expire_time|explicit_max_ttl|num_uses|renewable)|renewable|request_id)\s/i;
|
|
162353
162503
|
var _VAULT_SUCCESS_RE = /^\s*Success!\s+/i;
|
|
162354
162504
|
var _VAULT_HEADER_RE = /^\s*(?:WARNING|==>|Key\s+Value\s*$)/i;
|
|
162355
162505
|
var _VAULT_AUTH_HEADER_RE = /^\s*(?:Token\s+information:|The\s+token\s+information|Complete\s+the\s+following|vault\s+(?:kv|secrets|auth|policy|lease|token)\s)/i;
|
|
162356
|
-
var _VAULT_LIST_ITEM_RE = /^\s{
|
|
162506
|
+
var _VAULT_LIST_ITEM_RE = /^\s{0,6}[a-zA-Z0-9_./-]+\/?$/;
|
|
162357
162507
|
var _VAULT_LIST_HEADER_RE = /^\s*Keys\s*$/i;
|
|
162358
162508
|
var _VAULT_LIST_COLLAPSE_THRESHOLD = 10;
|
|
162359
162509
|
var VaultFilter = class extends ToolFilter {
|
|
@@ -162366,7 +162516,7 @@ var VaultFilter = class extends ToolFilter {
|
|
|
162366
162516
|
const kept = [];
|
|
162367
162517
|
let metaCount = 0;
|
|
162368
162518
|
let dividerCount = 0;
|
|
162369
|
-
const isListCmd = argv.length >= 2 && argv[0].toLowerCase() === "vault" && (argv[1].toLowerCase() === "list" || argv.length >= 3 && argv[1].toLowerCase() === "kv" && argv[2].toLowerCase() === "list");
|
|
162519
|
+
const isListCmd = argv.length >= 2 && pathStem(argv[0]).toLowerCase() === "vault" && (argv[1].toLowerCase() === "list" || argv.length >= 3 && argv[1].toLowerCase() === "kv" && argv[2].toLowerCase() === "list");
|
|
162370
162520
|
const listItems = [];
|
|
162371
162521
|
let inListBody = false;
|
|
162372
162522
|
for (const line of lines) {
|
|
@@ -166492,6 +166642,9 @@ var PSQL_NOTICE_RE = /^(NOTICE|WARNING|HINT|DETAIL):/i;
|
|
|
166492
166642
|
var PSQL_ERROR_RE = /^(ERROR|FATAL|PANIC):/i;
|
|
166493
166643
|
var PSQL_ROWS_RE = /^\((\d+) rows?\)$/;
|
|
166494
166644
|
var PSQL_CREATE_RE = /^(CREATE TABLE|CREATE INDEX|CREATE UNIQUE INDEX|CREATE SEQUENCE|CREATE TYPE|CREATE FUNCTION|CREATE VIEW|CREATE TRIGGER|ALTER TABLE|ADD CONSTRAINT)\b/i;
|
|
166645
|
+
function pluralize(n, singular, plural2 = `${singular}s`) {
|
|
166646
|
+
return `${n} ${n === 1 ? singular : plural2}`;
|
|
166647
|
+
}
|
|
166495
166648
|
var PsqlFilter = class _PsqlFilter extends ToolFilter {
|
|
166496
166649
|
name = "psql";
|
|
166497
166650
|
binaries = /* @__PURE__ */ new Set(["psql"]);
|
|
@@ -166505,14 +166658,26 @@ var PsqlFilter = class _PsqlFilter extends ToolFilter {
|
|
|
166505
166658
|
const lines = text.split("\n");
|
|
166506
166659
|
const createTables = lines.filter((ln) => /^CREATE TABLE\b/i.test(ln)).length;
|
|
166507
166660
|
const createIndexes = lines.filter((ln) => /^CREATE (UNIQUE )?INDEX\b/i.test(ln)).length;
|
|
166661
|
+
const createFunctions = lines.filter((ln) => /^CREATE FUNCTION\b/i.test(ln)).length;
|
|
166662
|
+
const createViews = lines.filter((ln) => /^CREATE VIEW\b/i.test(ln)).length;
|
|
166663
|
+
const createTypes = lines.filter((ln) => /^CREATE TYPE\b/i.test(ln)).length;
|
|
166664
|
+
const createSequences = lines.filter((ln) => /^CREATE SEQUENCE\b/i.test(ln)).length;
|
|
166665
|
+
const createTriggers = lines.filter((ln) => /^CREATE TRIGGER\b/i.test(ln)).length;
|
|
166666
|
+
const alterations = lines.filter((ln) => /^(ALTER TABLE|ADD CONSTRAINT)\b/i.test(ln)).length;
|
|
166508
166667
|
if (createTables >= 3) {
|
|
166509
166668
|
const nonDdl = [];
|
|
166510
166669
|
for (const ln of lines) {
|
|
166511
166670
|
if (PSQL_CREATE_RE.test(ln)) continue;
|
|
166512
166671
|
nonDdl.push(ln);
|
|
166513
166672
|
}
|
|
166514
|
-
const summaryParts = [
|
|
166515
|
-
if (createIndexes) summaryParts.push(
|
|
166673
|
+
const summaryParts = [pluralize(createTables, "table")];
|
|
166674
|
+
if (createIndexes) summaryParts.push(pluralize(createIndexes, "index", "indexes"));
|
|
166675
|
+
if (createFunctions) summaryParts.push(pluralize(createFunctions, "function"));
|
|
166676
|
+
if (createViews) summaryParts.push(pluralize(createViews, "view"));
|
|
166677
|
+
if (createTypes) summaryParts.push(pluralize(createTypes, "type"));
|
|
166678
|
+
if (createSequences) summaryParts.push(pluralize(createSequences, "sequence"));
|
|
166679
|
+
if (createTriggers) summaryParts.push(pluralize(createTriggers, "trigger"));
|
|
166680
|
+
if (alterations) summaryParts.push(pluralize(alterations, "alteration"));
|
|
166516
166681
|
nonDdl.unshift(`[token-goat: Created ${summaryParts.join(", ")}]`);
|
|
166517
166682
|
return this.finalize(nonDdl);
|
|
166518
166683
|
}
|
|
@@ -167446,6 +167611,14 @@ var EnvFilter = class extends ToolFilter {
|
|
|
167446
167611
|
};
|
|
167447
167612
|
var envFilter = new EnvFilter();
|
|
167448
167613
|
var JSON_ARRAY_MAX_ITEMS = 50;
|
|
167614
|
+
function stableStringify(value) {
|
|
167615
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
167616
|
+
if (value !== null && typeof value === "object") {
|
|
167617
|
+
const keys = Object.keys(value).sort();
|
|
167618
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
|
|
167619
|
+
}
|
|
167620
|
+
return JSON.stringify(value);
|
|
167621
|
+
}
|
|
167449
167622
|
var JsonArrayFilter = class extends ToolFilter {
|
|
167450
167623
|
name = "json_array";
|
|
167451
167624
|
binaries = /* @__PURE__ */ new Set(["json"]);
|
|
@@ -167473,14 +167646,15 @@ var JsonArrayFilter = class extends ToolFilter {
|
|
|
167473
167646
|
const dupCounts = /* @__PURE__ */ new Map();
|
|
167474
167647
|
for (const item of data) {
|
|
167475
167648
|
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
167649
|
+
const valueKey = stableStringify(item);
|
|
167476
167650
|
const ks = Object.keys(item).sort().join(",");
|
|
167477
167651
|
const preserve = Object.values(item).some(
|
|
167478
167652
|
(v) => typeof v === "string" && hasHighEntropyToken(v)
|
|
167479
167653
|
);
|
|
167480
|
-
if (seen.has(
|
|
167654
|
+
if (seen.has(valueKey) && !preserve) {
|
|
167481
167655
|
dupCounts.set(ks, (dupCounts.get(ks) ?? 0) + 1);
|
|
167482
167656
|
} else {
|
|
167483
|
-
if (!seen.has(
|
|
167657
|
+
if (!seen.has(valueKey)) seen.set(valueKey, kept.length);
|
|
167484
167658
|
kept.push(item);
|
|
167485
167659
|
}
|
|
167486
167660
|
} else {
|
|
@@ -169473,11 +169647,24 @@ export default function (pi: ExtensionAPI) {
|
|
|
169473
169647
|
pi.on("tool_result", async (event, _ctx) => {
|
|
169474
169648
|
const tg = TOOL_TO_TG[event.toolName];
|
|
169475
169649
|
if (!tg) return;
|
|
169650
|
+
// event.content is tool_result's real output field (ToolResultEventBase.content:
|
|
169651
|
+
// (TextContent | ImageContent)[] -- verified against pi's own
|
|
169652
|
+
// core/extensions/types.ts). Join the text blocks into a single string so
|
|
169653
|
+
// extractReadOutput's truncation-marker detection (which only recognizes a
|
|
169654
|
+
// string tool_response.output) can see it, mirroring opencode.ts's
|
|
169655
|
+
// tool_response: { output } shape.
|
|
169656
|
+
const contentBlocks = Array.isArray(event.content) ? event.content : [];
|
|
169657
|
+
const output = contentBlocks
|
|
169658
|
+
.filter((c: { type?: string }) => c && c.type === "text")
|
|
169659
|
+
.map((c: { text?: string }) => c.text ?? "")
|
|
169660
|
+
.join("
|
|
169661
|
+
");
|
|
169476
169662
|
callHook("post_tool_use", {
|
|
169477
169663
|
session_id: sessionId,
|
|
169478
169664
|
tool_name: tg,
|
|
169479
169665
|
tool_input: toToolInput(event.toolName, (event.input ?? {}) as Record<string, unknown>),
|
|
169480
169666
|
cwd,
|
|
169667
|
+
tool_response: { output },
|
|
169481
169668
|
});
|
|
169482
169669
|
});
|
|
169483
169670
|
|
|
@@ -194429,18 +194616,7 @@ function listSections(filePath) {
|
|
|
194429
194616
|
return headers.map((h) => h.heading);
|
|
194430
194617
|
}
|
|
194431
194618
|
function listAllSections(filePath) {
|
|
194432
|
-
|
|
194433
|
-
try {
|
|
194434
|
-
text = readFileSync22(filePath, "utf-8");
|
|
194435
|
-
} catch {
|
|
194436
|
-
return [];
|
|
194437
|
-
}
|
|
194438
|
-
if (text.charCodeAt(0) === 65279) {
|
|
194439
|
-
text = text.slice(1);
|
|
194440
|
-
}
|
|
194441
|
-
const language = detectLanguage(filePath);
|
|
194442
|
-
const { headers } = findHeaders(text, language);
|
|
194443
|
-
return headers.map((h) => h.heading);
|
|
194619
|
+
return listSections(filePath);
|
|
194444
194620
|
}
|
|
194445
194621
|
|
|
194446
194622
|
// src/overflow_guard.ts
|
|
@@ -197188,13 +197364,19 @@ function runLineRange(range2, opts) {
|
|
|
197188
197364
|
function resolveSymbolSpec(spec, forceRefresh) {
|
|
197189
197365
|
const { file: file2, symbol: symbol2 } = parseReadSpec(spec);
|
|
197190
197366
|
if (symbol2 === void 0 || symbol2 === "") return null;
|
|
197191
|
-
const dotParts = symbol2.split(".");
|
|
197192
|
-
const [symBase, methodName] = dotParts.length > 1 ? [dotParts[0] ?? symbol2, dotParts[dotParts.length - 1]] : [symbol2, void 0];
|
|
197193
|
-
const lookupName = methodName ?? symBase;
|
|
197194
197367
|
const resolved = resolveIndexPath(file2);
|
|
197195
197368
|
if (forceRefresh === true) {
|
|
197196
197369
|
indexFileSync(resolved, globalDbPath());
|
|
197197
197370
|
}
|
|
197371
|
+
if (symbol2.includes(".")) {
|
|
197372
|
+
const exactMatch = querySymbols({ name: symbol2, filePath: resolved, limit: 10 });
|
|
197373
|
+
if (exactMatch.length > 0) {
|
|
197374
|
+
return exactMatch[0] ?? null;
|
|
197375
|
+
}
|
|
197376
|
+
}
|
|
197377
|
+
const dotParts = symbol2.split(".");
|
|
197378
|
+
const [symBase, methodName] = dotParts.length > 1 ? [dotParts[0] ?? symbol2, dotParts[dotParts.length - 1]] : [symbol2, void 0];
|
|
197379
|
+
const lookupName = methodName ?? symBase;
|
|
197198
197380
|
let candidates = querySymbols({ name: lookupName, filePath: resolved, limit: 10 });
|
|
197199
197381
|
if (candidates.length === 0) {
|
|
197200
197382
|
const foldedFile = foldPath(file2);
|
|
@@ -203746,7 +203928,7 @@ async function cmdInstall(opts) {
|
|
|
203746
203928
|
}
|
|
203747
203929
|
}
|
|
203748
203930
|
if (opts.copilot === true) {
|
|
203749
|
-
const copilotResult = installCopilotCli();
|
|
203931
|
+
const copilotResult = installCopilotCli({ local: opts.local === true });
|
|
203750
203932
|
if (copilotResult.alreadyInstalled) {
|
|
203751
203933
|
out(`Copilot CLI integration already installed \u2192 ${copilotResult.configPath}`);
|
|
203752
203934
|
} else {
|
|
@@ -203827,7 +204009,7 @@ function cmdUninstall(opts) {
|
|
|
203827
204009
|
);
|
|
203828
204010
|
}
|
|
203829
204011
|
if (opts.copilot === true) {
|
|
203830
|
-
const copilotRemoved = uninstallCopilotCli();
|
|
204012
|
+
const copilotRemoved = uninstallCopilotCli({ local: opts.local === true });
|
|
203831
204013
|
out(
|
|
203832
204014
|
copilotRemoved ? "Removed token-goat Copilot CLI integration." : "No token-goat Copilot CLI integration to remove."
|
|
203833
204015
|
);
|