@gajae-code/coding-agent 0.17.1 → 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 +266 -0
- package/dist/types/async/job-manager.d.ts +7 -6
- 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 +24 -0
- package/dist/types/config/file-lock.d.ts +10 -1
- package/dist/types/config/model-profile-activation.d.ts +63 -4
- package/dist/types/config/model-registry.d.ts +20 -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/coordinator-mcp/server.d.ts +3 -0
- 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 +94 -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/thinking-selector.d.ts +2 -1
- 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/acp/adapter.d.ts +27 -0
- package/dist/types/sdk/acp/final-text.d.ts +8 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/ensure.d.ts +46 -1
- 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 +38 -1
- package/dist/types/sdk/prompt-failure.d.ts +30 -1
- package/dist/types/sdk/prompt-status.d.ts +8 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -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 +73 -2
- 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/thinking.d.ts +3 -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-wasm-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 +60 -9
- 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 +232 -100
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +16 -0
- package/src/config/file-lock.ts +199 -68
- package/src/config/model-profile-activation.ts +406 -53
- package/src/config/model-registry.ts +204 -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 +528 -87
- 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/debug/report-bundle.ts +114 -24
- 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/managed-owner-admission.ts +67 -50
- 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 +21 -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 +593 -47
- package/src/modes/acp/acp-event-mapper.ts +9 -0
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/model-selector.ts +31 -15
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/components/thinking-selector.ts +7 -3
- 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 +177 -18
- 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 +90 -9
- package/src/sdk/acp/final-text.ts +19 -2
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/ensure.ts +97 -19
- 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 +721 -84
- 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 +636 -9
- package/src/sdk/host/session-runtime.ts +499 -118
- 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 +136 -4
- package/src/sdk/prompt-failure.ts +43 -1
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
- package/src/sdk/router/session-router.ts +31 -4
- package/src/sdk/session.ts +194 -16
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +494 -49
- 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/session-import/codex.ts +12 -3
- 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/thinking.ts +21 -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-wasm-embedded.ts +3 -0
- package/src/utils/mupdf-wasm.ts +24 -2
- 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
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { XMLParser } from "fast-xml-parser";
|
|
2
|
+
import JSZip from "jszip";
|
|
3
|
+
import { createTurndown, normalizeTablesHtml } from "../utils/turndown.js";
|
|
4
|
+
const EXTENSIONS = [".epub"];
|
|
5
|
+
const MIMETYPES = [
|
|
6
|
+
"application/epub",
|
|
7
|
+
"application/epub+zip",
|
|
8
|
+
"application/x-epub+zip",
|
|
9
|
+
];
|
|
10
|
+
export class EpubConverter {
|
|
11
|
+
name = "epub";
|
|
12
|
+
accepts(streamInfo) {
|
|
13
|
+
if (streamInfo.extension && EXTENSIONS.includes(streamInfo.extension))
|
|
14
|
+
return true;
|
|
15
|
+
if (streamInfo.mimetype &&
|
|
16
|
+
MIMETYPES.some((m) => streamInfo.mimetype?.startsWith(m)))
|
|
17
|
+
return true;
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
async convert(input, _streamInfo) {
|
|
21
|
+
const zip = await JSZip.loadAsync(input);
|
|
22
|
+
const parser = new XMLParser({
|
|
23
|
+
ignoreAttributes: false,
|
|
24
|
+
attributeNamePrefix: "@_",
|
|
25
|
+
textNodeName: "#text",
|
|
26
|
+
processEntities: { maxTotalExpansions: 1_000_000 },
|
|
27
|
+
});
|
|
28
|
+
// Find content.opf path from container.xml
|
|
29
|
+
const containerXml = await zip
|
|
30
|
+
.file("META-INF/container.xml")
|
|
31
|
+
?.async("string");
|
|
32
|
+
if (!containerXml)
|
|
33
|
+
throw new Error("Invalid EPUB: missing container.xml");
|
|
34
|
+
const container = parser.parse(containerXml);
|
|
35
|
+
const rootfile = container.container?.rootfiles?.rootfile;
|
|
36
|
+
const opfPath = Array.isArray(rootfile)
|
|
37
|
+
? rootfile[0]["@_full-path"]
|
|
38
|
+
: rootfile?.["@_full-path"];
|
|
39
|
+
if (!opfPath)
|
|
40
|
+
throw new Error("Invalid EPUB: missing rootfile path");
|
|
41
|
+
// Parse content.opf
|
|
42
|
+
const opfXml = await zip.file(opfPath)?.async("string");
|
|
43
|
+
if (!opfXml)
|
|
44
|
+
throw new Error("Invalid EPUB: missing content.opf");
|
|
45
|
+
const opf = parser.parse(opfXml);
|
|
46
|
+
// Extract metadata
|
|
47
|
+
const meta = opf.package?.metadata ?? {};
|
|
48
|
+
const metadata = {
|
|
49
|
+
title: this.getText(meta["dc:title"]),
|
|
50
|
+
authors: this.getTextArray(meta["dc:creator"]).join(", ") || undefined,
|
|
51
|
+
language: this.getText(meta["dc:language"]),
|
|
52
|
+
publisher: this.getText(meta["dc:publisher"]),
|
|
53
|
+
date: this.getText(meta["dc:date"]),
|
|
54
|
+
description: this.getText(meta["dc:description"]),
|
|
55
|
+
};
|
|
56
|
+
// Build manifest map (id → href)
|
|
57
|
+
const manifestItems = opf.package?.manifest?.item;
|
|
58
|
+
const itemList = Array.isArray(manifestItems)
|
|
59
|
+
? manifestItems
|
|
60
|
+
: manifestItems
|
|
61
|
+
? [manifestItems]
|
|
62
|
+
: [];
|
|
63
|
+
const manifest = new Map();
|
|
64
|
+
for (const item of itemList) {
|
|
65
|
+
manifest.set(item["@_id"], item["@_href"]);
|
|
66
|
+
}
|
|
67
|
+
// Get spine order
|
|
68
|
+
const spineItems = opf.package?.spine?.itemref;
|
|
69
|
+
const spineList = Array.isArray(spineItems)
|
|
70
|
+
? spineItems
|
|
71
|
+
: spineItems
|
|
72
|
+
? [spineItems]
|
|
73
|
+
: [];
|
|
74
|
+
const spineOrder = spineList.map((s) => s["@_idref"]);
|
|
75
|
+
// Resolve file paths
|
|
76
|
+
const basePath = opfPath.includes("/")
|
|
77
|
+
? opfPath.substring(0, opfPath.lastIndexOf("/"))
|
|
78
|
+
: "";
|
|
79
|
+
const turndown = createTurndown();
|
|
80
|
+
const sections = [];
|
|
81
|
+
// Add metadata header
|
|
82
|
+
const metaLines = [];
|
|
83
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
84
|
+
if (value)
|
|
85
|
+
metaLines.push(`**${key.charAt(0).toUpperCase() + key.slice(1)}:** ${value}`);
|
|
86
|
+
}
|
|
87
|
+
if (metaLines.length > 0)
|
|
88
|
+
sections.push(metaLines.join("\n"));
|
|
89
|
+
// Convert spine files
|
|
90
|
+
for (const idref of spineOrder) {
|
|
91
|
+
const href = manifest.get(idref);
|
|
92
|
+
if (!href)
|
|
93
|
+
continue;
|
|
94
|
+
const filePath = basePath ? `${basePath}/${href}` : href;
|
|
95
|
+
const html = await zip.file(filePath)?.async("string");
|
|
96
|
+
if (!html)
|
|
97
|
+
continue;
|
|
98
|
+
// Strip script/style, convert to markdown
|
|
99
|
+
const cleaned = html
|
|
100
|
+
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
101
|
+
.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
102
|
+
const md = turndown.turndown(normalizeTablesHtml(cleaned)).trim();
|
|
103
|
+
if (md)
|
|
104
|
+
sections.push(md);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
markdown: sections.join("\n\n").trim(),
|
|
108
|
+
title: metadata.title,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
getText(node) {
|
|
112
|
+
if (!node)
|
|
113
|
+
return undefined;
|
|
114
|
+
if (typeof node === "string")
|
|
115
|
+
return node;
|
|
116
|
+
if (node["#text"])
|
|
117
|
+
return String(node["#text"]);
|
|
118
|
+
if (Array.isArray(node))
|
|
119
|
+
return this.getText(node[0]);
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
getTextArray(node) {
|
|
123
|
+
if (!node)
|
|
124
|
+
return [];
|
|
125
|
+
const list = Array.isArray(node) ? node : [node];
|
|
126
|
+
return list.map((n) => this.getText(n)).filter(Boolean);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ConversionResult, Converter, MarkitOptions, StreamInfo } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Matches GitHub URLs and fetches clean markdown content directly
|
|
4
|
+
* from raw endpoints or the GitHub API — no HTML scraping needed.
|
|
5
|
+
*
|
|
6
|
+
* Supported patterns:
|
|
7
|
+
* - Repos: github.com/owner/repo → raw README.md
|
|
8
|
+
* - Files: github.com/owner/repo/blob/… → raw file content
|
|
9
|
+
* - Gists: gist.github.com/owner/id → raw gist content
|
|
10
|
+
* - Issues: github.com/owner/repo/issues/N → API (title + body)
|
|
11
|
+
* - PRs: github.com/owner/repo/pull/N → API (title + body)
|
|
12
|
+
*/
|
|
13
|
+
export declare class GitHubConverter implements Converter {
|
|
14
|
+
name: string;
|
|
15
|
+
accepts(streamInfo: StreamInfo): boolean;
|
|
16
|
+
convertUrl(url: string, _options?: MarkitOptions): Promise<ConversionResult>;
|
|
17
|
+
convert(_input: Buffer, streamInfo: StreamInfo): Promise<ConversionResult>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const GITHUB_HOSTS = new Set([
|
|
2
|
+
"github.com",
|
|
3
|
+
"www.github.com",
|
|
4
|
+
"gist.github.com",
|
|
5
|
+
]);
|
|
6
|
+
/**
|
|
7
|
+
* Matches GitHub URLs and fetches clean markdown content directly
|
|
8
|
+
* from raw endpoints or the GitHub API — no HTML scraping needed.
|
|
9
|
+
*
|
|
10
|
+
* Supported patterns:
|
|
11
|
+
* - Repos: github.com/owner/repo → raw README.md
|
|
12
|
+
* - Files: github.com/owner/repo/blob/… → raw file content
|
|
13
|
+
* - Gists: gist.github.com/owner/id → raw gist content
|
|
14
|
+
* - Issues: github.com/owner/repo/issues/N → API (title + body)
|
|
15
|
+
* - PRs: github.com/owner/repo/pull/N → API (title + body)
|
|
16
|
+
*/
|
|
17
|
+
export class GitHubConverter {
|
|
18
|
+
name = "github";
|
|
19
|
+
accepts(streamInfo) {
|
|
20
|
+
if (!streamInfo.url)
|
|
21
|
+
return false;
|
|
22
|
+
try {
|
|
23
|
+
const { hostname } = new URL(streamInfo.url);
|
|
24
|
+
return GITHUB_HOSTS.has(hostname);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async convertUrl(url, _options) {
|
|
31
|
+
const parsed = new URL(url);
|
|
32
|
+
if (parsed.hostname === "gist.github.com") {
|
|
33
|
+
return fetchGist(parsed);
|
|
34
|
+
}
|
|
35
|
+
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
36
|
+
// Need at least owner/repo
|
|
37
|
+
if (segments.length < 2) {
|
|
38
|
+
throw new Error(`Unsupported GitHub URL: ${url}`);
|
|
39
|
+
}
|
|
40
|
+
const [owner, repo, type, ...rest] = segments;
|
|
41
|
+
// github.com/owner/repo/blob/ref/path → raw file
|
|
42
|
+
if (type === "blob" && rest.length >= 2) {
|
|
43
|
+
const ref = rest[0];
|
|
44
|
+
const filePath = rest.slice(1).join("/");
|
|
45
|
+
return fetchRawFile(owner, repo, ref, filePath);
|
|
46
|
+
}
|
|
47
|
+
// github.com/owner/repo/issues/N or /pull/N
|
|
48
|
+
if ((type === "issues" || type === "pull") && rest[0]) {
|
|
49
|
+
const number = Number.parseInt(rest[0], 10);
|
|
50
|
+
if (!Number.isNaN(number)) {
|
|
51
|
+
return fetchIssueOrPr(owner, repo, number);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// github.com/owner/repo (no subpath or tree/wiki/etc) → README
|
|
55
|
+
if (!type) {
|
|
56
|
+
return fetchReadme(owner, repo);
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Unsupported GitHub URL pattern: ${url}`);
|
|
59
|
+
}
|
|
60
|
+
async convert(_input, streamInfo) {
|
|
61
|
+
// GitHub URLs are handled entirely via convertUrl.
|
|
62
|
+
// If we end up here, the URL was already fetched by the default path —
|
|
63
|
+
// just delegate to convertUrl.
|
|
64
|
+
if (streamInfo.url) {
|
|
65
|
+
return this.convertUrl(streamInfo.url);
|
|
66
|
+
}
|
|
67
|
+
throw new Error("GitHub converter requires a URL");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Fetchers
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
async function fetchReadme(owner, repo) {
|
|
74
|
+
const url = `https://raw.githubusercontent.com/${owner}/${repo}/HEAD/README.md`;
|
|
75
|
+
const res = await fetch(url);
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
throw new Error(`Failed to fetch README: ${res.status} ${res.statusText}`);
|
|
78
|
+
}
|
|
79
|
+
const markdown = (await res.text()).trim();
|
|
80
|
+
const title = extractFirstHeading(markdown) ?? `${owner}/${repo}`;
|
|
81
|
+
return { markdown, title };
|
|
82
|
+
}
|
|
83
|
+
async function fetchRawFile(owner, repo, ref, filePath) {
|
|
84
|
+
const url = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath}`;
|
|
85
|
+
const res = await fetch(url);
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
throw new Error(`Failed to fetch file: ${res.status} ${res.statusText}`);
|
|
88
|
+
}
|
|
89
|
+
const content = (await res.text()).trim();
|
|
90
|
+
const filename = filePath.split("/").pop() ?? filePath;
|
|
91
|
+
// If it's markdown, return as-is. Otherwise wrap in a code block.
|
|
92
|
+
if (filePath.endsWith(".md") || filePath.endsWith(".mdx")) {
|
|
93
|
+
const title = extractFirstHeading(content) ?? filename;
|
|
94
|
+
return { markdown: content, title };
|
|
95
|
+
}
|
|
96
|
+
const ext = filename.includes(".") ? filename.split(".").pop() : "";
|
|
97
|
+
const markdown = `# ${filename}\n\n\`\`\`${ext}\n${content}\n\`\`\``;
|
|
98
|
+
return { markdown, title: filename };
|
|
99
|
+
}
|
|
100
|
+
async function fetchGist(parsed) {
|
|
101
|
+
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
102
|
+
// gist.github.com/owner/id
|
|
103
|
+
const [owner, id] = segments;
|
|
104
|
+
if (!owner || !id) {
|
|
105
|
+
throw new Error(`Unsupported gist URL: ${parsed.href}`);
|
|
106
|
+
}
|
|
107
|
+
const url = `https://gist.githubusercontent.com/${owner}/${id}/raw`;
|
|
108
|
+
const res = await fetch(url);
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
throw new Error(`Failed to fetch gist: ${res.status} ${res.statusText}`);
|
|
111
|
+
}
|
|
112
|
+
const content = (await res.text()).trim();
|
|
113
|
+
const title = `gist:${id}`;
|
|
114
|
+
return { markdown: content, title };
|
|
115
|
+
}
|
|
116
|
+
async function fetchIssueOrPr(owner, repo, number) {
|
|
117
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/issues/${number}`;
|
|
118
|
+
const res = await fetch(url, {
|
|
119
|
+
headers: { Accept: "application/vnd.github.v3+json" },
|
|
120
|
+
});
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
throw new Error(`Failed to fetch issue/PR: ${res.status} ${res.statusText}`);
|
|
123
|
+
}
|
|
124
|
+
const data = (await res.json());
|
|
125
|
+
const title = data.title ?? `#${number}`;
|
|
126
|
+
const parts = [`# ${title}`];
|
|
127
|
+
// Metadata line
|
|
128
|
+
const meta = [];
|
|
129
|
+
if (data.user?.login)
|
|
130
|
+
meta.push(`@${data.user.login}`);
|
|
131
|
+
if (data.state)
|
|
132
|
+
meta.push(data.state);
|
|
133
|
+
if (data.labels?.length) {
|
|
134
|
+
meta.push(data.labels.map((l) => l.name).join(", "));
|
|
135
|
+
}
|
|
136
|
+
if (meta.length > 0)
|
|
137
|
+
parts.push(meta.join(" · "));
|
|
138
|
+
if (data.body?.trim())
|
|
139
|
+
parts.push(data.body.trim());
|
|
140
|
+
return { markdown: parts.join("\n\n"), title };
|
|
141
|
+
}
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Helpers
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
function extractFirstHeading(markdown) {
|
|
146
|
+
const match = markdown.match(/^#\s+(.+)$/m);
|
|
147
|
+
return match?.[1]?.trim();
|
|
148
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConversionResult, Converter, StreamInfo } from "../types.js";
|
|
2
|
+
export declare class HtmlConverter implements Converter {
|
|
3
|
+
name: string;
|
|
4
|
+
accepts(streamInfo: StreamInfo): boolean;
|
|
5
|
+
convert(input: Buffer, streamInfo: StreamInfo): Promise<ConversionResult>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createTurndown, normalizeTablesHtml } from "../utils/turndown.js";
|
|
2
|
+
const EXTENSIONS = [".html", ".htm"];
|
|
3
|
+
const MIMETYPES = ["text/html", "application/xhtml"];
|
|
4
|
+
export class HtmlConverter {
|
|
5
|
+
name = "html";
|
|
6
|
+
accepts(streamInfo) {
|
|
7
|
+
if (streamInfo.extension && EXTENSIONS.includes(streamInfo.extension)) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (streamInfo.mimetype &&
|
|
11
|
+
MIMETYPES.some((m) => streamInfo.mimetype?.startsWith(m))) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
async convert(input, streamInfo) {
|
|
17
|
+
const charset = streamInfo.charset || "utf-8";
|
|
18
|
+
const html = new TextDecoder(charset).decode(input);
|
|
19
|
+
const turndown = createTurndown();
|
|
20
|
+
// Remove script and style tags before converting
|
|
21
|
+
const cleaned = html
|
|
22
|
+
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
23
|
+
.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
24
|
+
const markdown = turndown.turndown(normalizeTablesHtml(cleaned));
|
|
25
|
+
// Try to extract title
|
|
26
|
+
const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
27
|
+
const title = titleMatch ? titleMatch[1].trim() : undefined;
|
|
28
|
+
return { markdown: markdown.trim(), title };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConversionResult, Converter, MarkitOptions, StreamInfo } from "../types.js";
|
|
2
|
+
export declare class ImageConverter implements Converter {
|
|
3
|
+
name: string;
|
|
4
|
+
accepts(streamInfo: StreamInfo): boolean;
|
|
5
|
+
convert(input: Buffer, streamInfo: StreamInfo, options?: MarkitOptions): Promise<ConversionResult>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const EXTENSIONS = [
|
|
2
|
+
".jpg",
|
|
3
|
+
".jpeg",
|
|
4
|
+
".png",
|
|
5
|
+
".gif",
|
|
6
|
+
".webp",
|
|
7
|
+
".tiff",
|
|
8
|
+
".tif",
|
|
9
|
+
".bmp",
|
|
10
|
+
".svg",
|
|
11
|
+
];
|
|
12
|
+
const MIMETYPES = ["image/"];
|
|
13
|
+
export class ImageConverter {
|
|
14
|
+
name = "image";
|
|
15
|
+
accepts(streamInfo) {
|
|
16
|
+
if (streamInfo.extension && EXTENSIONS.includes(streamInfo.extension))
|
|
17
|
+
return true;
|
|
18
|
+
if (streamInfo.mimetype &&
|
|
19
|
+
MIMETYPES.some((m) => streamInfo.mimetype?.startsWith(m)))
|
|
20
|
+
return true;
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
async convert(input, streamInfo, options) {
|
|
24
|
+
const sections = [];
|
|
25
|
+
// Extract EXIF metadata
|
|
26
|
+
try {
|
|
27
|
+
const exifr = await import("exifr");
|
|
28
|
+
const metadata = await exifr.parse(input, {
|
|
29
|
+
pick: [
|
|
30
|
+
"ImageWidth",
|
|
31
|
+
"ImageHeight",
|
|
32
|
+
"Make",
|
|
33
|
+
"Model",
|
|
34
|
+
"DateTimeOriginal",
|
|
35
|
+
"CreateDate",
|
|
36
|
+
"GPSLatitude",
|
|
37
|
+
"GPSLongitude",
|
|
38
|
+
"Artist",
|
|
39
|
+
"Copyright",
|
|
40
|
+
"Description",
|
|
41
|
+
"Title",
|
|
42
|
+
"Keywords",
|
|
43
|
+
"Software",
|
|
44
|
+
"ExposureTime",
|
|
45
|
+
"FNumber",
|
|
46
|
+
"ISO",
|
|
47
|
+
"FocalLength",
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
51
|
+
sections.push("## Metadata\n");
|
|
52
|
+
if (metadata.ImageWidth && metadata.ImageHeight) {
|
|
53
|
+
sections.push(`ImageSize: ${metadata.ImageWidth}x${metadata.ImageHeight}`);
|
|
54
|
+
}
|
|
55
|
+
const fields = {
|
|
56
|
+
Title: metadata.Title,
|
|
57
|
+
Description: metadata.Description || metadata.ImageDescription,
|
|
58
|
+
Keywords: Array.isArray(metadata.Keywords)
|
|
59
|
+
? metadata.Keywords.join(", ")
|
|
60
|
+
: metadata.Keywords,
|
|
61
|
+
Artist: metadata.Artist,
|
|
62
|
+
Copyright: metadata.Copyright,
|
|
63
|
+
Camera: [metadata.Make, metadata.Model].filter(Boolean).join(" "),
|
|
64
|
+
DateTimeOriginal: metadata.DateTimeOriginal
|
|
65
|
+
? String(metadata.DateTimeOriginal)
|
|
66
|
+
: undefined,
|
|
67
|
+
CreateDate: metadata.CreateDate
|
|
68
|
+
? String(metadata.CreateDate)
|
|
69
|
+
: undefined,
|
|
70
|
+
GPS: metadata.GPSLatitude && metadata.GPSLongitude
|
|
71
|
+
? `${metadata.GPSLatitude}, ${metadata.GPSLongitude}`
|
|
72
|
+
: undefined,
|
|
73
|
+
ExposureTime: metadata.ExposureTime
|
|
74
|
+
? `1/${Math.round(1 / metadata.ExposureTime)}s`
|
|
75
|
+
: undefined,
|
|
76
|
+
FNumber: metadata.FNumber ? `f/${metadata.FNumber}` : undefined,
|
|
77
|
+
ISO: metadata.ISO ? String(metadata.ISO) : undefined,
|
|
78
|
+
FocalLength: metadata.FocalLength
|
|
79
|
+
? `${metadata.FocalLength}mm`
|
|
80
|
+
: undefined,
|
|
81
|
+
Software: metadata.Software,
|
|
82
|
+
};
|
|
83
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
84
|
+
if (value)
|
|
85
|
+
sections.push(`${key}: ${value}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// EXIF parsing failed — not all images have EXIF
|
|
91
|
+
}
|
|
92
|
+
// AI description
|
|
93
|
+
if (options?.describe) {
|
|
94
|
+
try {
|
|
95
|
+
const mimetype = streamInfo.mimetype || guessMimetype(streamInfo.extension);
|
|
96
|
+
const description = await options.describe(input, mimetype);
|
|
97
|
+
if (description) {
|
|
98
|
+
sections.push(`\n## Description\n\n${description}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Description failed — continue without it
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (sections.length === 0) {
|
|
106
|
+
return { markdown: `*[image: ${streamInfo.filename || "unknown"}]*` };
|
|
107
|
+
}
|
|
108
|
+
return { markdown: sections.join("\n").trim() };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function guessMimetype(ext) {
|
|
112
|
+
const map = {
|
|
113
|
+
".jpg": "image/jpeg",
|
|
114
|
+
".jpeg": "image/jpeg",
|
|
115
|
+
".png": "image/png",
|
|
116
|
+
".gif": "image/gif",
|
|
117
|
+
".webp": "image/webp",
|
|
118
|
+
".tiff": "image/tiff",
|
|
119
|
+
".tif": "image/tiff",
|
|
120
|
+
".bmp": "image/bmp",
|
|
121
|
+
".svg": "image/svg+xml",
|
|
122
|
+
};
|
|
123
|
+
return map[ext || ""] || "image/png";
|
|
124
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConversionResult, Converter, StreamInfo } from "../types.js";
|
|
2
|
+
export declare class IpynbConverter implements Converter {
|
|
3
|
+
name: string;
|
|
4
|
+
accepts(streamInfo: StreamInfo): boolean;
|
|
5
|
+
convert(input: Buffer, _streamInfo: StreamInfo): Promise<ConversionResult>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const EXTENSIONS = [".ipynb"];
|
|
2
|
+
export class IpynbConverter {
|
|
3
|
+
name = "ipynb";
|
|
4
|
+
accepts(streamInfo) {
|
|
5
|
+
if (streamInfo.extension && EXTENSIONS.includes(streamInfo.extension))
|
|
6
|
+
return true;
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
async convert(input, _streamInfo) {
|
|
10
|
+
const text = new TextDecoder("utf-8").decode(input);
|
|
11
|
+
const notebook = JSON.parse(text);
|
|
12
|
+
const sections = [];
|
|
13
|
+
let title;
|
|
14
|
+
for (const cell of notebook.cells ?? []) {
|
|
15
|
+
const source = Array.isArray(cell.source)
|
|
16
|
+
? cell.source.join("")
|
|
17
|
+
: (cell.source ?? "");
|
|
18
|
+
if (cell.cell_type === "markdown") {
|
|
19
|
+
sections.push(source);
|
|
20
|
+
// Extract first heading as title
|
|
21
|
+
if (!title) {
|
|
22
|
+
const match = source.match(/^# (.+)$/m);
|
|
23
|
+
if (match)
|
|
24
|
+
title = match[1].trim();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (cell.cell_type === "code") {
|
|
28
|
+
// Detect language from kernel
|
|
29
|
+
const lang = notebook.metadata?.kernelspec?.language ||
|
|
30
|
+
notebook.metadata?.language_info?.name ||
|
|
31
|
+
"python";
|
|
32
|
+
sections.push(`\`\`\`${lang}\n${source}\n\`\`\``);
|
|
33
|
+
// Include text outputs
|
|
34
|
+
const outputs = [];
|
|
35
|
+
for (const out of cell.outputs ?? []) {
|
|
36
|
+
if (out.output_type === "stream") {
|
|
37
|
+
const text = Array.isArray(out.text)
|
|
38
|
+
? out.text.join("")
|
|
39
|
+
: (out.text ?? "");
|
|
40
|
+
if (text.trim())
|
|
41
|
+
outputs.push(text.trim());
|
|
42
|
+
}
|
|
43
|
+
else if (out.output_type === "execute_result" ||
|
|
44
|
+
out.output_type === "display_data") {
|
|
45
|
+
const data = out.data;
|
|
46
|
+
if (data?.["text/plain"]) {
|
|
47
|
+
const plain = Array.isArray(data["text/plain"])
|
|
48
|
+
? data["text/plain"].join("")
|
|
49
|
+
: data["text/plain"];
|
|
50
|
+
if (plain.trim())
|
|
51
|
+
outputs.push(plain.trim());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (out.output_type === "error") {
|
|
55
|
+
const tb = (out.traceback ?? []).join("\n");
|
|
56
|
+
if (tb.trim())
|
|
57
|
+
outputs.push(`Error: ${out.ename}: ${out.evalue}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (outputs.length > 0) {
|
|
61
|
+
sections.push(`\`\`\`\n${outputs.join("\n")}\n\`\`\``);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (cell.cell_type === "raw") {
|
|
65
|
+
sections.push(`\`\`\`\n${source}\n\`\`\``);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Check metadata for title
|
|
69
|
+
title = notebook.metadata?.title ?? title;
|
|
70
|
+
return {
|
|
71
|
+
markdown: sections.join("\n\n").trim(),
|
|
72
|
+
title,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConversionResult, Converter, StreamInfo } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Converts Apple iWork files (Pages, Keynote, Numbers) to markdown.
|
|
4
|
+
*
|
|
5
|
+
* All three formats are ZIP archives containing an XML file:
|
|
6
|
+
* - Pages: index.xml (sf:p paragraphs with named styles)
|
|
7
|
+
* - Keynote: index.apxl (key:slide elements with sf:p text)
|
|
8
|
+
* - Numbers: index.xml (sf:t text cells + sf:n number cells)
|
|
9
|
+
*/
|
|
10
|
+
export declare class IWorkConverter implements Converter {
|
|
11
|
+
name: string;
|
|
12
|
+
accepts(streamInfo: StreamInfo): boolean;
|
|
13
|
+
convert(input: Buffer, streamInfo: StreamInfo): Promise<ConversionResult>;
|
|
14
|
+
private convertPages;
|
|
15
|
+
private convertKeynote;
|
|
16
|
+
private convertNumbers;
|
|
17
|
+
private extractGrid;
|
|
18
|
+
private convertNumbersFallback;
|
|
19
|
+
private readIndex;
|
|
20
|
+
}
|