@visual-z/xeno 0.8.4 → 0.9.0
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 +8 -0
- package/README.md +31 -746
- package/bin/xeno.exe +26 -0
- package/install.cjs +88 -0
- package/package.json +18 -48
- package/docs/app-server.md +0 -115
- package/docs/foundations.md +0 -88
- package/docs/install.md +0 -244
- package/docs/providers.md +0 -172
- package/docs/research/foundation-clients-2026-10-09.md +0 -27
- package/docs/research/foundation-editing-2026-10-09.md +0 -56
- package/docs/research/foundation-network-2026-10-09.md +0 -37
- package/docs/research/foundation-workflow-2026-10-09.md +0 -37
- package/src/apps/acp-server.ts +0 -41
- package/src/apps/agent-profiles.ts +0 -19
- package/src/apps/app-server.ts +0 -30
- package/src/apps/approve.ts +0 -49
- package/src/apps/cli.ts +0 -99
- package/src/apps/commands.ts +0 -319
- package/src/apps/completions.ts +0 -87
- package/src/apps/control-transport.ts +0 -90
- package/src/apps/export-cli.ts +0 -24
- package/src/apps/goal-flow.ts +0 -70
- package/src/apps/image-draft.ts +0 -46
- package/src/apps/input.ts +0 -312
- package/src/apps/model-catalog.ts +0 -69
- package/src/apps/preferences.ts +0 -20
- package/src/apps/project-trust.ts +0 -9
- package/src/apps/provider-connect.ts +0 -346
- package/src/apps/question-ui.ts +0 -27
- package/src/apps/render.ts +0 -181
- package/src/apps/resources.ts +0 -66
- package/src/apps/review.ts +0 -109
- package/src/apps/session-hub.ts +0 -96
- package/src/apps/session-lifecycle.ts +0 -64
- package/src/apps/shell.ts +0 -2071
- package/src/apps/startup-input.ts +0 -135
- package/src/apps/startup.ts +0 -1677
- package/src/apps/ui/app.ts +0 -1818
- package/src/apps/ui/control-model.ts +0 -43
- package/src/apps/ui/extension-host.ts +0 -194
- package/src/apps/ui/image-cache.ts +0 -121
- package/src/apps/ui/palette.ts +0 -88
- package/src/apps/ui/project.ts +0 -127
- package/src/apps/ui/standalone.ts +0 -148
- package/src/apps/ui/status-model.ts +0 -68
- package/src/apps/ui/surface.ts +0 -91
- package/src/apps/ui/theme.ts +0 -86
- package/src/apps/update-check.ts +0 -112
- package/src/apps/workflow.ts +0 -58
- package/src/core/acceptance.ts +0 -139
- package/src/core/action-defaults.ts +0 -58
- package/src/core/activity-status.ts +0 -52
- package/src/core/agent-profile.ts +0 -130
- package/src/core/attachment-input.ts +0 -17
- package/src/core/blind-checks.ts +0 -72
- package/src/core/boundary.ts +0 -174
- package/src/core/branch-receipt.ts +0 -26
- package/src/core/catalog-merge.ts +0 -19
- package/src/core/checkpoints.ts +0 -85
- package/src/core/churn.ts +0 -61
- package/src/core/command-artifacts.ts +0 -94
- package/src/core/command-contract.ts +0 -151
- package/src/core/completion-action.ts +0 -20
- package/src/core/completion-review.ts +0 -98
- package/src/core/context-detail.ts +0 -37
- package/src/core/context-policy.ts +0 -133
- package/src/core/context-window.ts +0 -54
- package/src/core/continuation.ts +0 -130
- package/src/core/control-protocol.ts +0 -69
- package/src/core/control-view.ts +0 -39
- package/src/core/cycle.ts +0 -17
- package/src/core/data-query.ts +0 -201
- package/src/core/deadline.ts +0 -40
- package/src/core/derive.ts +0 -516
- package/src/core/draft-images.ts +0 -56
- package/src/core/edit-plan.ts +0 -200
- package/src/core/environment.ts +0 -181
- package/src/core/event-validation.ts +0 -220
- package/src/core/events.ts +0 -670
- package/src/core/evidence-ladder.ts +0 -62
- package/src/core/evidence-links.ts +0 -68
- package/src/core/evidence.ts +0 -240
- package/src/core/execution.ts +0 -18
- package/src/core/exhaustive.ts +0 -18
- package/src/core/export.ts +0 -179
- package/src/core/extension-flags.ts +0 -14
- package/src/core/external-effects.ts +0 -488
- package/src/core/failure-recovery.ts +0 -173
- package/src/core/file-precondition.ts +0 -78
- package/src/core/file-references.ts +0 -35
- package/src/core/frontmatter.ts +0 -213
- package/src/core/git-status.ts +0 -29
- package/src/core/goal-view.ts +0 -64
- package/src/core/goal.ts +0 -200
- package/src/core/handoff.ts +0 -479
- package/src/core/history-query.ts +0 -139
- package/src/core/history.ts +0 -237
- package/src/core/image-limits.ts +0 -72
- package/src/core/images.ts +0 -46
- package/src/core/integration-health.ts +0 -34
- package/src/core/json-event.ts +0 -131
- package/src/core/json-pointer.ts +0 -46
- package/src/core/keymap.ts +0 -153
- package/src/core/lsp-framing.ts +0 -34
- package/src/core/mcp-config.ts +0 -68
- package/src/core/model-picker.ts +0 -64
- package/src/core/model-preferences.ts +0 -28
- package/src/core/model-replay.ts +0 -22
- package/src/core/model-scope.ts +0 -53
- package/src/core/note-guidance.ts +0 -34
- package/src/core/oauth-fields.ts +0 -44
- package/src/core/observation-view.ts +0 -152
- package/src/core/outcome.ts +0 -44
- package/src/core/overflow.ts +0 -59
- package/src/core/packages.ts +0 -47
- package/src/core/patch.ts +0 -130
- package/src/core/path-suggestions.ts +0 -59
- package/src/core/permissions.ts +0 -410
- package/src/core/process-receipt.ts +0 -105
- package/src/core/process-state.ts +0 -37
- package/src/core/program-status.ts +0 -40
- package/src/core/progress.ts +0 -150
- package/src/core/project.ts +0 -431
- package/src/core/prompt-policy.ts +0 -46
- package/src/core/prompts.ts +0 -111
- package/src/core/question.ts +0 -94
- package/src/core/queue.ts +0 -78
- package/src/core/read-bounds.ts +0 -24
- package/src/core/read-observation.ts +0 -106
- package/src/core/recovery-sources.ts +0 -74
- package/src/core/regex-dialect.ts +0 -25
- package/src/core/request-budget.ts +0 -23
- package/src/core/request-progress.ts +0 -87
- package/src/core/request-state.ts +0 -273
- package/src/core/resource-selection.ts +0 -36
- package/src/core/response-recovery.ts +0 -59
- package/src/core/resume.ts +0 -59
- package/src/core/review.ts +0 -68
- package/src/core/ripgrep-release.ts +0 -64
- package/src/core/runtime-target.ts +0 -94
- package/src/core/scheduling.ts +0 -8
- package/src/core/search-observation.ts +0 -97
- package/src/core/secrets.ts +0 -188
- package/src/core/session-archive.ts +0 -4
- package/src/core/session-browser.ts +0 -82
- package/src/core/session-entry.ts +0 -61
- package/src/core/session-exit.ts +0 -42
- package/src/core/session-format.ts +0 -169
- package/src/core/session-position.ts +0 -26
- package/src/core/session-tree.ts +0 -147
- package/src/core/settings.ts +0 -192
- package/src/core/skills.ts +0 -165
- package/src/core/sql-query.ts +0 -211
- package/src/core/stall.ts +0 -128
- package/src/core/stop-report.ts +0 -68
- package/src/core/text-normalize.ts +0 -81
- package/src/core/theme.ts +0 -166
- package/src/core/thinking.ts +0 -26
- package/src/core/tokens.ts +0 -151
- package/src/core/tool-contract.ts +0 -153
- package/src/core/tool-discovery.ts +0 -87
- package/src/core/tool-failure.ts +0 -81
- package/src/core/tool-input.ts +0 -44
- package/src/core/transcript.ts +0 -108
- package/src/core/tui-mode.ts +0 -29
- package/src/core/update-check.ts +0 -157
- package/src/core/version.ts +0 -55
- package/src/core/web-content.ts +0 -80
- package/src/core/work-state.ts +0 -154
- package/src/core/workflow-mode.ts +0 -34
- package/src/core/working-set.ts +0 -119
- package/src/core/yaml.ts +0 -282
- package/src/runtime/acp-agent.ts +0 -289
- package/src/runtime/agent-profiles.ts +0 -21
- package/src/runtime/auth.ts +0 -367
- package/src/runtime/blind-check.ts +0 -36
- package/src/runtime/branch-jobs.ts +0 -36
- package/src/runtime/catalog.ts +0 -285
- package/src/runtime/clipboard.ts +0 -125
- package/src/runtime/command-artifacts.ts +0 -64
- package/src/runtime/connection-reuse.ts +0 -40
- package/src/runtime/control-client.ts +0 -149
- package/src/runtime/control-connection.ts +0 -139
- package/src/runtime/counter-check.ts +0 -74
- package/src/runtime/environment-tools.ts +0 -60
- package/src/runtime/evidence-notes.ts +0 -35
- package/src/runtime/exec-sessions.ts +0 -456
- package/src/runtime/execution-control.ts +0 -40
- package/src/runtime/extension-loader.ts +0 -37
- package/src/runtime/extension-ui.ts +0 -47
- package/src/runtime/extensions.ts +0 -370
- package/src/runtime/formatter-tool.ts +0 -38
- package/src/runtime/formatter.ts +0 -50
- package/src/runtime/foundation.ts +0 -116
- package/src/runtime/history-cache.ts +0 -57
- package/src/runtime/history-tools.ts +0 -168
- package/src/runtime/images.ts +0 -80
- package/src/runtime/integrations.ts +0 -216
- package/src/runtime/loop.ts +0 -3108
- package/src/runtime/lsp-client.ts +0 -201
- package/src/runtime/mcp-client.ts +0 -264
- package/src/runtime/mcp-oauth.ts +0 -168
- package/src/runtime/mcp-schema.ts +0 -51
- package/src/runtime/model-config.ts +0 -232
- package/src/runtime/model-data.LICENSE +0 -27
- package/src/runtime/model-data.ts +0 -21
- package/src/runtime/model-discovery.ts +0 -208
- package/src/runtime/model-replay.ts +0 -10
- package/src/runtime/model-scope.ts +0 -20
- package/src/runtime/model-sources.ts +0 -151
- package/src/runtime/model.ts +0 -686
- package/src/runtime/models-fetch.ts +0 -57
- package/src/runtime/oauth-device.ts +0 -86
- package/src/runtime/oauth.ts +0 -853
- package/src/runtime/open-image.ts +0 -42
- package/src/runtime/openai-responses.ts +0 -304
- package/src/runtime/openai.ts +0 -697
- package/src/runtime/output-schema.ts +0 -26
- package/src/runtime/package-manager.ts +0 -125
- package/src/runtime/patch-tool.ts +0 -38
- package/src/runtime/permission-resources.ts +0 -18
- package/src/runtime/pi-provider.ts +0 -423
- package/src/runtime/program-status.ts +0 -38
- package/src/runtime/progress.ts +0 -26
- package/src/runtime/provider-access.ts +0 -21
- package/src/runtime/provider-connect.ts +0 -109
- package/src/runtime/provider-presets.ts +0 -98
- package/src/runtime/provider-protocols.ts +0 -29
- package/src/runtime/provider-request.ts +0 -87
- package/src/runtime/provider-tool-policy.ts +0 -33
- package/src/runtime/provider.ts +0 -580
- package/src/runtime/question-tool.ts +0 -62
- package/src/runtime/retry.ts +0 -447
- package/src/runtime/review-tool.ts +0 -48
- package/src/runtime/rich-text.ts +0 -36
- package/src/runtime/runtime-target.ts +0 -149
- package/src/runtime/secrets.ts +0 -79
- package/src/runtime/self-update.ts +0 -74
- package/src/runtime/session-control.ts +0 -265
- package/src/runtime/session-hub.ts +0 -85
- package/src/runtime/stream-idle.ts +0 -80
- package/src/runtime/tool-broker.ts +0 -137
- package/src/runtime/tool-discovery.ts +0 -58
- package/src/runtime/tool-queue.ts +0 -77
- package/src/runtime/tools.ts +0 -1820
- package/src/runtime/turn-effects.ts +0 -31
- package/src/runtime/update-check.ts +0 -48
- package/src/runtime/usage.ts +0 -253
- package/src/runtime/version.ts +0 -12
- package/src/runtime/web-http.ts +0 -56
- package/src/runtime/web-tools.ts +0 -88
- package/src/runtime/working-notes.ts +0 -60
- package/src/runtime/workspace-lifecycle.ts +0 -141
- package/src/store/acceptance.ts +0 -15
- package/src/store/agent-profile-files.ts +0 -13
- package/src/store/atomic.ts +0 -31
- package/src/store/auth-store.ts +0 -50
- package/src/store/blind-checks.ts +0 -32
- package/src/store/blobs.ts +0 -143
- package/src/store/checkpoint-history.ts +0 -32
- package/src/store/command-artifacts.ts +0 -96
- package/src/store/command.ts +0 -111
- package/src/store/config.ts +0 -69
- package/src/store/context-files.ts +0 -436
- package/src/store/file-checkpoints.ts +0 -108
- package/src/store/file-index.ts +0 -174
- package/src/store/foundation-config.ts +0 -24
- package/src/store/git-checkpoints.ts +0 -67
- package/src/store/git-status.ts +0 -15
- package/src/store/history-search.ts +0 -19
- package/src/store/log.ts +0 -725
- package/src/store/lsp-document.ts +0 -30
- package/src/store/mcp-credentials.ts +0 -85
- package/src/store/models.ts +0 -60
- package/src/store/observations.ts +0 -224
- package/src/store/packages.ts +0 -98
- package/src/store/patch.ts +0 -92
- package/src/store/permission-paths.ts +0 -34
- package/src/store/process-receipts.ts +0 -34
- package/src/store/query-source.ts +0 -49
- package/src/store/recovery.ts +0 -44
- package/src/store/replay.ts +0 -76
- package/src/store/resource-index.ts +0 -170
- package/src/store/resources.ts +0 -285
- package/src/store/restore.ts +0 -110
- package/src/store/review.ts +0 -109
- package/src/store/runtime-target.ts +0 -64
- package/src/store/search.ts +0 -728
- package/src/store/secrets.ts +0 -44
- package/src/store/serial.ts +0 -13
- package/src/store/session-archive.ts +0 -165
- package/src/store/session-browser.ts +0 -68
- package/src/store/session-position.ts +0 -27
- package/src/store/sessions.ts +0 -525
- package/src/store/source-cancellation.ts +0 -6
- package/src/store/tool-binaries.ts +0 -90
- package/src/store/trust.ts +0 -82
- package/src/store/update-cache.ts +0 -36
- package/src/store/user-settings.ts +0 -30
- package/src/store/workspace-clone.ts +0 -42
- package/src/store/workspace-observation.ts +0 -113
- package/src/store/workspace.ts +0 -115
- package/src/store/worktree.ts +0 -278
- package/src/tui/ansi-spans.ts +0 -126
- package/src/tui/diff.ts +0 -160
- package/src/tui/exhaustive.ts +0 -14
- package/src/tui/fuzzy.ts +0 -75
- package/src/tui/style.ts +0 -208
- package/src/tui/ui/atomic-draft.ts +0 -121
- package/src/tui/ui/branch-panel.ts +0 -47
- package/src/tui/ui/canvas.ts +0 -96
- package/src/tui/ui/colors.ts +0 -70
- package/src/tui/ui/composer.ts +0 -199
- package/src/tui/ui/control-panel.ts +0 -25
- package/src/tui/ui/control-sidebar.ts +0 -49
- package/src/tui/ui/dialog.ts +0 -398
- package/src/tui/ui/draft.ts +0 -23
- package/src/tui/ui/duration.ts +0 -16
- package/src/tui/ui/edge.ts +0 -186
- package/src/tui/ui/image-size.ts +0 -44
- package/src/tui/ui/ink.ts +0 -210
- package/src/tui/ui/items.ts +0 -42
- package/src/tui/ui/keys.ts +0 -40
- package/src/tui/ui/layout.ts +0 -74
- package/src/tui/ui/list-model.ts +0 -86
- package/src/tui/ui/list-view.ts +0 -172
- package/src/tui/ui/mascot.ts +0 -67
- package/src/tui/ui/messages.ts +0 -518
- package/src/tui/ui/motion.ts +0 -28
- package/src/tui/ui/paths.ts +0 -10
- package/src/tui/ui/pictures.ts +0 -108
- package/src/tui/ui/prompt-history.ts +0 -60
- package/src/tui/ui/screen.ts +0 -579
- package/src/tui/ui/status.ts +0 -403
- package/src/tui/ui/styled.ts +0 -85
- package/src/tui/ui/tool-card.ts +0 -150
- package/src/tui/width.ts +0 -567
- package/src/vendor/pi-rich/LICENSE.upstream +0 -21
- package/src/vendor/pi-rich/UPSTREAM.json +0 -17
- package/src/vendor/pi-rich/clipboard-command.ts +0 -44
- package/src/vendor/pi-rich/exif-orientation.ts +0 -182
- package/src/vendor/pi-rich/html.ts +0 -51
- package/src/vendor/pi-rich/image-convert.ts +0 -49
- package/src/vendor/pi-rich/image-resize-core.ts +0 -164
- package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
- package/src/vendor/pi-rich/image-resize.ts +0 -123
- package/src/vendor/pi-rich/mime.ts +0 -116
- package/src/vendor/pi-rich/photon.ts +0 -139
- package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { open } from "node:fs/promises";
|
|
2
|
-
|
|
3
|
-
const IMAGE_TYPE_SNIFF_BYTES = 4100;
|
|
4
|
-
const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
|
5
|
-
|
|
6
|
-
export function detectSupportedImageMimeType(buffer: Uint8Array): string | null {
|
|
7
|
-
if (startsWith(buffer, [0xff, 0xd8, 0xff])) {
|
|
8
|
-
return buffer[3] === 0xf7 ? null : "image/jpeg";
|
|
9
|
-
}
|
|
10
|
-
if (startsWith(buffer, PNG_SIGNATURE)) {
|
|
11
|
-
return isPng(buffer) && !isAnimatedPng(buffer) ? "image/png" : null;
|
|
12
|
-
}
|
|
13
|
-
if (startsWithAscii(buffer, 0, "GIF87a") || startsWithAscii(buffer, 0, "GIF89a")) {
|
|
14
|
-
return "image/gif";
|
|
15
|
-
}
|
|
16
|
-
if (startsWithAscii(buffer, 0, "RIFF") && startsWithAscii(buffer, 8, "WEBP")) {
|
|
17
|
-
return "image/webp";
|
|
18
|
-
}
|
|
19
|
-
if (startsWithAscii(buffer, 0, "BM") && isBmp(buffer)) {
|
|
20
|
-
return "image/bmp";
|
|
21
|
-
}
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function detectSupportedImageMimeTypeFromFile(filePath: string): Promise<string | null> {
|
|
26
|
-
const fileHandle = await open(filePath, "r");
|
|
27
|
-
try {
|
|
28
|
-
const buffer = Buffer.alloc(IMAGE_TYPE_SNIFF_BYTES);
|
|
29
|
-
const { bytesRead } = await fileHandle.read(buffer, 0, IMAGE_TYPE_SNIFF_BYTES, 0);
|
|
30
|
-
return detectSupportedImageMimeType(buffer.subarray(0, bytesRead));
|
|
31
|
-
} finally {
|
|
32
|
-
await fileHandle.close();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function isPng(buffer: Uint8Array): boolean {
|
|
37
|
-
return (
|
|
38
|
-
buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, "IHDR")
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function isAnimatedPng(buffer: Uint8Array): boolean {
|
|
43
|
-
let offset = PNG_SIGNATURE.length;
|
|
44
|
-
while (offset + 8 <= buffer.length) {
|
|
45
|
-
const chunkLength = readUint32BE(buffer, offset);
|
|
46
|
-
const chunkTypeOffset = offset + 4;
|
|
47
|
-
if (startsWithAscii(buffer, chunkTypeOffset, "acTL")) return true;
|
|
48
|
-
if (startsWithAscii(buffer, chunkTypeOffset, "IDAT")) return false;
|
|
49
|
-
|
|
50
|
-
const nextOffset = offset + 8 + chunkLength + 4;
|
|
51
|
-
if (nextOffset <= offset || nextOffset > buffer.length) return false;
|
|
52
|
-
offset = nextOffset;
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isBmp(buffer: Uint8Array): boolean {
|
|
58
|
-
if (buffer.length < 26) return false;
|
|
59
|
-
|
|
60
|
-
const declaredFileSize = readUint32LE(buffer, 2);
|
|
61
|
-
const pixelDataOffset = readUint32LE(buffer, 10);
|
|
62
|
-
const dibHeaderSize = readUint32LE(buffer, 14);
|
|
63
|
-
if (declaredFileSize !== 0 && declaredFileSize < 26) return false;
|
|
64
|
-
if (pixelDataOffset < 14 + dibHeaderSize) return false;
|
|
65
|
-
if (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize) return false;
|
|
66
|
-
|
|
67
|
-
let colorPlanes: number;
|
|
68
|
-
let bitsPerPixel: number;
|
|
69
|
-
if (dibHeaderSize === 12) {
|
|
70
|
-
colorPlanes = readUint16LE(buffer, 22);
|
|
71
|
-
bitsPerPixel = readUint16LE(buffer, 24);
|
|
72
|
-
} else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {
|
|
73
|
-
if (buffer.length < 30) return false;
|
|
74
|
-
colorPlanes = readUint16LE(buffer, 26);
|
|
75
|
-
bitsPerPixel = readUint16LE(buffer, 28);
|
|
76
|
-
} else {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function readUint16LE(buffer: Uint8Array, offset: number): number {
|
|
84
|
-
return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function readUint32BE(buffer: Uint8Array, offset: number): number {
|
|
88
|
-
return (
|
|
89
|
-
(buffer[offset] ?? 0) * 0x1000000 +
|
|
90
|
-
((buffer[offset + 1] ?? 0) << 16) +
|
|
91
|
-
((buffer[offset + 2] ?? 0) << 8) +
|
|
92
|
-
(buffer[offset + 3] ?? 0)
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function readUint32LE(buffer: Uint8Array, offset: number): number {
|
|
97
|
-
return (
|
|
98
|
-
(buffer[offset] ?? 0) +
|
|
99
|
-
((buffer[offset + 1] ?? 0) << 8) +
|
|
100
|
-
((buffer[offset + 2] ?? 0) << 16) +
|
|
101
|
-
(buffer[offset + 3] ?? 0) * 0x1000000
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function startsWith(buffer: Uint8Array, bytes: number[]): boolean {
|
|
106
|
-
if (buffer.length < bytes.length) return false;
|
|
107
|
-
return bytes.every((byte, index) => buffer[index] === byte);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function startsWithAscii(buffer: Uint8Array, offset: number, text: string): boolean {
|
|
111
|
-
if (buffer.length < offset + text.length) return false;
|
|
112
|
-
for (let index = 0; index < text.length; index++) {
|
|
113
|
-
if (buffer[offset + index] !== text.charCodeAt(index)) return false;
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Photon image processing wrapper.
|
|
3
|
-
*
|
|
4
|
-
* This module provides a unified interface to @silvia-odwyer/photon-node that works in:
|
|
5
|
-
* 1. Node.js (development, npm run build)
|
|
6
|
-
* 2. Bun compiled binaries (standalone distribution)
|
|
7
|
-
*
|
|
8
|
-
* The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')
|
|
9
|
-
* which bakes the build machine's absolute path into Bun compiled binaries.
|
|
10
|
-
*
|
|
11
|
-
* Solution:
|
|
12
|
-
* 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads
|
|
13
|
-
* 2. Copy photon_rs_bg.wasm next to the executable in build:binary
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { PathOrFileDescriptor } from "fs";
|
|
17
|
-
import { createRequire } from "module";
|
|
18
|
-
import * as path from "path";
|
|
19
|
-
import { fileURLToPath } from "url";
|
|
20
|
-
|
|
21
|
-
const require = createRequire(import.meta.url);
|
|
22
|
-
const fs = require("fs") as typeof import("fs");
|
|
23
|
-
|
|
24
|
-
// Re-export types from the main package
|
|
25
|
-
export type { PhotonImage as PhotonImageType } from "@silvia-odwyer/photon-node";
|
|
26
|
-
|
|
27
|
-
type ReadFileSync = typeof fs.readFileSync;
|
|
28
|
-
|
|
29
|
-
const WASM_FILENAME = "photon_rs_bg.wasm";
|
|
30
|
-
|
|
31
|
-
// Lazy-loaded photon module
|
|
32
|
-
let photonModule: typeof import("@silvia-odwyer/photon-node") | null = null;
|
|
33
|
-
let loadPromise: Promise<typeof import("@silvia-odwyer/photon-node") | null> | null = null;
|
|
34
|
-
|
|
35
|
-
function pathOrNull(file: PathOrFileDescriptor): string | null {
|
|
36
|
-
if (typeof file === "string") {
|
|
37
|
-
return file;
|
|
38
|
-
}
|
|
39
|
-
if (file instanceof URL) {
|
|
40
|
-
return fileURLToPath(file);
|
|
41
|
-
}
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getFallbackWasmPaths(): string[] {
|
|
46
|
-
const execDir = path.dirname(process.execPath);
|
|
47
|
-
return [
|
|
48
|
-
path.join(execDir, WASM_FILENAME),
|
|
49
|
-
path.join(execDir, "photon", WASM_FILENAME),
|
|
50
|
-
path.join(process.cwd(), WASM_FILENAME),
|
|
51
|
-
];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function patchPhotonWasmRead(): () => void {
|
|
55
|
-
const originalReadFileSync: ReadFileSync = fs.readFileSync.bind(fs);
|
|
56
|
-
const fallbackPaths = getFallbackWasmPaths();
|
|
57
|
-
const mutableFs = fs as { readFileSync: ReadFileSync };
|
|
58
|
-
|
|
59
|
-
const patchedReadFileSync: ReadFileSync = ((...args: Parameters<ReadFileSync>) => {
|
|
60
|
-
const [file, options] = args;
|
|
61
|
-
const resolvedPath = pathOrNull(file);
|
|
62
|
-
|
|
63
|
-
if (resolvedPath?.endsWith(WASM_FILENAME)) {
|
|
64
|
-
try {
|
|
65
|
-
return originalReadFileSync(...args);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
const err = error as NodeJS.ErrnoException;
|
|
68
|
-
if (err?.code && err.code !== "ENOENT") {
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
for (const fallbackPath of fallbackPaths) {
|
|
73
|
-
if (!fs.existsSync(fallbackPath)) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (options === undefined) {
|
|
77
|
-
return originalReadFileSync(fallbackPath);
|
|
78
|
-
}
|
|
79
|
-
return originalReadFileSync(fallbackPath, options);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return originalReadFileSync(...args);
|
|
87
|
-
}) as ReadFileSync;
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
mutableFs.readFileSync = patchedReadFileSync;
|
|
91
|
-
} catch {
|
|
92
|
-
Object.defineProperty(fs, "readFileSync", {
|
|
93
|
-
value: patchedReadFileSync,
|
|
94
|
-
writable: true,
|
|
95
|
-
configurable: true,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return () => {
|
|
100
|
-
try {
|
|
101
|
-
mutableFs.readFileSync = originalReadFileSync;
|
|
102
|
-
} catch {
|
|
103
|
-
Object.defineProperty(fs, "readFileSync", {
|
|
104
|
-
value: originalReadFileSync,
|
|
105
|
-
writable: true,
|
|
106
|
-
configurable: true,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Load the photon module asynchronously.
|
|
114
|
-
* Returns cached module on subsequent calls.
|
|
115
|
-
*/
|
|
116
|
-
export async function loadPhoton(): Promise<typeof import("@silvia-odwyer/photon-node") | null> {
|
|
117
|
-
if (photonModule) {
|
|
118
|
-
return photonModule;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (loadPromise) {
|
|
122
|
-
return loadPromise;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
loadPromise = (async () => {
|
|
126
|
-
const restoreReadFileSync = patchPhotonWasmRead();
|
|
127
|
-
try {
|
|
128
|
-
photonModule = await import("@silvia-odwyer/photon-node");
|
|
129
|
-
return photonModule;
|
|
130
|
-
} catch {
|
|
131
|
-
photonModule = null;
|
|
132
|
-
return photonModule;
|
|
133
|
-
} finally {
|
|
134
|
-
restoreReadFileSync();
|
|
135
|
-
}
|
|
136
|
-
})();
|
|
137
|
-
|
|
138
|
-
return loadPromise;
|
|
139
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import hljs from "highlight.js/lib/core.js";
|
|
2
|
-
import bash from "highlight.js/lib/languages/bash.js";
|
|
3
|
-
import c from "highlight.js/lib/languages/c.js";
|
|
4
|
-
import cpp from "highlight.js/lib/languages/cpp.js";
|
|
5
|
-
import csharp from "highlight.js/lib/languages/csharp.js";
|
|
6
|
-
import dart from "highlight.js/lib/languages/dart.js";
|
|
7
|
-
import go from "highlight.js/lib/languages/go.js";
|
|
8
|
-
import groovy from "highlight.js/lib/languages/groovy.js";
|
|
9
|
-
import java from "highlight.js/lib/languages/java.js";
|
|
10
|
-
import javascript from "highlight.js/lib/languages/javascript.js";
|
|
11
|
-
import json from "highlight.js/lib/languages/json.js";
|
|
12
|
-
import kotlin from "highlight.js/lib/languages/kotlin.js";
|
|
13
|
-
import lua from "highlight.js/lib/languages/lua.js";
|
|
14
|
-
import nix from "highlight.js/lib/languages/nix.js";
|
|
15
|
-
import perl from "highlight.js/lib/languages/perl.js";
|
|
16
|
-
import php from "highlight.js/lib/languages/php.js";
|
|
17
|
-
import python from "highlight.js/lib/languages/python.js";
|
|
18
|
-
import ruby from "highlight.js/lib/languages/ruby.js";
|
|
19
|
-
import rust from "highlight.js/lib/languages/rust.js";
|
|
20
|
-
import scala from "highlight.js/lib/languages/scala.js";
|
|
21
|
-
import swift from "highlight.js/lib/languages/swift.js";
|
|
22
|
-
import typescript from "highlight.js/lib/languages/typescript.js";
|
|
23
|
-
import { decodeHtmlEntityAt } from "./html.ts";
|
|
24
|
-
|
|
25
|
-
const eagerLanguages = {
|
|
26
|
-
python,
|
|
27
|
-
java,
|
|
28
|
-
go,
|
|
29
|
-
javascript,
|
|
30
|
-
json,
|
|
31
|
-
cpp,
|
|
32
|
-
typescript,
|
|
33
|
-
php,
|
|
34
|
-
ruby,
|
|
35
|
-
c,
|
|
36
|
-
csharp,
|
|
37
|
-
nix,
|
|
38
|
-
bash,
|
|
39
|
-
rust,
|
|
40
|
-
scala,
|
|
41
|
-
kotlin,
|
|
42
|
-
swift,
|
|
43
|
-
dart,
|
|
44
|
-
groovy,
|
|
45
|
-
perl,
|
|
46
|
-
lua,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
for (const [name, language] of Object.entries(eagerLanguages)) {
|
|
50
|
-
hljs.registerLanguage(name, language);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let allLanguagesPromise: Promise<void> | undefined;
|
|
54
|
-
|
|
55
|
-
export function loadAllHighlightLanguages(): Promise<void> {
|
|
56
|
-
if (!allLanguagesPromise) {
|
|
57
|
-
allLanguagesPromise = new Promise((resolve) => {
|
|
58
|
-
setImmediate(() => {
|
|
59
|
-
void import("highlight.js/lib/index.js").then(
|
|
60
|
-
() => resolve(),
|
|
61
|
-
() => {
|
|
62
|
-
// Eager languages and plaintext fallback remain available.
|
|
63
|
-
resolve();
|
|
64
|
-
},
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return allLanguagesPromise;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export type HighlightFormatter = (text: string) => string;
|
|
73
|
-
export type HighlightTheme = Partial<Record<string, HighlightFormatter>>;
|
|
74
|
-
|
|
75
|
-
export interface HighlightOptions {
|
|
76
|
-
language?: string;
|
|
77
|
-
ignoreIllegals?: boolean;
|
|
78
|
-
languageSubset?: string[];
|
|
79
|
-
theme?: HighlightTheme;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const SPAN_CLOSE = "</span>";
|
|
83
|
-
const HIGHLIGHT_CLASS_PREFIX = "hljs-";
|
|
84
|
-
|
|
85
|
-
function getScopeFromSpanTag(tag: string): string | undefined {
|
|
86
|
-
const match = /\sclass\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(tag);
|
|
87
|
-
const classValue = match?.[1] ?? match?.[2];
|
|
88
|
-
if (!classValue) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
for (const className of classValue.split(/\s+/)) {
|
|
93
|
-
if (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {
|
|
94
|
-
return className.slice(HIGHLIGHT_CLASS_PREFIX.length);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {
|
|
102
|
-
const exact = theme[scope];
|
|
103
|
-
if (exact) {
|
|
104
|
-
return exact;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const dotIndex = scope.indexOf(".");
|
|
108
|
-
if (dotIndex !== -1) {
|
|
109
|
-
const prefixFormatter = theme[scope.slice(0, dotIndex)];
|
|
110
|
-
if (prefixFormatter) {
|
|
111
|
-
return prefixFormatter;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const dashIndex = scope.indexOf("-");
|
|
116
|
-
if (dashIndex !== -1) {
|
|
117
|
-
const prefixFormatter = theme[scope.slice(0, dashIndex)];
|
|
118
|
-
if (prefixFormatter) {
|
|
119
|
-
return prefixFormatter;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return undefined;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {
|
|
127
|
-
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
128
|
-
const scope = scopes[i];
|
|
129
|
-
if (!scope) {
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
const formatter = getScopeFormatter(scope, theme);
|
|
133
|
-
if (formatter) {
|
|
134
|
-
return formatter;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return theme.default;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function isSpanOpenTagStart(html: string, index: number): boolean {
|
|
141
|
-
if (!html.startsWith("<span", index)) {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
const nextChar = html[index + "<span".length];
|
|
145
|
-
return nextChar === ">" || nextChar === " " || nextChar === "\t" || nextChar === "\n" || nextChar === "\r";
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {
|
|
149
|
-
let output = "";
|
|
150
|
-
let textBuffer = "";
|
|
151
|
-
const scopes: Array<string | undefined> = [];
|
|
152
|
-
|
|
153
|
-
const flushText = () => {
|
|
154
|
-
if (!textBuffer) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
const formatter = getActiveFormatter(scopes, theme);
|
|
158
|
-
output += formatter ? formatter(textBuffer) : textBuffer;
|
|
159
|
-
textBuffer = "";
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
let index = 0;
|
|
163
|
-
while (index < html.length) {
|
|
164
|
-
if (isSpanOpenTagStart(html, index)) {
|
|
165
|
-
const tagEndIndex = html.indexOf(">", index + 5);
|
|
166
|
-
if (tagEndIndex !== -1) {
|
|
167
|
-
flushText();
|
|
168
|
-
const tag = html.slice(index, tagEndIndex + 1);
|
|
169
|
-
const scope = getScopeFromSpanTag(tag);
|
|
170
|
-
scopes.push(scope);
|
|
171
|
-
index = tagEndIndex + 1;
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (html.startsWith(SPAN_CLOSE, index)) {
|
|
177
|
-
flushText();
|
|
178
|
-
if (scopes.length > 0) {
|
|
179
|
-
scopes.pop();
|
|
180
|
-
}
|
|
181
|
-
index += SPAN_CLOSE.length;
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (html[index] === "&") {
|
|
186
|
-
const decoded = decodeHtmlEntityAt(html, index);
|
|
187
|
-
if (decoded) {
|
|
188
|
-
textBuffer += decoded.text;
|
|
189
|
-
index += decoded.length;
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
textBuffer += html[index];
|
|
195
|
-
index++;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
flushText();
|
|
199
|
-
return output;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export function highlight(code: string, options: HighlightOptions = {}): string {
|
|
203
|
-
const html = options.language
|
|
204
|
-
? hljs.highlight(code, {
|
|
205
|
-
language: options.language,
|
|
206
|
-
ignoreIllegals: options.ignoreIllegals,
|
|
207
|
-
}).value
|
|
208
|
-
: hljs.highlightAuto(code, options.languageSubset).value;
|
|
209
|
-
return renderHighlightedHtml(html, options.theme);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function supportsLanguage(name: string): boolean {
|
|
213
|
-
return hljs.getLanguage(name) !== undefined;
|
|
214
|
-
}
|