@gajae-code/coding-agent 0.17.2 → 0.17.4
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 +194 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/github-release.d.ts +17 -0
- package/dist/types/cli/public-command-entry.d.ts +56 -0
- package/dist/types/cli/public-command-errors.d.ts +126 -0
- package/dist/types/cli/public-command-evidence.d.ts +99 -0
- package/dist/types/cli/public-command-help.d.ts +65 -0
- package/dist/types/cli/public-command-registry.d.ts +69 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -0
- package/dist/types/cli/skills-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +4 -50
- package/dist/types/commands/sdk.d.ts +20 -37
- package/dist/types/commands/setup.d.ts +3 -0
- package/dist/types/commands/skills.d.ts +9 -0
- package/dist/types/config/autorouting-tier-map.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +9 -1
- package/dist/types/config/model-profile-activation.d.ts +45 -1
- package/dist/types/config/model-registry.d.ts +11 -2
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +12 -0
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
- package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/parse.d.ts +9 -1
- package/dist/types/main.d.ts +22 -0
- package/dist/types/modes/acp/acp-agent.d.ts +55 -1
- package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
- package/dist/types/modes/components/session-selector.d.ts +5 -2
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
- package/dist/types/modes/types.d.ts +2 -2
- package/dist/types/runtime/process-lifecycle.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +56 -0
- package/dist/types/runtime-mcp/pool.d.ts +17 -0
- package/dist/types/runtime-mcp/redaction.d.ts +20 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/identity.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
- package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
- package/dist/types/sdk/broker/runtime.d.ts +1 -1
- package/dist/types/sdk/broker/session-index.d.ts +22 -3
- package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
- package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
- package/dist/types/sdk/bus/index.d.ts +19 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
- package/dist/types/sdk/cli/master-cli.d.ts +6 -10
- package/dist/types/sdk/cli/rows.d.ts +19 -1
- package/dist/types/sdk/cli/session-cli.d.ts +22 -5
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/guides/cli.d.ts +3 -4
- package/dist/types/sdk/guides/verify.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +9 -0
- package/dist/types/sdk/host/session-runtime.d.ts +31 -0
- package/dist/types/sdk/host/types.d.ts +10 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +37 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +48 -4
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +168 -21
- package/dist/types/session/fallback-chain-controller.d.ts +6 -6
- package/dist/types/session/fold-coordinator.d.ts +17 -3
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
- package/dist/types/session/session-manager.d.ts +64 -1
- package/dist/types/session/session-work-lease.d.ts +14 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
- package/dist/types/setup/provider-onboarding.d.ts +81 -1
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf.d.ts +4 -0
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/dist/types/web/scrapers/types.d.ts +3 -0
- package/package.json +18 -10
- package/scripts/build-binary.ts +9 -3
- package/scripts/compile-args.ts +0 -9
- package/scripts/embed-mupdf.ts +52 -0
- package/scripts/generate-sdk-operation-inventory.ts +31 -1
- package/scripts/vendor-markit.ts +196 -0
- package/src/async/job-manager.ts +22 -1
- package/src/cli/daemon-cli.ts +53 -18
- package/src/cli/github-release.ts +87 -5
- package/src/cli/mcp-cli.ts +38 -4
- package/src/cli/public-command-entry.ts +450 -0
- package/src/cli/public-command-errors.ts +581 -0
- package/src/cli/public-command-evidence.ts +717 -0
- package/src/cli/public-command-help.ts +360 -0
- package/src/cli/public-command-registry.ts +535 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +9 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +175 -117
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +14 -0
- package/src/config/file-lock.ts +147 -51
- package/src/config/model-profile-activation.ts +334 -43
- package/src/config/model-registry.ts +183 -25
- package/src/config/settings-schema.ts +26 -2
- package/src/coordinator-mcp/policy.ts +10 -5
- package/src/coordinator-mcp/question-gate-codec.ts +17 -0
- package/src/coordinator-mcp/question-state.ts +175 -8
- package/src/coordinator-mcp/server.ts +507 -81
- package/src/coordinator-mcp/session-reaper.ts +6 -4
- package/src/crash/record-loader.ts +6 -2
- package/src/daemon/operator-contract.ts +26 -12
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
- package/src/eval/js/context-manager.ts +8 -8
- package/src/eval/js/worker-core.ts +9 -4
- package/src/eval/js/worker-protocol.ts +2 -0
- package/src/extensibility/extensions/runner.ts +52 -4
- package/src/extensibility/extensions/types.ts +10 -0
- package/src/extensibility/gjc-plugins/registry.ts +196 -37
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +20 -19
- package/src/internal-urls/embedded-protocol.ts +83 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/parse.ts +21 -1
- package/src/internal-urls/router.ts +4 -2
- package/src/main.ts +123 -55
- package/src/modes/acp/acp-agent.ts +408 -35
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/controllers/command-controller.ts +58 -32
- package/src/modes/controllers/extension-ui-controller.ts +33 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +161 -15
- package/src/modes/interactive-mode.ts +21 -7
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
- package/src/modes/types.ts +2 -2
- package/src/prompts/agent-fragments/browser-aside.md +1 -0
- package/src/prompts/system/title-system.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/read.md +2 -0
- package/src/runtime/network-prewarm-service.test.ts +36 -1
- package/src/runtime/network-prewarm-service.ts +28 -3
- package/src/runtime/process-lifecycle.ts +22 -11
- package/src/runtime-mcp/config.ts +16 -1
- package/src/runtime-mcp/manager.ts +689 -55
- package/src/runtime-mcp/pool.test.ts +31 -0
- package/src/runtime-mcp/pool.ts +304 -28
- package/src/runtime-mcp/redaction.ts +42 -0
- package/src/runtime-mcp/startup-policy.ts +7 -0
- package/src/runtime-mcp/tool-bridge.ts +71 -0
- package/src/runtime-mcp/transports/http.ts +108 -25
- package/src/sdk/acp/adapter.ts +27 -8
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/identity.ts +9 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +35 -7
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
- package/src/sdk/bus/index.ts +690 -80
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -3
- package/src/sdk/cli/master-cli.ts +47 -36
- package/src/sdk/cli/rows.ts +30 -7
- package/src/sdk/cli/session-cli.ts +687 -184
- package/src/sdk/client/client.ts +18 -0
- package/src/sdk/guides/catalog.ts +2 -2
- package/src/sdk/guides/cli.ts +20 -62
- package/src/sdk/guides/verify.ts +14 -0
- package/src/sdk/host/host.ts +49 -5
- package/src/sdk/host/session-runtime.test.ts +138 -2
- package/src/sdk/host/session-runtime.ts +311 -97
- package/src/sdk/host/types.ts +12 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
- package/src/sdk/host/websocket-transport.ts +40 -6
- package/src/sdk/index.ts +11 -0
- package/src/sdk/prompt-deadline-flush.ts +334 -0
- package/src/sdk/prompt-deadline-manager.ts +133 -1
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/session-router.ts +9 -1
- package/src/sdk/session.ts +182 -7
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +397 -42
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2437 -400
- package/src/session/fallback-chain-controller.ts +6 -7
- package/src/session/fold-coordinator.ts +24 -5
- package/src/session/internal/managed-session-scope.ts +58 -18
- package/src/session/internal/managed-session-storage.ts +304 -11
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/slash-commands/builtin-registry.ts +258 -14
- package/src/task/index.ts +14 -2
- package/src/tools/bash.ts +98 -78
- package/src/tools/fetch.ts +119 -20
- package/src/tools/job.ts +151 -25
- package/src/tools/output-meta.ts +15 -2
- package/src/tools/path-utils.ts +27 -3
- package/src/tools/read.ts +3 -3
- package/src/tools/steer-fold.ts +107 -0
- package/src/tools/tool-catalog.generated.ts +29 -2
- package/src/tools/tool-errors.ts +4 -0
- package/src/utils/git.ts +53 -3
- package/src/utils/markit.ts +55 -41
- package/src/utils/mupdf-assets.d.ts +4 -0
- package/src/utils/mupdf-embedded.ts +4 -0
- package/src/utils/mupdf.ts +129 -0
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
- package/src/web/scrapers/types.ts +24 -3
- package/vendor/markit-ai/LICENSE +21 -0
- package/vendor/markit-ai/MANIFEST.json +412 -0
- package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/config.js +139 -0
- package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
- package/vendor/markit-ai/dist/commands/convert.js +113 -0
- package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/formats.js +92 -0
- package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/init.js +29 -0
- package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/onboard.js +61 -0
- package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/plugin.js +58 -0
- package/vendor/markit-ai/dist/config.d.ts +26 -0
- package/vendor/markit-ai/dist/config.js +42 -0
- package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/audio.js +104 -0
- package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/csv.js +83 -0
- package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/docx.js +57 -0
- package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/epub.js +128 -0
- package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
- package/vendor/markit-ai/dist/converters/github.js +148 -0
- package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/html.js +30 -0
- package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/image.js +124 -0
- package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
- package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
- package/vendor/markit-ai/dist/converters/iwork.js +391 -0
- package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/json.js +21 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
- package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
- package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
- package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
- package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
- package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
- package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
- package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/pptx.js +289 -0
- package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
- package/vendor/markit-ai/dist/converters/rss.js +138 -0
- package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
- package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
- package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/xml.js +18 -0
- package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/yaml.js +17 -0
- package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/zip.js +57 -0
- package/vendor/markit-ai/dist/index.d.ts +30 -0
- package/vendor/markit-ai/dist/index.js +26 -0
- package/vendor/markit-ai/dist/main.d.ts +2 -0
- package/vendor/markit-ai/dist/main.js +191 -0
- package/vendor/markit-ai/dist/markit.d.ts +45 -0
- package/vendor/markit-ai/dist/markit.js +267 -0
- package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
- package/vendor/markit-ai/dist/plugins/api.js +42 -0
- package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
- package/vendor/markit-ai/dist/plugins/index.js +3 -0
- package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/installer.js +176 -0
- package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
- package/vendor/markit-ai/dist/plugins/loader.js +61 -0
- package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/types.js +1 -0
- package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
- package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
- package/vendor/markit-ai/dist/providers/index.js +56 -0
- package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/openai.js +76 -0
- package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
- package/vendor/markit-ai/dist/providers/types.js +1 -0
- package/vendor/markit-ai/dist/types.d.ts +36 -0
- package/vendor/markit-ai/dist/types.js +1 -0
- package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
- package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
- package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
- package/vendor/markit-ai/dist/utils/output.js +31 -0
- package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
- package/vendor/markit-ai/dist/utils/turndown.js +70 -0
- package/vendor/markit-ai/package.json +74 -0
- package/vendor/markit-ai.patch +49 -0
package/src/utils/git.ts
CHANGED
|
@@ -805,10 +805,18 @@ export const status = Object.assign(
|
|
|
805
805
|
// ════════════════════════════════════════════════════════════════════════════
|
|
806
806
|
|
|
807
807
|
export const stage = {
|
|
808
|
-
/**
|
|
809
|
-
|
|
808
|
+
/**
|
|
809
|
+
* Stage files. Empty array stages all (`git add -A`). Accepts a bare signal or
|
|
810
|
+
* `{ env, signal }`; `env` exists so a caller can stage into an isolated
|
|
811
|
+
* `GIT_INDEX_FILE` instead of the repository's real index.
|
|
812
|
+
*/
|
|
813
|
+
async files(
|
|
814
|
+
cwd: string,
|
|
815
|
+
files: readonly string[] = [],
|
|
816
|
+
options: AbortSignal | Pick<CommandOptions, "env" | "signal"> = {},
|
|
817
|
+
): Promise<void> {
|
|
810
818
|
const args = files.length === 0 ? ["add", "-A"] : ["add", "--", ...files];
|
|
811
|
-
await runEffect(cwd, args, { signal });
|
|
819
|
+
await runEffect(cwd, args, options instanceof AbortSignal ? { signal: options } : options);
|
|
812
820
|
},
|
|
813
821
|
|
|
814
822
|
/** Selectively stage hunks from the provided diff or the current working tree diff. */
|
|
@@ -902,6 +910,28 @@ export async function writeTree(cwd: string, options: Pick<CommandOptions, "env"
|
|
|
902
910
|
return (await runText(cwd, ["write-tree"], options)).trim();
|
|
903
911
|
}
|
|
904
912
|
|
|
913
|
+
export interface CommitTreeOptions {
|
|
914
|
+
readonly env?: Record<string, string | undefined>;
|
|
915
|
+
readonly parents?: readonly string[];
|
|
916
|
+
readonly signal?: AbortSignal;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Create a commit object from an existing tree and return its SHA. Plumbing:
|
|
921
|
+
* unlike `commit` this touches neither the index nor any ref, and runs no
|
|
922
|
+
* `pre-commit`/`commit-msg` hook.
|
|
923
|
+
*/
|
|
924
|
+
export async function commitTree(
|
|
925
|
+
cwd: string,
|
|
926
|
+
tree: string,
|
|
927
|
+
message: string,
|
|
928
|
+
options: CommitTreeOptions = {},
|
|
929
|
+
): Promise<string> {
|
|
930
|
+
const args = ["commit-tree", tree];
|
|
931
|
+
for (const parent of options.parents ?? []) args.push("-p", parent);
|
|
932
|
+
return (await runText(cwd, args, { env: options.env, signal: options.signal, stdin: message })).trim();
|
|
933
|
+
}
|
|
934
|
+
|
|
905
935
|
// ════════════════════════════════════════════════════════════════════════════
|
|
906
936
|
// API: show
|
|
907
937
|
// ════════════════════════════════════════════════════════════════════════════
|
|
@@ -1075,6 +1105,26 @@ export const ref = {
|
|
|
1075
1105
|
return result.stdout.trim() || null;
|
|
1076
1106
|
},
|
|
1077
1107
|
|
|
1108
|
+
/**
|
|
1109
|
+
* Move a ref to `newValue`, but only while it still holds `expectedOldValue`
|
|
1110
|
+
* (the empty string asserts the ref does not exist yet). Git verifies the old
|
|
1111
|
+
* value and writes the new one under its own ref lock, so this is an atomic
|
|
1112
|
+
* compare-and-swap: a concurrent writer that moved the ref first makes this
|
|
1113
|
+
* throw instead of silently clobbering their commit.
|
|
1114
|
+
*/
|
|
1115
|
+
async update(
|
|
1116
|
+
cwd: string,
|
|
1117
|
+
refName: string,
|
|
1118
|
+
newValue: string,
|
|
1119
|
+
expectedOldValue: string,
|
|
1120
|
+
options: { reason?: string; signal?: AbortSignal } = {},
|
|
1121
|
+
): Promise<void> {
|
|
1122
|
+
const args = ["update-ref"];
|
|
1123
|
+
if (options.reason) args.push("-m", options.reason);
|
|
1124
|
+
args.push(refName, newValue, expectedOldValue);
|
|
1125
|
+
await runEffect(cwd, args, { signal: options.signal });
|
|
1126
|
+
},
|
|
1127
|
+
|
|
1078
1128
|
/** Tags pointing at a ref. */
|
|
1079
1129
|
async tags(cwd: string, refName = "HEAD", signal?: AbortSignal): Promise<string[]> {
|
|
1080
1130
|
return splitLines(
|
package/src/utils/markit.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { untilAborted } from "@gajae-code/utils";
|
|
2
|
-
import type { Markit, StreamInfo } from "markit-ai";
|
|
2
|
+
import type { Markit, StreamInfo } from "../../vendor/markit-ai/dist/index.js";
|
|
3
3
|
import { ToolAbortError } from "../tools/tool-errors";
|
|
4
|
-
import {
|
|
4
|
+
import { prepareMuPdf, sanitizeMuPdfDiagnostic, withMuPdfDiagnostic } from "./mupdf";
|
|
5
5
|
|
|
6
6
|
export interface MarkitConversionResult {
|
|
7
7
|
content: string;
|
|
@@ -9,20 +9,23 @@ export interface MarkitConversionResult {
|
|
|
9
9
|
error?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
const instance = new Markit();
|
|
15
|
-
markit = () => instance;
|
|
16
|
-
return instance;
|
|
17
|
-
});
|
|
18
|
-
markit = () => promise;
|
|
19
|
-
return promise;
|
|
20
|
-
};
|
|
12
|
+
let instance: Markit | undefined;
|
|
13
|
+
let instancePromise: Promise<Markit> | undefined;
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
async function loadMarkit(): Promise<Markit> {
|
|
16
|
+
if (instancePromise === undefined) {
|
|
17
|
+
instancePromise = import("../../vendor/markit-ai/dist/index.js")
|
|
18
|
+
.then(({ Markit: MarkitConstructor }) => {
|
|
19
|
+
instance = new MarkitConstructor();
|
|
20
|
+
return instance;
|
|
21
|
+
})
|
|
22
|
+
.catch(error => {
|
|
23
|
+
instancePromise = undefined;
|
|
24
|
+
throw error;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return instancePromise;
|
|
28
|
+
}
|
|
26
29
|
|
|
27
30
|
function normalizeExtension(extension: string): string {
|
|
28
31
|
const trimmed = extension.trim().toLowerCase();
|
|
@@ -30,33 +33,27 @@ function normalizeExtension(extension: string): string {
|
|
|
30
33
|
return trimmed.startsWith(".") ? trimmed : `.${trimmed}`;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
function normalizeError(error: unknown): string {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const base = normalizeError(error);
|
|
47
|
-
if (!base.includes("PDF support requires 'mupdf'")) return base;
|
|
48
|
-
try {
|
|
49
|
-
await import("mupdf");
|
|
50
|
-
} catch (cause) {
|
|
51
|
-
return `${base} (mupdf import failed: ${normalizeError(cause)})`;
|
|
36
|
+
function normalizeError(error: unknown, pdf = false): string {
|
|
37
|
+
const messages: string[] = [];
|
|
38
|
+
const seen = new Set<unknown>();
|
|
39
|
+
while (error !== undefined && !seen.has(error)) {
|
|
40
|
+
seen.add(error);
|
|
41
|
+
if (error instanceof Error) {
|
|
42
|
+
const message = `${error.name}: ${error.message}`;
|
|
43
|
+
messages.push(pdf ? sanitizeMuPdfDiagnostic(message) : message);
|
|
44
|
+
error = error.cause;
|
|
45
|
+
} else {
|
|
46
|
+
messages.push(pdf ? sanitizeMuPdfDiagnostic(String(error)) : String(error));
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
52
49
|
}
|
|
53
|
-
return
|
|
50
|
+
return messages.join("; caused by: ") || "Conversion failed";
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
async function runMarkitConversion<T>(task: (markit: Markit) => Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
57
54
|
try {
|
|
58
|
-
const
|
|
59
|
-
return signal ? await untilAborted(signal, () => task(
|
|
55
|
+
const markit = instance ?? (await loadMarkit());
|
|
56
|
+
return signal ? await untilAborted(signal, () => task(markit)) : await task(markit);
|
|
60
57
|
} catch (error) {
|
|
61
58
|
if (error instanceof ToolAbortError) {
|
|
62
59
|
throw error;
|
|
@@ -78,13 +75,22 @@ function finalizeConversion(markdown?: string): MarkitConversionResult {
|
|
|
78
75
|
|
|
79
76
|
export async function convertFileWithMarkit(filePath: string, signal?: AbortSignal): Promise<MarkitConversionResult> {
|
|
80
77
|
try {
|
|
81
|
-
|
|
78
|
+
if (filePath.toLowerCase().endsWith(".pdf")) await prepareMuPdf();
|
|
79
|
+
const result = await runMarkitConversion(async markit => {
|
|
80
|
+
return markit.convertFile(filePath);
|
|
81
|
+
}, signal);
|
|
82
82
|
return finalizeConversion(result.markdown);
|
|
83
83
|
} catch (error) {
|
|
84
84
|
if (error instanceof ToolAbortError) {
|
|
85
85
|
throw error;
|
|
86
86
|
}
|
|
87
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
content: "",
|
|
89
|
+
ok: false,
|
|
90
|
+
error: filePath.toLowerCase().endsWith(".pdf")
|
|
91
|
+
? normalizeError(withMuPdfDiagnostic(error), true)
|
|
92
|
+
: normalizeError(error),
|
|
93
|
+
};
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
|
|
@@ -100,12 +106,20 @@ export async function convertBufferWithMarkit(
|
|
|
100
106
|
};
|
|
101
107
|
|
|
102
108
|
try {
|
|
103
|
-
|
|
109
|
+
if (normalizedExtension === ".pdf") await prepareMuPdf();
|
|
110
|
+
const result = await runMarkitConversion(async markit => {
|
|
111
|
+
return markit.convert(Buffer.from(buffer), streamInfo);
|
|
112
|
+
}, signal);
|
|
104
113
|
return finalizeConversion(result.markdown);
|
|
105
114
|
} catch (error) {
|
|
106
115
|
if (error instanceof ToolAbortError) {
|
|
107
116
|
throw error;
|
|
108
117
|
}
|
|
109
|
-
return {
|
|
118
|
+
return {
|
|
119
|
+
content: "",
|
|
120
|
+
ok: false,
|
|
121
|
+
error:
|
|
122
|
+
normalizedExtension === ".pdf" ? normalizeError(withMuPdfDiagnostic(error), true) : normalizeError(error),
|
|
123
|
+
};
|
|
110
124
|
}
|
|
111
125
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import * as url from "node:url";
|
|
3
|
+
import * as util from "node:util";
|
|
4
|
+
import { logger } from "@gajae-code/utils";
|
|
5
|
+
import { embeddedMuPdfModule, embeddedMuPdfWasm } from "./mupdf-embedded";
|
|
6
|
+
|
|
7
|
+
export let mupdfAssetMapping = "module mupdf; WASM mupdf-wasm.wasm -> unresolved";
|
|
8
|
+
let wasmAsset: string | undefined;
|
|
9
|
+
let initializationFailure: unknown;
|
|
10
|
+
let preparation: Promise<void> | undefined;
|
|
11
|
+
|
|
12
|
+
interface MuPdfModuleConfiguration {
|
|
13
|
+
wasmBinary?: Uint8Array;
|
|
14
|
+
locateFile?: (filename?: string) => string;
|
|
15
|
+
onAbort?: (error: unknown) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type MuPdfGlobal = typeof globalThis & {
|
|
19
|
+
$libmupdf_wasm_Module?: MuPdfModuleConfiguration;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function resolveWasmAsset(): string {
|
|
23
|
+
if (wasmAsset) return wasmAsset;
|
|
24
|
+
let moduleMapping: string;
|
|
25
|
+
if (embeddedMuPdfWasm) {
|
|
26
|
+
wasmAsset = embeddedMuPdfWasm;
|
|
27
|
+
moduleMapping = `build-time provenance ${embeddedMuPdfModule}`;
|
|
28
|
+
} else {
|
|
29
|
+
if (process.env.PI_COMPILED || /\$bunfs|~BUN|%7EBUN/.test(import.meta.url)) {
|
|
30
|
+
throw new Error("Compiled MuPDF WASM mapping is missing; run scripts/embed-mupdf.ts before compiling.");
|
|
31
|
+
}
|
|
32
|
+
const markitModule = url.fileURLToPath(new URL("../../vendor/markit-ai/dist/index.js", import.meta.url));
|
|
33
|
+
moduleMapping = Bun.resolveSync("mupdf", path.dirname(markitModule));
|
|
34
|
+
wasmAsset = path.join(path.dirname(moduleMapping), "mupdf-wasm.wasm");
|
|
35
|
+
}
|
|
36
|
+
mupdfAssetMapping = `module mupdf -> ${moduleMapping}; WASM mupdf-wasm.wasm -> ${wasmAsset}`;
|
|
37
|
+
return wasmAsset;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The official Emscripten hook is consumed by markit-ai's lazy MuPDF import.
|
|
41
|
+
// Capture initialization aborts while preserving the import error's cause chain.
|
|
42
|
+
const globalScope = globalThis as MuPdfGlobal;
|
|
43
|
+
const hostConfiguration = globalScope.$libmupdf_wasm_Module;
|
|
44
|
+
const configuration: MuPdfModuleConfiguration = hostConfiguration ?? {
|
|
45
|
+
locateFile: resolveWasmAsset,
|
|
46
|
+
onAbort(error: unknown) {
|
|
47
|
+
initializationFailure = error;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (hostConfiguration === undefined) {
|
|
52
|
+
globalScope.$libmupdf_wasm_Module = configuration;
|
|
53
|
+
} else {
|
|
54
|
+
// Reuse an SDK host's configuration and hooks. Only fill absent fields; do
|
|
55
|
+
// not replace locateFile/onAbort or discard caller-owned settings.
|
|
56
|
+
if (configuration.locateFile === undefined) configuration.locateFile = resolveWasmAsset;
|
|
57
|
+
if (configuration.onAbort === undefined) {
|
|
58
|
+
configuration.onAbort = error => {
|
|
59
|
+
initializationFailure = error;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function preparationAsset(): string {
|
|
65
|
+
const configuredPath = configuration.locateFile?.("mupdf-wasm.wasm");
|
|
66
|
+
return configuredPath ?? resolveWasmAsset();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function prepareMuPdf(): Promise<void> {
|
|
70
|
+
// A new conversion attempt must not inherit an abort from a prior attempt.
|
|
71
|
+
initializationFailure = undefined;
|
|
72
|
+
const previousWasmBinary = configuration.wasmBinary;
|
|
73
|
+
preparation ??= Promise.resolve()
|
|
74
|
+
.then(async () => {
|
|
75
|
+
const bytes = await Bun.file(preparationAsset()).bytes();
|
|
76
|
+
// Reject corrupt assets before Emscripten starts: its abort path can also
|
|
77
|
+
// reject a secondary promise even when the module import is caught.
|
|
78
|
+
await WebAssembly.compile(bytes);
|
|
79
|
+
if (configuration.wasmBinary === undefined) configuration.wasmBinary = bytes;
|
|
80
|
+
})
|
|
81
|
+
.catch(error => {
|
|
82
|
+
preparation = undefined;
|
|
83
|
+
configuration.wasmBinary = previousWasmBinary;
|
|
84
|
+
throw error;
|
|
85
|
+
});
|
|
86
|
+
return preparation;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function withMuPdfDiagnostic(error: unknown): Error {
|
|
90
|
+
const capturedInitializationFailure = initializationFailure;
|
|
91
|
+
initializationFailure = undefined;
|
|
92
|
+
const cause = capturedInitializationFailure ?? error;
|
|
93
|
+
const debugDetails: Record<string, unknown> = {
|
|
94
|
+
asset: embeddedMuPdfWasm ? "embedded" : "package",
|
|
95
|
+
error: formatMuPdfCauseChain(error),
|
|
96
|
+
};
|
|
97
|
+
if (capturedInitializationFailure !== undefined) {
|
|
98
|
+
debugDetails.initializationFailure = formatMuPdfCauseChain(capturedInitializationFailure);
|
|
99
|
+
}
|
|
100
|
+
logger.debug("MuPDF conversion failed", debugDetails);
|
|
101
|
+
const asset = embeddedMuPdfWasm ? "embedded asset" : "package asset";
|
|
102
|
+
return new Error(`PDF conversion failed [MuPDF; ${asset}; mupdf-wasm.wasm]`, { cause });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function formatMuPdfCauseChain(error: unknown): string {
|
|
106
|
+
const messages: string[] = [];
|
|
107
|
+
const seen = new Set<unknown>();
|
|
108
|
+
while (error !== undefined && !seen.has(error)) {
|
|
109
|
+
seen.add(error);
|
|
110
|
+
if (error instanceof Error) {
|
|
111
|
+
messages.push(sanitizeMuPdfDiagnostic(`${error.name}: ${error.message}`));
|
|
112
|
+
error = error.cause;
|
|
113
|
+
} else {
|
|
114
|
+
messages.push(sanitizeMuPdfDiagnostic(String(error)));
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return messages.join("; caused by: ") || "Conversion failed";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Only the model-facing rendering is redacted; Error.cause remains intact for
|
|
122
|
+
// internal inspection and operational debug logging. Conservatively redact the
|
|
123
|
+
// rest of a path-bearing field so spaces in install paths cannot leak suffixes.
|
|
124
|
+
export function sanitizeMuPdfDiagnostic(message: string): string {
|
|
125
|
+
return util
|
|
126
|
+
.stripVTControlCharacters(message)
|
|
127
|
+
.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029\u202a-\u202e\u2066-\u2069]/g, "")
|
|
128
|
+
.replace(/[^\s"'`]*(?:[/\\]|%2f|%5c)[^"'`]*(?=["'`]|$)/gi, "[path redacted]");
|
|
129
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory generation lease for asynchronous session-title regeneration.
|
|
3
|
+
*
|
|
4
|
+
* The lease is keyed by the session manager instance so TUI and ACP command
|
|
5
|
+
* dispatchers share the same ordering state without adding protocol fields to
|
|
6
|
+
* the persisted session format.
|
|
7
|
+
*/
|
|
8
|
+
const generations = new WeakMap<object, number>();
|
|
9
|
+
|
|
10
|
+
function currentGeneration(owner: object): number {
|
|
11
|
+
return generations.get(owner) ?? 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Start a new regeneration and invalidate every older completion. */
|
|
15
|
+
export function beginSessionTitleGeneration(owner: object): number {
|
|
16
|
+
const generation = currentGeneration(owner) + 1;
|
|
17
|
+
generations.set(owner, generation);
|
|
18
|
+
return generation;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Invalidate pending regeneration after a newer session mutation is accepted. */
|
|
22
|
+
export function invalidateSessionTitleGeneration(owner: object): void {
|
|
23
|
+
generations.set(owner, currentGeneration(owner) + 1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Return whether a regeneration still owns the latest generation lease. */
|
|
27
|
+
export function isSessionTitleGenerationCurrent(owner: object, generation: number): boolean {
|
|
28
|
+
return currentGeneration(owner) === generation;
|
|
29
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
|
|
6
|
+
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
6
7
|
import { type Api, type AssistantMessage, completeSimple, type Model, type Tool } from "@gajae-code/ai/core";
|
|
7
8
|
import { logger, prompt } from "@gajae-code/utils";
|
|
8
9
|
import type { ModelRegistry } from "../config/model-registry";
|
|
@@ -17,6 +18,9 @@ const TITLE_SYSTEM_PROMPT = prompt.render(titleSystemPrompt);
|
|
|
17
18
|
const DEFAULT_TERMINAL_TITLE = "GJC";
|
|
18
19
|
const TERMINAL_TITLE_CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
19
20
|
|
|
21
|
+
const MAX_TITLE_CONVERSATION_MESSAGES = 6;
|
|
22
|
+
const MAX_TITLE_MESSAGE_CHARS = 400;
|
|
23
|
+
|
|
20
24
|
const MAX_INPUT_CHARS = 2000;
|
|
21
25
|
const TITLE_MAX_TOKENS = 30;
|
|
22
26
|
const REASONING_SAFE_MAX_TOKENS = 1024;
|
|
@@ -29,6 +33,44 @@ const SET_TITLE_TOOL_NAME = "set_title";
|
|
|
29
33
|
const MAX_TITLE_CHARS = 80;
|
|
30
34
|
const MAX_TITLE_WORDS = 12;
|
|
31
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Build a bounded conversation digest for title regeneration. Regeneration
|
|
38
|
+
* reads several messages so a throwaway first prompt can be corrected, while
|
|
39
|
+
* the automatic first-message path intentionally uses only its initial input.
|
|
40
|
+
*/
|
|
41
|
+
export function buildConversationTitleInput(messages: readonly AgentMessage[]): string | undefined {
|
|
42
|
+
const userMessages: string[] = [];
|
|
43
|
+
for (const message of messages) {
|
|
44
|
+
if (message.role !== "user") continue;
|
|
45
|
+
const content = message.content;
|
|
46
|
+
const text =
|
|
47
|
+
typeof content === "string"
|
|
48
|
+
? content
|
|
49
|
+
: content
|
|
50
|
+
.filter(block => block.type === "text")
|
|
51
|
+
.map(block => block.text)
|
|
52
|
+
.join("\n");
|
|
53
|
+
const trimmed = text.trim();
|
|
54
|
+
if (trimmed) userMessages.push(trimmed);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (userMessages.length === 0) return undefined;
|
|
58
|
+
|
|
59
|
+
const keptMessages =
|
|
60
|
+
userMessages.length > MAX_TITLE_CONVERSATION_MESSAGES
|
|
61
|
+
? [userMessages[0]!, ...userMessages.slice(-(MAX_TITLE_CONVERSATION_MESSAGES - 1))]
|
|
62
|
+
: userMessages;
|
|
63
|
+
// Reserve separator and ellipsis room so the digest is already within the
|
|
64
|
+
// generator's MAX_INPUT_CHARS bound; its existing truncation is a no-op here.
|
|
65
|
+
const maxMessageChars = Math.min(
|
|
66
|
+
MAX_TITLE_MESSAGE_CHARS,
|
|
67
|
+
Math.floor((MAX_INPUT_CHARS - (keptMessages.length - 1) - keptMessages.length) / keptMessages.length),
|
|
68
|
+
);
|
|
69
|
+
return keptMessages
|
|
70
|
+
.map(message => (message.length > maxMessageChars ? `${message.slice(0, maxMessageChars)}…` : message))
|
|
71
|
+
.join("\n");
|
|
72
|
+
}
|
|
73
|
+
|
|
32
74
|
const setTitleTool: Tool = {
|
|
33
75
|
name: SET_TITLE_TOOL_NAME,
|
|
34
76
|
description: "Set the generated session title.",
|
|
@@ -58,9 +100,11 @@ function getTitleModel(registry: ModelRegistry, settings: Settings, currentModel
|
|
|
58
100
|
}
|
|
59
101
|
|
|
60
102
|
/**
|
|
61
|
-
* Generate a title for a session based on the
|
|
103
|
+
* Generate a title for a session based on the provided user-message input.
|
|
104
|
+
* Automatic titles pass the first user message; regeneration passes a bounded
|
|
105
|
+
* conversation digest.
|
|
62
106
|
*
|
|
63
|
-
* @param firstMessage The first user message
|
|
107
|
+
* @param firstMessage The first user message or bounded conversation digest
|
|
64
108
|
* @param registry Model registry
|
|
65
109
|
* @param settings Settings used to resolve the smol role
|
|
66
110
|
* @param sessionId Optional session id for sticky API key selection
|
|
@@ -78,7 +78,10 @@ export interface LoadPageOptions {
|
|
|
78
78
|
|
|
79
79
|
export interface LoadPageResult {
|
|
80
80
|
content: string;
|
|
81
|
+
/** The bounded response bytes retained for binary classification/conversion. */
|
|
82
|
+
buffer?: Uint8Array;
|
|
81
83
|
contentType: string;
|
|
84
|
+
contentDisposition?: string;
|
|
82
85
|
finalUrl: string;
|
|
83
86
|
ok: boolean;
|
|
84
87
|
status?: number;
|
|
@@ -173,6 +176,7 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
const contentType = response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
179
|
+
const contentDisposition = response.headers.get("content-disposition") || undefined;
|
|
176
180
|
const finalUrl = logicalUrl;
|
|
177
181
|
|
|
178
182
|
const reader = response.body?.getReader();
|
|
@@ -196,16 +200,33 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
196
200
|
}
|
|
197
201
|
}
|
|
198
202
|
|
|
199
|
-
const
|
|
203
|
+
const bytes = Buffer.concat(chunks);
|
|
204
|
+
const content = bytes.toString("utf-8");
|
|
205
|
+
const buffer =
|
|
206
|
+
contentType.length === 0 ||
|
|
207
|
+
contentType === "application/octet-stream" ||
|
|
208
|
+
contentType === "binary/octet-stream" ||
|
|
209
|
+
contentType === "unknown" ||
|
|
210
|
+
contentDisposition !== undefined
|
|
211
|
+
? bytes
|
|
212
|
+
: undefined;
|
|
200
213
|
if (isBotBlocked(response.status, content) && attempt < USER_AGENTS.length - 1) {
|
|
201
214
|
continue attempts;
|
|
202
215
|
}
|
|
203
216
|
|
|
204
217
|
if (!response.ok) {
|
|
205
|
-
return {
|
|
218
|
+
return {
|
|
219
|
+
content,
|
|
220
|
+
buffer,
|
|
221
|
+
contentType,
|
|
222
|
+
contentDisposition,
|
|
223
|
+
finalUrl,
|
|
224
|
+
ok: false,
|
|
225
|
+
status: response.status,
|
|
226
|
+
};
|
|
206
227
|
}
|
|
207
228
|
|
|
208
|
-
return { content, contentType, finalUrl, ok: true, status: response.status };
|
|
229
|
+
return { content, buffer, contentType, contentDisposition, finalUrl, ok: true, status: response.status };
|
|
209
230
|
}
|
|
210
231
|
return {
|
|
211
232
|
content: "",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Liv
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|