open-multi-agent-kit 0.98.3 → 0.98.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 +32 -0
- package/README.md +11 -2
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +14 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +3 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/mcp-attach.d.ts +3 -3
- package/dist/cli/mcp-attach.d.ts.map +1 -1
- package/dist/cli/mcp-attach.js +5 -4
- package/dist/cli/mcp-attach.js.map +1 -1
- package/dist/cli/model-contract.d.ts +5 -0
- package/dist/cli/model-contract.d.ts.map +1 -0
- package/dist/cli/model-contract.js +45 -0
- package/dist/cli/model-contract.js.map +1 -0
- package/dist/commands/adaptorch-doctor-cli.d.ts.map +1 -1
- package/dist/commands/adaptorch-doctor-cli.js +32 -10
- package/dist/commands/adaptorch-doctor-cli.js.map +1 -1
- package/dist/commands/init-cli.d.ts +12 -0
- package/dist/commands/init-cli.d.ts.map +1 -0
- package/dist/commands/init-cli.js +76 -0
- package/dist/commands/init-cli.js.map +1 -0
- package/dist/commands/provider-sync-cli.d.ts +27 -0
- package/dist/commands/provider-sync-cli.d.ts.map +1 -0
- package/dist/commands/provider-sync-cli.js +177 -0
- package/dist/commands/provider-sync-cli.js.map +1 -0
- package/dist/commands/run-command.d.ts +8 -0
- package/dist/commands/run-command.d.ts.map +1 -0
- package/dist/commands/run-command.js +26 -0
- package/dist/commands/run-command.js.map +1 -0
- package/dist/core/active-skill-state.d.ts +7 -0
- package/dist/core/active-skill-state.d.ts.map +1 -0
- package/dist/core/active-skill-state.js +25 -0
- package/dist/core/active-skill-state.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +2 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +0 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +30 -85
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/codex-chatgpt-web-bridge.d.ts +99 -0
- package/dist/core/codex-chatgpt-web-bridge.d.ts.map +1 -0
- package/dist/core/codex-chatgpt-web-bridge.js +192 -0
- package/dist/core/codex-chatgpt-web-bridge.js.map +1 -0
- package/dist/core/codex-chatgpt-web-sync.d.ts +50 -0
- package/dist/core/codex-chatgpt-web-sync.d.ts.map +1 -0
- package/dist/core/codex-chatgpt-web-sync.js +119 -0
- package/dist/core/codex-chatgpt-web-sync.js.map +1 -0
- package/dist/core/compaction/compaction-headroom.d.ts +30 -0
- package/dist/core/compaction/compaction-headroom.d.ts.map +1 -0
- package/dist/core/compaction/compaction-headroom.js +48 -0
- package/dist/core/compaction/compaction-headroom.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +2 -29
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +19 -47
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/overflow-retry-guard.d.ts +20 -0
- package/dist/core/compaction/overflow-retry-guard.d.ts.map +1 -0
- package/dist/core/compaction/overflow-retry-guard.js +38 -0
- package/dist/core/compaction/overflow-retry-guard.js.map +1 -0
- package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-types.js +1 -1
- package/dist/core/context-budget-headroom-types.js.map +1 -1
- package/dist/core/context-budget-token-counter-types.d.ts +27 -0
- package/dist/core/context-budget-token-counter-types.d.ts.map +1 -0
- package/dist/core/context-budget-token-counter-types.js +2 -0
- package/dist/core/context-budget-token-counter-types.js.map +1 -0
- package/dist/core/context-budget-token-counter.d.ts +2 -26
- package/dist/core/context-budget-token-counter.d.ts.map +1 -1
- package/dist/core/context-budget-token-counter.js +2 -0
- package/dist/core/context-budget-token-counter.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js +14 -10
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/domain-router.d.ts.map +1 -1
- package/dist/core/domain-router.js +1 -1
- package/dist/core/domain-router.js.map +1 -1
- package/dist/core/grok-harness-dispatch.d.ts +4 -0
- package/dist/core/grok-harness-dispatch.d.ts.map +1 -1
- package/dist/core/grok-harness-dispatch.js +20 -3
- package/dist/core/grok-harness-dispatch.js.map +1 -1
- package/dist/core/grok-harness.d.ts +15 -9
- package/dist/core/grok-harness.d.ts.map +1 -1
- package/dist/core/grok-harness.js +34 -8
- package/dist/core/grok-harness.js.map +1 -1
- package/dist/core/mcp/tools.d.ts +2 -2
- package/dist/core/mcp/tools.d.ts.map +1 -1
- package/dist/core/mcp/tools.js +29 -3
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/model-registry-schema.d.ts +1081 -0
- package/dist/core/model-registry-schema.d.ts.map +1 -0
- package/dist/core/model-registry-schema.js +148 -0
- package/dist/core/model-registry-schema.js.map +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +1 -146
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +2 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-preset.d.ts +1 -1
- package/dist/core/prompt-preset.d.ts.map +1 -1
- package/dist/core/prompt-preset.js +16 -1
- package/dist/core/prompt-preset.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/provider-resilience.d.ts +8 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +20 -3
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-usage-types.d.ts +42 -0
- package/dist/core/provider-usage-types.d.ts.map +1 -0
- package/dist/core/provider-usage-types.js +2 -0
- package/dist/core/provider-usage-types.js.map +1 -0
- package/dist/core/provider-usage.d.ts +2 -31
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +4 -0
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/redaction.d.ts.map +1 -1
- package/dist/core/redaction.js +18 -2
- package/dist/core/redaction.js.map +1 -1
- package/dist/core/sandbox/policy-merge.d.ts +6 -0
- package/dist/core/sandbox/policy-merge.d.ts.map +1 -0
- package/dist/core/sandbox/policy-merge.js +74 -0
- package/dist/core/sandbox/policy-merge.js.map +1 -0
- package/dist/core/sandbox/policy-paths.d.ts +4 -0
- package/dist/core/sandbox/policy-paths.d.ts.map +1 -0
- package/dist/core/sandbox/policy-paths.js +21 -0
- package/dist/core/sandbox/policy-paths.js.map +1 -0
- package/dist/core/sandbox/policy-types.d.ts +75 -0
- package/dist/core/sandbox/policy-types.d.ts.map +1 -0
- package/dist/core/sandbox/policy-types.js +2 -0
- package/dist/core/sandbox/policy-types.js.map +1 -0
- package/dist/core/sandbox/policy.d.ts +3 -77
- package/dist/core/sandbox/policy.d.ts.map +1 -1
- package/dist/core/sandbox/policy.js +3 -98
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/sdk-provider-stream.d.ts +14 -0
- package/dist/core/sdk-provider-stream.d.ts.map +1 -0
- package/dist/core/sdk-provider-stream.js +38 -0
- package/dist/core/sdk-provider-stream.js.map +1 -0
- package/dist/core/sdk.d.ts +5 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +17 -33
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-failure-cause.d.ts.map +1 -1
- package/dist/core/session-failure-cause.js +10 -3
- package/dist/core/session-failure-cause.js.map +1 -1
- package/dist/core/session-run-termination.d.ts +18 -0
- package/dist/core/session-run-termination.d.ts.map +1 -0
- package/dist/core/session-run-termination.js +61 -0
- package/dist/core/session-run-termination.js.map +1 -0
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +1 -1
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/skill-selector.d.ts +40 -0
- package/dist/core/skill-selector.d.ts.map +1 -0
- package/dist/core/skill-selector.js +102 -0
- package/dist/core/skill-selector.js.map +1 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +2 -4
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/turn-metrics-record.d.ts +55 -0
- package/dist/core/turn-metrics-record.d.ts.map +1 -0
- package/dist/core/turn-metrics-record.js +149 -0
- package/dist/core/turn-metrics-record.js.map +1 -0
- package/dist/core/turn-metrics.d.ts +4 -56
- package/dist/core/turn-metrics.d.ts.map +1 -1
- package/dist/core/turn-metrics.js +12 -60
- package/dist/core/turn-metrics.js.map +1 -1
- package/dist/guardrails/evidence-system.d.ts +1 -1
- package/dist/guardrails/evidence-system.d.ts.map +1 -1
- package/dist/guardrails/evidence-system.js +18 -29
- package/dist/guardrails/evidence-system.js.map +1 -1
- package/dist/guardrails/merge-gate-result.d.ts +4 -0
- package/dist/guardrails/merge-gate-result.d.ts.map +1 -0
- package/dist/guardrails/merge-gate-result.js +32 -0
- package/dist/guardrails/merge-gate-result.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +22 -22
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/interactive-login-options.d.ts +27 -0
- package/dist/modes/interactive/interactive-login-options.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-login-options.js +54 -0
- package/dist/modes/interactive/interactive-login-options.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +7 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +138 -140
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-resume-command.d.ts +3 -0
- package/dist/modes/interactive/interactive-resume-command.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-resume-command.js +24 -0
- package/dist/modes/interactive/interactive-resume-command.js.map +1 -0
- package/dist/modes/interactive/interactive-tool-result.d.ts +32 -0
- package/dist/modes/interactive/interactive-tool-result.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-tool-result.js +59 -0
- package/dist/modes/interactive/interactive-tool-result.js.map +1 -0
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +22 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +10 -60
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/terminal-links.d.ts +13 -0
- package/dist/utils/terminal-links.d.ts.map +1 -0
- package/dist/utils/terminal-links.js +68 -0
- package/dist/utils/terminal-links.js.map +1 -0
- package/dist/utils/windows-clipboard-image.d.ts +16 -0
- package/dist/utils/windows-clipboard-image.d.ts.map +1 -0
- package/dist/utils/windows-clipboard-image.js +87 -0
- package/dist/utils/windows-clipboard-image.js.map +1 -0
- package/docs/adaptorch-onboarding.md +80 -0
- package/docs/containerization.md +12 -0
- package/docs/context-files.md +97 -0
- package/docs/correctness-wall.md +8 -0
- package/docs/custom-provider.md +35 -0
- package/docs/development.md +18 -3
- package/docs/environment-variables.md +2 -0
- package/docs/grok-harness.md +4 -0
- package/docs/harness-boundaries.md +154 -0
- package/docs/harness-improvements.md +90 -0
- package/docs/json.md +19 -0
- package/docs/keybindings.md +1 -1
- package/docs/mcp.md +22 -2
- package/docs/metrics.md +66 -16
- package/docs/model-catalog-refresh.md +190 -0
- package/docs/model-contract.md +168 -0
- package/docs/models.md +21 -4
- package/docs/provider-resilience.md +5 -3
- package/docs/providers.md +68 -1
- package/docs/quickstart.md +4 -0
- package/docs/release-audit-0.98.4.md +112 -0
- package/docs/review-bundle-followup.md +195 -0
- package/docs/runtime-algorithms.md +19 -0
- package/docs/sdk.md +11 -2
- package/docs/sessions.md +1 -1
- package/docs/settings.md +17 -1
- package/docs/skills.md +2 -0
- package/docs/tb21-audit.md +131 -0
- package/docs/terminal-setup.md +20 -0
- package/docs/usage.md +23 -1
- package/docs/windows.md +48 -0
- package/examples/README.md +4 -0
- package/examples/context/AGENTS.md +64 -0
- package/examples/context/CLAUDE.md +17 -0
- package/examples/context/INTERNET.md +42 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +6 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-resume-command.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-resume-command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AASpE,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAatF","sourcesContent":["import * as fs from \"node:fs\";\nimport { APP_NAME } from \"../../config.ts\";\nimport type { SessionManager } from \"../../core/session-manager.ts\";\n\nfunction quoteIfNeeded(value: string): string {\n\tif (value.length > 0 && !/[^a-zA-Z0-9_\\-./~:@]/.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport function formatResumeCommand(sessionManager: SessionManager): string | undefined {\n\tif (!process.stdout.isTTY) return undefined;\n\tif (!sessionManager.isPersisted()) return undefined;\n\n\tconst sessionFile = sessionManager.getSessionFile();\n\tif (!sessionFile || !fs.existsSync(sessionFile)) return undefined;\n\n\tconst args = [APP_NAME];\n\tif (!sessionManager.usesDefaultSessionDir()) {\n\t\targs.push(\"--session-dir\", quoteIfNeeded(sessionManager.getSessionDir()));\n\t}\n\targs.push(\"--session\", sessionManager.getSessionId());\n\treturn args.join(\" \");\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { APP_NAME } from "../../config.js";
|
|
3
|
+
function quoteIfNeeded(value) {
|
|
4
|
+
if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value)) {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
8
|
+
}
|
|
9
|
+
export function formatResumeCommand(sessionManager) {
|
|
10
|
+
if (!process.stdout.isTTY)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (!sessionManager.isPersisted())
|
|
13
|
+
return undefined;
|
|
14
|
+
const sessionFile = sessionManager.getSessionFile();
|
|
15
|
+
if (!sessionFile || !fs.existsSync(sessionFile))
|
|
16
|
+
return undefined;
|
|
17
|
+
const args = [APP_NAME];
|
|
18
|
+
if (!sessionManager.usesDefaultSessionDir()) {
|
|
19
|
+
args.push("--session-dir", quoteIfNeeded(sessionManager.getSessionDir()));
|
|
20
|
+
}
|
|
21
|
+
args.push("--session", sessionManager.getSessionId());
|
|
22
|
+
return args.join(" ");
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=interactive-resume-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-resume-command.js","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-resume-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,SAAS,aAAa,CAAC,KAAa,EAAU;IAC7C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAAA,CAC3C;AAED,MAAM,UAAU,mBAAmB,CAAC,cAA8B,EAAsB;IACvF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE;QAAE,OAAO,SAAS,CAAC;IAEpD,MAAM,WAAW,GAAG,cAAc,CAAC,cAAc,EAAE,CAAC;IACpD,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IAElE,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,CAAC,cAAc,CAAC,qBAAqB,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CACtB","sourcesContent":["import * as fs from \"node:fs\";\nimport { APP_NAME } from \"../../config.ts\";\nimport type { SessionManager } from \"../../core/session-manager.ts\";\n\nfunction quoteIfNeeded(value: string): string {\n\tif (value.length > 0 && !/[^a-zA-Z0-9_\\-./~:@]/.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport function formatResumeCommand(sessionManager: SessionManager): string | undefined {\n\tif (!process.stdout.isTTY) return undefined;\n\tif (!sessionManager.isPersisted()) return undefined;\n\n\tconst sessionFile = sessionManager.getSessionFile();\n\tif (!sessionFile || !fs.existsSync(sessionFile)) return undefined;\n\n\tconst args = [APP_NAME];\n\tif (!sessionManager.usesDefaultSessionDir()) {\n\t\targs.push(\"--session-dir\", quoteIfNeeded(sessionManager.getSessionDir()));\n\t}\n\targs.push(\"--session\", sessionManager.getSessionId());\n\treturn args.join(\" \");\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Text } from "omk-tui";
|
|
2
|
+
/** Interface for components that can be expanded/collapsed */
|
|
3
|
+
interface Expandable {
|
|
4
|
+
setExpanded(expanded: boolean): void;
|
|
5
|
+
}
|
|
6
|
+
export declare function isExpandable(obj: unknown): obj is Expandable;
|
|
7
|
+
export declare function disposeComponent(component: unknown): void;
|
|
8
|
+
type ToolExecutionContent = {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: "image";
|
|
13
|
+
data: string;
|
|
14
|
+
mimeType: string;
|
|
15
|
+
};
|
|
16
|
+
type ToolExecutionResult = {
|
|
17
|
+
content: ToolExecutionContent[];
|
|
18
|
+
details?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare function normalizeToolExecutionResult(result: unknown, isError: boolean): ToolExecutionResult & {
|
|
21
|
+
isError: boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare class ExpandableText extends Text implements Expandable {
|
|
24
|
+
private readonly getCollapsedText;
|
|
25
|
+
private readonly getExpandedText;
|
|
26
|
+
private expanded;
|
|
27
|
+
constructor(getCollapsedText: () => string, getExpandedText: () => string, expanded?: boolean, paddingX?: number, paddingY?: number);
|
|
28
|
+
setExpanded(expanded: boolean): void;
|
|
29
|
+
invalidate(): void;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=interactive-tool-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-tool-result.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-tool-result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,8DAA8D;AAC9D,UAAU,UAAU;IACnB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CACrC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CASzD;AACD,KAAK,oBAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/G,KAAK,mBAAmB,GAAG;IAC1B,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAgBF,wBAAgB,4BAA4B,CAC3C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,GACd,mBAAmB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAa5C;AAED,qBAAa,cAAe,SAAQ,IAAK,YAAW,UAAU;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,OAAO,CAAC,QAAQ,CAAU;IAE1B,YACC,gBAAgB,EAAE,MAAM,MAAM,EAC9B,eAAe,EAAE,MAAM,MAAM,EAC7B,QAAQ,UAAQ,EAChB,QAAQ,SAAI,EACZ,QAAQ,SAAI,EAMZ;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;CACD","sourcesContent":["import { Text } from \"omk-tui\";\n\n/** Interface for components that can be expanded/collapsed */\ninterface Expandable {\n\tsetExpanded(expanded: boolean): void;\n}\n\nexport function isExpandable(obj: unknown): obj is Expandable {\n\treturn typeof obj === \"object\" && obj !== null && \"setExpanded\" in obj && typeof obj.setExpanded === \"function\";\n}\n\nexport function disposeComponent(component: unknown): void {\n\tif (\n\t\ttypeof component === \"object\" &&\n\t\tcomponent !== null &&\n\t\t\"dispose\" in component &&\n\t\ttypeof component.dispose === \"function\"\n\t) {\n\t\tcomponent.dispose();\n\t}\n}\ntype ToolExecutionContent = { type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string };\n\ntype ToolExecutionResult = {\n\tcontent: ToolExecutionContent[];\n\tdetails?: unknown;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isToolExecutionContent(value: unknown): value is ToolExecutionContent {\n\tif (!isRecord(value)) return false;\n\tif (value.type === \"text\") return typeof value.text === \"string\";\n\treturn value.type === \"image\" && typeof value.data === \"string\" && typeof value.mimeType === \"string\";\n}\n\nfunction isToolExecutionResult(value: unknown): value is ToolExecutionResult {\n\treturn isRecord(value) && Array.isArray(value.content) && value.content.every(isToolExecutionContent);\n}\n\nexport function normalizeToolExecutionResult(\n\tresult: unknown,\n\tisError: boolean,\n): ToolExecutionResult & { isError: boolean } {\n\ttry {\n\t\tif (isToolExecutionResult(result)) {\n\t\t\treturn { content: result.content, details: result.details, isError };\n\t\t}\n\t} catch {\n\t\t// Treat inaccessible or malformed extension payloads as invalid results.\n\t}\n\n\treturn {\n\t\tcontent: [{ type: \"text\", text: \"Tool returned an invalid result.\" }],\n\t\tisError: true,\n\t};\n}\n\nexport class ExpandableText extends Text implements Expandable {\n\tprivate readonly getCollapsedText: () => string;\n\tprivate readonly getExpandedText: () => string;\n\tprivate expanded: boolean;\n\n\tconstructor(\n\t\tgetCollapsedText: () => string,\n\t\tgetExpandedText: () => string,\n\t\texpanded = false,\n\t\tpaddingX = 0,\n\t\tpaddingY = 0,\n\t) {\n\t\tsuper(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);\n\t\tthis.getCollapsedText = getCollapsedText;\n\t\tthis.getExpandedText = getExpandedText;\n\t\tthis.expanded = expanded;\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.setText(expanded ? this.getExpandedText() : this.getCollapsedText());\n\t}\n\n\toverride invalidate(): void {\n\t\tthis.setText(this.expanded ? this.getExpandedText() : this.getCollapsedText());\n\t\tsuper.invalidate();\n\t}\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Text } from "omk-tui";
|
|
2
|
+
export function isExpandable(obj) {
|
|
3
|
+
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
4
|
+
}
|
|
5
|
+
export function disposeComponent(component) {
|
|
6
|
+
if (typeof component === "object" &&
|
|
7
|
+
component !== null &&
|
|
8
|
+
"dispose" in component &&
|
|
9
|
+
typeof component.dispose === "function") {
|
|
10
|
+
component.dispose();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function isToolExecutionContent(value) {
|
|
17
|
+
if (!isRecord(value))
|
|
18
|
+
return false;
|
|
19
|
+
if (value.type === "text")
|
|
20
|
+
return typeof value.text === "string";
|
|
21
|
+
return value.type === "image" && typeof value.data === "string" && typeof value.mimeType === "string";
|
|
22
|
+
}
|
|
23
|
+
function isToolExecutionResult(value) {
|
|
24
|
+
return isRecord(value) && Array.isArray(value.content) && value.content.every(isToolExecutionContent);
|
|
25
|
+
}
|
|
26
|
+
export function normalizeToolExecutionResult(result, isError) {
|
|
27
|
+
try {
|
|
28
|
+
if (isToolExecutionResult(result)) {
|
|
29
|
+
return { content: result.content, details: result.details, isError };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Treat inaccessible or malformed extension payloads as invalid results.
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: "Tool returned an invalid result." }],
|
|
37
|
+
isError: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export class ExpandableText extends Text {
|
|
41
|
+
getCollapsedText;
|
|
42
|
+
getExpandedText;
|
|
43
|
+
expanded;
|
|
44
|
+
constructor(getCollapsedText, getExpandedText, expanded = false, paddingX = 0, paddingY = 0) {
|
|
45
|
+
super(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);
|
|
46
|
+
this.getCollapsedText = getCollapsedText;
|
|
47
|
+
this.getExpandedText = getExpandedText;
|
|
48
|
+
this.expanded = expanded;
|
|
49
|
+
}
|
|
50
|
+
setExpanded(expanded) {
|
|
51
|
+
this.expanded = expanded;
|
|
52
|
+
this.setText(expanded ? this.getExpandedText() : this.getCollapsedText());
|
|
53
|
+
}
|
|
54
|
+
invalidate() {
|
|
55
|
+
this.setText(this.expanded ? this.getExpandedText() : this.getCollapsedText());
|
|
56
|
+
super.invalidate();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=interactive-tool-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-tool-result.js","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-tool-result.ts"],"names":[],"mappings":"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","sourcesContent":["import { Text } from \"omk-tui\";\n\n/** Interface for components that can be expanded/collapsed */\ninterface Expandable {\n\tsetExpanded(expanded: boolean): void;\n}\n\nexport function isExpandable(obj: unknown): obj is Expandable {\n\treturn typeof obj === \"object\" && obj !== null && \"setExpanded\" in obj && typeof obj.setExpanded === \"function\";\n}\n\nexport function disposeComponent(component: unknown): void {\n\tif (\n\t\ttypeof component === \"object\" &&\n\t\tcomponent !== null &&\n\t\t\"dispose\" in component &&\n\t\ttypeof component.dispose === \"function\"\n\t) {\n\t\tcomponent.dispose();\n\t}\n}\ntype ToolExecutionContent = { type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string };\n\ntype ToolExecutionResult = {\n\tcontent: ToolExecutionContent[];\n\tdetails?: unknown;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isToolExecutionContent(value: unknown): value is ToolExecutionContent {\n\tif (!isRecord(value)) return false;\n\tif (value.type === \"text\") return typeof value.text === \"string\";\n\treturn value.type === \"image\" && typeof value.data === \"string\" && typeof value.mimeType === \"string\";\n}\n\nfunction isToolExecutionResult(value: unknown): value is ToolExecutionResult {\n\treturn isRecord(value) && Array.isArray(value.content) && value.content.every(isToolExecutionContent);\n}\n\nexport function normalizeToolExecutionResult(\n\tresult: unknown,\n\tisError: boolean,\n): ToolExecutionResult & { isError: boolean } {\n\ttry {\n\t\tif (isToolExecutionResult(result)) {\n\t\t\treturn { content: result.content, details: result.details, isError };\n\t\t}\n\t} catch {\n\t\t// Treat inaccessible or malformed extension payloads as invalid results.\n\t}\n\n\treturn {\n\t\tcontent: [{ type: \"text\", text: \"Tool returned an invalid result.\" }],\n\t\tisError: true,\n\t};\n}\n\nexport class ExpandableText extends Text implements Expandable {\n\tprivate readonly getCollapsedText: () => string;\n\tprivate readonly getExpandedText: () => string;\n\tprivate expanded: boolean;\n\n\tconstructor(\n\t\tgetCollapsedText: () => string,\n\t\tgetExpandedText: () => string,\n\t\texpanded = false,\n\t\tpaddingX = 0,\n\t\tpaddingY = 0,\n\t) {\n\t\tsuper(expanded ? getExpandedText() : getCollapsedText(), paddingX, paddingY);\n\t\tthis.getCollapsedText = getCollapsedText;\n\t\tthis.getExpandedText = getExpandedText;\n\t\tthis.expanded = expanded;\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.setText(expanded ? this.getExpandedText() : this.getCollapsedText());\n\t}\n\n\toverride invalidate(): void {\n\t\tthis.setText(this.expanded ? this.getExpandedText() : this.getCollapsedText());\n\t\tsuper.invalidate();\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAM5E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0M/G","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `omk -p \"prompt\"` - text output\n * - `omk --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"omk-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.ts\";\nimport type { PromptSettlementOutcome } from \"../core/prompt-settlement.ts\";\nimport { formatSessionTermination, type SessionTermination } from \"../core/session-termination.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet disposed = false;\n\tlet promptStarted = false;\n\tlet latestTermination: SessionTermination | undefined;\n\tlet latestOutcome: PromptSettlementOutcome | undefined;\n\tlet renderedTermination: SessionTermination | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst renderTermination = (termination: SessionTermination): void => {\n\t\tif (termination.kind === \"completed\" || renderedTermination === termination) return;\n\t\trenderedTermination = termination;\n\t\tif (mode === \"json\") {\n\t\t\twriteRawStdout(`${JSON.stringify({ type: \"session_termination\", termination })}\\n`);\n\t\t} else {\n\t\t\tconsole.error(formatSessionTermination(termination));\n\t\t}\n\t};\n\n\tconst renderFailure = (fallback: string): void => {\n\t\tconst termination = latestTermination ?? (!promptStarted ? session.lastTermination : undefined);\n\t\tif (termination && termination.kind !== \"completed\") {\n\t\t\trenderTermination(termination);\n\t\t\treturn;\n\t\t}\n\t\tconsole.error(fallback);\n\t};\n\n\tconst promptFailed = (): boolean => {\n\t\tconst last = session.state.messages.at(-1);\n\t\tconst assistantFailed =\n\t\t\tlast?.role === \"assistant\" && (last.stopReason === \"error\" || last.stopReason === \"aborted\");\n\t\tconst failed =\n\t\t\tlatestOutcome !== undefined\n\t\t\t\t? latestOutcome !== \"completed\"\n\t\t\t\t: assistantFailed || (latestTermination !== undefined && latestTermination.kind !== \"completed\");\n\t\tif (failed)\n\t\t\trenderFailure(\n\t\t\t\tassistantFailed ? last.errorMessage || `Request ${last.stopReason}` : \"Prompt did not complete.\",\n\t\t\t);\n\t\treturn failed;\n\t};\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: Array<\"SIGTERM\" | \"SIGHUP\"> = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tsession.recordProcessSignal(signal);\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tpromptStarted = false;\n\t\tlatestTermination = undefined;\n\t\tlatestOutcome = undefined;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"prompt_settled\") latestOutcome = event.outcome;\n\t\t\tif (event.type === \"session_termination\") {\n\t\t\t\tlatestTermination = event.termination;\n\t\t\t\tif (mode === \"text\") {\n\t\t\t\t\trenderTermination(event.termination);\n\t\t\t\t} else {\n\t\t\t\t\trenderedTermination = event.termination;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\tconst startupTermination = session.lastTermination;\n\t\tif (startupTermination?.kind === \"process_crash\" && startupTermination.source === \"inferred_on_resume\") {\n\t\t\trenderTermination(startupTermination);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tconst hasPrompt =\n\t\t\t!!initialMessage?.trim() ||\n\t\t\tmessages.some((m) => typeof m === \"string\" && m.trim().length > 0) ||\n\t\t\t!!(initialImages && initialImages.length > 0);\n\t\tif (!hasPrompt) {\n\t\t\t// Bare `omk` with no prompt used to exit silently in print mode.\n\t\t\tconsole.error('No prompt provided. Use: omk -p \"...\" or run `omk` in an interactive terminal.');\n\t\t\texitCode = 2;\n\t\t\treturn exitCode;\n\t\t}\n\n\t\tif (initialMessage) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(message);\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\trenderFailure(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\trenderFailure(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
|
package/dist/modes/print-mode.js
CHANGED
|
@@ -20,6 +20,7 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
20
20
|
let disposed = false;
|
|
21
21
|
let promptStarted = false;
|
|
22
22
|
let latestTermination;
|
|
23
|
+
let latestOutcome;
|
|
23
24
|
let renderedTermination;
|
|
24
25
|
const signalCleanupHandlers = [];
|
|
25
26
|
const renderTermination = (termination) => {
|
|
@@ -41,6 +42,16 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
41
42
|
}
|
|
42
43
|
console.error(fallback);
|
|
43
44
|
};
|
|
45
|
+
const promptFailed = () => {
|
|
46
|
+
const last = session.state.messages.at(-1);
|
|
47
|
+
const assistantFailed = last?.role === "assistant" && (last.stopReason === "error" || last.stopReason === "aborted");
|
|
48
|
+
const failed = latestOutcome !== undefined
|
|
49
|
+
? latestOutcome !== "completed"
|
|
50
|
+
: assistantFailed || (latestTermination !== undefined && latestTermination.kind !== "completed");
|
|
51
|
+
if (failed)
|
|
52
|
+
renderFailure(assistantFailed ? last.errorMessage || `Request ${last.stopReason}` : "Prompt did not complete.");
|
|
53
|
+
return failed;
|
|
54
|
+
};
|
|
44
55
|
const disposeRuntime = async () => {
|
|
45
56
|
if (disposed)
|
|
46
57
|
return;
|
|
@@ -73,6 +84,7 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
73
84
|
session = runtimeHost.session;
|
|
74
85
|
promptStarted = false;
|
|
75
86
|
latestTermination = undefined;
|
|
87
|
+
latestOutcome = undefined;
|
|
76
88
|
await session.bindExtensions({
|
|
77
89
|
mode: mode === "json" ? "json" : "print",
|
|
78
90
|
commandContextActions: {
|
|
@@ -104,6 +116,8 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
104
116
|
});
|
|
105
117
|
unsubscribe?.();
|
|
106
118
|
unsubscribe = session.subscribe((event) => {
|
|
119
|
+
if (event.type === "prompt_settled")
|
|
120
|
+
latestOutcome = event.outcome;
|
|
107
121
|
if (event.type === "session_termination") {
|
|
108
122
|
latestTermination = event.termination;
|
|
109
123
|
if (mode === "text") {
|
|
@@ -141,11 +155,19 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
141
155
|
}
|
|
142
156
|
if (initialMessage) {
|
|
143
157
|
promptStarted = true;
|
|
158
|
+
latestTermination = undefined;
|
|
159
|
+
latestOutcome = undefined;
|
|
144
160
|
await session.prompt(initialMessage, { images: initialImages });
|
|
161
|
+
if (promptFailed())
|
|
162
|
+
return 1;
|
|
145
163
|
}
|
|
146
164
|
for (const message of messages) {
|
|
147
165
|
promptStarted = true;
|
|
166
|
+
latestTermination = undefined;
|
|
167
|
+
latestOutcome = undefined;
|
|
148
168
|
await session.prompt(message);
|
|
169
|
+
if (promptFailed())
|
|
170
|
+
return 1;
|
|
149
171
|
}
|
|
150
172
|
if (mode === "text") {
|
|
151
173
|
const state = session.state;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `omk -p \"prompt\"` - text output\n * - `omk --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"omk-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.ts\";\nimport { formatSessionTermination, type SessionTermination } from \"../core/session-termination.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet disposed = false;\n\tlet promptStarted = false;\n\tlet latestTermination: SessionTermination | undefined;\n\tlet renderedTermination: SessionTermination | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst renderTermination = (termination: SessionTermination): void => {\n\t\tif (termination.kind === \"completed\" || renderedTermination === termination) return;\n\t\trenderedTermination = termination;\n\t\tif (mode === \"json\") {\n\t\t\twriteRawStdout(`${JSON.stringify({ type: \"session_termination\", termination })}\\n`);\n\t\t} else {\n\t\t\tconsole.error(formatSessionTermination(termination));\n\t\t}\n\t};\n\n\tconst renderFailure = (fallback: string): void => {\n\t\tconst termination = latestTermination ?? (!promptStarted ? session.lastTermination : undefined);\n\t\tif (termination && termination.kind !== \"completed\") {\n\t\t\trenderTermination(termination);\n\t\t\treturn;\n\t\t}\n\t\tconsole.error(fallback);\n\t};\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: Array<\"SIGTERM\" | \"SIGHUP\"> = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tsession.recordProcessSignal(signal);\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tpromptStarted = false;\n\t\tlatestTermination = undefined;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"session_termination\") {\n\t\t\t\tlatestTermination = event.termination;\n\t\t\t\tif (mode === \"text\") {\n\t\t\t\t\trenderTermination(event.termination);\n\t\t\t\t} else {\n\t\t\t\t\trenderedTermination = event.termination;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\tconst startupTermination = session.lastTermination;\n\t\tif (startupTermination?.kind === \"process_crash\" && startupTermination.source === \"inferred_on_resume\") {\n\t\t\trenderTermination(startupTermination);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tconst hasPrompt =\n\t\t\t!!initialMessage?.trim() ||\n\t\t\tmessages.some((m) => typeof m === \"string\" && m.trim().length > 0) ||\n\t\t\t!!(initialImages && initialImages.length > 0);\n\t\tif (!hasPrompt) {\n\t\t\t// Bare `omk` with no prompt used to exit silently in print mode.\n\t\t\tconsole.error('No prompt provided. Use: omk -p \"...\" or run `omk` in an interactive terminal.');\n\t\t\texitCode = 2;\n\t\t\treturn exitCode;\n\t\t}\n\n\t\tif (initialMessage) {\n\t\t\tpromptStarted = true;\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tpromptStarted = true;\n\t\t\tawait session.prompt(message);\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\trenderFailure(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\trenderFailure(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `omk -p \"prompt\"` - text output\n * - `omk --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"omk-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.ts\";\nimport type { PromptSettlementOutcome } from \"../core/prompt-settlement.ts\";\nimport { formatSessionTermination, type SessionTermination } from \"../core/session-termination.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet disposed = false;\n\tlet promptStarted = false;\n\tlet latestTermination: SessionTermination | undefined;\n\tlet latestOutcome: PromptSettlementOutcome | undefined;\n\tlet renderedTermination: SessionTermination | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst renderTermination = (termination: SessionTermination): void => {\n\t\tif (termination.kind === \"completed\" || renderedTermination === termination) return;\n\t\trenderedTermination = termination;\n\t\tif (mode === \"json\") {\n\t\t\twriteRawStdout(`${JSON.stringify({ type: \"session_termination\", termination })}\\n`);\n\t\t} else {\n\t\t\tconsole.error(formatSessionTermination(termination));\n\t\t}\n\t};\n\n\tconst renderFailure = (fallback: string): void => {\n\t\tconst termination = latestTermination ?? (!promptStarted ? session.lastTermination : undefined);\n\t\tif (termination && termination.kind !== \"completed\") {\n\t\t\trenderTermination(termination);\n\t\t\treturn;\n\t\t}\n\t\tconsole.error(fallback);\n\t};\n\n\tconst promptFailed = (): boolean => {\n\t\tconst last = session.state.messages.at(-1);\n\t\tconst assistantFailed =\n\t\t\tlast?.role === \"assistant\" && (last.stopReason === \"error\" || last.stopReason === \"aborted\");\n\t\tconst failed =\n\t\t\tlatestOutcome !== undefined\n\t\t\t\t? latestOutcome !== \"completed\"\n\t\t\t\t: assistantFailed || (latestTermination !== undefined && latestTermination.kind !== \"completed\");\n\t\tif (failed)\n\t\t\trenderFailure(\n\t\t\t\tassistantFailed ? last.errorMessage || `Request ${last.stopReason}` : \"Prompt did not complete.\",\n\t\t\t);\n\t\treturn failed;\n\t};\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: Array<\"SIGTERM\" | \"SIGHUP\"> = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tsession.recordProcessSignal(signal);\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tpromptStarted = false;\n\t\tlatestTermination = undefined;\n\t\tlatestOutcome = undefined;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"prompt_settled\") latestOutcome = event.outcome;\n\t\t\tif (event.type === \"session_termination\") {\n\t\t\t\tlatestTermination = event.termination;\n\t\t\t\tif (mode === \"text\") {\n\t\t\t\t\trenderTermination(event.termination);\n\t\t\t\t} else {\n\t\t\t\t\trenderedTermination = event.termination;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\tconst startupTermination = session.lastTermination;\n\t\tif (startupTermination?.kind === \"process_crash\" && startupTermination.source === \"inferred_on_resume\") {\n\t\t\trenderTermination(startupTermination);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tconst hasPrompt =\n\t\t\t!!initialMessage?.trim() ||\n\t\t\tmessages.some((m) => typeof m === \"string\" && m.trim().length > 0) ||\n\t\t\t!!(initialImages && initialImages.length > 0);\n\t\tif (!hasPrompt) {\n\t\t\t// Bare `omk` with no prompt used to exit silently in print mode.\n\t\t\tconsole.error('No prompt provided. Use: omk -p \"...\" or run `omk` in an interactive terminal.');\n\t\t\texitCode = 2;\n\t\t\treturn exitCode;\n\t\t}\n\n\t\tif (initialMessage) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(message);\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\trenderFailure(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\trenderFailure(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard-image.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AASF,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE9E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAazE;AA6OD,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA+BjC","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync, unlinkSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nfunction readClipboardImageViaPowerShell(): ClipboardImage | null {\n\tconst tmpFile = join(tmpdir(), `omk-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\t\tif (!winPathResult.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (!result.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.stdout.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaPowerShell());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\treturn image;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"clipboard-image.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAQF,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE9E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAazE;AAoLD,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmCjC","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\nimport { readWindowsClipboardImage, WindowsClipboardError } from \"./windows-clipboard-image.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst windows = wsl ? await readWindowsClipboardImage(env) : undefined;\n\tif (windows?.kind === \"image\") return { bytes: windows.bytes, mimeType: windows.mimeType };\n\tif (windows?.kind === \"empty\") return null;\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tif (!image && windows?.kind === \"unavailable\") {\n\t\tthrow new WindowsClipboardError(\n\t\t\t`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`,\n\t\t);\n\t}\n\treturn image;\n}\n"]}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
import { readFileSync, unlinkSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
6
3
|
import { clipboard } from "./clipboard-native.js";
|
|
7
4
|
import { loadPhoton } from "./photon.js";
|
|
5
|
+
import { readWindowsClipboardImage, WindowsClipboardError } from "./windows-clipboard-image.js";
|
|
8
6
|
const SUPPORTED_IMAGE_MIME_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
9
7
|
const DEFAULT_LIST_TIMEOUT_MS = 1000;
|
|
10
8
|
const DEFAULT_READ_TIMEOUT_MS = 3000;
|
|
11
|
-
const DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;
|
|
12
9
|
const DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
13
10
|
export function isWaylandSession(env = process.env) {
|
|
14
11
|
return Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === "wayland";
|
|
@@ -125,58 +122,6 @@ function isWSL(env = process.env, inspectProcVersion = true) {
|
|
|
125
122
|
return false;
|
|
126
123
|
}
|
|
127
124
|
}
|
|
128
|
-
/**
|
|
129
|
-
* On WSL, the Linux clipboard (Wayland/X11) does not receive image data from
|
|
130
|
-
* Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard
|
|
131
|
-
* directly, so we use it as a fallback.
|
|
132
|
-
*/
|
|
133
|
-
function readClipboardImageViaPowerShell() {
|
|
134
|
-
const tmpFile = join(tmpdir(), `omk-wsl-clip-${randomUUID()}.png`);
|
|
135
|
-
try {
|
|
136
|
-
const winPathResult = runCommand("wslpath", ["-w", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
|
|
137
|
-
if (!winPathResult.ok) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
const winPath = winPathResult.stdout.toString("utf-8").trim();
|
|
141
|
-
if (!winPath) {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
const psQuotedWinPath = winPath.replaceAll("'", "''");
|
|
145
|
-
const psScript = [
|
|
146
|
-
"Add-Type -AssemblyName System.Windows.Forms",
|
|
147
|
-
"Add-Type -AssemblyName System.Drawing",
|
|
148
|
-
`$path = '${psQuotedWinPath}'`,
|
|
149
|
-
"$img = [System.Windows.Forms.Clipboard]::GetImage()",
|
|
150
|
-
"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }",
|
|
151
|
-
].join("; ");
|
|
152
|
-
const result = runCommand("powershell.exe", ["-NoProfile", "-Command", psScript], {
|
|
153
|
-
timeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,
|
|
154
|
-
});
|
|
155
|
-
if (!result.ok) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
const output = result.stdout.toString("utf-8").trim();
|
|
159
|
-
if (output !== "ok") {
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
const bytes = readFileSync(tmpFile);
|
|
163
|
-
if (bytes.length === 0) {
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
return { bytes: new Uint8Array(bytes), mimeType: "image/png" };
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
finally {
|
|
172
|
-
try {
|
|
173
|
-
unlinkSync(tmpFile);
|
|
174
|
-
}
|
|
175
|
-
catch {
|
|
176
|
-
// Ignore cleanup errors.
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
125
|
function readClipboardImageViaXclip() {
|
|
181
126
|
const targets = runCommand("xclip", ["-selection", "clipboard", "-t", "TARGETS", "-o"], {
|
|
182
127
|
timeoutMs: DEFAULT_LIST_TIMEOUT_MS,
|
|
@@ -241,18 +186,23 @@ export async function readClipboardImage(options) {
|
|
|
241
186
|
return toSupportedImage(await readClipboardImageViaNativeClipboard());
|
|
242
187
|
}
|
|
243
188
|
const wsl = isWSL(env, !hasExplicitEnv);
|
|
189
|
+
const windows = wsl ? await readWindowsClipboardImage(env) : undefined;
|
|
190
|
+
if (windows?.kind === "image")
|
|
191
|
+
return { bytes: windows.bytes, mimeType: windows.mimeType };
|
|
192
|
+
if (windows?.kind === "empty")
|
|
193
|
+
return null;
|
|
244
194
|
const wayland = isWaylandSession(env);
|
|
245
195
|
let image = null;
|
|
246
196
|
if (wayland || wsl) {
|
|
247
197
|
image = await toSupportedImage(readClipboardImageViaWlPaste());
|
|
248
198
|
image ??= await toSupportedImage(readClipboardImageViaXclip());
|
|
249
199
|
}
|
|
250
|
-
if (!image && wsl) {
|
|
251
|
-
image = await toSupportedImage(readClipboardImageViaPowerShell());
|
|
252
|
-
}
|
|
253
200
|
if (!image && !wayland) {
|
|
254
201
|
image = await toSupportedImage(await readClipboardImageViaNativeClipboard());
|
|
255
202
|
}
|
|
203
|
+
if (!image && windows?.kind === "unavailable") {
|
|
204
|
+
throw new WindowsClipboardError(`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`);
|
|
205
|
+
}
|
|
256
206
|
return image;
|
|
257
207
|
}
|
|
258
208
|
//# sourceMappingURL=clipboard-image.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync, unlinkSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nfunction readClipboardImageViaPowerShell(): ClipboardImage | null {\n\tconst tmpFile = join(tmpdir(), `omk-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\t\tif (!winPathResult.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (!result.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.stdout.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaPowerShell());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\treturn image;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\nimport { readWindowsClipboardImage, WindowsClipboardError } from \"./windows-clipboard-image.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst windows = wsl ? await readWindowsClipboardImage(env) : undefined;\n\tif (windows?.kind === \"image\") return { bytes: windows.bytes, mimeType: windows.mimeType };\n\tif (windows?.kind === \"empty\") return null;\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tif (!image && windows?.kind === \"unavailable\") {\n\t\tthrow new WindowsClipboardError(\n\t\t\t`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`,\n\t\t);\n\t}\n\treturn image;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface TerminalLinkEnvironment {
|
|
2
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
3
|
+
readonly platform?: NodeJS.Platform;
|
|
4
|
+
}
|
|
5
|
+
/** File URLs are opened by the host terminal, not by a Linux process inside WSL. */
|
|
6
|
+
export declare function terminalFileUrl(path: string, cwd: string, options?: TerminalLinkEnvironment): string;
|
|
7
|
+
/** Bind destinations to the active project so resumed sessions do not use the launch cwd. */
|
|
8
|
+
export declare function terminalMarkdownLinks(cwd: string, options?: TerminalLinkEnvironment): {
|
|
9
|
+
resolveLink(href: string): string | undefined;
|
|
10
|
+
resolveFileLink(text: string): string | undefined;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=terminal-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-links.d.ts","sourceRoot":"","sources":["../../src/utils/terminal-links.ts"],"names":[],"mappings":"AAKA,UAAU,uBAAuB;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CACpC;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,MAAM,CAcxG;AAED,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B;;;EAkCvF","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { win32 } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { normalizePath, resolvePath } from \"./paths.ts\";\n\ninterface TerminalLinkEnvironment {\n\treadonly env?: NodeJS.ProcessEnv;\n\treadonly platform?: NodeJS.Platform;\n}\n\n/** File URLs are opened by the host terminal, not by a Linux process inside WSL. */\nexport function terminalFileUrl(path: string, cwd: string, options: TerminalLinkEnvironment = {}): string {\n\tconst env = options.env ?? process.env;\n\tconst platform = options.platform ?? process.platform;\n\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(path)) return pathToFileURL(path, { windows: true }).href;\n\tconst absolute = platform === \"win32\" ? win32.resolve(cwd, normalizePath(path)) : resolvePath(path, cwd);\n\tconst distro = env.WSL_DISTRO_NAME;\n\tif (platform === \"linux\" && distro && !env.SSH_CONNECTION && !env.SSH_TTY && !/[\\\\/\\x00-\\x1f]/.test(distro)) {\n\t\tconst drive = /^\\/mnt\\/([a-z])(?:\\/|$)/i.exec(absolute);\n\t\tconst windowsPath = drive\n\t\t\t? `${drive[1].toUpperCase()}:\\\\${absolute.slice(drive[0].length).replaceAll(\"/\", \"\\\\\")}`\n\t\t\t: `\\\\\\\\wsl.localhost\\\\${distro}${absolute.replaceAll(\"/\", \"\\\\\")}`;\n\t\treturn pathToFileURL(windowsPath, { windows: true }).href;\n\t}\n\treturn pathToFileURL(absolute, { windows: platform === \"win32\" }).href;\n}\n\n/** Bind destinations to the active project so resumed sessions do not use the launch cwd. */\nexport function terminalMarkdownLinks(cwd: string, options: TerminalLinkEnvironment = {}) {\n\treturn {\n\t\tresolveLink(href: string): string | undefined {\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(href)) return undefined;\n\t\t\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(href)) return terminalFileUrl(href, cwd, options);\n\t\t\tif (href.startsWith(\"#\")) return href;\n\t\t\tif (/^file:/i.test(href)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = new URL(href);\n\t\t\t\t\tif (url.hostname && url.hostname !== \"localhost\") return href;\n\t\t\t\t\tconst windows = /^\\/[a-z]:\\//i.test(url.pathname);\n\t\t\t\t\treturn terminalFileUrl(fileURLToPath(url, { windows }), cwd, options) + url.search + url.hash;\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(href) || href.startsWith(\"//\")) return href;\n\t\t\tconst boundary = href.search(/[?#]/);\n\t\t\tconst pathname = boundary < 0 ? href : href.slice(0, boundary);\n\t\t\tconst suffix = boundary < 0 ? \"\" : href.slice(boundary);\n\t\t\ttry {\n\t\t\t\treturn terminalFileUrl(decodeURIComponent(pathname), cwd, options) + suffix;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof URIError) return terminalFileUrl(pathname, cwd, options) + suffix;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tresolveFileLink(text: string): string | undefined {\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(text) && !/^[a-z]:[\\\\/]/i.test(text)) return undefined;\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(text) || (!/[\\\\/]/.test(text) && !/\\.[a-z\\d]{1,10}$/i.test(text))) return undefined;\n\t\t\tconst path = resolvePath(text, cwd);\n\t\t\treturn existsSync(path) ? terminalFileUrl(text, cwd, options) : undefined;\n\t\t},\n\t};\n}\n"]}
|