@gajae-code/coding-agent 0.18.7 → 0.18.9
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 +377 -1
- package/dist/types/async/endpoint-id.d.ts +16 -0
- package/dist/types/async/job-manager.d.ts +1 -1
- package/dist/types/async/support.d.ts +0 -14
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/capability/skill.d.ts +2 -0
- package/dist/types/capability/types.d.ts +2 -0
- package/dist/types/cli/public-command-errors.d.ts +3 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/mcp-serve.d.ts +4 -0
- package/dist/types/config/autorouting-tier-map.d.ts +348 -9
- package/dist/types/config/file-lock.d.ts +1 -0
- package/dist/types/config/model-bindings-applier.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -3
- package/dist/types/config/model-registry.d.ts +4 -9
- package/dist/types/config/skill-settings-defaults.d.ts +2 -0
- package/dist/types/cursor-delete-path.d.ts +1 -0
- package/dist/types/cursor-mcp-name.d.ts +8 -0
- package/dist/types/customization/inventory.d.ts +2 -0
- package/dist/types/debug/report-bundle-parent.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
- package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
- package/dist/types/discovery/helpers.d.ts +6 -1
- package/dist/types/discovery/mcp-json.d.ts +1 -0
- package/dist/types/eval/py/kernel.d.ts +18 -0
- package/dist/types/export/html/css-color.d.ts +2 -0
- package/dist/types/export/html/html-export-destination.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +5 -0
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
- package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
- package/dist/types/extensibility/skill-management.d.ts +4 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -3
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
- package/dist/types/gjc-runtime/sidecar-bootstrap-env.d.ts +6 -0
- package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
- package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
- package/dist/types/gjc-runtime/tmux-common.d.ts +8 -5
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
- package/dist/types/internal-urls/skill-path.d.ts +1 -0
- package/dist/types/lsp/config.d.ts +8 -5
- package/dist/types/lsp/workspace-path.d.ts +1 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
- package/dist/types/modes/controllers/input-controller.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
- package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
- package/dist/types/progress/collect-project-progress.d.ts +38 -0
- package/dist/types/progress/progress-contract.d.ts +154 -0
- package/dist/types/progress/progress-snapshot.d.ts +11 -0
- package/dist/types/progress/project-progress.d.ts +141 -0
- package/dist/types/progress/render-progress.d.ts +28 -0
- package/dist/types/runtime-mcp/manager.d.ts +2 -1
- package/dist/types/runtime-mcp/mcp-redirect.d.ts +9 -0
- package/dist/types/runtime-mcp/oauth-public-url.d.ts +3 -0
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
- package/dist/types/runtime-mcp/project-host-values.d.ts +27 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk/acp/adapter.d.ts +1 -1
- package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
- package/dist/types/sdk/broker/broker.d.ts +24 -2
- package/dist/types/sdk/broker/doctor-restart.d.ts +5 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -1
- package/dist/types/sdk/broker/session-index.d.ts +12 -6
- package/dist/types/sdk/bus/index.d.ts +12 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +3 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +38 -9
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
- package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
- package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
- package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
- package/dist/types/session/session-manager.d.ts +31 -5
- package/dist/types/session/session-retirement.d.ts +31 -7
- package/dist/types/session/session-storage.d.ts +69 -2
- package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
- package/dist/types/setup/credential-auto-import.d.ts +1 -1
- package/dist/types/setup/credential-import.d.ts +6 -4
- package/dist/types/skill-state/active-state.d.ts +38 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +3 -0
- package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/isolation-dir.d.ts +26 -0
- package/dist/types/tools/ast-edit-write-path.d.ts +13 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -1
- package/dist/types/tools/browser/cdp-url.d.ts +2 -0
- package/dist/types/tools/github-side-effect.d.ts +22 -0
- package/dist/types/tools/index.d.ts +3 -0
- package/dist/types/tools/monitor-mutation.d.ts +9 -0
- package/dist/types/tools/python.d.ts +9 -1
- package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
- package/dist/types/tools/restricted-cwd.d.ts +1 -0
- package/dist/types/tools/todo-write.d.ts +6 -0
- package/dist/types/utils/tools-checksum.d.ts +7 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +21 -0
- package/scripts/verify-managed-empty-stop.ts +28 -0
- package/src/async/endpoint-id.ts +26 -0
- package/src/async/job-manager.ts +247 -132
- package/src/async/support.ts +0 -25
- package/src/capability/index.ts +15 -0
- package/src/capability/mcp.ts +2 -0
- package/src/capability/skill.ts +2 -0
- package/src/capability/types.ts +2 -0
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/customize-doctor.ts +15 -2
- package/src/cli/doctor/repairs.ts +4 -1
- package/src/cli/doctor-supervisor.ts +3 -0
- package/src/cli/public-command-errors.ts +21 -1
- package/src/cli/public-command-registry.ts +28 -6
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/skills-cli.ts +5 -0
- package/src/commands/deep-interview.ts +47 -8
- package/src/commands/mcp-serve.ts +7 -0
- package/src/commands/sdk.ts +455 -397
- package/src/config/autorouting-tier-map.ts +117 -7
- package/src/config/file-lock.ts +316 -79
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-bindings-applier.ts +20 -0
- package/src/config/model-profile-activation.ts +240 -46
- package/src/config/model-registry.ts +47 -153
- package/src/config/skill-settings-defaults.ts +7 -0
- package/src/coordinator-mcp/policy.ts +3 -2
- package/src/coordinator-mcp/server.ts +2 -0
- package/src/cursor-delete-path.ts +10 -0
- package/src/cursor-mcp-name.ts +15 -0
- package/src/cursor.ts +13 -2
- package/src/customization/inventory.ts +4 -13
- package/src/dap/config.ts +2 -2
- package/src/debug/report-bundle-parent.ts +22 -0
- package/src/debug/report-bundle.ts +3 -0
- package/src/debug/system-info.ts +13 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +10 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
- package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
- package/src/defaults/gjc-defaults.test.ts +18 -1
- package/src/defaults/gjc-defaults.ts +3 -0
- package/src/defaults/gjc-skills.generated.ts +58 -36
- package/src/discovery/agents.ts +6 -1
- package/src/discovery/builtin.ts +13 -1
- package/src/discovery/helpers.ts +171 -29
- package/src/discovery/mcp-json.ts +26 -12
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/substitute-plugin-root.ts +3 -1
- package/src/edit/file-read-cache.ts +1 -1
- package/src/eval/py/executor.ts +796 -154
- package/src/eval/py/kernel.ts +79 -13
- package/src/eval/py/tool-bridge.ts +4 -0
- package/src/export/html/css-color.ts +9 -0
- package/src/export/html/html-export-destination.ts +16 -0
- package/src/export/html/index.ts +7 -10
- package/src/export/html/template.generated.ts +1 -1
- package/src/extensibility/extensions/function-hooks-internal.ts +27 -0
- package/src/extensibility/extensions/runner.ts +15 -1
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/extensibility/gjc-plugins/mcp-policy.ts +2 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +85 -8
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/plugins/marketplace/cache.ts +15 -0
- package/src/extensibility/plugins/marketplace/manager.ts +11 -3
- package/src/extensibility/plugins/plugin-link-path.ts +12 -0
- package/src/extensibility/runtime-skill-discovery.ts +20 -2
- package/src/extensibility/skill-management.ts +9 -2
- package/src/extensibility/skills.ts +6 -1
- package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
- package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
- package/src/gjc-runtime/deep-interview-stage.ts +98 -21
- package/src/gjc-runtime/gc-runtime.ts +206 -9
- package/src/gjc-runtime/launch-worktree.ts +70 -9
- package/src/gjc-runtime/psmux-detect.ts +28 -4
- package/src/gjc-runtime/ralplan-runtime.ts +447 -52
- package/src/gjc-runtime/session-state-sidecar.ts +3 -2
- package/src/gjc-runtime/sidecar-bootstrap-env.ts +19 -0
- package/src/gjc-runtime/state-argv.ts +2 -0
- package/src/gjc-runtime/state-migrations.ts +91 -29
- package/src/gjc-runtime/state-runtime.ts +3716 -135
- package/src/gjc-runtime/state-writer.ts +105 -16
- package/src/gjc-runtime/tmux-common.ts +8 -5
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
- package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
- package/src/gjc-runtime/workflow-manifest.ts +54 -21
- package/src/harness-control-plane/operate.ts +12 -4
- package/src/harness-control-plane/owner.ts +5 -1
- package/src/hashline/parser.ts +48 -9
- package/src/hashline/recovery.ts +13 -4
- package/src/internal-urls/docs-index.generated.ts +20 -19
- package/src/internal-urls/skill-path.ts +19 -0
- package/src/internal-urls/skill-protocol.ts +2 -0
- package/src/lsp/config.ts +12 -63
- package/src/lsp/edits.ts +6 -0
- package/src/lsp/workspace-path.ts +51 -0
- package/src/main.ts +195 -31
- package/src/memories/index.ts +88 -7
- package/src/modes/acp/acp-agent.ts +88 -4
- package/src/modes/components/custom-editor.ts +14 -0
- package/src/modes/components/customization/customization-dashboard.ts +12 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -2
- package/src/modes/components/extensions/state-manager.ts +15 -5
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/hook-selector.ts +1 -1
- package/src/modes/components/model-selector.ts +1 -4
- package/src/modes/components/provider-onboarding-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +4 -0
- package/src/modes/controllers/event-controller.ts +11 -4
- package/src/modes/controllers/input-controller.ts +76 -31
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -16
- package/src/modes/controllers/selector-controller.ts +24 -15
- package/src/modes/controllers/todo-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -1
- package/src/modes/runtime-init.ts +4 -0
- package/src/modes/utils/abort-message.ts +3 -1
- package/src/modes/utils/interrupt-ownership.ts +12 -0
- package/src/modes/utils/keybinding-matchers.ts +4 -0
- package/src/modes/utils/macos-option-forwarding.ts +80 -0
- package/src/progress/collect-project-progress.ts +153 -0
- package/src/progress/progress-contract.ts +172 -0
- package/src/progress/progress-snapshot.ts +140 -0
- package/src/progress/project-progress.ts +446 -0
- package/src/progress/render-progress.ts +209 -0
- package/src/prompts/system/master-mode.md +1 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/runtime-mcp/client.ts +4 -2
- package/src/runtime-mcp/config-writer.ts +10 -6
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/json-rpc.ts +2 -1
- package/src/runtime-mcp/manager.ts +29 -11
- package/src/runtime-mcp/mcp-redirect.ts +73 -0
- package/src/runtime-mcp/oauth-flow.ts +14 -2
- package/src/runtime-mcp/oauth-public-url.ts +14 -0
- package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
- package/src/runtime-mcp/pool.ts +6 -0
- package/src/runtime-mcp/project-host-values.ts +46 -0
- package/src/runtime-mcp/smithery-registry.ts +22 -3
- package/src/runtime-mcp/transports/http.ts +4 -3
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk/acp/adapter.ts +95 -8
- package/src/sdk/broker/broker-exit.ts +52 -23
- package/src/sdk/broker/broker.ts +81 -6
- package/src/sdk/broker/doctor-restart.ts +4 -0
- package/src/sdk/broker/ensure.ts +31 -2
- package/src/sdk/broker/lifecycle.ts +711 -66
- package/src/sdk/broker/session-index.ts +191 -81
- package/src/sdk/bus/chat-daemon-cli.ts +38 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +238 -43
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
- package/src/sdk/cli/session-cli.ts +17 -3
- package/src/sdk/client/client.ts +28 -8
- package/src/sdk/host/query/handlers.ts +9 -1
- package/src/sdk/host/session-runtime.test.ts +2705 -303
- package/src/sdk/host/session-runtime.ts +490 -143
- package/src/sdk/host/surface-policy.ts +1 -0
- package/src/sdk/index.ts +8 -0
- package/src/sdk/lifecycle-session.ts +3 -1
- package/src/sdk/prompt-deadline-manager.ts +15 -0
- package/src/sdk/protocol/operation-inventory.generated.json +146 -0
- package/src/sdk/protocol/operation-registry.ts +9 -2
- package/src/sdk/router/session-router.ts +82 -18
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +69 -45
- package/src/session/agent-session.ts +679 -238
- package/src/session/artifacts.ts +176 -71
- package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
- package/src/session/internal/managed-session-scope.ts +3779 -462
- package/src/session/internal/managed-session-storage.ts +501 -78
- package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
- package/src/session/internal/task-artifact-owner-access.ts +19 -3
- package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
- package/src/session/session-manager.ts +951 -133
- package/src/session/session-retirement.ts +573 -14
- package/src/session/session-storage.ts +447 -15
- package/src/session/task-artifact-owner-codec.ts +71 -8
- package/src/session/task-artifact-owner-retirement.ts +21 -19
- package/src/setup/credential-auto-import.ts +12 -3
- package/src/setup/credential-import.ts +176 -5
- package/src/setup/paseo/announce.ts +6 -1
- package/src/skill-state/active-state.ts +145 -2
- package/src/skill-state/workflow-mutation-guard.ts +102 -10
- package/src/slash-commands/builtin-registry.ts +39 -9
- package/src/slash-commands/helpers/mcp.ts +8 -4
- package/src/slash-commands/helpers/progress-report.ts +23 -0
- package/src/stt/setup.ts +3 -5
- package/src/task/commands.ts +3 -1
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +6 -0
- package/src/task/isolation-dir.ts +143 -0
- package/src/task/worktree.ts +16 -7
- package/src/tools/ask.ts +205 -6
- package/src/tools/ast-edit-write-path.ts +68 -0
- package/src/tools/ast-edit.ts +10 -1
- package/src/tools/bash-allowed-prefixes.ts +15 -0
- package/src/tools/bash-skill-urls.ts +56 -3
- package/src/tools/bash.ts +48 -79
- package/src/tools/browser/cdp-url.ts +18 -0
- package/src/tools/browser.ts +8 -1
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/eval.ts +56 -36
- package/src/tools/gh.ts +10 -0
- package/src/tools/github-side-effect.ts +112 -0
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -0
- package/src/tools/monitor-mutation.ts +27 -0
- package/src/tools/monitor.ts +7 -0
- package/src/tools/python.ts +188 -66
- package/src/tools/recipe/index.ts +9 -0
- package/src/tools/recipe/recipe-guard.ts +19 -0
- package/src/tools/restricted-cwd.ts +10 -0
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +28 -1
- package/src/tools/todo-write.ts +10 -1
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/write.ts +1 -0
- package/src/utils/external-editor.ts +3 -2
- package/src/utils/tools-checksum.ts +34 -0
- package/src/utils/tools-manager.ts +24 -6
- package/src/web/insane/url-guard.ts +2 -1
- package/src/web/search/providers/codex.ts +3 -2
package/src/memories/index.ts
CHANGED
|
@@ -3,7 +3,14 @@ import type * as fsNode from "node:fs";
|
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
6
|
-
import {
|
|
6
|
+
import { estimateTextTokensHeuristic } from "@gajae-code/agent-core/compaction";
|
|
7
|
+
import {
|
|
8
|
+
ANTHROPIC_THINKING,
|
|
9
|
+
completeSimple,
|
|
10
|
+
Effort,
|
|
11
|
+
type Model,
|
|
12
|
+
resolveDefaultRequestMaxTokens,
|
|
13
|
+
} from "@gajae-code/ai/core";
|
|
7
14
|
import { clampThinkingLevelForModel } from "@gajae-code/ai/model-thinking";
|
|
8
15
|
import { getAgentDbPath, getMemoriesDir, logger, parseJsonlLenient, prompt } from "@gajae-code/utils";
|
|
9
16
|
import type { ModelRegistry } from "../config/model-registry";
|
|
@@ -74,6 +81,20 @@ const DEFAULTS: MemoryRuntimeConfig = {
|
|
|
74
81
|
summaryInjectionTokenLimit: 5_000,
|
|
75
82
|
};
|
|
76
83
|
|
|
84
|
+
const PHASE2_RAW_MEMORIES_TOKEN_LIMIT = 20_000;
|
|
85
|
+
const PHASE2_ROLLOUT_SUMMARIES_TOKEN_LIMIT = 12_000;
|
|
86
|
+
// Ceiling for the phase 2 response. Phase 2 rewrites MEMORY.md, the summary and every
|
|
87
|
+
// skill in one JSON response, and on adaptive-thinking / reasoning-effort models the
|
|
88
|
+
// reasoning shares this budget. Twice the (approximate) input caps is a generous
|
|
89
|
+
// practical ceiling, not a guarantee that every response fits; a response that still
|
|
90
|
+
// overruns it is reported as truncation.
|
|
91
|
+
const PHASE2_MAX_OUTPUT_TOKENS = 2 * (PHASE2_RAW_MEMORIES_TOKEN_LIMIT + PHASE2_ROLLOUT_SUMMARIES_TOKEN_LIMIT);
|
|
92
|
+
// On a small context window phase 2 shrinks its inputs rather than let the response
|
|
93
|
+
// budget drop below the previous fixed budget.
|
|
94
|
+
const PHASE2_MIN_OUTPUT_TOKENS = 8_192;
|
|
95
|
+
// Request framing plus estimator error when fitting input + output into the context window.
|
|
96
|
+
const PHASE2_CONTEXT_SAFETY_TOKENS = 2_048;
|
|
97
|
+
|
|
77
98
|
interface Stage1Stats {
|
|
78
99
|
claimed: number;
|
|
79
100
|
succeeded: number;
|
|
@@ -738,10 +759,8 @@ async function runConsolidationModel(options: {
|
|
|
738
759
|
const { memoryRoot, model, apiKey } = options;
|
|
739
760
|
const rawMemories = await Bun.file(path.join(memoryRoot, "raw_memories.md")).text();
|
|
740
761
|
const rolloutSummaries = await readRolloutSummaries(memoryRoot);
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
rollout_summaries: truncateByApproxTokens(rolloutSummaries, 12_000),
|
|
744
|
-
});
|
|
762
|
+
const reasoning = clampThinkingLevelForModel(model, Effort.Low);
|
|
763
|
+
const { input, maxTokens } = buildPhase2Request(model, rawMemories, rolloutSummaries, reasoning);
|
|
745
764
|
|
|
746
765
|
const response = await completeSimple(
|
|
747
766
|
model,
|
|
@@ -751,18 +770,27 @@ async function runConsolidationModel(options: {
|
|
|
751
770
|
{
|
|
752
771
|
apiKey,
|
|
753
772
|
metadata: options.metadata,
|
|
754
|
-
maxTokens
|
|
755
|
-
reasoning
|
|
773
|
+
maxTokens,
|
|
774
|
+
reasoning,
|
|
756
775
|
},
|
|
757
776
|
);
|
|
758
777
|
if (response.stopReason === "error") {
|
|
759
778
|
throw new Error(response.errorMessage || "phase2 model error");
|
|
760
779
|
}
|
|
780
|
+
if (response.stopReason === "length") {
|
|
781
|
+
throw new Error(`phase2 output truncated at the max output token limit (${response.usage.output} output tokens)`);
|
|
782
|
+
}
|
|
761
783
|
const text = response.content
|
|
762
784
|
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
763
785
|
.map(c => c.text)
|
|
764
786
|
.join("\n")
|
|
765
787
|
.trim();
|
|
788
|
+
if (!text) {
|
|
789
|
+
const thinkingBlocks = response.content.filter(c => c.type === "thinking").length;
|
|
790
|
+
throw new Error(
|
|
791
|
+
`phase2 returned no text (stopReason=${response.stopReason}, ${response.usage.output} output tokens, ${thinkingBlocks} thinking blocks)`,
|
|
792
|
+
);
|
|
793
|
+
}
|
|
766
794
|
const parsed = parseJsonObject(text);
|
|
767
795
|
if (!parsed) throw new Error("phase2 JSON parse failure");
|
|
768
796
|
const schemaOutput = parseConsolidationOutputSchema(parsed);
|
|
@@ -1101,6 +1129,59 @@ function truncateByApproxTokens(text: string, tokenLimit: number): string {
|
|
|
1101
1129
|
return `${text.slice(0, head)}\n\n...[truncated]...\n\n${text.slice(-tail)}`;
|
|
1102
1130
|
}
|
|
1103
1131
|
|
|
1132
|
+
/**
|
|
1133
|
+
* Render the phase 2 prompt and choose its response budget.
|
|
1134
|
+
*
|
|
1135
|
+
* The budget is the model's output limit capped at PHASE2_MAX_OUTPUT_TOKENS (or the
|
|
1136
|
+
* provider layer's request default when the limit is unknown). When the context window
|
|
1137
|
+
* is known, input + response + any thinking budget the provider adds on top must fit
|
|
1138
|
+
* in it: the response budget is clamped to the remaining room, and the inputs are
|
|
1139
|
+
* shrunk when that room would fall below PHASE2_MIN_OUTPUT_TOKENS.
|
|
1140
|
+
*/
|
|
1141
|
+
function buildPhase2Request(
|
|
1142
|
+
model: Model,
|
|
1143
|
+
rawMemories: string,
|
|
1144
|
+
rolloutSummaries: string,
|
|
1145
|
+
reasoning: Effort | undefined,
|
|
1146
|
+
): { input: string; maxTokens: number | undefined } {
|
|
1147
|
+
const outputLimit =
|
|
1148
|
+
Number.isSafeInteger(model.maxTokens) && model.maxTokens > 0
|
|
1149
|
+
? Math.min(model.maxTokens, PHASE2_MAX_OUTPUT_TOKENS)
|
|
1150
|
+
: undefined;
|
|
1151
|
+
let rawTokens = Math.min(PHASE2_RAW_MEMORIES_TOKEN_LIMIT, Math.ceil(rawMemories.length / 4));
|
|
1152
|
+
let rolloutTokens = Math.min(PHASE2_ROLLOUT_SUMMARIES_TOKEN_LIMIT, Math.ceil(rolloutSummaries.length / 4));
|
|
1153
|
+
const render = () =>
|
|
1154
|
+
prompt.render(consolidationTemplate, {
|
|
1155
|
+
raw_memories: truncateByApproxTokens(rawMemories, rawTokens),
|
|
1156
|
+
rollout_summaries: truncateByApproxTokens(rolloutSummaries, rolloutTokens),
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
const contextWindow =
|
|
1160
|
+
Number.isSafeInteger(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : undefined;
|
|
1161
|
+
if (contextWindow === undefined) return { input: render(), maxTokens: outputLimit };
|
|
1162
|
+
|
|
1163
|
+
const responseCeiling = resolveDefaultRequestMaxTokens(model, outputLimit);
|
|
1164
|
+
const minResponse = Math.min(PHASE2_MIN_OUTPUT_TOKENS, responseCeiling);
|
|
1165
|
+
// Budget-mode providers may add the thinking budget on top of maxTokens.
|
|
1166
|
+
const addsThinkingBudget = model.thinking?.mode === "budget" || model.thinking?.mode === "anthropic-budget-effort";
|
|
1167
|
+
const thinkingReserve = reasoning && addsThinkingBudget ? ANTHROPIC_THINKING[reasoning] : 0;
|
|
1168
|
+
const inputRoom = contextWindow - PHASE2_CONTEXT_SAFETY_TOKENS - thinkingReserve - minResponse;
|
|
1169
|
+
|
|
1170
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
1171
|
+
const input = render();
|
|
1172
|
+
const inputTokens = estimateTextTokensHeuristic(input);
|
|
1173
|
+
if (inputTokens <= inputRoom) {
|
|
1174
|
+
const room = contextWindow - PHASE2_CONTEXT_SAFETY_TOKENS - thinkingReserve - inputTokens;
|
|
1175
|
+
return { input, maxTokens: Math.min(responseCeiling, room) };
|
|
1176
|
+
}
|
|
1177
|
+
if (inputRoom <= 0 || rawTokens + rolloutTokens === 0) break;
|
|
1178
|
+
const scale = (inputRoom / inputTokens) * 0.9;
|
|
1179
|
+
rawTokens = Math.floor(rawTokens * scale);
|
|
1180
|
+
rolloutTokens = Math.floor(rolloutTokens * scale);
|
|
1181
|
+
}
|
|
1182
|
+
throw new Error(`phase2 input does not fit the model context window (${contextWindow} tokens)`);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1104
1185
|
function computeModelTokenBudget(model: Model, config: MemoryRuntimeConfig): number {
|
|
1105
1186
|
const maxTokens =
|
|
1106
1187
|
Number.isFinite(model.contextWindow) && model.contextWindow > 0 ? model.contextWindow : config.fallbackTokenLimit;
|
|
@@ -38,6 +38,8 @@ import {
|
|
|
38
38
|
} from "@agentclientprotocol/sdk";
|
|
39
39
|
import { getAgentDir, logger, resolveEquivalentPath } from "@gajae-code/utils";
|
|
40
40
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
41
|
+
import { PROJECT_PROGRESS_SNAPSHOT_SCHEMA, type ProjectProgressSnapshot } from "../../progress/progress-contract";
|
|
42
|
+
import { PROGRESS_COMMAND_ACP_DESCRIPTION, renderProgressSnapshot } from "../../progress/render-progress";
|
|
41
43
|
import {
|
|
42
44
|
ACP_SESSION_RECONNECT,
|
|
43
45
|
type AcpProviderRegistration,
|
|
@@ -258,6 +260,8 @@ type PendingAttachment = { epoch: number; task: Promise<void> };
|
|
|
258
260
|
|
|
259
261
|
type PromptAdmissionSettlement = { kind: "cancelled" } | { kind: "rejected"; error: AcpSdkAdapterError };
|
|
260
262
|
type PromptAdmissionReservation = {
|
|
263
|
+
/** Held by a model-free builtin (`/progress`) answered locally; no host turn exists to abort. */
|
|
264
|
+
localCommand?: true;
|
|
261
265
|
cancelled?: boolean;
|
|
262
266
|
settlement?: PromptAdmissionSettlement;
|
|
263
267
|
wake: () => void;
|
|
@@ -526,9 +530,12 @@ function pageItems(value: unknown): unknown[] {
|
|
|
526
530
|
return Array.isArray(page?.items) ? page.items : [];
|
|
527
531
|
}
|
|
528
532
|
|
|
533
|
+
/** Builtin `/progress`: answered locally from the read-only `session.progress` SDK query, never a model turn. */
|
|
534
|
+
const ACP_PROGRESS_COMMAND: AvailableCommand = { name: "progress", description: PROGRESS_COMMAND_ACP_DESCRIPTION };
|
|
535
|
+
|
|
529
536
|
/** Build the ACP command palette from the shared builtins and live SDK skill state. */
|
|
530
537
|
export function acpAvailableCommandsFromSkills(query: unknown): AvailableCommand[] {
|
|
531
|
-
const commands = new Map<string, AvailableCommand>();
|
|
538
|
+
const commands = new Map<string, AvailableCommand>([[ACP_PROGRESS_COMMAND.name, ACP_PROGRESS_COMMAND]]);
|
|
532
539
|
for (const item of pageItems(query)) {
|
|
533
540
|
const skill = object(item);
|
|
534
541
|
if (typeof skill?.name !== "string" || !skill.name) continue;
|
|
@@ -1508,6 +1515,22 @@ export function acpSkillInvocation(blocks: PromptRequest["prompt"]): { name: str
|
|
|
1508
1515
|
return { name: match[1], args: match[2]?.trim() ?? "" };
|
|
1509
1516
|
}
|
|
1510
1517
|
|
|
1518
|
+
/**
|
|
1519
|
+
* Recognize the builtin `/progress` command only when it is the complete, single text
|
|
1520
|
+
* prompt. Like the TUI (`allowArgs: false`), `/progress <args>` is not the command.
|
|
1521
|
+
*/
|
|
1522
|
+
export function isAcpProgressCommand(blocks: PromptRequest["prompt"]): boolean {
|
|
1523
|
+
return blocks.length === 1 && blocks[0]?.type === "text" && blocks[0].text.trim() === "/progress";
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
/** Render the `session.progress` query result as the plain-text `/progress` view. */
|
|
1527
|
+
export function acpProgressReportText(query: unknown): string {
|
|
1528
|
+
const snapshot = object(pageItems(query)[0]);
|
|
1529
|
+
if (snapshot?.schema !== PROJECT_PROGRESS_SNAPSHOT_SCHEMA)
|
|
1530
|
+
throw new AcpSdkAdapterError("unavailable", "SDK session.progress response omitted the progress snapshot.");
|
|
1531
|
+
return renderProgressSnapshot(snapshot as unknown as ProjectProgressSnapshot).join("\n");
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1511
1534
|
/** Convert every ACP prompt block the agent advertises without silently discarding context. */
|
|
1512
1535
|
export function acpPromptPayload(blocks: PromptRequest["prompt"]): {
|
|
1513
1536
|
text: string;
|
|
@@ -2398,6 +2421,38 @@ export class AcpAgent implements Agent {
|
|
|
2398
2421
|
}
|
|
2399
2422
|
}
|
|
2400
2423
|
|
|
2424
|
+
/**
|
|
2425
|
+
* Read-only builtin `/progress`: answered from the session.progress query instead of a
|
|
2426
|
+
* model turn. It owns prompt admission (`pendingPromptAdmission`) from the query until its
|
|
2427
|
+
* response is published, so a concurrent prompt is refused as `conflict` exactly as it is
|
|
2428
|
+
* while a model turn is active. `cancel` and session teardown settle that reservation
|
|
2429
|
+
* through the existing admission paths; this command observes it and stops publishing.
|
|
2430
|
+
*/
|
|
2431
|
+
async #runProgressCommand(sessionId: string, record: SessionRecord): Promise<PromptResponse> {
|
|
2432
|
+
const { promise: woken, resolve: wake } = Promise.withResolvers<void>();
|
|
2433
|
+
const reservation: PromptAdmissionReservation = { localCommand: true, wake, woken };
|
|
2434
|
+
// Replaces a follow-up reservation this prompt already consumed; `#submitPrompt` only
|
|
2435
|
+
// clears the reservation it installed, so ownership stays with this command.
|
|
2436
|
+
record.pendingPromptAdmission = reservation;
|
|
2437
|
+
try {
|
|
2438
|
+
const query = record.adapter.query("session.progress");
|
|
2439
|
+
void query.catch(() => undefined);
|
|
2440
|
+
const result = await Promise.race([query.then(value => ({ value })), woken.then(() => undefined)]);
|
|
2441
|
+
const settlement = reservation.settlement;
|
|
2442
|
+
if (settlement?.kind === "rejected") throw settlement.error;
|
|
2443
|
+
if (settlement?.kind === "cancelled" || reservation.cancelled || !result) return { stopReason: "cancelled" };
|
|
2444
|
+
const text = acpProgressReportText(result.value);
|
|
2445
|
+
await this.#publishSessionUpdate(
|
|
2446
|
+
sessionId,
|
|
2447
|
+
{ sessionId, update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text } } },
|
|
2448
|
+
record.adapter,
|
|
2449
|
+
);
|
|
2450
|
+
return { stopReason: "end_turn" };
|
|
2451
|
+
} finally {
|
|
2452
|
+
if (record.pendingPromptAdmission === reservation) record.pendingPromptAdmission = undefined;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2401
2456
|
async #waitForPromptSettlement(
|
|
2402
2457
|
waiter: PromptWaiter,
|
|
2403
2458
|
admissionReservation: PromptAdmissionReservation,
|
|
@@ -2482,6 +2537,7 @@ export class AcpAgent implements Agent {
|
|
|
2482
2537
|
);
|
|
2483
2538
|
return { stopReason: "end_turn" };
|
|
2484
2539
|
}
|
|
2540
|
+
if (isAcpProgressCommand(params.prompt)) return await this.#runProgressCommand(params.sessionId, record);
|
|
2485
2541
|
// The SDK transport hard-caps a single request frame at 256 KiB and answers an
|
|
2486
2542
|
// oversize frame by closing the socket (CloseCode::Size, crates/gjc-sdk/src/server.rs),
|
|
2487
2543
|
// which surfaces to the client as an opaque `connection_closed` mid-turn. Reject
|
|
@@ -2969,6 +3025,7 @@ export class AcpAgent implements Agent {
|
|
|
2969
3025
|
// Record the client's intent before awaiting the SDK so a prompt that rejects
|
|
2970
3026
|
// mid-cancel (e.g. preflight `busy`) can still settle as `cancelled`.
|
|
2971
3027
|
record.cancelRequested = true;
|
|
3028
|
+
const localCommand = !record.activePrompt && record.pendingPromptAdmission?.localCommand === true;
|
|
2972
3029
|
this.#settlePendingPromptAdmission(record, { kind: "cancelled" });
|
|
2973
3030
|
// C04 terminal abort: an external client cancel stops the current turn
|
|
2974
3031
|
// (`scope:"turn"`, the default, matching the SDK `turn.abort` default and
|
|
@@ -2976,6 +3033,12 @@ export class AcpAgent implements Agent {
|
|
|
2976
3033
|
// subagents and background tasks stopped opts in with
|
|
2977
3034
|
// `_meta.gjc.abortScope: "owned"` (or `GJC_ACP_ABORT_SCOPE=owned`).
|
|
2978
3035
|
const scope = resolveAcpAbortScope(params._meta, process.env);
|
|
3036
|
+
// The current turn is a model-free builtin answered locally: settling its reservation
|
|
3037
|
+
// above cancels it, and the host has no turn to abort.
|
|
3038
|
+
if (localCommand && scope === "turn") {
|
|
3039
|
+
record.cancelRequested = false;
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
2979
3042
|
const waiter = record.activePrompt;
|
|
2980
3043
|
const waiterWasUnacknowledged = waiter !== undefined && !waiter.acknowledged;
|
|
2981
3044
|
const waiterWasBeforeActivity = waiter !== undefined && !waiter.observedTurnActivity;
|
|
@@ -3051,9 +3114,11 @@ export class AcpAgent implements Agent {
|
|
|
3051
3114
|
// publication is advisory and must never gate the settlement above.
|
|
3052
3115
|
void this.#publishPromptPhaseIdle(params.sessionId, record.adapter);
|
|
3053
3116
|
} else {
|
|
3117
|
+
if (waiter && record.activePrompt === waiter && waiter.terminal && !waiter.settled)
|
|
3118
|
+
this.#settlePrompt(params.sessionId, record, waiter);
|
|
3054
3119
|
// The acknowledgement proves the run was aborted, not that its terminal was
|
|
3055
3120
|
// published. Arm the bounded settlement so the turn cannot outlive the cancel.
|
|
3056
|
-
this.#scheduleCancelSettlement(params.sessionId, record);
|
|
3121
|
+
else this.#scheduleCancelSettlement(params.sessionId, record);
|
|
3057
3122
|
}
|
|
3058
3123
|
waiter?.cancelAttemptResolve?.(true);
|
|
3059
3124
|
} catch (error) {
|
|
@@ -3069,6 +3134,9 @@ export class AcpAgent implements Agent {
|
|
|
3069
3134
|
!waiter.settled
|
|
3070
3135
|
) {
|
|
3071
3136
|
if (waiter.terminalReserved) {
|
|
3137
|
+
await record.frameTail;
|
|
3138
|
+
if (record.activePrompt === waiter && waiter.terminal && !waiter.settled)
|
|
3139
|
+
this.#settlePrompt(params.sessionId, record, waiter);
|
|
3072
3140
|
waiter.cancelAttemptResolve?.(true);
|
|
3073
3141
|
return;
|
|
3074
3142
|
}
|
|
@@ -3124,6 +3192,9 @@ export class AcpAgent implements Agent {
|
|
|
3124
3192
|
waiter.cancelAttempt = undefined;
|
|
3125
3193
|
waiter.cancelAttemptResolve = undefined;
|
|
3126
3194
|
}
|
|
3195
|
+
const cancelWaveSettled = !waiter || waiter.cancelAcknowledged || (waiter.pendingCancelAttempts ?? 0) <= 1;
|
|
3196
|
+
if (cancelWaveSettled && waiter && record.activePrompt === waiter && waiter.terminal && !waiter.settled)
|
|
3197
|
+
this.#settlePrompt(params.sessionId, record, waiter);
|
|
3127
3198
|
throw cancellationError;
|
|
3128
3199
|
} finally {
|
|
3129
3200
|
if (waiter) {
|
|
@@ -4885,7 +4956,18 @@ export class AcpAgent implements Agent {
|
|
|
4885
4956
|
// Failure diagnostics are useful but advisory. Settle before any mapped
|
|
4886
4957
|
// session update can await a backpressured client transport; otherwise an
|
|
4887
4958
|
// already-decided failure can still lose to the inactivity watchdog.
|
|
4888
|
-
|
|
4959
|
+
// A terminal that races an in-flight cancel must not settle the public prompt before
|
|
4960
|
+
// the cancel request proves its outcome. Otherwise a follow-up prompt can be admitted
|
|
4961
|
+
// between the stale terminal settlement and the abort acknowledgement, leaving the
|
|
4962
|
+
// cancelled background request reported as `end_turn`.
|
|
4963
|
+
const cancelSettlementPending =
|
|
4964
|
+
activePrompt.cancelAttempt !== undefined &&
|
|
4965
|
+
!activePrompt.cancelAcknowledged &&
|
|
4966
|
+
record.statusRecovery !== activePrompt &&
|
|
4967
|
+
!this.#ownsUncertainAbort(record, activePrompt);
|
|
4968
|
+
if (!cancelSettlementPending) {
|
|
4969
|
+
this.#settlePrompt(id, record, activePrompt);
|
|
4970
|
+
}
|
|
4889
4971
|
}
|
|
4890
4972
|
if (!isTerminal && derivedCorrelation === undefined) return;
|
|
4891
4973
|
if (!isTerminal && hasCorrelation(correlation)) {
|
|
@@ -5274,7 +5356,9 @@ export class AcpAgent implements Agent {
|
|
|
5274
5356
|
const { outcome } = waiter.terminal;
|
|
5275
5357
|
this.#rememberSettledPromptCorrelation(id, record, waiter.correlation);
|
|
5276
5358
|
if (outcome.kind === "stopped") {
|
|
5277
|
-
|
|
5359
|
+
// Once the SDK has acknowledged a client cancel, the cancellation owns the
|
|
5360
|
+
// turn even if a stale terminal frame races in with another stopped reason.
|
|
5361
|
+
waiter.resolve({ stopReason: waiter.cancelAcknowledged ? "cancelled" : outcome.reason });
|
|
5278
5362
|
return;
|
|
5279
5363
|
}
|
|
5280
5364
|
// `phase` is the host's own claim, and a host that omits it leaves `terminalOutcome`
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Editor, type KeyId, matchesKey, parseKittySequence } from "@gajae-code/tui";
|
|
2
2
|
import { BracketedPasteHandler } from "@gajae-code/tui/bracketed-paste";
|
|
3
3
|
import { type AppKeybinding, KEYBINDINGS } from "../../config/keybindings";
|
|
4
|
+
import { macosOptionChordForComposedText } from "../utils/macos-option-forwarding";
|
|
4
5
|
|
|
5
6
|
type ConfigurableEditorAction = Extract<
|
|
6
7
|
AppKeybinding,
|
|
@@ -116,6 +117,12 @@ export class CustomEditor extends Editor {
|
|
|
116
117
|
onQueue?: () => void;
|
|
117
118
|
/** Called when Caps Lock is pressed. */
|
|
118
119
|
onCapsLock?: () => void;
|
|
120
|
+
/**
|
|
121
|
+
* Called when typed text is what macOS composes for a bound Option chord
|
|
122
|
+
* (for example `œ` for a bound `alt+q`), meaning the terminal sent Option as
|
|
123
|
+
* text. The text is still inserted; the callback only explains the miss.
|
|
124
|
+
*/
|
|
125
|
+
onUnforwardedOptionChord?: (key: KeyId, text: string) => void;
|
|
119
126
|
/** Called when PageUp/PageDown should scroll the transcript viewport instead of prompt history. */
|
|
120
127
|
onViewportPageScroll?: (direction: -1 | 1) => void;
|
|
121
128
|
/** Called before regular composer input should return the transcript viewport to the live bottom. */
|
|
@@ -473,6 +480,13 @@ export class CustomEditor extends Editor {
|
|
|
473
480
|
}
|
|
474
481
|
}
|
|
475
482
|
|
|
483
|
+
if (this.onUnforwardedOptionChord) {
|
|
484
|
+
const optionKey = macosOptionChordForComposedText(data);
|
|
485
|
+
if (optionKey && (this.hasActionKey(optionKey) || this.#customKeyHandlers.has(optionKey))) {
|
|
486
|
+
this.onUnforwardedOptionChord(optionKey, data);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
476
490
|
// Pass to parent for normal handling.
|
|
477
491
|
super.handleInput(data);
|
|
478
492
|
}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { Container, matchesKey, type SelectItem, SelectList, Text } from "@gajae-code/tui";
|
|
22
22
|
import { sanitizeText } from "@gajae-code/utils";
|
|
23
|
+
import { resolveGlobalUserSkillLinkTrust } from "../../../config/skill-settings-defaults";
|
|
23
24
|
import { type CustomizationInventory, loadCustomizationInventory } from "../../../customization/inventory";
|
|
24
25
|
import {
|
|
25
26
|
removeHookFile,
|
|
@@ -47,6 +48,7 @@ import { ImportWizard } from "./import-wizard";
|
|
|
47
48
|
/** Minimal settings slice the dashboard reads and writes. */
|
|
48
49
|
export interface CustomizationSettingsSlice {
|
|
49
50
|
get(key: string): unknown;
|
|
51
|
+
getGlobal?(key: string): unknown;
|
|
50
52
|
set?(key: string, value: unknown): void;
|
|
51
53
|
}
|
|
52
54
|
|
|
@@ -150,6 +152,16 @@ export class CustomizationDashboard extends Container {
|
|
|
150
152
|
cwd: this.#cwd,
|
|
151
153
|
home: this.#homeDir,
|
|
152
154
|
policy: this.#skillPolicy(),
|
|
155
|
+
allowExternalUserSkillSymlinks: resolveGlobalUserSkillLinkTrust({
|
|
156
|
+
trustUserSkills:
|
|
157
|
+
typeof this.#settings?.getGlobal === "function"
|
|
158
|
+
? (this.#settings.getGlobal("skills.trustUserSkills") as boolean | undefined)
|
|
159
|
+
: undefined,
|
|
160
|
+
enablePiUser:
|
|
161
|
+
typeof this.#settings?.getGlobal === "function"
|
|
162
|
+
? (this.#settings.getGlobal("skills.enablePiUser") as boolean | undefined)
|
|
163
|
+
: undefined,
|
|
164
|
+
}),
|
|
153
165
|
disabledExtensions: this.#getStringArray("disabledExtensions"),
|
|
154
166
|
});
|
|
155
167
|
}
|
|
@@ -59,7 +59,7 @@ export class ExtensionDashboard extends Container {
|
|
|
59
59
|
async #init(): Promise<void> {
|
|
60
60
|
const sm = this.settings ?? (await Settings.init());
|
|
61
61
|
const disabledIds = sm ? ((sm.get("disabledExtensions") as string[]) ?? []) : [];
|
|
62
|
-
this.#state = await createInitialState(this.cwd, disabledIds);
|
|
62
|
+
this.#state = await createInitialState(this.cwd, disabledIds, sm);
|
|
63
63
|
|
|
64
64
|
// Calculate max visible items based on terminal height
|
|
65
65
|
// Reserve ~10 lines for header, tabs, help text, borders
|
|
@@ -193,7 +193,7 @@ export class ExtensionDashboard extends Container {
|
|
|
193
193
|
|
|
194
194
|
const sm = this.settings ?? Settings.instance;
|
|
195
195
|
const disabledIds = sm ? ((sm.get("disabledExtensions") as string[]) ?? []) : [];
|
|
196
|
-
const nextState = await refreshState(this.#state, this.cwd, disabledIds);
|
|
196
|
+
const nextState = await refreshState(this.#state, this.cwd, disabledIds, sm);
|
|
197
197
|
if (refreshToken !== this.#refreshToken) return;
|
|
198
198
|
this.#state = nextState;
|
|
199
199
|
|
|
@@ -14,6 +14,7 @@ import type { Skill } from "../../../capability/skill";
|
|
|
14
14
|
import type { SlashCommand } from "../../../capability/slash-command";
|
|
15
15
|
import type { CustomTool } from "../../../capability/tool";
|
|
16
16
|
import type { SourceMeta } from "../../../capability/types";
|
|
17
|
+
import type { Settings } from "../../../config/settings";
|
|
17
18
|
import {
|
|
18
19
|
disableProvider,
|
|
19
20
|
enableProvider,
|
|
@@ -43,7 +44,11 @@ export interface ExtensionSettingsManager {
|
|
|
43
44
|
/**
|
|
44
45
|
* Load all extensions from all capabilities.
|
|
45
46
|
*/
|
|
46
|
-
export async function loadAllExtensions(
|
|
47
|
+
export async function loadAllExtensions(
|
|
48
|
+
cwd?: string,
|
|
49
|
+
disabledIds?: string[],
|
|
50
|
+
settings?: Settings,
|
|
51
|
+
): Promise<Extension[]> {
|
|
47
52
|
const extensions: Extension[] = [];
|
|
48
53
|
const disabledExtensions = new Set<string>(disabledIds ?? []);
|
|
49
54
|
|
|
@@ -97,7 +102,7 @@ export async function loadAllExtensions(cwd?: string, disabledIds?: string[]): P
|
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
|
|
100
|
-
const loadOpts = cwd ? { cwd, includeDisabled: true } : { includeDisabled: true };
|
|
105
|
+
const loadOpts = cwd ? { cwd, includeDisabled: true, settings } : { includeDisabled: true, settings };
|
|
101
106
|
|
|
102
107
|
// Load skills
|
|
103
108
|
try {
|
|
@@ -553,8 +558,12 @@ export function applyDisabledExtensionsToState(state: DashboardState, disabledId
|
|
|
553
558
|
/**
|
|
554
559
|
* Create initial dashboard state.
|
|
555
560
|
*/
|
|
556
|
-
export async function createInitialState(
|
|
557
|
-
|
|
561
|
+
export async function createInitialState(
|
|
562
|
+
cwd?: string,
|
|
563
|
+
disabledIds?: string[],
|
|
564
|
+
settings?: Settings,
|
|
565
|
+
): Promise<DashboardState> {
|
|
566
|
+
const extensions = await loadAllExtensions(cwd, disabledIds, settings);
|
|
558
567
|
const tabs = buildProviderTabs(extensions);
|
|
559
568
|
const tabFiltered = extensions; // "all" tab by default
|
|
560
569
|
const searchFiltered = tabFiltered;
|
|
@@ -592,8 +601,9 @@ export async function refreshState(
|
|
|
592
601
|
state: DashboardState,
|
|
593
602
|
cwd?: string,
|
|
594
603
|
disabledIds?: string[],
|
|
604
|
+
settings?: Settings,
|
|
595
605
|
): Promise<DashboardState> {
|
|
596
|
-
const extensions = await loadAllExtensions(cwd, disabledIds);
|
|
606
|
+
const extensions = await loadAllExtensions(cwd, disabledIds, settings);
|
|
597
607
|
const tabs = buildProviderTabs(extensions);
|
|
598
608
|
|
|
599
609
|
// Get current provider from tabs
|
|
@@ -146,7 +146,7 @@ export class HookEditorComponent extends Container {
|
|
|
146
146
|
|
|
147
147
|
const currentText = this.#editor.getExpandedText();
|
|
148
148
|
try {
|
|
149
|
-
this.#tui.
|
|
149
|
+
this.#tui.suspend();
|
|
150
150
|
const result = await openInEditor(editorCmd, currentText);
|
|
151
151
|
if (result !== null) {
|
|
152
152
|
this.#editor.setText(result);
|
|
@@ -734,7 +734,7 @@ export class HookSelectorComponent extends Container {
|
|
|
734
734
|
|
|
735
735
|
const currentText = editor.getExpandedText();
|
|
736
736
|
try {
|
|
737
|
-
this.#tui.
|
|
737
|
+
this.#tui.suspend();
|
|
738
738
|
const result = await openInEditor(editorCmd, currentText);
|
|
739
739
|
if (result !== null) {
|
|
740
740
|
editor.setText(result);
|
|
@@ -1369,10 +1369,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
1369
1369
|
}
|
|
1370
1370
|
|
|
1371
1371
|
#getProfileAvailableModels(): Model[] {
|
|
1372
|
-
|
|
1373
|
-
return typeof getAvailableForProfileActivation === "function"
|
|
1374
|
-
? getAvailableForProfileActivation.call(this.#modelRegistry)
|
|
1375
|
-
: this.#modelRegistry.getAvailable();
|
|
1372
|
+
return this.#modelRegistry.getAvailable();
|
|
1376
1373
|
}
|
|
1377
1374
|
|
|
1378
1375
|
#createProfileResolutionRegistry(availableModels: readonly Model[]) {
|
|
@@ -30,7 +30,7 @@ const PROVIDER_ONBOARDING_OPTIONS: ProviderOnboardingOption[] = [
|
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
label: "Import existing credentials",
|
|
33
|
-
description: "Detect and import Claude Code / Codex CLI logins already on this machine.",
|
|
33
|
+
description: "Detect and import Claude Code / Codex CLI / Kiro CLI logins already on this machine.",
|
|
34
34
|
action: "import-credentials",
|
|
35
35
|
},
|
|
36
36
|
];
|
|
@@ -109,6 +109,10 @@ const modelSegment: StatusLineSegment = {
|
|
|
109
109
|
const modelName = shortenModelId(state.model?.id ?? state.model?.name);
|
|
110
110
|
|
|
111
111
|
let content = withIcon(theme.icon.model, modelName);
|
|
112
|
+
const unavailableProfile = ctx.session.getUnavailableModelProfile?.();
|
|
113
|
+
if (unavailableProfile) {
|
|
114
|
+
content = `${theme.fg("warning", `profile unavailable: ${sanitizeStatusText(unavailableProfile)}`)} ${content}`;
|
|
115
|
+
}
|
|
112
116
|
|
|
113
117
|
if (ctx.session.isFastModeActive() && theme.icon.fast) {
|
|
114
118
|
content += ` ${theme.icon.fast}`;
|
|
@@ -60,6 +60,8 @@ export const __eventControllerPerfCounters = {
|
|
|
60
60
|
const COMPLETION_NOTIFY_COMMAND_TIMEOUT_MS = 10_000;
|
|
61
61
|
const TEXTLESS_LENGTH_WARNING =
|
|
62
62
|
'Response ended with stopReason "length" before producing visible text or a tool call. Check the model\'s output and context token limits (maxTokens in models.yml) or lower the reasoning level (/reasoning), then retry.';
|
|
63
|
+
const TEXTLESS_INCOMPLETE_WARNING =
|
|
64
|
+
"Response ended before producing visible text or a tool call. See the provider diagnostic for the reason.";
|
|
63
65
|
|
|
64
66
|
function isTextlessLengthStop(message: AssistantMessage | undefined): boolean {
|
|
65
67
|
return (
|
|
@@ -1090,7 +1092,7 @@ export class EventController {
|
|
|
1090
1092
|
event.stopReason !== "maintenance" &&
|
|
1091
1093
|
isTextlessLengthStop(lastAssistant)
|
|
1092
1094
|
) {
|
|
1093
|
-
this.ctx.showWarning(TEXTLESS_LENGTH_WARNING);
|
|
1095
|
+
this.ctx.showWarning(lastAssistant?.errorMessage ? TEXTLESS_INCOMPLETE_WARNING : TEXTLESS_LENGTH_WARNING);
|
|
1094
1096
|
}
|
|
1095
1097
|
this.sendCompletionNotification();
|
|
1096
1098
|
this.ctx.promptSuggestion?.onAgentEnd();
|
|
@@ -1372,15 +1374,20 @@ export class EventController {
|
|
|
1372
1374
|
|
|
1373
1375
|
const sessionName = this.ctx.sessionManager.getSessionName();
|
|
1374
1376
|
const textlessLengthStop = isTextlessLengthStop(last);
|
|
1377
|
+
const incompleteTitle = last?.errorMessage ? "Response incomplete" : "Output limit reached";
|
|
1375
1378
|
const title = textlessLengthStop
|
|
1376
1379
|
? sessionName
|
|
1377
|
-
? `${sessionName}:
|
|
1378
|
-
:
|
|
1380
|
+
? `${sessionName}: ${incompleteTitle}`
|
|
1381
|
+
: incompleteTitle
|
|
1379
1382
|
: sessionName
|
|
1380
1383
|
? `${sessionName}: Complete`
|
|
1381
1384
|
: "Complete";
|
|
1382
1385
|
const summary = summaryFromMessage(last, 1000);
|
|
1383
|
-
const body = textlessLengthStop
|
|
1386
|
+
const body = textlessLengthStop
|
|
1387
|
+
? last?.errorMessage
|
|
1388
|
+
? TEXTLESS_INCOMPLETE_WARNING
|
|
1389
|
+
: TEXTLESS_LENGTH_WARNING
|
|
1390
|
+
: (summary ?? "Complete");
|
|
1384
1391
|
const sessionManager = this.ctx.sessionManager as { getCwd?: () => string; getSessionId?: () => string };
|
|
1385
1392
|
const payload: CompletionNotifyPayload = {
|
|
1386
1393
|
type: "agent-turn-complete",
|