@gajae-code/coding-agent 0.8.2 → 0.9.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/CHANGELOG.md +53 -0
- package/dist/types/append-only-mode.d.ts +31 -0
- package/dist/types/capability/rule.d.ts +8 -0
- package/dist/types/cli/fixture-report.d.ts +20 -0
- package/dist/types/cli/fixture-report.test.d.ts +1 -0
- package/dist/types/cli/nofile-limit.d.ts +11 -0
- package/dist/types/cli/update-cli.d.ts +22 -0
- package/dist/types/config/settings-schema.d.ts +119 -1
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/export/ttsr.d.ts +14 -3
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +5 -2
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +26 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +1 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +119 -13
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/hooks/native-skill-hook.d.ts +12 -0
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/status-line.d.ts +9 -0
- package/dist/types/modes/components/thinking-selector.d.ts +2 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +5 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +4 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +1 -3
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +3 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
- package/dist/types/modes/types.d.ts +3 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +52 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/notifications/config-commands.d.ts +9 -0
- package/dist/types/notifications/config.d.ts +22 -0
- package/dist/types/notifications/index.d.ts +2 -0
- package/dist/types/notifications/lifecycle-commands.d.ts +1 -0
- package/dist/types/notifications/lifecycle-control-runtime.d.ts +2 -1
- package/dist/types/notifications/reply-sent-store.d.ts +53 -0
- package/dist/types/notifications/rich-draft.d.ts +68 -0
- package/dist/types/notifications/rich-render.d.ts +90 -0
- package/dist/types/notifications/telegram-daemon-cli.d.ts +3 -3
- package/dist/types/notifications/telegram-daemon.d.ts +30 -0
- package/dist/types/notifications/telegram-reference.d.ts +7 -0
- package/dist/types/notifications/threaded-render.d.ts +14 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +43 -1
- package/dist/types/session/file-mention-pruning.d.ts +8 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/skill-state/active-state.d.ts +18 -1
- package/dist/types/system-prompt.d.ts +18 -2
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/fork-context-budget.d.ts +7 -0
- package/dist/types/task/token-log.d.ts +30 -0
- package/dist/types/task/token-log.test.d.ts +1 -0
- package/dist/types/tools/bisect.d.ts +81 -0
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/utils/file-mentions.d.ts +14 -0
- package/dist/types/utils/git.d.ts +32 -0
- package/dist/types/utils/pasted-image-path.d.ts +30 -0
- package/dist/types/web/scrapers/youtube.d.ts +8 -0
- package/package.json +8 -11
- package/src/append-only-mode.ts +58 -0
- package/src/autoresearch/prompt.md +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/capability/rule.ts +9 -0
- package/src/cli/config-cli.ts +27 -3
- package/src/cli/fixture-report.test.ts +230 -0
- package/src/cli/fixture-report.ts +171 -0
- package/src/cli/nofile-limit.ts +48 -0
- package/src/cli/notify-cli.ts +11 -9
- package/src/cli/update-cli.ts +85 -9
- package/src/cli.ts +26 -0
- package/src/commands/contribution-prep.ts +1 -1
- package/src/config/keybindings.ts +1 -1
- package/src/config/settings-schema.ts +76 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +12 -13
- package/src/defaults/gjc/skills/ralplan/SKILL.md +30 -93
- package/src/defaults/gjc/skills/team/SKILL.md +16 -13
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +59 -4
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
- package/src/defaults/gjc-defaults.ts +9 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/index.ts +1 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +60 -2
- package/src/export/ttsr.ts +96 -18
- package/src/extensibility/extensions/runner.ts +181 -219
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +156 -44
- package/src/gjc-runtime/deep-interview-state.ts +31 -2
- package/src/gjc-runtime/launch-tmux.ts +6 -0
- package/src/gjc-runtime/session-state-sidecar.ts +208 -13
- package/src/gjc-runtime/state-writer.ts +15 -0
- package/src/gjc-runtime/team-runtime.ts +175 -19
- package/src/gjc-runtime/tmux-common.ts +1 -0
- package/src/gjc-runtime/ultragoal-guard.ts +55 -66
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +315 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1602 -143
- package/src/gjc-runtime/workflow-manifest.generated.json +113 -2
- package/src/gjc-runtime/workflow-manifest.ts +74 -1
- package/src/goals/runtime.ts +10 -2
- package/src/hindsight/backend.ts +1 -3
- package/src/hooks/native-skill-hook.ts +95 -4
- package/src/internal-urls/docs-index.generated.ts +18 -9
- package/src/lsp/client.ts +1 -0
- package/src/main.ts +43 -2
- package/src/memories/index.ts +12 -1
- package/src/modes/components/assistant-message.ts +241 -82
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/footer.ts +7 -2
- package/src/modes/components/status-line.ts +167 -54
- package/src/modes/components/thinking-selector.ts +10 -8
- package/src/modes/components/tool-execution.ts +44 -19
- package/src/modes/controllers/command-controller.ts +39 -2
- package/src/modes/controllers/event-controller.ts +77 -49
- package/src/modes/controllers/extension-ui-controller.ts +8 -1
- package/src/modes/controllers/input-controller.ts +13 -18
- package/src/modes/controllers/selector-controller.ts +41 -0
- package/src/modes/interactive-mode.ts +14 -1
- package/src/modes/rpc/rpc-mode.ts +32 -12
- package/src/modes/rpc/rpc-socket-security.ts +13 -1
- package/src/modes/rpc/rpc-types.ts +9 -0
- package/src/modes/shared/agent-wire/command-validation.ts +4 -0
- package/src/modes/shared/agent-wire/event-contract.ts +22 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/types.ts +3 -0
- package/src/modes/utils/injected-user-submission.ts +94 -0
- package/src/modes/utils/ui-helpers.ts +17 -4
- package/src/notifications/config-commands.ts +20 -0
- package/src/notifications/config.ts +43 -4
- package/src/notifications/index.ts +105 -9
- package/src/notifications/lifecycle-commands.ts +37 -16
- package/src/notifications/lifecycle-control-runtime.ts +8 -3
- package/src/notifications/reply-sent-store.ts +134 -0
- package/src/notifications/rich-draft.ts +107 -0
- package/src/notifications/rich-render.ts +142 -0
- package/src/notifications/telegram-daemon-cli.ts +54 -7
- package/src/notifications/telegram-daemon-control.ts +2 -2
- package/src/notifications/telegram-daemon.ts +390 -56
- package/src/notifications/telegram-reference.ts +17 -0
- package/src/notifications/threaded-render.ts +45 -2
- package/src/prompts/agents/architect.md +19 -10
- package/src/prompts/agents/critic.md +16 -18
- package/src/prompts/agents/executor.md +14 -11
- package/src/prompts/agents/planner.md +18 -13
- package/src/prompts/ci-green-request.md +3 -8
- package/src/prompts/goals/goal-continuation.md +0 -5
- package/src/prompts/goals/goal-mode-active.md +0 -5
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +3 -3
- package/src/prompts/system/project-prompt.md +0 -13
- package/src/prompts/system/subagent-system-prompt.md +3 -2
- package/src/prompts/system/system-prompt.md +26 -19
- package/src/prompts/system/volatile-project-context.md +10 -0
- package/src/prompts/system/web-search.md +4 -7
- package/src/prompts/tools/apply-patch.md +6 -0
- package/src/prompts/tools/ast-edit.md +1 -0
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/bisect.md +22 -0
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +0 -2
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/github.md +6 -6
- package/src/prompts/tools/goal.md +1 -3
- package/src/prompts/tools/image-gen.md +12 -5
- package/src/prompts/tools/irc.md +5 -4
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/monitor.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/replace.md +2 -21
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search-tool-bm25.md +6 -11
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/skill.md +3 -2
- package/src/prompts/tools/ssh.md +2 -1
- package/src/prompts/tools/subagent.md +2 -2
- package/src/prompts/tools/task.md +4 -5
- package/src/prompts/tools/todo-write.md +1 -1
- package/src/prompts/tools/vim.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/prompts/tools/write.md +8 -2
- package/src/sdk.ts +68 -30
- package/src/session/agent-session.ts +734 -107
- package/src/session/file-mention-pruning.ts +64 -0
- package/src/session/messages.ts +4 -0
- package/src/session/session-manager.ts +59 -2
- package/src/skill-state/active-state.ts +141 -5
- package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
- package/src/slash-commands/builtin-registry.ts +143 -1
- package/src/system-prompt.ts +57 -16
- package/src/task/executor.ts +125 -20
- package/src/task/fork-context-advisory.ts +2 -7
- package/src/task/fork-context-budget.ts +9 -0
- package/src/task/index.ts +4 -3
- package/src/task/output-manager.ts +4 -2
- package/src/task/token-log.test.ts +188 -0
- package/src/task/token-log.ts +179 -0
- package/src/tools/bisect.ts +367 -0
- package/src/tools/index.ts +3 -0
- package/src/tools/output-meta.ts +116 -4
- package/src/tools/search.ts +8 -2
- package/src/tools/skill.ts +15 -0
- package/src/utils/file-mentions.ts +39 -7
- package/src/utils/git.ts +73 -0
- package/src/utils/pasted-image-path.ts +170 -0
- package/src/web/scrapers/youtube.ts +24 -12
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
2
2
|
import type { ImageContent, Message, MessageAttribution, ServiceTier, TextContent } from "@gajae-code/ai";
|
|
3
|
+
import type { TtsrInjectionRecord } from "../export/ttsr";
|
|
3
4
|
import { ArtifactManager } from "./artifacts";
|
|
4
5
|
import { type BlobPutResult, BlobStore } from "./blob-store";
|
|
5
6
|
import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
|
|
@@ -141,6 +142,10 @@ export interface TtsrInjectionEntry extends SessionEntryBase {
|
|
|
141
142
|
type: "ttsr_injection";
|
|
142
143
|
/** Names of rules that were injected */
|
|
143
144
|
injectedRules: string[];
|
|
145
|
+
/** Rich rule injection records with repeat state. */
|
|
146
|
+
injectedRuleRecords?: TtsrInjectionRecord[];
|
|
147
|
+
/** TTSR manager message count when this injection was recorded. */
|
|
148
|
+
ttsrMessageCount?: number;
|
|
144
149
|
}
|
|
145
150
|
/** Persisted MCP discovery selection state for a session branch. */
|
|
146
151
|
export interface MCPToolSelectionEntry extends SessionEntryBase {
|
|
@@ -212,6 +217,10 @@ export interface SessionContext {
|
|
|
212
217
|
models: Record<string, string>;
|
|
213
218
|
/** Names of TTSR rules that have been injected this session */
|
|
214
219
|
injectedTtsrRules: string[];
|
|
220
|
+
/** Rich TTSR rule injection records for repeat resume. */
|
|
221
|
+
injectedTtsrRuleRecords?: TtsrInjectionRecord[];
|
|
222
|
+
/** TTSR manager message count for repeat resume. */
|
|
223
|
+
ttsrMessageCount?: number;
|
|
215
224
|
/** MCP tool names selected through discovery for this session branch. */
|
|
216
225
|
selectedMCPToolNames: string[];
|
|
217
226
|
/** Whether this branch contains an explicit persisted MCP selection entry. */
|
|
@@ -477,6 +486,13 @@ export declare class SessionManager {
|
|
|
477
486
|
appendCompaction<T = unknown>(summary: string, shortSummary: string | undefined, firstKeptEntryId: string, tokensBefore: number, details?: T, fromExtension?: boolean, preserveData?: Record<string, unknown>): string;
|
|
478
487
|
/** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */
|
|
479
488
|
appendCustomEntry(customType: string, data?: unknown): string;
|
|
489
|
+
/**
|
|
490
|
+
* Append a root marker that starts a fresh active branch without changing the
|
|
491
|
+
* session id or deleting earlier durable entries. Subsequent messages descend
|
|
492
|
+
* from this marker, so provider context is clear while history remains
|
|
493
|
+
* available for diagnostics/export.
|
|
494
|
+
*/
|
|
495
|
+
appendContextClearEntry(data?: Record<string, unknown>): string;
|
|
480
496
|
/**
|
|
481
497
|
* Write mutated message entries back into the canonical entry store by id.
|
|
482
498
|
*
|
|
@@ -511,7 +527,7 @@ export declare class SessionManager {
|
|
|
511
527
|
* @param ruleNames Names of rules that were injected
|
|
512
528
|
* @returns Entry id
|
|
513
529
|
*/
|
|
514
|
-
appendTtsrInjection(ruleNames: string[]): string;
|
|
530
|
+
appendTtsrInjection(ruleNames: string[], records?: TtsrInjectionRecord[], ttsrMessageCount?: number): string;
|
|
515
531
|
/**
|
|
516
532
|
* Get all unique TTSR rule names that have been injected in the current branch.
|
|
517
533
|
* Scans from root to current leaf for ttsr_injection entries.
|
|
@@ -92,7 +92,24 @@ export declare function listActiveSkills(raw: unknown): SkillActiveEntry[];
|
|
|
92
92
|
export declare function normalizeSkillActiveState(raw: unknown): SkillActiveState | null;
|
|
93
93
|
export declare function getSkillActiveStatePaths(cwd: string, sessionId?: string): SkillActiveStatePaths;
|
|
94
94
|
export declare function collapsePlanningPipeline(entries: readonly SkillActiveEntry[]): SkillActiveEntry[];
|
|
95
|
-
export
|
|
95
|
+
export type VisibleSkillActiveStateCacheTier = "security" | "hud";
|
|
96
|
+
export interface ReadVisibleSkillActiveStateOptions {
|
|
97
|
+
tier?: VisibleSkillActiveStateCacheTier;
|
|
98
|
+
}
|
|
99
|
+
interface ActiveStateStatSignature {
|
|
100
|
+
path: string;
|
|
101
|
+
mtimeMs: number;
|
|
102
|
+
size: number;
|
|
103
|
+
}
|
|
104
|
+
interface ActiveStateSignature {
|
|
105
|
+
sessionPath: ActiveStateStatSignature | null;
|
|
106
|
+
activeDir: ActiveStateStatSignature | null;
|
|
107
|
+
activeEntries: ActiveStateStatSignature[];
|
|
108
|
+
ralplanModeState: ActiveStateStatSignature | null;
|
|
109
|
+
}
|
|
110
|
+
export declare function computeActiveStateSignature(cwd: string, sessionId: string): Promise<ActiveStateSignature>;
|
|
111
|
+
export declare function invalidateVisibleSkillActiveStateCache(cwd?: string, sessionId?: string): void;
|
|
112
|
+
export declare function readVisibleSkillActiveState(cwd: string, sessionId?: string, opts?: ReadVisibleSkillActiveStateOptions): Promise<SkillActiveState | null>;
|
|
96
113
|
export declare function syncSkillActiveState(options: SyncSkillActiveStateOptions): Promise<void>;
|
|
97
114
|
export interface ApplyHandoffOptions {
|
|
98
115
|
cwd: string;
|
|
@@ -17,9 +17,12 @@ export interface LoadContextFilesOptions {
|
|
|
17
17
|
cwd?: string;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* Load all
|
|
20
|
+
* Load all context files using the capability API.
|
|
21
21
|
* Returns {path, content, depth} entries for all discovered context files.
|
|
22
|
-
*
|
|
22
|
+
* Native user-global files (`~/.gjc/agent/AGENTS.md`) come first, then project
|
|
23
|
+
* files sorted by depth (descending) so files closer to cwd appear last/more
|
|
24
|
+
* prominent. User-home files from foreign providers (`~/.claude/CLAUDE.md`,
|
|
25
|
+
* `~/.codex/AGENTS.md`, …) stay excluded — only gjc's own user config applies.
|
|
23
26
|
*/
|
|
24
27
|
export declare function loadProjectContextFiles(options?: LoadContextFilesOptions): Promise<Array<{
|
|
25
28
|
path: string;
|
|
@@ -91,12 +94,25 @@ export interface BuildSystemPromptOptions {
|
|
|
91
94
|
secretsEnabled?: boolean;
|
|
92
95
|
/** Pre-loaded workspace tree (skips discovery if provided). May be a Promise to allow early kick-off. */
|
|
93
96
|
workspaceTree?: WorkspaceTree | Promise<WorkspaceTree>;
|
|
97
|
+
/**
|
|
98
|
+
* Render a trimmed role-agent base prompt for subagent sessions: omits the
|
|
99
|
+
* workflow-surface/routing/self-awareness (`<gjc-runtime>`) and `<soul>` blocks
|
|
100
|
+
* that only apply to the top-level interactive/print agent. Tool safety, repo
|
|
101
|
+
* safety, and the completion contract are retained. Default: false.
|
|
102
|
+
*/
|
|
103
|
+
subagent?: boolean;
|
|
94
104
|
}
|
|
95
105
|
/** Result of building provider-facing system prompt messages. */
|
|
96
106
|
export interface BuildSystemPromptResult {
|
|
97
107
|
/** Ordered system prompt blocks. Providers should preserve entries as distinct messages/blocks. */
|
|
98
108
|
systemPrompt: string[];
|
|
99
109
|
}
|
|
110
|
+
export interface BuildVolatileProjectContextOptions {
|
|
111
|
+
cwd?: string;
|
|
112
|
+
date?: string;
|
|
113
|
+
workspaceTree?: WorkspaceTree;
|
|
114
|
+
}
|
|
115
|
+
export declare function buildVolatileProjectContext(options?: BuildVolatileProjectContextOptions): string;
|
|
100
116
|
/** Build the system prompt with tools, guidelines, and context */
|
|
101
117
|
export declare function buildSystemPrompt(options?: BuildSystemPromptOptions): Promise<BuildSystemPromptResult>;
|
|
102
118
|
export {};
|
|
@@ -114,6 +114,7 @@ interface FinalizeSubprocessOutputResult {
|
|
|
114
114
|
}
|
|
115
115
|
export declare const SUBAGENT_WARNING_NULL_YIELD = "SYSTEM WARNING: Subagent called yield with null data.";
|
|
116
116
|
export declare const SUBAGENT_WARNING_MISSING_YIELD = "SYSTEM WARNING: Subagent exited without calling yield tool after 3 reminders.";
|
|
117
|
+
export declare const SUBAGENT_WARNING_PLACEHOLDER_YIELD = "SYSTEM WARNING: Subagent yield data contains a placeholder instead of the actual result.";
|
|
117
118
|
export declare function finalizeSubprocessOutput(args: FinalizeSubprocessOutputArgs): FinalizeSubprocessOutputResult;
|
|
118
119
|
export declare function createSubagentSettings(baseSettings: Settings, inheritedServiceTier?: ServiceTier): Settings;
|
|
119
120
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChatUsageSnapshot, CostEstimate } from "@gajae-code/agent-core";
|
|
2
|
+
import type { TaskTokenLog, TaskTokenMetrics } from "./types";
|
|
3
|
+
export interface TaskTokenLogChatBuckets {
|
|
4
|
+
readonly inputTokens: number;
|
|
5
|
+
readonly outputTokens: number;
|
|
6
|
+
readonly cachedInputTokens: number;
|
|
7
|
+
readonly cacheWriteTokens: number;
|
|
8
|
+
readonly costUsd?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface TaskTokenLogSessionManager {
|
|
11
|
+
getSessionId(): string;
|
|
12
|
+
}
|
|
13
|
+
export interface TaskTokenLogContext {
|
|
14
|
+
readonly subagentId: string;
|
|
15
|
+
readonly agent?: string;
|
|
16
|
+
readonly turn: number;
|
|
17
|
+
readonly at: string;
|
|
18
|
+
readonly model?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function taskTokenLogFromChat(chat: TaskTokenLogChatBuckets, ctx: TaskTokenLogContext): TaskTokenLog;
|
|
21
|
+
export declare function taskTokenLogFromUsage(usage: ChatUsageSnapshot, ctx: TaskTokenLogContext & {
|
|
22
|
+
readonly cost?: CostEstimate;
|
|
23
|
+
}): TaskTokenLog;
|
|
24
|
+
export declare function resolveTaskTokenLogDir(cwd: string, sessionManager: TaskTokenLogSessionManager | undefined, envSessionId?: string | undefined): Promise<string | undefined>;
|
|
25
|
+
export declare function persistTaskTokenLog(entry: TaskTokenLog, opts: {
|
|
26
|
+
dir: string;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
export declare function readTaskTokenLogs(dir: string): Promise<TaskTokenLog[]>;
|
|
29
|
+
export declare function computeTaskTokenMetrics(logs: readonly TaskTokenLog[]): TaskTokenMetrics;
|
|
30
|
+
export declare function computeCacheHitRate(input: number, cacheRead: number): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
import type { ToolSession } from ".";
|
|
4
|
+
import type { OutputMeta } from "./output-meta";
|
|
5
|
+
declare const bisectSchema: z.ZodObject<{
|
|
6
|
+
good: z.ZodString;
|
|
7
|
+
bad: z.ZodDefault<z.ZodString>;
|
|
8
|
+
run: z.ZodString;
|
|
9
|
+
invert: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
maxSteps: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
stepTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
type BisectParams = z.infer<typeof bisectSchema>;
|
|
14
|
+
export type BisectVerdict = "good" | "bad" | "skip";
|
|
15
|
+
export interface BisectStep {
|
|
16
|
+
rev: string;
|
|
17
|
+
verdict: BisectVerdict;
|
|
18
|
+
}
|
|
19
|
+
export interface BisectMarkResult {
|
|
20
|
+
exitCode: number;
|
|
21
|
+
output: string;
|
|
22
|
+
}
|
|
23
|
+
export interface BisectControllerDeps {
|
|
24
|
+
maxSteps: number;
|
|
25
|
+
/** SHA of the revision git currently has checked out. */
|
|
26
|
+
currentRev: () => Promise<string>;
|
|
27
|
+
/** Evaluate the predicate at the checked-out revision. */
|
|
28
|
+
evaluate: (rev: string) => Promise<BisectVerdict>;
|
|
29
|
+
/** Apply the verdict via `git bisect good|bad|skip` and return the raw result. */
|
|
30
|
+
mark: (verdict: BisectVerdict) => Promise<BisectMarkResult>;
|
|
31
|
+
}
|
|
32
|
+
export interface BisectOutcome {
|
|
33
|
+
culprit: string | null;
|
|
34
|
+
steps: BisectStep[];
|
|
35
|
+
concluded: boolean;
|
|
36
|
+
reason?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface BisectToolDetails {
|
|
39
|
+
meta?: OutputMeta;
|
|
40
|
+
culprit: string | null;
|
|
41
|
+
invert: boolean;
|
|
42
|
+
concluded: boolean;
|
|
43
|
+
steps: BisectStep[];
|
|
44
|
+
author?: string;
|
|
45
|
+
date?: string;
|
|
46
|
+
subject?: string;
|
|
47
|
+
reason?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Parse the culprit SHA from `git bisect good|bad` output, or null when not yet converged. */
|
|
50
|
+
export declare function parseFirstBadCommit(output: string): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Map a predicate exit code to a bisect verdict. `invert` swaps the good/bad
|
|
53
|
+
* mapping (to hunt for a fixing commit) but never reinterprets a skip.
|
|
54
|
+
*/
|
|
55
|
+
export declare function classifyExit(exitCode: number, invert: boolean): BisectVerdict;
|
|
56
|
+
/**
|
|
57
|
+
* Drive the bisect loop. Pure orchestration — every git/predicate effect is
|
|
58
|
+
* injected — so it can be exercised deterministically without a real repo.
|
|
59
|
+
*/
|
|
60
|
+
export declare function runBisectController(deps: BisectControllerDeps, signal?: AbortSignal): Promise<BisectOutcome>;
|
|
61
|
+
export declare class BisectTool implements AgentTool<typeof bisectSchema, BisectToolDetails> {
|
|
62
|
+
private readonly session;
|
|
63
|
+
readonly name = "bisect";
|
|
64
|
+
readonly label = "Bisect";
|
|
65
|
+
readonly summary = "Find the commit that introduced a regression by driving git bisect with a shell predicate";
|
|
66
|
+
readonly description: string;
|
|
67
|
+
readonly parameters: z.ZodObject<{
|
|
68
|
+
good: z.ZodString;
|
|
69
|
+
bad: z.ZodDefault<z.ZodString>;
|
|
70
|
+
run: z.ZodString;
|
|
71
|
+
invert: z.ZodDefault<z.ZodBoolean>;
|
|
72
|
+
maxSteps: z.ZodDefault<z.ZodNumber>;
|
|
73
|
+
stepTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
readonly strict = true;
|
|
76
|
+
readonly loadMode = "discoverable";
|
|
77
|
+
readonly intent: (args: Partial<BisectParams>) => string;
|
|
78
|
+
constructor(session: ToolSession);
|
|
79
|
+
execute(_toolCallId: string, params: BisectParams, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<BisectToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<BisectToolDetails>>;
|
|
80
|
+
}
|
|
81
|
+
export {};
|
|
@@ -8,7 +8,7 @@ import type { ToolSession } from ".";
|
|
|
8
8
|
import { type OutputMeta } from "./output-meta";
|
|
9
9
|
declare const searchSchema: z.ZodObject<{
|
|
10
10
|
pattern: z.ZodString;
|
|
11
|
-
paths: z.ZodArray<z.ZodString
|
|
11
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
12
|
i: z.ZodOptional<z.ZodBoolean>;
|
|
13
13
|
gitignore: z.ZodOptional<z.ZodBoolean>;
|
|
14
14
|
skip: z.ZodOptional<z.ZodNumber>;
|
|
@@ -61,7 +61,7 @@ export declare class SearchTool implements AgentTool<typeof searchSchema, Search
|
|
|
61
61
|
readonly description: string;
|
|
62
62
|
readonly parameters: z.ZodObject<{
|
|
63
63
|
pattern: z.ZodString;
|
|
64
|
-
paths: z.ZodArray<z.ZodString
|
|
64
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
65
65
|
i: z.ZodOptional<z.ZodBoolean>;
|
|
66
66
|
gitignore: z.ZodOptional<z.ZodBoolean>;
|
|
67
67
|
skip: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
2
|
+
/**
|
|
3
|
+
* Default inline cap for auto-read file mentions, deliberately below the
|
|
4
|
+
* read-tool cap (`DEFAULT_MAX_BYTES`, 50KB) so an incidental `@path` mention
|
|
5
|
+
* injects a smaller snippet than an explicit `read`. Overridable per call.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_FILE_MENTION_INLINE_BYTES: number;
|
|
2
8
|
/** Extract all @filepath mentions from text */
|
|
3
9
|
export declare function extractFileMentions(text: string): string[];
|
|
4
10
|
/**
|
|
@@ -8,4 +14,12 @@ export declare function extractFileMentions(text: string): string[];
|
|
|
8
14
|
export declare function generateFileMentionMessages(filePaths: string[], cwd: string, options?: {
|
|
9
15
|
autoResizeImages?: boolean;
|
|
10
16
|
useHashLines?: boolean;
|
|
17
|
+
/** Inline byte cap for auto-read text. Default: DEFAULT_FILE_MENTION_INLINE_BYTES. */
|
|
18
|
+
maxInlineBytes?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Resolved paths already shown (read or mentioned) recently in the
|
|
21
|
+
* conversation. A mention of one of these emits a compact duplicate note
|
|
22
|
+
* instead of re-injecting the full body.
|
|
23
|
+
*/
|
|
24
|
+
recentlyShownPaths?: ReadonlySet<string>;
|
|
11
25
|
}): Promise<AgentMessage[]>;
|
|
@@ -307,6 +307,38 @@ export declare function clean(cwd: string, options?: {
|
|
|
307
307
|
paths?: readonly string[];
|
|
308
308
|
signal?: AbortSignal;
|
|
309
309
|
}): Promise<void>;
|
|
310
|
+
export interface BisectCommitInfo {
|
|
311
|
+
sha: string;
|
|
312
|
+
author: string;
|
|
313
|
+
date: string;
|
|
314
|
+
subject: string;
|
|
315
|
+
stat: string;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Thin wrappers over `git bisect`. The marking commands (`good`/`bad`/`skip`)
|
|
319
|
+
* return the raw {@link GitCommandResult} without throwing so callers can both
|
|
320
|
+
* detect a genuine failure (non-zero exit) and scan the output for the
|
|
321
|
+
* "<sha> is the first bad commit" conclusion. `reset` is best-effort and never
|
|
322
|
+
* throws so it is safe to call from a `finally` block to restore the worktree.
|
|
323
|
+
*/
|
|
324
|
+
export declare const bisect: {
|
|
325
|
+
/** Begin a bisect session (does not seed good/bad endpoints). */
|
|
326
|
+
start(cwd: string, signal?: AbortSignal): Promise<void>;
|
|
327
|
+
/** Mark a revision (or current HEAD when omitted) good. Returns raw output. */
|
|
328
|
+
good(cwd: string, ref?: string, signal?: AbortSignal): Promise<GitCommandResult>;
|
|
329
|
+
/** Mark a revision (or current HEAD when omitted) bad. Returns raw output. */
|
|
330
|
+
bad(cwd: string, ref?: string, signal?: AbortSignal): Promise<GitCommandResult>;
|
|
331
|
+
/** Skip the current (untestable) revision. Returns raw output. */
|
|
332
|
+
skip(cwd: string, signal?: AbortSignal): Promise<GitCommandResult>;
|
|
333
|
+
/** Read the replayable bisect log for the current session. */
|
|
334
|
+
log(cwd: string, signal?: AbortSignal): Promise<string>;
|
|
335
|
+
/** End the bisect session, restoring the original HEAD. Never throws. */
|
|
336
|
+
reset(cwd: string, signal?: AbortSignal): Promise<void>;
|
|
337
|
+
/** True when `ancestor` is a first-parent-or-merge ancestor of `descendant`. */
|
|
338
|
+
isAncestor(cwd: string, ancestor: string, descendant: string, signal?: AbortSignal): Promise<boolean>;
|
|
339
|
+
/** Resolve author/date/subject and a diffstat for a commit (for the receipt). */
|
|
340
|
+
describe(cwd: string, sha: string, signal?: AbortSignal): Promise<BisectCommitInfo>;
|
|
341
|
+
};
|
|
310
342
|
export declare const ls: {
|
|
311
343
|
/** List files tracked or untracked by git. */
|
|
312
344
|
files(cwd: string, options?: {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DecodePastedPathOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Platform whose path semantics apply when decoding (shell unescaping,
|
|
4
|
+
* `file://` drive letters / UNC hosts). Defaults to `process.platform`;
|
|
5
|
+
* injectable so tests can pin the win32 contract from any host.
|
|
6
|
+
*/
|
|
7
|
+
platform?: NodeJS.Platform;
|
|
8
|
+
/** Home directory for `~/` expansion. Defaults to `os.homedir()`. */
|
|
9
|
+
homedir?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ResolvePastedImagePathOptions extends DecodePastedPathOptions {
|
|
12
|
+
/** Base directory for relative paths. Defaults to `process.cwd()`. */
|
|
13
|
+
cwd?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Decode pasted text into a filesystem path candidate. No filesystem access.
|
|
17
|
+
*
|
|
18
|
+
* Handles terminal drag-drop shell escaping (`\ `, `\(`, ...; skipped on
|
|
19
|
+
* win32 where `\` is the path separator), quoted paths, `file://` URIs
|
|
20
|
+
* (drive-letter, `file://localhost`, and UNC forms on win32), and `~/`
|
|
21
|
+
* expansion. Returns `undefined` when the text is empty, spans multiple
|
|
22
|
+
* lines, or is an invalid `file://` URI.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decodePastedPathCandidate(text: string, options?: DecodePastedPathOptions): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the resolved path when the whole pasted text is a single path to an
|
|
27
|
+
* existing image file (verified by extension AND content signature),
|
|
28
|
+
* otherwise `undefined` (the paste is inserted as text).
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolvePastedImagePath(text: string, options?: ResolvePastedImagePathOptions): string | undefined;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { SpecialHandler } from "./types";
|
|
2
|
+
export interface YouTubeUrl {
|
|
3
|
+
videoId: string;
|
|
4
|
+
playlistId?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse YouTube URL into components
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseYouTubeUrl(url: string): YouTubeUrl | null;
|
|
2
10
|
/**
|
|
3
11
|
* Handle YouTube URLs - fetch metadata and transcript
|
|
4
12
|
*/
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.1",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
|
-
"author": "Yeachan-Heo",
|
|
8
|
-
"contributors": [
|
|
9
|
-
"Mario Zechner"
|
|
10
|
-
],
|
|
7
|
+
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
11
8
|
"license": "MIT",
|
|
12
9
|
"repository": {
|
|
13
10
|
"type": "git",
|
|
@@ -52,12 +49,12 @@
|
|
|
52
49
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
53
50
|
"@babel/parser": "^7.29.3",
|
|
54
51
|
"@mozilla/readability": "^0.6.0",
|
|
55
|
-
"@gajae-code/stats": "0.
|
|
56
|
-
"@gajae-code/agent-core": "0.
|
|
57
|
-
"@gajae-code/ai": "0.
|
|
58
|
-
"@gajae-code/natives": "0.
|
|
59
|
-
"@gajae-code/tui": "0.
|
|
60
|
-
"@gajae-code/utils": "0.
|
|
52
|
+
"@gajae-code/stats": "0.9.1",
|
|
53
|
+
"@gajae-code/agent-core": "0.9.1",
|
|
54
|
+
"@gajae-code/ai": "0.9.1",
|
|
55
|
+
"@gajae-code/natives": "0.9.1",
|
|
56
|
+
"@gajae-code/tui": "0.9.1",
|
|
57
|
+
"@gajae-code/utils": "0.9.1",
|
|
61
58
|
"@puppeteer/browsers": "^2.13.0",
|
|
62
59
|
"@types/turndown": "5.0.6",
|
|
63
60
|
"@xterm/headless": "^6.0.0",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for append-only context-mode resolution and manager
|
|
3
|
+
* construction. Both the initial session build (`sdk.ts`) and the runtime
|
|
4
|
+
* model/setting-change path (`agent-session.ts`), plus the status UI, resolve
|
|
5
|
+
* through here so the auto allowlist and prefix-reset diagnostics never drift.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { AppendOnlyContextManager } from "@gajae-code/agent-core";
|
|
9
|
+
import { logger } from "@gajae-code/utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Providers for which append-only context auto-enables. Exact provider-string
|
|
13
|
+
* match only: `anthropic` reached via a gateway/aggregator provider string
|
|
14
|
+
* (e.g. `openrouter`, a custom gateway) does NOT match and stays opt-in via
|
|
15
|
+
* `provider.appendOnlyContext: "on"`, because those transports can rewrite or
|
|
16
|
+
* renormalize the request in ways that have not been validated for append-only
|
|
17
|
+
* prefix stability.
|
|
18
|
+
*/
|
|
19
|
+
export function providerSupportsAppendOnlyAuto(provider: string): boolean {
|
|
20
|
+
return provider === "deepseek" || provider === "anthropic";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolve whether to enable append-only context mode based on the setting and provider.
|
|
25
|
+
*
|
|
26
|
+
* - `"on"` → always enable
|
|
27
|
+
* - `"off"` → never enable
|
|
28
|
+
* - `"auto"` → enable for providers with strong prompt-prefix caching that this
|
|
29
|
+
* harness has validated (see {@link providerSupportsAppendOnlyAuto})
|
|
30
|
+
*/
|
|
31
|
+
export function resolveAppendOnlyMode(setting: "auto" | "on" | "off" | undefined, provider: string): boolean {
|
|
32
|
+
switch (setting ?? "auto") {
|
|
33
|
+
case "on":
|
|
34
|
+
return true;
|
|
35
|
+
case "off":
|
|
36
|
+
return false;
|
|
37
|
+
default:
|
|
38
|
+
return providerSupportsAppendOnlyAuto(provider);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Construct an {@link AppendOnlyContextManager} wired to emit per-session
|
|
44
|
+
* stable-prefix reset diagnostics. Use this at every creation site so the
|
|
45
|
+
* telemetry is uniform.
|
|
46
|
+
*/
|
|
47
|
+
export function createAppendOnlyContextManager(provider: string | undefined): AppendOnlyContextManager {
|
|
48
|
+
return new AppendOnlyContextManager({
|
|
49
|
+
onPrefixChange: info =>
|
|
50
|
+
logger.debug("append-only stable prefix changed (cache prefix reset)", {
|
|
51
|
+
provider,
|
|
52
|
+
from: info.from,
|
|
53
|
+
to: info.to,
|
|
54
|
+
version: info.version,
|
|
55
|
+
reason: info.from === "<unbuilt>" ? "initial-build" : "prefix-mutation",
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -22,7 +22,7 @@ You are running an autonomous experiment loop. Keep iterating until the user int
|
|
|
22
22
|
### Available tools
|
|
23
23
|
- `init_experiment` — open or reconfigure the session. Pass `new_segment: true` to start a fresh baseline within the current session.
|
|
24
24
|
- `run_experiment` — run the benchmark (`bash autoresearch.sh`). Output is captured automatically and `METRIC name=value` / `ASI key=value` lines printed by the harness are parsed back to you. The command is fixed; if you need a different workload, edit `autoresearch.sh` and bump segment via `init_experiment new_segment: true`.
|
|
25
|
-
- `log_experiment` — record the result. On `keep`,
|
|
25
|
+
- `log_experiment` — record the result. On `keep`, changes are committed only on a dedicated `autoresearch/*` branch; otherwise the tool warns and leaves files in the worktree. On `discard`/`crash`/`checks_failed`, the worktree is reverted. Pass `flag_runs` to mark earlier runs as suspect; flagged runs are excluded from baseline and best-metric math.
|
|
26
26
|
- `update_notes` — replace the durable session playbook (`body`) or append to the ideas backlog (`append_idea`). The notes are injected into your system prompt every iteration.
|
|
27
27
|
|
|
28
28
|
### Operating protocol
|
|
@@ -62,7 +62,7 @@ export function createLogExperimentTool(
|
|
|
62
62
|
name: "log_experiment",
|
|
63
63
|
label: "Log Experiment",
|
|
64
64
|
description:
|
|
65
|
-
"Log the result of the latest run_experiment. Records the metric, optional ASI metadata, modified paths, and scope deviations. On `keep`, modified files are committed
|
|
65
|
+
"Log the result of the latest run_experiment. Records the metric, optional ASI metadata, modified paths, and scope deviations. On `keep`, modified files are committed only on a dedicated `autoresearch/*` branch; otherwise the tool warns and leaves them in the worktree. On `discard`/`crash`/`checks_failed`, the worktree is reverted. Pass `flag_runs` to mark earlier runs as suspect; flagged runs are excluded from baseline and best-metric math.",
|
|
66
66
|
parameters: logExperimentSchema,
|
|
67
67
|
defaultInactive: true,
|
|
68
68
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
package/src/capability/rule.ts
CHANGED
|
@@ -22,6 +22,11 @@ export interface RuleFrontmatter {
|
|
|
22
22
|
scope?: string | string[];
|
|
23
23
|
/** Per-rule TTSR interrupt mode override. */
|
|
24
24
|
interruptMode?: "never" | "prose-only" | "tool-only" | "always";
|
|
25
|
+
/** Per-rule TTSR repeat mode override. */
|
|
26
|
+
repeatMode?: "once" | "after-gap";
|
|
27
|
+
/** Per-rule TTSR repeat gap override. */
|
|
28
|
+
repeatGap?: number;
|
|
29
|
+
|
|
25
30
|
[key: string]: unknown;
|
|
26
31
|
}
|
|
27
32
|
|
|
@@ -47,6 +52,10 @@ export interface Rule {
|
|
|
47
52
|
scope?: string[];
|
|
48
53
|
/** Per-rule TTSR interrupt mode override (falls back to global ttsr.interruptMode). */
|
|
49
54
|
interruptMode?: "never" | "prose-only" | "tool-only" | "always";
|
|
55
|
+
/** Per-rule TTSR repeat mode override (falls back to global ttsr.repeatMode). */
|
|
56
|
+
repeatMode?: "once" | "after-gap";
|
|
57
|
+
/** Per-rule TTSR repeat gap override (falls back to global ttsr.repeatGap). */
|
|
58
|
+
repeatGap?: number;
|
|
50
59
|
/** Source metadata */
|
|
51
60
|
_source: SourceMeta;
|
|
52
61
|
}
|
package/src/cli/config-cli.ts
CHANGED
|
@@ -49,14 +49,38 @@ type CliSettingDef = {
|
|
|
49
49
|
|
|
50
50
|
const ALL_SETTING_PATHS = Object.keys(SETTINGS_SCHEMA) as SettingPath[];
|
|
51
51
|
const REDACTED_SECRET_VALUE = "<redacted>";
|
|
52
|
-
const
|
|
52
|
+
const SECRET_SETTING_WORDS = new Set(["token", "secret", "password", "passwd", "pwd", "credential", "credentials"]);
|
|
53
|
+
const SECRET_SETTING_COMPOUND_PREFIXES = [
|
|
54
|
+
"api",
|
|
55
|
+
"auth",
|
|
56
|
+
"access",
|
|
57
|
+
"refresh",
|
|
58
|
+
"bearer",
|
|
59
|
+
"session",
|
|
60
|
+
"client",
|
|
61
|
+
"broker",
|
|
62
|
+
"bot",
|
|
63
|
+
"basic",
|
|
64
|
+
];
|
|
65
|
+
const SECRET_SETTING_COMPOUND_SUFFIXES = ["token", "secret", "password", "credential"];
|
|
66
|
+
|
|
67
|
+
function isSecretSettingSegment(segment: string): boolean {
|
|
68
|
+
const normalized = segment.toLowerCase();
|
|
69
|
+
if (SECRET_SETTING_WORDS.has(normalized)) return true;
|
|
70
|
+
if (/api[-_]?key/i.test(segment)) return true;
|
|
71
|
+
const words = normalized.split(/[-_]/).filter(Boolean);
|
|
72
|
+
if (words.some(word => SECRET_SETTING_WORDS.has(word))) return true;
|
|
73
|
+
return SECRET_SETTING_COMPOUND_PREFIXES.some(prefix =>
|
|
74
|
+
SECRET_SETTING_COMPOUND_SUFFIXES.some(suffix => normalized === `${prefix}${suffix}`),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
53
77
|
|
|
54
78
|
function isSecretSettingPath(path: string): boolean {
|
|
55
|
-
return path.split(".").some(segment =>
|
|
79
|
+
return path.split(".").some(segment => isSecretSettingSegment(segment));
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
function redactConfigValue(path: string, value: unknown, showSecrets?: boolean): unknown {
|
|
59
|
-
if (showSecrets ||
|
|
83
|
+
if (showSecrets || value === undefined || value === null || !isSecretSettingPath(path)) {
|
|
60
84
|
return value;
|
|
61
85
|
}
|
|
62
86
|
return REDACTED_SECRET_VALUE;
|