@aigne/cli 1.60.0-beta → 1.74.0-beta
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/README.md +12 -12
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/bunwrapper.cjs +22 -0
- package/dist/bunwrapper.d.cts +1 -0
- package/dist/bunwrapper.d.mts +1 -0
- package/dist/bunwrapper.mjs +23 -0
- package/dist/bunwrapper.mjs.map +1 -0
- package/dist/cli.cjs +42 -0
- package/dist/cli.d.cts +9 -0
- package/dist/cli.d.cts.map +1 -0
- package/dist/cli.d.mts +10 -0
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +41 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/commands/aigne.cjs +23 -0
- package/dist/commands/aigne.mjs +22 -0
- package/dist/commands/aigne.mjs.map +1 -0
- package/dist/commands/app/agent.cjs +117 -0
- package/dist/commands/app/agent.mjs +113 -0
- package/dist/commands/app/agent.mjs.map +1 -0
- package/dist/commands/app/app.cjs +92 -0
- package/dist/commands/app/app.mjs +90 -0
- package/dist/commands/app/app.mjs.map +1 -0
- package/dist/commands/app/cli.cjs +6 -0
- package/dist/commands/app/cli.d.cts +1 -0
- package/dist/commands/app/cli.d.mts +1 -0
- package/dist/commands/app/cli.mjs +8 -0
- package/dist/commands/app/cli.mjs.map +1 -0
- package/dist/commands/app/upgrade.cjs +243 -0
- package/dist/commands/app/upgrade.mjs +240 -0
- package/dist/commands/app/upgrade.mjs.map +1 -0
- package/dist/commands/app.cjs +53 -0
- package/dist/commands/app.mjs +53 -0
- package/dist/commands/app.mjs.map +1 -0
- package/dist/commands/create.cjs +66 -0
- package/dist/commands/create.mjs +65 -0
- package/dist/commands/create.mjs.map +1 -0
- package/dist/commands/deploy.cjs +237 -0
- package/dist/commands/deploy.mjs +237 -0
- package/dist/commands/deploy.mjs.map +1 -0
- package/dist/commands/eval.cjs +88 -0
- package/dist/commands/eval.mjs +88 -0
- package/dist/commands/eval.mjs.map +1 -0
- package/dist/commands/hub.cjs +297 -0
- package/dist/commands/hub.mjs +294 -0
- package/dist/commands/hub.mjs.map +1 -0
- package/dist/commands/observe.cjs +49 -0
- package/dist/commands/observe.mjs +46 -0
- package/dist/commands/observe.mjs.map +1 -0
- package/dist/commands/run-skill.cjs +84 -0
- package/dist/commands/run-skill.mjs +81 -0
- package/dist/commands/run-skill.mjs.map +1 -0
- package/dist/commands/run.cjs +172 -0
- package/dist/commands/run.mjs +171 -0
- package/dist/commands/run.mjs.map +1 -0
- package/dist/commands/serve-mcp.cjs +68 -0
- package/dist/commands/serve-mcp.mjs +67 -0
- package/dist/commands/serve-mcp.mjs.map +1 -0
- package/dist/commands/test.cjs +40 -0
- package/dist/commands/test.mjs +39 -0
- package/dist/commands/test.mjs.map +1 -0
- package/dist/constants.cjs +28 -0
- package/dist/constants.d.cts +9 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +9 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +24 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/global.d.cjs +0 -0
- package/dist/global.d.cts +6 -0
- package/dist/global.d.cts.map +1 -0
- package/dist/global.d.mts +6 -0
- package/dist/global.d.mts.map +1 -0
- package/dist/index.cjs +0 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/tracer/terminal.cjs +336 -0
- package/dist/tracer/terminal.mjs +332 -0
- package/dist/tracer/terminal.mjs.map +1 -0
- package/dist/type.cjs +0 -0
- package/dist/type.d.cts +10 -0
- package/dist/type.d.cts.map +1 -0
- package/dist/type.d.mts +10 -0
- package/dist/type.d.mts.map +1 -0
- package/dist/type.mjs +1 -0
- package/dist/ui/utils/terminal-input.cjs +145 -0
- package/dist/ui/utils/terminal-input.mjs +144 -0
- package/dist/ui/utils/terminal-input.mjs.map +1 -0
- package/dist/ui/utils/text-buffer.cjs +865 -0
- package/dist/ui/utils/text-buffer.mjs +865 -0
- package/dist/ui/utils/text-buffer.mjs.map +1 -0
- package/dist/ui/utils/text-utils.cjs +85 -0
- package/dist/ui/utils/text-utils.mjs +78 -0
- package/dist/ui/utils/text-utils.mjs.map +1 -0
- package/dist/utils/agent-v1.cjs +180 -0
- package/dist/utils/agent-v1.d.cts +138 -0
- package/dist/utils/agent-v1.d.cts.map +1 -0
- package/dist/utils/agent-v1.d.mts +138 -0
- package/dist/utils/agent-v1.d.mts.map +1 -0
- package/dist/utils/agent-v1.mjs +179 -0
- package/dist/utils/agent-v1.mjs.map +1 -0
- package/dist/utils/aigne-hub/constants.cjs +22 -0
- package/dist/utils/aigne-hub/constants.mjs +18 -0
- package/dist/utils/aigne-hub/constants.mjs.map +1 -0
- package/dist/utils/aigne-hub/credential.cjs +179 -0
- package/dist/utils/aigne-hub/credential.mjs +175 -0
- package/dist/utils/aigne-hub/credential.mjs.map +1 -0
- package/dist/utils/aigne-hub/crypto.cjs +41 -0
- package/dist/utils/aigne-hub/crypto.mjs +33 -0
- package/dist/utils/aigne-hub/crypto.mjs.map +1 -0
- package/dist/utils/aigne-hub/model.cjs +112 -0
- package/dist/utils/aigne-hub/model.d.cts +19 -0
- package/dist/utils/aigne-hub/model.d.cts.map +1 -0
- package/dist/utils/aigne-hub/model.d.mts +19 -0
- package/dist/utils/aigne-hub/model.d.mts.map +1 -0
- package/dist/utils/aigne-hub/model.mjs +106 -0
- package/dist/utils/aigne-hub/model.mjs.map +1 -0
- package/dist/utils/aigne-hub/store/file.cjs +64 -0
- package/dist/utils/aigne-hub/store/file.mjs +64 -0
- package/dist/utils/aigne-hub/store/file.mjs.map +1 -0
- package/dist/utils/aigne-hub/store/index.cjs +37 -0
- package/dist/utils/aigne-hub/store/index.mjs +37 -0
- package/dist/utils/aigne-hub/store/index.mjs.map +1 -0
- package/dist/utils/aigne-hub/store/keytar.cjs +61 -0
- package/dist/utils/aigne-hub/store/keytar.mjs +61 -0
- package/dist/utils/aigne-hub/store/keytar.mjs.map +1 -0
- package/dist/utils/aigne-hub/store/migrate.cjs +46 -0
- package/dist/utils/aigne-hub/store/migrate.mjs +45 -0
- package/dist/utils/aigne-hub/store/migrate.mjs.map +1 -0
- package/dist/utils/aigne-hub/type.d.cts +18 -0
- package/dist/utils/aigne-hub/type.d.cts.map +1 -0
- package/dist/utils/aigne-hub/type.d.mts +18 -0
- package/dist/utils/aigne-hub/type.d.mts.map +1 -0
- package/dist/utils/aigne-hub-user.cjs +11 -0
- package/dist/utils/aigne-hub-user.d.cts +23 -0
- package/dist/utils/aigne-hub-user.d.cts.map +1 -0
- package/dist/utils/aigne-hub-user.d.mts +23 -0
- package/dist/utils/aigne-hub-user.d.mts.map +1 -0
- package/dist/utils/aigne-hub-user.mjs +11 -0
- package/dist/utils/aigne-hub-user.mjs.map +1 -0
- package/dist/utils/ascii-logo.cjs +30 -0
- package/dist/utils/ascii-logo.d.cts +5 -0
- package/dist/utils/ascii-logo.d.cts.map +1 -0
- package/dist/utils/ascii-logo.d.mts +5 -0
- package/dist/utils/ascii-logo.d.mts.map +1 -0
- package/dist/utils/{ascii-logo.js → ascii-logo.mjs} +13 -3
- package/dist/utils/ascii-logo.mjs.map +1 -0
- package/dist/utils/download.cjs +25 -0
- package/dist/utils/download.d.cts +7 -0
- package/dist/utils/download.d.cts.map +1 -0
- package/dist/utils/download.d.mts +7 -0
- package/dist/utils/download.d.mts.map +1 -0
- package/dist/utils/download.mjs +25 -0
- package/dist/utils/download.mjs.map +1 -0
- package/dist/utils/evaluation/core.cjs +84 -0
- package/dist/utils/evaluation/core.mjs +84 -0
- package/dist/utils/evaluation/core.mjs.map +1 -0
- package/dist/utils/evaluation/dataset.cjs +47 -0
- package/dist/utils/evaluation/dataset.mjs +46 -0
- package/dist/utils/evaluation/dataset.mjs.map +1 -0
- package/dist/utils/evaluation/evaluator.cjs +109 -0
- package/dist/utils/evaluation/{evaluator.js → evaluator.mjs} +48 -45
- package/dist/utils/evaluation/evaluator.mjs.map +1 -0
- package/dist/utils/evaluation/reporter.cjs +225 -0
- package/dist/utils/evaluation/reporter.mjs +220 -0
- package/dist/utils/evaluation/reporter.mjs.map +1 -0
- package/dist/utils/evaluation/runner.cjs +85 -0
- package/dist/utils/evaluation/runner.mjs +85 -0
- package/dist/utils/evaluation/runner.mjs.map +1 -0
- package/dist/utils/get-url-origin.cjs +12 -0
- package/dist/utils/get-url-origin.d.cts +5 -0
- package/dist/utils/get-url-origin.d.cts.map +1 -0
- package/dist/utils/get-url-origin.d.mts +5 -0
- package/dist/utils/get-url-origin.d.mts.map +1 -0
- package/dist/utils/get-url-origin.mjs +12 -0
- package/dist/utils/get-url-origin.mjs.map +1 -0
- package/dist/utils/inquirer/checkbox.cjs +265 -0
- package/dist/utils/inquirer/checkbox.mjs +262 -0
- package/dist/utils/inquirer/checkbox.mjs.map +1 -0
- package/dist/utils/listr.cjs +226 -0
- package/dist/utils/listr.d.cts +71 -0
- package/dist/utils/listr.d.cts.map +1 -0
- package/dist/utils/listr.d.mts +71 -0
- package/dist/utils/listr.d.mts.map +1 -0
- package/dist/utils/listr.mjs +222 -0
- package/dist/utils/listr.mjs.map +1 -0
- package/dist/utils/load-aigne.cjs +77 -0
- package/dist/utils/load-aigne.d.cts +29 -0
- package/dist/utils/load-aigne.d.cts.map +1 -0
- package/dist/utils/load-aigne.d.mts +29 -0
- package/dist/utils/load-aigne.d.mts.map +1 -0
- package/dist/utils/load-aigne.mjs +74 -0
- package/dist/utils/load-aigne.mjs.map +1 -0
- package/dist/utils/run-chat-loop.cjs +90 -0
- package/dist/utils/run-chat-loop.d.cts +20 -0
- package/dist/utils/run-chat-loop.d.cts.map +1 -0
- package/dist/utils/run-chat-loop.d.mts +20 -0
- package/dist/utils/run-chat-loop.d.mts.map +1 -0
- package/dist/utils/run-chat-loop.mjs +89 -0
- package/dist/utils/run-chat-loop.mjs.map +1 -0
- package/dist/utils/run-with-aigne.cjs +131 -0
- package/dist/utils/run-with-aigne.d.cts +46 -0
- package/dist/utils/run-with-aigne.d.cts.map +1 -0
- package/dist/utils/run-with-aigne.d.mts +46 -0
- package/dist/utils/run-with-aigne.d.mts.map +1 -0
- package/dist/utils/run-with-aigne.mjs +126 -0
- package/dist/utils/run-with-aigne.mjs.map +1 -0
- package/dist/utils/serve-mcp.cjs +91 -0
- package/dist/utils/serve-mcp.d.cts +20 -0
- package/dist/utils/serve-mcp.d.cts.map +1 -0
- package/dist/utils/serve-mcp.d.mts +20 -0
- package/dist/utils/serve-mcp.d.mts.map +1 -0
- package/dist/utils/serve-mcp.mjs +89 -0
- package/dist/utils/serve-mcp.mjs.map +1 -0
- package/dist/utils/spinner.cjs +19 -0
- package/dist/utils/spinner.d.cts +5 -0
- package/dist/utils/spinner.d.cts.map +1 -0
- package/dist/utils/spinner.d.mts +5 -0
- package/dist/utils/spinner.d.mts.map +1 -0
- package/dist/utils/spinner.mjs +19 -0
- package/dist/utils/spinner.mjs.map +1 -0
- package/dist/utils/string-utils.cjs +11 -0
- package/dist/utils/string-utils.d.cts +5 -0
- package/dist/utils/string-utils.d.cts.map +1 -0
- package/dist/utils/string-utils.d.mts +5 -0
- package/dist/utils/string-utils.d.mts.map +1 -0
- package/dist/utils/string-utils.mjs +10 -0
- package/dist/utils/string-utils.mjs.map +1 -0
- package/dist/utils/time.cjs +14 -0
- package/dist/utils/time.d.cts +5 -0
- package/dist/utils/time.d.cts.map +1 -0
- package/dist/utils/time.d.mts +5 -0
- package/dist/utils/time.d.mts.map +1 -0
- package/dist/utils/time.mjs +14 -0
- package/dist/utils/time.mjs.map +1 -0
- package/dist/utils/url.cjs +8 -0
- package/dist/utils/url.d.cts +5 -0
- package/dist/utils/url.d.cts.map +1 -0
- package/dist/utils/url.d.mts +5 -0
- package/dist/utils/url.d.mts.map +1 -0
- package/dist/utils/url.mjs +8 -0
- package/dist/utils/url.mjs.map +1 -0
- package/dist/utils/yargs.cjs +191 -0
- package/dist/utils/yargs.d.cts +96 -0
- package/dist/utils/yargs.d.cts.map +1 -0
- package/dist/utils/yargs.d.mts +96 -0
- package/dist/utils/yargs.d.mts.map +1 -0
- package/dist/utils/yargs.mjs +186 -0
- package/dist/utils/yargs.mjs.map +1 -0
- package/package.json +122 -45
- package/CHANGELOG.md +0 -5019
- package/dist/bunwrapper.d.ts +0 -2
- package/dist/bunwrapper.js +0 -18
- package/dist/cli.d.ts +0 -7
- package/dist/cli.js +0 -42
- package/dist/commands/aigne.d.ts +0 -4
- package/dist/commands/aigne.js +0 -35
- package/dist/commands/app/agent.d.ts +0 -26
- package/dist/commands/app/agent.js +0 -122
- package/dist/commands/app/app.d.ts +0 -7
- package/dist/commands/app/app.js +0 -92
- package/dist/commands/app/cli.d.ts +0 -1
- package/dist/commands/app/cli.js +0 -2
- package/dist/commands/app/upgrade.d.ts +0 -54
- package/dist/commands/app/upgrade.js +0 -236
- package/dist/commands/app.d.ts +0 -4
- package/dist/commands/app.js +0 -54
- package/dist/commands/create.d.ts +0 -6
- package/dist/commands/create.js +0 -74
- package/dist/commands/deploy.d.ts +0 -11
- package/dist/commands/deploy.js +0 -255
- package/dist/commands/eval.d.ts +0 -11
- package/dist/commands/eval.js +0 -110
- package/dist/commands/hub.d.ts +0 -3
- package/dist/commands/hub.js +0 -323
- package/dist/commands/observe.d.ts +0 -7
- package/dist/commands/observe.js +0 -41
- package/dist/commands/run-skill.d.ts +0 -6
- package/dist/commands/run-skill.js +0 -102
- package/dist/commands/run.d.ts +0 -9
- package/dist/commands/run.js +0 -187
- package/dist/commands/serve-mcp.d.ts +0 -20
- package/dist/commands/serve-mcp.js +0 -67
- package/dist/commands/test.d.ts +0 -9
- package/dist/commands/test.js +0 -33
- package/dist/constants.d.ts +0 -7
- package/dist/constants.js +0 -21
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/tracer/terminal.d.ts +0 -62
- package/dist/tracer/terminal.js +0 -404
- package/dist/type.d.ts +0 -5
- package/dist/type.js +0 -1
- package/dist/ui/utils/terminal-input.d.ts +0 -19
- package/dist/ui/utils/terminal-input.js +0 -123
- package/dist/ui/utils/text-buffer.d.ts +0 -87
- package/dist/ui/utils/text-buffer.js +0 -1059
- package/dist/ui/utils/text-utils.d.ts +0 -37
- package/dist/ui/utils/text-utils.js +0 -185
- package/dist/utils/agent-v1.d.ts +0 -134
- package/dist/utils/agent-v1.js +0 -213
- package/dist/utils/aigne-hub/constants.d.ts +0 -6
- package/dist/utils/aigne-hub/constants.js +0 -12
- package/dist/utils/aigne-hub/credential.d.ts +0 -20
- package/dist/utils/aigne-hub/credential.js +0 -182
- package/dist/utils/aigne-hub/crypto.d.ts +0 -4
- package/dist/utils/aigne-hub/crypto.js +0 -30
- package/dist/utils/aigne-hub/model.d.ts +0 -13
- package/dist/utils/aigne-hub/model.js +0 -122
- package/dist/utils/aigne-hub/store/file.d.ts +0 -15
- package/dist/utils/aigne-hub/store/file.js +0 -69
- package/dist/utils/aigne-hub/store/index.d.ts +0 -5
- package/dist/utils/aigne-hub/store/index.js +0 -43
- package/dist/utils/aigne-hub/store/keytar.d.ts +0 -15
- package/dist/utils/aigne-hub/store/keytar.js +0 -67
- package/dist/utils/aigne-hub/store/migrate.d.ts +0 -2
- package/dist/utils/aigne-hub/store/migrate.js +0 -57
- package/dist/utils/aigne-hub/type.d.ts +0 -38
- package/dist/utils/aigne-hub/type.js +0 -1
- package/dist/utils/aigne-hub-user.d.ts +0 -16
- package/dist/utils/aigne-hub-user.js +0 -10
- package/dist/utils/ascii-logo.d.ts +0 -1
- package/dist/utils/download.d.ts +0 -3
- package/dist/utils/download.js +0 -19
- package/dist/utils/evaluation/core.d.ts +0 -8
- package/dist/utils/evaluation/core.js +0 -83
- package/dist/utils/evaluation/dataset.d.ts +0 -15
- package/dist/utils/evaluation/dataset.js +0 -61
- package/dist/utils/evaluation/evaluator.d.ts +0 -9
- package/dist/utils/evaluation/reporter.d.ts +0 -28
- package/dist/utils/evaluation/reporter.js +0 -221
- package/dist/utils/evaluation/runner.d.ts +0 -16
- package/dist/utils/evaluation/runner.js +0 -129
- package/dist/utils/evaluation/type.d.ts +0 -69
- package/dist/utils/evaluation/type.js +0 -1
- package/dist/utils/get-url-origin.d.ts +0 -1
- package/dist/utils/get-url-origin.js +0 -8
- package/dist/utils/inquirer/checkbox.d.ts +0 -55
- package/dist/utils/inquirer/checkbox.js +0 -319
- package/dist/utils/listr.d.ts +0 -64
- package/dist/utils/listr.js +0 -265
- package/dist/utils/load-aigne.d.ts +0 -18
- package/dist/utils/load-aigne.js +0 -80
- package/dist/utils/run-chat-loop.d.ts +0 -15
- package/dist/utils/run-chat-loop.js +0 -87
- package/dist/utils/run-with-aigne.d.ts +0 -27
- package/dist/utils/run-with-aigne.js +0 -157
- package/dist/utils/serve-mcp.d.ts +0 -9
- package/dist/utils/serve-mcp.js +0 -93
- package/dist/utils/spinner.d.ts +0 -1
- package/dist/utils/spinner.js +0 -14
- package/dist/utils/string-utils.d.ts +0 -1
- package/dist/utils/string-utils.js +0 -4
- package/dist/utils/time.d.ts +0 -1
- package/dist/utils/time.js +0 -12
- package/dist/utils/url.d.ts +0 -1
- package/dist/utils/url.js +0 -3
- package/dist/utils/yargs.d.ts +0 -94
- package/dist/utils/yargs.js +0 -210
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-buffer.mjs","names":["startColInLogical","currentLine","lines","visualLayout"],"sources":["../../../src/ui/utils/text-buffer.ts"],"sourcesContent":["// biome-ignore-all lint/style/noNonNullAssertion: code is from gemini-cli\n// biome-ignore-all lint/correctness/useExhaustiveDependencies: code is from gemini-cli\n\n/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { useCallback, useEffect, useMemo, useReducer, useState } from \"react\";\nimport {\n cpLen,\n cpSlice,\n getCachedStringWidth,\n stripUnsafeCharacters,\n toCodePoints,\n} from \"./text-utils.js\";\n\nexport type Direction =\n | \"left\"\n | \"right\"\n | \"up\"\n | \"down\"\n | \"wordLeft\"\n | \"wordRight\"\n | \"home\"\n | \"end\";\n\n// Simple helper for word‑wise ops.\nfunction isWordChar(ch: string | undefined): boolean {\n if (ch === undefined) {\n return false;\n }\n return !/[\\s,.;!?]/.test(ch);\n}\n\n// Helper functions for line-based word navigation\nconst isWordCharStrict = (char: string): boolean => /[\\w\\p{L}\\p{N}]/u.test(char);\n\nconst isWhitespace = (char: string): boolean => /\\s/.test(char);\n\nconst isCombiningMark = (char: string): boolean => /\\p{M}/u.test(char);\n\nconst isWordCharWithCombining = (char: string): boolean =>\n isWordCharStrict(char) || isCombiningMark(char);\n\nconst getCharScript = (char: string): string => {\n if (/[\\p{Script=Latin}]/u.test(char)) return \"latin\";\n if (/[\\p{Script=Han}]/u.test(char)) return \"han\";\n if (/[\\p{Script=Arabic}]/u.test(char)) return \"arabic\";\n if (/[\\p{Script=Hiragana}]/u.test(char)) return \"hiragana\";\n if (/[\\p{Script=Katakana}]/u.test(char)) return \"katakana\";\n if (/[\\p{Script=Cyrillic}]/u.test(char)) return \"cyrillic\";\n return \"other\";\n};\n\nconst isDifferentScript = (char1: string, char2: string): boolean => {\n if (!isWordCharStrict(char1) || !isWordCharStrict(char2)) return false;\n return getCharScript(char1) !== getCharScript(char2);\n};\n\nconst findNextWordStartInLine = (line: string, col: number): number | null => {\n const chars = toCodePoints(line);\n let i = col;\n\n if (i >= chars.length) return null;\n\n const currentChar = chars[i]!;\n\n // Skip current word/sequence based on character type\n if (isWordCharStrict(currentChar)) {\n while (i < chars.length && isWordCharWithCombining(chars[i]!)) {\n // Check for script boundary - if next character is from different script, stop here\n if (\n i + 1 < chars.length &&\n isWordCharStrict(chars[i + 1]!) &&\n isDifferentScript(chars[i]!, chars[i + 1]!)\n ) {\n i++; // Include current character\n break; // Stop at script boundary\n }\n i++;\n }\n } else if (!isWhitespace(currentChar)) {\n while (i < chars.length && !isWordCharStrict(chars[i]!) && !isWhitespace(chars[i]!)) {\n i++;\n }\n }\n\n // Skip whitespace\n while (i < chars.length && isWhitespace(chars[i]!)) {\n i++;\n }\n\n return i < chars.length ? i : null;\n};\n\n// Find previous word start within a line\nconst findPrevWordStartInLine = (line: string, col: number): number | null => {\n const chars = toCodePoints(line);\n let i = col;\n\n if (i <= 0) return null;\n\n i--;\n\n // Skip whitespace moving backwards\n while (i >= 0 && isWhitespace(chars[i]!)) {\n i--;\n }\n\n if (i < 0) return null;\n\n if (isWordCharStrict(chars[i]!)) {\n // We're in a word, move to its beginning\n while (i >= 0 && isWordCharStrict(chars[i]!)) {\n // Check for script boundary - if previous character is from different script, stop here\n if (\n i - 1 >= 0 &&\n isWordCharStrict(chars[i - 1]!) &&\n isDifferentScript(chars[i]!, chars[i - 1]!)\n ) {\n return i; // Return current position at script boundary\n }\n i--;\n }\n return i + 1;\n } else {\n // We're in punctuation, move to its beginning\n while (i >= 0 && !isWordCharStrict(chars[i]!) && !isWhitespace(chars[i]!)) {\n i--;\n }\n return i + 1;\n }\n};\n\n// Find word end within a line\n\n// Find next word across lines\n\n// Find previous word across lines\n\n// Helper functions for vim line operations\n\nconst replaceRangeInternal = (\n state: TextBufferState,\n startRow: number,\n startCol: number,\n endRow: number,\n endCol: number,\n text: string,\n): TextBufferState => {\n const currentLine = (row: number) => state.lines[row] || \"\";\n const currentLineLen = (row: number) => cpLen(currentLine(row));\n const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);\n\n if (\n startRow > endRow ||\n (startRow === endRow && startCol > endCol) ||\n startRow < 0 ||\n startCol < 0 ||\n endRow >= state.lines.length ||\n (endRow < state.lines.length && endCol > currentLineLen(endRow))\n ) {\n return state; // Invalid range\n }\n\n const newLines = [...state.lines];\n\n const sCol = clamp(startCol, 0, currentLineLen(startRow));\n const eCol = clamp(endCol, 0, currentLineLen(endRow));\n\n const prefix = cpSlice(currentLine(startRow), 0, sCol);\n const suffix = cpSlice(currentLine(endRow), eCol);\n\n const normalisedReplacement = text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const replacementParts = normalisedReplacement.split(\"\\n\");\n\n // The combined first line of the new text\n const firstLine = prefix + replacementParts[0];\n\n if (replacementParts.length === 1) {\n // No newlines in replacement: combine prefix, replacement, and suffix on one line.\n newLines.splice(startRow, endRow - startRow + 1, firstLine + suffix);\n } else {\n // Newlines in replacement: create new lines.\n const lastLine = replacementParts[replacementParts.length - 1]! + suffix;\n const middleLines = replacementParts.slice(1, -1);\n newLines.splice(startRow, endRow - startRow + 1, firstLine, ...middleLines, lastLine);\n }\n\n const finalCursorRow = startRow + replacementParts.length - 1;\n const finalCursorCol =\n (replacementParts.length > 1 ? 0 : sCol) +\n cpLen(replacementParts[replacementParts.length - 1]!);\n\n return {\n ...state,\n lines: newLines,\n cursorRow: Math.min(Math.max(finalCursorRow, 0), newLines.length - 1),\n cursorCol: Math.max(0, Math.min(finalCursorCol, cpLen(newLines[finalCursorRow]! || \"\"))),\n preferredCol: null,\n };\n};\n\ninterface Viewport {\n height: number;\n width: number;\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return v < min ? min : v > max ? max : v;\n}\n\n/* ────────────────────────────────────────────────────────────────────────── */\n\ninterface UseTextBufferProps {\n initialText?: string;\n initialCursorOffset?: number;\n viewport: Viewport;\n onChange?: (text: string) => void;\n isValidPath: (path: string) => boolean;\n shellModeActive?: boolean;\n}\n\ninterface UndoHistoryEntry {\n lines: string[];\n cursorRow: number;\n cursorCol: number;\n}\n\nfunction calculateInitialCursorPosition(initialLines: string[], offset: number): [number, number] {\n let remainingChars = offset;\n let row = 0;\n while (row < initialLines.length) {\n const lineLength = cpLen(initialLines[row]!);\n // Add 1 for the newline character (except for the last line)\n const totalCharsInLineAndNewline = lineLength + (row < initialLines.length - 1 ? 1 : 0);\n\n if (remainingChars <= lineLength) {\n // Cursor is on this line\n return [row, remainingChars];\n }\n remainingChars -= totalCharsInLineAndNewline;\n row++;\n }\n // Offset is beyond the text, place cursor at the end of the last line\n if (initialLines.length > 0) {\n const lastRow = initialLines.length - 1;\n return [lastRow, cpLen(initialLines[lastRow]!)];\n }\n return [0, 0]; // Default for empty text\n}\n\nfunction offsetToLogicalPos(text: string, offset: number): [number, number] {\n let row = 0;\n let col = 0;\n let currentOffset = 0;\n\n if (offset === 0) return [0, 0];\n\n const lines = text.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineLength = cpLen(line!);\n const lineLengthWithNewline = lineLength + (i < lines.length - 1 ? 1 : 0);\n\n if (offset <= currentOffset + lineLength) {\n // Check against lineLength first\n row = i;\n col = offset - currentOffset;\n return [row, col];\n } else if (offset <= currentOffset + lineLengthWithNewline) {\n // Check if offset is the newline itself\n row = i;\n col = lineLength; // Position cursor at the end of the current line content\n // If the offset IS the newline, and it's not the last line, advance to next line, col 0\n if (offset === currentOffset + lineLengthWithNewline && i < lines.length - 1) {\n return [i + 1, 0];\n }\n return [row, col]; // Otherwise, it's at the end of the current line content\n }\n currentOffset += lineLengthWithNewline;\n }\n\n // If offset is beyond the text length, place cursor at the end of the last line\n // or [0,0] if text is empty\n if (lines.length > 0) {\n row = lines.length - 1;\n col = cpLen(lines[row]!);\n } else {\n row = 0;\n col = 0;\n }\n return [row, col];\n}\n\n/**\n * Converts logical row/col position to absolute text offset\n * Inverse operation of offsetToLogicalPos\n */\n\ninterface VisualLayout {\n visualLines: string[];\n logicalToVisualMap: Array<Array<[number, number]>>;\n visualToLogicalMap: Array<[number, number]>;\n}\n\n// Calculates the visual wrapping of lines and the mapping between logical and visual coordinates.\n// This is an expensive operation and should be memoized.\nfunction calculateLayout(logicalLines: string[], viewportWidth: number): VisualLayout {\n const visualLines: string[] = [];\n const logicalToVisualMap: Array<Array<[number, number]>> = [];\n const visualToLogicalMap: Array<[number, number]> = [];\n\n logicalLines.forEach((logLine, logIndex) => {\n logicalToVisualMap[logIndex] = [];\n if (logLine.length === 0) {\n // Handle empty logical line\n logicalToVisualMap[logIndex].push([visualLines.length, 0]);\n visualToLogicalMap.push([logIndex, 0]);\n visualLines.push(\"\");\n } else {\n // Non-empty logical line\n let currentPosInLogLine = 0; // Tracks position within the current logical line (code point index)\n const codePointsInLogLine = toCodePoints(logLine);\n\n while (currentPosInLogLine < codePointsInLogLine.length) {\n let currentChunk = \"\";\n let currentChunkVisualWidth = 0;\n let numCodePointsInChunk = 0;\n let lastWordBreakPoint = -1; // Index in codePointsInLogLine for word break\n let numCodePointsAtLastWordBreak = 0;\n\n // Iterate through code points to build the current visual line (chunk)\n for (let i = currentPosInLogLine; i < codePointsInLogLine.length; i++) {\n const char = codePointsInLogLine[i];\n const charVisualWidth = getCachedStringWidth(char!);\n\n if (currentChunkVisualWidth + charVisualWidth > viewportWidth) {\n // Character would exceed viewport width\n if (\n lastWordBreakPoint !== -1 &&\n numCodePointsAtLastWordBreak > 0 &&\n currentPosInLogLine + numCodePointsAtLastWordBreak < i\n ) {\n // We have a valid word break point to use, and it's not the start of the current segment\n currentChunk = codePointsInLogLine\n .slice(currentPosInLogLine, currentPosInLogLine + numCodePointsAtLastWordBreak)\n .join(\"\");\n numCodePointsInChunk = numCodePointsAtLastWordBreak;\n } else {\n // No word break, or word break is at the start of this potential chunk, or word break leads to empty chunk.\n // Hard break: take characters up to viewportWidth, or just the current char if it alone is too wide.\n if (numCodePointsInChunk === 0 && charVisualWidth > viewportWidth) {\n // Single character is wider than viewport, take it anyway\n currentChunk = char!;\n numCodePointsInChunk = 1;\n } else if (numCodePointsInChunk === 0 && charVisualWidth <= viewportWidth) {\n // This case should ideally be caught by the next iteration if the char fits.\n // If it doesn't fit (because currentChunkVisualWidth was already > 0 from a previous char that filled the line),\n // then numCodePointsInChunk would not be 0.\n // This branch means the current char *itself* doesn't fit an empty line, which is handled by the above.\n // If we are here, it means the loop should break and the current chunk (which is empty) is finalized.\n }\n }\n break; // Break from inner loop to finalize this chunk\n }\n\n currentChunk += char;\n currentChunkVisualWidth += charVisualWidth;\n numCodePointsInChunk++;\n\n // Check for word break opportunity (space)\n if (char === \" \") {\n lastWordBreakPoint = i; // Store code point index of the space\n // Store the state *before* adding the space, if we decide to break here.\n numCodePointsAtLastWordBreak = numCodePointsInChunk - 1; // Chars *before* the space\n }\n }\n\n // If the inner loop completed without breaking (i.e., remaining text fits)\n // or if the loop broke but numCodePointsInChunk is still 0 (e.g. first char too wide for empty line)\n if (numCodePointsInChunk === 0 && currentPosInLogLine < codePointsInLogLine.length) {\n // This can happen if the very first character considered for a new visual line is wider than the viewport.\n // In this case, we take that single character.\n const firstChar = codePointsInLogLine[currentPosInLogLine]!;\n currentChunk = firstChar;\n numCodePointsInChunk = 1; // Ensure we advance\n }\n\n // If after everything, numCodePointsInChunk is still 0 but we haven't processed the whole logical line,\n // it implies an issue, like viewportWidth being 0 or less. Avoid infinite loop.\n if (numCodePointsInChunk === 0 && currentPosInLogLine < codePointsInLogLine.length) {\n // Force advance by one character to prevent infinite loop if something went wrong\n currentChunk = codePointsInLogLine[currentPosInLogLine]!;\n numCodePointsInChunk = 1;\n }\n\n logicalToVisualMap[logIndex].push([visualLines.length, currentPosInLogLine]);\n visualToLogicalMap.push([logIndex, currentPosInLogLine]);\n visualLines.push(currentChunk);\n\n const logicalStartOfThisChunk = currentPosInLogLine;\n currentPosInLogLine += numCodePointsInChunk;\n\n // If the chunk processed did not consume the entire logical line,\n // and the character immediately following the chunk is a space,\n // advance past this space as it acted as a delimiter for word wrapping.\n if (\n logicalStartOfThisChunk + numCodePointsInChunk < codePointsInLogLine.length &&\n currentPosInLogLine < codePointsInLogLine.length && // Redundant if previous is true, but safe\n codePointsInLogLine[currentPosInLogLine]! === \" \"\n ) {\n currentPosInLogLine++;\n }\n }\n }\n });\n\n // If the entire logical text was empty, ensure there's one empty visual line.\n if (logicalLines.length === 0 || (logicalLines.length === 1 && logicalLines[0] === \"\")) {\n if (visualLines.length === 0) {\n visualLines.push(\"\");\n if (!logicalToVisualMap[0]) logicalToVisualMap[0] = [];\n logicalToVisualMap[0].push([0, 0]);\n visualToLogicalMap.push([0, 0]);\n }\n }\n\n return {\n visualLines,\n logicalToVisualMap,\n visualToLogicalMap,\n };\n}\n\n// Calculates the visual cursor position based on a pre-calculated layout.\n// This is a lightweight operation.\nfunction calculateVisualCursorFromLayout(\n layout: VisualLayout,\n logicalCursor: [number, number],\n): [number, number] {\n const { logicalToVisualMap, visualLines } = layout;\n const [logicalRow, logicalCol] = logicalCursor;\n\n const segmentsForLogicalLine = logicalToVisualMap[logicalRow]!;\n\n if (!segmentsForLogicalLine || segmentsForLogicalLine.length === 0) {\n // This can happen for an empty document.\n return [0, 0];\n }\n\n // Find the segment where the logical column fits.\n // The segments are sorted by startColInLogical.\n let targetSegmentIndex = segmentsForLogicalLine.findIndex(([, startColInLogical], index) => {\n const nextStartColInLogical =\n index + 1 < segmentsForLogicalLine.length ? segmentsForLogicalLine[index + 1]![1] : Infinity;\n return logicalCol >= startColInLogical && logicalCol < nextStartColInLogical;\n });\n\n // If not found, it means the cursor is at the end of the logical line.\n if (targetSegmentIndex === -1) {\n if (logicalCol === 0) {\n targetSegmentIndex = 0;\n } else {\n targetSegmentIndex = segmentsForLogicalLine.length - 1;\n }\n }\n\n const [visualRow, startColInLogical] = segmentsForLogicalLine[targetSegmentIndex]!;\n const visualCol = logicalCol - startColInLogical;\n\n // The visual column should not exceed the length of the visual line.\n const clampedVisualCol = Math.min(visualCol, cpLen(visualLines[visualRow]! ?? \"\"));\n\n return [visualRow, clampedVisualCol];\n}\n\n// --- Start of reducer logic ---\n\ninterface TextBufferState {\n lines: string[];\n cursorRow: number;\n cursorCol: number;\n preferredCol: number | null; // This is visual preferred col\n undoStack: UndoHistoryEntry[];\n redoStack: UndoHistoryEntry[];\n clipboard: string | null;\n selectionAnchor: [number, number] | null;\n viewportWidth: number;\n viewportHeight: number;\n visualLayout: VisualLayout;\n}\n\nconst historyLimit = 100;\n\nconst pushUndo = (currentState: TextBufferState): TextBufferState => {\n const snapshot = {\n lines: [...currentState.lines],\n cursorRow: currentState.cursorRow,\n cursorCol: currentState.cursorCol,\n };\n const newStack = [...currentState.undoStack, snapshot];\n if (newStack.length > historyLimit) {\n newStack.shift();\n }\n return { ...currentState, undoStack: newStack, redoStack: [] };\n};\n\ntype TextBufferAction =\n | { type: \"set_text\"; payload: string; pushToUndo?: boolean }\n | { type: \"insert\"; payload: string }\n | { type: \"backspace\" }\n | {\n type: \"move\";\n payload: {\n dir: Direction;\n };\n }\n | {\n type: \"set_cursor\";\n payload: {\n cursorRow: number;\n cursorCol: number;\n preferredCol: number | null;\n };\n }\n | { type: \"delete\" }\n | { type: \"delete_word_left\" }\n | { type: \"delete_word_right\" }\n | { type: \"kill_line_right\" }\n | { type: \"kill_line_left\" }\n | { type: \"undo\" }\n | { type: \"redo\" }\n | {\n type: \"replace_range\";\n payload: {\n startRow: number;\n startCol: number;\n endRow: number;\n endCol: number;\n text: string;\n };\n }\n | { type: \"move_to_offset\"; payload: { offset: number } }\n | { type: \"create_undo_snapshot\" }\n | { type: \"set_viewport\"; payload: { width: number; height: number } };\n\nfunction textBufferReducerLogic(state: TextBufferState, action: TextBufferAction): TextBufferState {\n const pushUndoLocal = pushUndo;\n\n const currentLine = (r: number): string => state.lines[r]! ?? \"\";\n const currentLineLen = (r: number): number => cpLen(currentLine(r));\n\n switch (action.type) {\n case \"set_text\": {\n let nextState = state;\n if (action.pushToUndo !== false) {\n nextState = pushUndoLocal(state);\n }\n const newContentLines = action.payload.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n const lines = newContentLines.length === 0 ? [\"\"] : newContentLines;\n const lastNewLineIndex = lines.length - 1;\n return {\n ...nextState,\n lines,\n cursorRow: lastNewLineIndex,\n cursorCol: cpLen(lines[lastNewLineIndex] ?? \"\"),\n preferredCol: null,\n };\n }\n\n case \"insert\": {\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n let newCursorRow = nextState.cursorRow;\n let newCursorCol = nextState.cursorCol;\n\n const currentLine = (r: number) => newLines[r]! ?? \"\";\n\n const str = stripUnsafeCharacters(action.payload.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\"));\n const parts = str.split(\"\\n\");\n const lineContent = currentLine(newCursorRow);\n const before = cpSlice(lineContent, 0, newCursorCol);\n const after = cpSlice(lineContent, newCursorCol);\n\n if (parts.length > 1) {\n newLines[newCursorRow]! = before + parts[0];\n const remainingParts = parts.slice(1);\n const lastPartOriginal = remainingParts.pop() ?? \"\";\n newLines.splice(newCursorRow + 1, 0, ...remainingParts);\n newLines.splice(newCursorRow + parts.length - 1, 0, lastPartOriginal + after);\n newCursorRow = newCursorRow + parts.length - 1;\n newCursorCol = cpLen(lastPartOriginal);\n } else {\n newLines[newCursorRow]! = before + parts[0] + after;\n newCursorCol = cpLen(before) + cpLen(parts[0]!);\n }\n\n return {\n ...nextState,\n lines: newLines,\n cursorRow: newCursorRow,\n cursorCol: newCursorCol,\n preferredCol: null,\n };\n }\n\n case \"backspace\": {\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n let newCursorRow = nextState.cursorRow;\n let newCursorCol = nextState.cursorCol;\n\n const currentLine = (r: number) => newLines[r]! ?? \"\";\n\n if (newCursorCol === 0 && newCursorRow === 0) return state;\n\n if (newCursorCol > 0) {\n const lineContent = currentLine(newCursorRow);\n newLines[newCursorRow]! =\n cpSlice(lineContent, 0, newCursorCol - 1) + cpSlice(lineContent, newCursorCol);\n newCursorCol--;\n } else if (newCursorRow > 0) {\n const prevLineContent = currentLine(newCursorRow - 1);\n const currentLineContentVal = currentLine(newCursorRow);\n const newCol = cpLen(prevLineContent);\n newLines[newCursorRow - 1] = prevLineContent + currentLineContentVal;\n newLines.splice(newCursorRow, 1);\n newCursorRow--;\n newCursorCol = newCol;\n }\n\n return {\n ...nextState,\n lines: newLines,\n cursorRow: newCursorRow,\n cursorCol: newCursorCol,\n preferredCol: null,\n };\n }\n\n case \"set_viewport\": {\n const { width, height } = action.payload;\n if (width === state.viewportWidth && height === state.viewportHeight) {\n return state;\n }\n return {\n ...state,\n viewportWidth: width,\n viewportHeight: height,\n };\n }\n\n case \"move\": {\n const { dir } = action.payload;\n const { cursorRow, cursorCol, lines, visualLayout, preferredCol } = state;\n\n // Visual movements\n if (\n dir === \"left\" ||\n dir === \"right\" ||\n dir === \"up\" ||\n dir === \"down\" ||\n dir === \"home\" ||\n dir === \"end\"\n ) {\n const visualCursor = calculateVisualCursorFromLayout(visualLayout, [cursorRow, cursorCol]);\n const { visualLines, visualToLogicalMap } = visualLayout;\n\n let newVisualRow = visualCursor[0];\n let newVisualCol = visualCursor[1];\n let newPreferredCol = preferredCol;\n\n const currentVisLineLen = cpLen(visualLines[newVisualRow]! ?? \"\");\n\n switch (dir) {\n case \"left\":\n newPreferredCol = null;\n if (newVisualCol > 0) {\n newVisualCol--;\n } else if (newVisualRow > 0) {\n newVisualRow--;\n newVisualCol = cpLen(visualLines[newVisualRow]! ?? \"\");\n }\n break;\n case \"right\":\n newPreferredCol = null;\n if (newVisualCol < currentVisLineLen) {\n newVisualCol++;\n } else if (newVisualRow < visualLines.length - 1) {\n newVisualRow++;\n newVisualCol = 0;\n }\n break;\n case \"up\":\n if (newVisualRow > 0) {\n if (newPreferredCol === null) newPreferredCol = newVisualCol;\n newVisualRow--;\n newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow]! ?? \"\"));\n }\n break;\n case \"down\":\n if (newVisualRow < visualLines.length - 1) {\n if (newPreferredCol === null) newPreferredCol = newVisualCol;\n newVisualRow++;\n newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow]! ?? \"\"));\n }\n break;\n case \"home\":\n newPreferredCol = null;\n newVisualCol = 0;\n break;\n case \"end\":\n newPreferredCol = null;\n newVisualCol = currentVisLineLen;\n break;\n default: {\n const exhaustiveCheck: never = dir;\n console.error(`Unknown visual movement direction: ${exhaustiveCheck}`);\n return state;\n }\n }\n\n if (visualToLogicalMap[newVisualRow]) {\n const [logRow, logStartCol] = visualToLogicalMap[newVisualRow]!;\n return {\n ...state,\n cursorRow: logRow,\n cursorCol: clamp(logStartCol + newVisualCol, 0, cpLen(lines[logRow] ?? \"\")),\n preferredCol: newPreferredCol,\n };\n }\n return state;\n }\n\n // Logical movements\n switch (dir) {\n case \"wordLeft\": {\n if (cursorCol === 0 && cursorRow === 0) return state;\n\n let newCursorRow = cursorRow;\n let newCursorCol = cursorCol;\n\n if (cursorCol === 0) {\n newCursorRow--;\n newCursorCol = cpLen(lines[newCursorRow] ?? \"\");\n } else {\n const lineContent = lines[cursorRow]!;\n const arr = toCodePoints(lineContent);\n let start = cursorCol;\n let onlySpaces = true;\n for (let i = 0; i < start; i++) {\n if (isWordChar(arr[i]!)) {\n onlySpaces = false;\n break;\n }\n }\n if (onlySpaces && start > 0) {\n start--;\n } else {\n while (start > 0 && !isWordChar(arr[start - 1])) start--;\n while (start > 0 && isWordChar(arr[start - 1])) start--;\n }\n newCursorCol = start;\n }\n return {\n ...state,\n cursorRow: newCursorRow,\n cursorCol: newCursorCol,\n preferredCol: null,\n };\n }\n case \"wordRight\": {\n if (cursorRow === lines.length - 1 && cursorCol === cpLen(lines[cursorRow]! ?? \"\")) {\n return state;\n }\n\n let newCursorRow = cursorRow;\n let newCursorCol = cursorCol;\n const lineContent = lines[cursorRow]! ?? \"\";\n const arr = toCodePoints(lineContent);\n\n if (cursorCol >= arr.length) {\n newCursorRow++;\n newCursorCol = 0;\n } else {\n let end = cursorCol;\n while (end < arr.length && !isWordChar(arr[end])) end++;\n while (end < arr.length && isWordChar(arr[end])) end++;\n newCursorCol = end;\n }\n return {\n ...state,\n cursorRow: newCursorRow,\n cursorCol: newCursorCol,\n preferredCol: null,\n };\n }\n default:\n return state;\n }\n }\n\n case \"set_cursor\": {\n return {\n ...state,\n ...action.payload,\n };\n }\n\n case \"delete\": {\n const { cursorRow, cursorCol, lines } = state;\n const lineContent = currentLine(cursorRow);\n if (cursorCol < currentLineLen(cursorRow)) {\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n newLines[cursorRow]! =\n cpSlice(lineContent, 0, cursorCol) + cpSlice(lineContent, cursorCol + 1);\n return {\n ...nextState,\n lines: newLines,\n preferredCol: null,\n };\n } else if (cursorRow < lines.length - 1) {\n const nextState = pushUndoLocal(state);\n const nextLineContent = currentLine(cursorRow + 1);\n const newLines = [...nextState.lines];\n newLines[cursorRow]! = lineContent + nextLineContent;\n newLines.splice(cursorRow + 1, 1);\n return {\n ...nextState,\n lines: newLines,\n preferredCol: null,\n };\n }\n return state;\n }\n\n case \"delete_word_left\": {\n const { cursorRow, cursorCol } = state;\n if (cursorCol === 0 && cursorRow === 0) return state;\n\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n let newCursorRow = cursorRow;\n let newCursorCol = cursorCol;\n\n if (newCursorCol > 0) {\n const lineContent = currentLine(newCursorRow);\n const prevWordStart = findPrevWordStartInLine(lineContent, newCursorCol);\n const start = prevWordStart === null ? 0 : prevWordStart;\n newLines[newCursorRow]! =\n cpSlice(lineContent, 0, start) + cpSlice(lineContent, newCursorCol);\n newCursorCol = start;\n } else {\n // Act as a backspace\n const prevLineContent = currentLine(cursorRow - 1);\n const currentLineContentVal = currentLine(cursorRow);\n const newCol = cpLen(prevLineContent);\n newLines[cursorRow - 1] = prevLineContent + currentLineContentVal;\n newLines.splice(cursorRow, 1);\n newCursorRow--;\n newCursorCol = newCol;\n }\n\n return {\n ...nextState,\n lines: newLines,\n cursorRow: newCursorRow,\n cursorCol: newCursorCol,\n preferredCol: null,\n };\n }\n\n case \"delete_word_right\": {\n const { cursorRow, cursorCol, lines } = state;\n const lineContent = currentLine(cursorRow);\n const lineLen = cpLen(lineContent);\n\n if (cursorCol >= lineLen && cursorRow === lines.length - 1) {\n return state;\n }\n\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n\n if (cursorCol >= lineLen) {\n // Act as a delete, joining with the next line\n const nextLineContent = currentLine(cursorRow + 1);\n newLines[cursorRow]! = lineContent + nextLineContent;\n newLines.splice(cursorRow + 1, 1);\n } else {\n const nextWordStart = findNextWordStartInLine(lineContent, cursorCol);\n const end = nextWordStart === null ? lineLen : nextWordStart;\n newLines[cursorRow]! = cpSlice(lineContent, 0, cursorCol) + cpSlice(lineContent, end);\n }\n\n return {\n ...nextState,\n lines: newLines,\n preferredCol: null,\n };\n }\n\n case \"kill_line_right\": {\n const { cursorRow, cursorCol, lines } = state;\n const lineContent = currentLine(cursorRow);\n if (cursorCol < currentLineLen(cursorRow)) {\n const nextState = pushUndoLocal(state);\n const newLines = [...nextState.lines];\n newLines[cursorRow]! = cpSlice(lineContent, 0, cursorCol);\n return {\n ...nextState,\n lines: newLines,\n };\n } else if (cursorRow < lines.length - 1) {\n // Act as a delete\n const nextState = pushUndoLocal(state);\n const nextLineContent = currentLine(cursorRow + 1);\n const newLines = [...nextState.lines];\n newLines[cursorRow]! = lineContent + nextLineContent;\n newLines.splice(cursorRow + 1, 1);\n return {\n ...nextState,\n lines: newLines,\n preferredCol: null,\n };\n }\n return state;\n }\n\n case \"kill_line_left\": {\n const { cursorRow, cursorCol } = state;\n if (cursorCol > 0) {\n const nextState = pushUndoLocal(state);\n const lineContent = currentLine(cursorRow);\n const newLines = [...nextState.lines];\n newLines[cursorRow]! = cpSlice(lineContent, cursorCol);\n return {\n ...nextState,\n lines: newLines,\n cursorCol: 0,\n preferredCol: null,\n };\n }\n return state;\n }\n\n case \"undo\": {\n const stateToRestore = state.undoStack[state.undoStack.length - 1];\n if (!stateToRestore) return state;\n\n const currentSnapshot = {\n lines: [...state.lines],\n cursorRow: state.cursorRow,\n cursorCol: state.cursorCol,\n };\n return {\n ...state,\n ...stateToRestore,\n undoStack: state.undoStack.slice(0, -1),\n redoStack: [...state.redoStack, currentSnapshot],\n };\n }\n\n case \"redo\": {\n const stateToRestore = state.redoStack[state.redoStack.length - 1];\n if (!stateToRestore) return state;\n\n const currentSnapshot = {\n lines: [...state.lines],\n cursorRow: state.cursorRow,\n cursorCol: state.cursorCol,\n };\n return {\n ...state,\n ...stateToRestore,\n redoStack: state.redoStack.slice(0, -1),\n undoStack: [...state.undoStack, currentSnapshot],\n };\n }\n\n case \"replace_range\": {\n const { startRow, startCol, endRow, endCol, text } = action.payload;\n const nextState = pushUndoLocal(state);\n return replaceRangeInternal(nextState, startRow, startCol, endRow, endCol, text);\n }\n\n case \"move_to_offset\": {\n const { offset } = action.payload;\n const [newRow, newCol] = offsetToLogicalPos(state.lines.join(\"\\n\"), offset);\n return {\n ...state,\n cursorRow: newRow,\n cursorCol: newCol,\n preferredCol: null,\n };\n }\n\n case \"create_undo_snapshot\": {\n return pushUndoLocal(state);\n }\n\n default: {\n const exhaustiveCheck: never = action;\n console.error(`Unknown action encountered: ${exhaustiveCheck}`);\n return state;\n }\n }\n}\n\nfunction textBufferReducer(state: TextBufferState, action: TextBufferAction): TextBufferState {\n const newState = textBufferReducerLogic(state, action);\n\n if (newState.lines !== state.lines || newState.viewportWidth !== state.viewportWidth) {\n return {\n ...newState,\n visualLayout: calculateLayout(newState.lines, newState.viewportWidth),\n };\n }\n\n return newState;\n}\n\n// --- End of reducer logic ---\n\nexport function useTextBuffer({\n initialText = \"\",\n initialCursorOffset = 0,\n viewport,\n onChange,\n isValidPath,\n shellModeActive = false,\n}: UseTextBufferProps): TextBuffer {\n const initialState = useMemo((): TextBufferState => {\n const lines = initialText.split(\"\\n\");\n const [initialCursorRow, initialCursorCol] = calculateInitialCursorPosition(\n lines.length === 0 ? [\"\"] : lines,\n initialCursorOffset,\n );\n const visualLayout = calculateLayout(lines.length === 0 ? [\"\"] : lines, viewport.width);\n return {\n lines: lines.length === 0 ? [\"\"] : lines,\n cursorRow: initialCursorRow,\n cursorCol: initialCursorCol,\n preferredCol: null,\n undoStack: [],\n redoStack: [],\n clipboard: null,\n selectionAnchor: null,\n viewportWidth: viewport.width,\n viewportHeight: viewport.height,\n visualLayout,\n };\n }, [initialText, initialCursorOffset, viewport.width, viewport.height]);\n\n const [state, dispatch] = useReducer(textBufferReducer, initialState);\n const { lines, cursorRow, cursorCol, preferredCol, selectionAnchor, visualLayout } = state;\n\n const text = useMemo(() => lines.join(\"\\n\"), [lines]);\n\n const visualCursor = useMemo(\n () => calculateVisualCursorFromLayout(visualLayout, [cursorRow, cursorCol]),\n [visualLayout, cursorRow, cursorCol],\n );\n\n const { visualLines, visualToLogicalMap } = visualLayout;\n\n const [visualScrollRow, setVisualScrollRow] = useState<number>(0);\n\n useEffect(() => {\n if (onChange) {\n onChange(text);\n }\n }, [text, onChange]);\n\n useEffect(() => {\n dispatch({\n type: \"set_viewport\",\n payload: { width: viewport.width, height: viewport.height },\n });\n }, [viewport.width, viewport.height]);\n\n // Update visual scroll (vertical)\n useEffect(() => {\n const { height } = viewport;\n const totalVisualLines = visualLines.length;\n const maxScrollStart = Math.max(0, totalVisualLines - height);\n let newVisualScrollRow = visualScrollRow;\n\n if (visualCursor[0] < visualScrollRow) {\n newVisualScrollRow = visualCursor[0];\n } else if (visualCursor[0] >= visualScrollRow + height) {\n newVisualScrollRow = visualCursor[0] - height + 1;\n }\n\n // When the number of visual lines shrinks (e.g., after widening the viewport),\n // ensure scroll never starts beyond the last valid start so we can render a full window.\n newVisualScrollRow = clamp(newVisualScrollRow, 0, maxScrollStart);\n\n if (newVisualScrollRow !== visualScrollRow) {\n setVisualScrollRow(newVisualScrollRow);\n }\n }, [visualCursor, visualScrollRow, viewport, visualLines.length]);\n\n const insert = useCallback(\n (ch: string, { paste = false }: { paste?: boolean } = {}): void => {\n if (/[\\n\\r]/.test(ch)) {\n dispatch({ type: \"insert\", payload: ch });\n return;\n }\n\n const minLengthToInferAsDragDrop = 3;\n if (ch.length >= minLengthToInferAsDragDrop && !shellModeActive && paste) {\n let potentialPath = ch.trim();\n const quoteMatch = potentialPath.match(/^'(.*)'$/);\n if (quoteMatch) {\n potentialPath = quoteMatch[1]!;\n }\n\n potentialPath = potentialPath.trim();\n if (isValidPath(potentialPath)) {\n ch = `@${potentialPath} `;\n }\n }\n\n let currentText = \"\";\n for (const char of toCodePoints(ch)) {\n if (char.codePointAt(0) === 127) {\n if (currentText.length > 0) {\n dispatch({ type: \"insert\", payload: currentText });\n currentText = \"\";\n }\n dispatch({ type: \"backspace\" });\n } else {\n currentText += char;\n }\n }\n if (currentText.length > 0) {\n dispatch({ type: \"insert\", payload: currentText });\n }\n },\n [isValidPath, shellModeActive],\n );\n\n const newline = useCallback((): void => {\n dispatch({ type: \"insert\", payload: \"\\n\" });\n }, []);\n\n const backspace = useCallback((): void => {\n dispatch({ type: \"backspace\" });\n }, []);\n\n const del = useCallback((): void => {\n dispatch({ type: \"delete\" });\n }, []);\n\n const move = useCallback(\n (dir: Direction): void => {\n dispatch({ type: \"move\", payload: { dir } });\n },\n [dispatch],\n );\n\n const undo = useCallback((): void => {\n dispatch({ type: \"undo\" });\n }, []);\n\n const redo = useCallback((): void => {\n dispatch({ type: \"redo\" });\n }, []);\n\n const setText = useCallback((newText: string): void => {\n dispatch({ type: \"set_text\", payload: newText });\n }, []);\n\n const deleteWordLeft = useCallback((): void => {\n dispatch({ type: \"delete_word_left\" });\n }, []);\n\n const deleteWordRight = useCallback((): void => {\n dispatch({ type: \"delete_word_right\" });\n }, []);\n\n const killLineRight = useCallback((): void => {\n dispatch({ type: \"kill_line_right\" });\n }, []);\n\n const killLineLeft = useCallback((): void => {\n dispatch({ type: \"kill_line_left\" });\n }, []);\n\n const handleInput = useCallback(\n (key: {\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n paste: boolean;\n sequence: string;\n }): void => {\n const { sequence: input } = key;\n\n if (key.paste) {\n // Do not do any other processing on pastes so ensure we handle them\n // before all other cases.\n insert(input, { paste: key.paste });\n return;\n }\n\n if (\n key.name === \"return\" ||\n input === \"\\r\" ||\n input === \"\\n\" ||\n input === \"\\\\\\r\" // VSCode terminal represents shift + enter this way\n )\n newline();\n else if (key.name === \"left\" && !key.meta && !key.ctrl) move(\"left\");\n else if (key.ctrl && key.name === \"b\") move(\"left\");\n else if (key.name === \"right\" && !key.meta && !key.ctrl) move(\"right\");\n else if (key.ctrl && key.name === \"f\") move(\"right\");\n else if (key.name === \"up\") move(\"up\");\n else if (key.name === \"down\") move(\"down\");\n else if ((key.ctrl || key.meta) && key.name === \"left\") move(\"wordLeft\");\n else if (key.meta && key.name === \"b\") move(\"wordLeft\");\n else if ((key.ctrl || key.meta) && key.name === \"right\") move(\"wordRight\");\n else if (key.meta && key.name === \"f\") move(\"wordRight\");\n else if (key.name === \"home\") move(\"home\");\n else if (key.ctrl && key.name === \"a\") move(\"home\");\n else if (key.name === \"end\") move(\"end\");\n else if (key.ctrl && key.name === \"e\") move(\"end\");\n else if (key.ctrl && key.name === \"w\") deleteWordLeft();\n else if ((key.meta || key.ctrl) && (key.name === \"backspace\" || input === \"\\x7f\"))\n deleteWordLeft();\n else if ((key.meta || key.ctrl) && key.name === \"delete\") deleteWordRight();\n else if (key.name === \"backspace\" || input === \"\\x7f\" || (key.ctrl && key.name === \"h\"))\n backspace();\n else if (key.name === \"delete\" || (key.ctrl && key.name === \"d\")) del();\n else if (key.ctrl && !key.shift && key.name === \"z\") undo();\n else if (key.ctrl && key.shift && key.name === \"z\") redo();\n else if (input && !key.ctrl && !key.meta) {\n insert(input, { paste: key.paste });\n }\n },\n [newline, move, deleteWordLeft, deleteWordRight, backspace, del, insert, undo, redo],\n );\n\n const renderedVisualLines = useMemo(\n () => visualLines.slice(visualScrollRow, visualScrollRow + viewport.height),\n [visualLines, visualScrollRow, viewport.height],\n );\n\n const returnValue: TextBuffer = useMemo(\n () => ({\n lines,\n text,\n cursor: [cursorRow, cursorCol],\n preferredCol,\n selectionAnchor,\n\n allVisualLines: visualLines,\n viewportVisualLines: renderedVisualLines,\n visualCursor,\n visualScrollRow,\n visualToLogicalMap,\n\n setText,\n insert,\n newline,\n backspace,\n del,\n move,\n undo,\n redo,\n deleteWordLeft,\n deleteWordRight,\n\n killLineRight,\n killLineLeft,\n handleInput,\n }),\n [\n lines,\n text,\n cursorRow,\n cursorCol,\n preferredCol,\n selectionAnchor,\n visualLines,\n renderedVisualLines,\n visualCursor,\n visualScrollRow,\n setText,\n insert,\n newline,\n backspace,\n del,\n move,\n undo,\n redo,\n deleteWordLeft,\n deleteWordRight,\n killLineRight,\n killLineLeft,\n handleInput,\n visualToLogicalMap,\n ],\n );\n return returnValue;\n}\n\nexport interface TextBuffer {\n // State\n lines: string[]; // Logical lines\n text: string;\n cursor: [number, number]; // Logical cursor [row, col]\n /**\n * When the user moves the caret vertically we try to keep their original\n * horizontal column even when passing through shorter lines. We remember\n * that *preferred* column in this field while the user is still travelling\n * vertically. Any explicit horizontal movement resets the preference.\n */\n preferredCol: number | null; // Preferred visual column\n selectionAnchor: [number, number] | null; // Logical selection anchor\n\n // Visual state (handles wrapping)\n allVisualLines: string[]; // All visual lines for the current text and viewport width.\n viewportVisualLines: string[]; // The subset of visual lines to be rendered based on visualScrollRow and viewport.height\n visualCursor: [number, number]; // Visual cursor [row, col] relative to the start of all visualLines\n visualScrollRow: number; // Scroll position for visual lines (index of the first visible visual line)\n /**\n * For each visual line (by absolute index in allVisualLines) provides a tuple\n * [logicalLineIndex, startColInLogical] that maps where that visual line\n * begins within the logical buffer. Indices are code-point based.\n */\n visualToLogicalMap: Array<[number, number]>;\n\n // Actions\n\n /**\n * Replaces the entire buffer content with the provided text.\n * The operation is undoable.\n */\n setText: (text: string) => void;\n /**\n * Insert a single character or string without newlines.\n */\n insert: (ch: string, opts?: { paste?: boolean }) => void;\n newline: () => void;\n backspace: () => void;\n del: () => void;\n move: (dir: Direction) => void;\n undo: () => void;\n redo: () => void;\n /**\n * Delete the word to the *left* of the caret, mirroring common\n * Ctrl/Alt+Backspace behaviour in editors & terminals. Both the adjacent\n * whitespace *and* the word characters immediately preceding the caret are\n * removed. If the caret is already at column‑0 this becomes a no-op.\n */\n deleteWordLeft: () => void;\n /**\n * Delete the word to the *right* of the caret, akin to many editors'\n * Ctrl/Alt+Delete shortcut. Removes any whitespace/punctuation that\n * follows the caret and the next contiguous run of word characters.\n */\n deleteWordRight: () => void;\n\n /**\n * Deletes text from the cursor to the end of the current line.\n */\n killLineRight: () => void;\n /**\n * Deletes text from the start of the current line to the cursor.\n */\n killLineLeft: () => void;\n /**\n * High level \"handleInput\" – receives what Ink gives us.\n */\n handleInput: (key: {\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n paste: boolean;\n sequence: string;\n }) => void;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let node_util = require("node:util");
|
|
3
|
+
let ansi_regex = require("ansi-regex");
|
|
4
|
+
ansi_regex = require_rolldown_runtime.__toESM(ansi_regex);
|
|
5
|
+
let string_width = require("string-width");
|
|
6
|
+
string_width = require_rolldown_runtime.__toESM(string_width);
|
|
7
|
+
let strip_ansi = require("strip-ansi");
|
|
8
|
+
strip_ansi = require_rolldown_runtime.__toESM(strip_ansi);
|
|
9
|
+
|
|
10
|
+
//#region src/ui/utils/text-utils.ts
|
|
11
|
+
/**
|
|
12
|
+
* @license
|
|
13
|
+
* Copyright 2025 Google LLC
|
|
14
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
15
|
+
*/
|
|
16
|
+
const codePointsCache = /* @__PURE__ */ new Map();
|
|
17
|
+
const MAX_STRING_LENGTH_TO_CACHE = 1e3;
|
|
18
|
+
function toCodePoints(str) {
|
|
19
|
+
let isAscii = true;
|
|
20
|
+
for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) > 127) {
|
|
21
|
+
isAscii = false;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
if (isAscii) return str.split("");
|
|
25
|
+
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {
|
|
26
|
+
const cached = codePointsCache.get(str);
|
|
27
|
+
if (cached) return cached;
|
|
28
|
+
}
|
|
29
|
+
const result = Array.from(str);
|
|
30
|
+
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) codePointsCache.set(str, result);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
function cpLen(str) {
|
|
34
|
+
return toCodePoints(str).length;
|
|
35
|
+
}
|
|
36
|
+
function cpSlice(str, start, end) {
|
|
37
|
+
return toCodePoints(str).slice(start, end).join("");
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Strip characters that can break terminal rendering.
|
|
41
|
+
*
|
|
42
|
+
* Uses Node.js built-in stripVTControlCharacters to handle VT sequences,
|
|
43
|
+
* then filters remaining control characters that can disrupt display.
|
|
44
|
+
*
|
|
45
|
+
* Characters stripped:
|
|
46
|
+
* - ANSI escape sequences (via strip-ansi)
|
|
47
|
+
* - VT control sequences (via Node.js util.stripVTControlCharacters)
|
|
48
|
+
* - C0 control chars (0x00-0x1F) except CR/LF which are handled elsewhere
|
|
49
|
+
* - C1 control chars (0x80-0x9F) that can cause display issues
|
|
50
|
+
*
|
|
51
|
+
* Characters preserved:
|
|
52
|
+
* - All printable Unicode including emojis
|
|
53
|
+
* - DEL (0x7F) - handled functionally by applyOperations, not a display issue
|
|
54
|
+
* - CR/LF (0x0D/0x0A) - needed for line breaks
|
|
55
|
+
*/
|
|
56
|
+
function stripUnsafeCharacters(str) {
|
|
57
|
+
return toCodePoints((0, node_util.stripVTControlCharacters)((0, strip_ansi.default)(str))).filter((char) => {
|
|
58
|
+
const code = char.codePointAt(0);
|
|
59
|
+
if (code === void 0) return false;
|
|
60
|
+
if (code === 10 || code === 13) return true;
|
|
61
|
+
if (code >= 0 && code <= 31) return false;
|
|
62
|
+
if (code >= 128 && code <= 159) return false;
|
|
63
|
+
return true;
|
|
64
|
+
}).join("");
|
|
65
|
+
}
|
|
66
|
+
const stringWidthCache = /* @__PURE__ */ new Map();
|
|
67
|
+
/**
|
|
68
|
+
* Cached version of stringWidth function for better performance
|
|
69
|
+
* Follows Ink's approach with unlimited cache (no eviction)
|
|
70
|
+
*/
|
|
71
|
+
const getCachedStringWidth = (str) => {
|
|
72
|
+
if (/^[\x20-\x7E]*$/.test(str)) return str.length;
|
|
73
|
+
if (stringWidthCache.has(str)) return stringWidthCache.get(str);
|
|
74
|
+
const width = (0, string_width.default)(str);
|
|
75
|
+
stringWidthCache.set(str, width);
|
|
76
|
+
return width;
|
|
77
|
+
};
|
|
78
|
+
const regex = (0, ansi_regex.default)();
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
exports.cpLen = cpLen;
|
|
82
|
+
exports.cpSlice = cpSlice;
|
|
83
|
+
exports.getCachedStringWidth = getCachedStringWidth;
|
|
84
|
+
exports.stripUnsafeCharacters = stripUnsafeCharacters;
|
|
85
|
+
exports.toCodePoints = toCodePoints;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
import ansiRegex from "ansi-regex";
|
|
3
|
+
import stringWidth from "string-width";
|
|
4
|
+
import stripAnsi from "strip-ansi";
|
|
5
|
+
|
|
6
|
+
//#region src/ui/utils/text-utils.ts
|
|
7
|
+
/**
|
|
8
|
+
* @license
|
|
9
|
+
* Copyright 2025 Google LLC
|
|
10
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
11
|
+
*/
|
|
12
|
+
const codePointsCache = /* @__PURE__ */ new Map();
|
|
13
|
+
const MAX_STRING_LENGTH_TO_CACHE = 1e3;
|
|
14
|
+
function toCodePoints(str) {
|
|
15
|
+
let isAscii = true;
|
|
16
|
+
for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) > 127) {
|
|
17
|
+
isAscii = false;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
if (isAscii) return str.split("");
|
|
21
|
+
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {
|
|
22
|
+
const cached = codePointsCache.get(str);
|
|
23
|
+
if (cached) return cached;
|
|
24
|
+
}
|
|
25
|
+
const result = Array.from(str);
|
|
26
|
+
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) codePointsCache.set(str, result);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
function cpLen(str) {
|
|
30
|
+
return toCodePoints(str).length;
|
|
31
|
+
}
|
|
32
|
+
function cpSlice(str, start, end) {
|
|
33
|
+
return toCodePoints(str).slice(start, end).join("");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Strip characters that can break terminal rendering.
|
|
37
|
+
*
|
|
38
|
+
* Uses Node.js built-in stripVTControlCharacters to handle VT sequences,
|
|
39
|
+
* then filters remaining control characters that can disrupt display.
|
|
40
|
+
*
|
|
41
|
+
* Characters stripped:
|
|
42
|
+
* - ANSI escape sequences (via strip-ansi)
|
|
43
|
+
* - VT control sequences (via Node.js util.stripVTControlCharacters)
|
|
44
|
+
* - C0 control chars (0x00-0x1F) except CR/LF which are handled elsewhere
|
|
45
|
+
* - C1 control chars (0x80-0x9F) that can cause display issues
|
|
46
|
+
*
|
|
47
|
+
* Characters preserved:
|
|
48
|
+
* - All printable Unicode including emojis
|
|
49
|
+
* - DEL (0x7F) - handled functionally by applyOperations, not a display issue
|
|
50
|
+
* - CR/LF (0x0D/0x0A) - needed for line breaks
|
|
51
|
+
*/
|
|
52
|
+
function stripUnsafeCharacters(str) {
|
|
53
|
+
return toCodePoints(stripVTControlCharacters(stripAnsi(str))).filter((char) => {
|
|
54
|
+
const code = char.codePointAt(0);
|
|
55
|
+
if (code === void 0) return false;
|
|
56
|
+
if (code === 10 || code === 13) return true;
|
|
57
|
+
if (code >= 0 && code <= 31) return false;
|
|
58
|
+
if (code >= 128 && code <= 159) return false;
|
|
59
|
+
return true;
|
|
60
|
+
}).join("");
|
|
61
|
+
}
|
|
62
|
+
const stringWidthCache = /* @__PURE__ */ new Map();
|
|
63
|
+
/**
|
|
64
|
+
* Cached version of stringWidth function for better performance
|
|
65
|
+
* Follows Ink's approach with unlimited cache (no eviction)
|
|
66
|
+
*/
|
|
67
|
+
const getCachedStringWidth = (str) => {
|
|
68
|
+
if (/^[\x20-\x7E]*$/.test(str)) return str.length;
|
|
69
|
+
if (stringWidthCache.has(str)) return stringWidthCache.get(str);
|
|
70
|
+
const width = stringWidth(str);
|
|
71
|
+
stringWidthCache.set(str, width);
|
|
72
|
+
return width;
|
|
73
|
+
};
|
|
74
|
+
const regex = ansiRegex();
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { cpLen, cpSlice, getCachedStringWidth, stripUnsafeCharacters, toCodePoints };
|
|
78
|
+
//# sourceMappingURL=text-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-utils.mjs","names":[],"sources":["../../../src/ui/utils/text-utils.ts"],"sourcesContent":["// biome-ignore-all lint/style/noNonNullAssertion: code is from gemini-cli\n\n/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { stripVTControlCharacters } from \"node:util\";\nimport ansiRegex from \"ansi-regex\";\nimport stringWidth from \"string-width\";\nimport stripAnsi from \"strip-ansi\";\n\n/**\n * Calculates the maximum width of a multi-line ASCII art string.\n * @param asciiArt The ASCII art string.\n * @returns The length of the longest line in the ASCII art.\n */\nexport const getAsciiArtWidth = (asciiArt: string): number => {\n if (!asciiArt) {\n return 0;\n }\n const lines = asciiArt.split(\"\\n\");\n return Math.max(...lines.map((line) => line.length));\n};\n\n/*\n * -------------------------------------------------------------------------\n * Unicode‑aware helpers (work at the code‑point level rather than UTF‑16\n * code units so that surrogate‑pair emoji count as one \"column\".)\n * ---------------------------------------------------------------------- */\n\n// Cache for code points to reduce GC pressure\nconst codePointsCache = new Map<string, string[]>();\nconst MAX_STRING_LENGTH_TO_CACHE = 1000;\n\nexport function toCodePoints(str: string): string[] {\n // ASCII fast path - check if all chars are ASCII (0-127)\n let isAscii = true;\n for (let i = 0; i < str.length; i++) {\n if (str.charCodeAt(i) > 127) {\n isAscii = false;\n break;\n }\n }\n if (isAscii) {\n return str.split(\"\");\n }\n\n // Cache short strings\n if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {\n const cached = codePointsCache.get(str);\n if (cached) {\n return cached;\n }\n }\n\n const result = Array.from(str);\n\n // Cache result (unlimited like Ink)\n if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {\n codePointsCache.set(str, result);\n }\n\n return result;\n}\n\nexport function cpLen(str: string): number {\n return toCodePoints(str).length;\n}\n\nexport function cpSlice(str: string, start: number, end?: number): string {\n // Slice by code‑point indices and re‑join.\n const arr = toCodePoints(str).slice(start, end);\n return arr.join(\"\");\n}\n\n/**\n * Strip characters that can break terminal rendering.\n *\n * Uses Node.js built-in stripVTControlCharacters to handle VT sequences,\n * then filters remaining control characters that can disrupt display.\n *\n * Characters stripped:\n * - ANSI escape sequences (via strip-ansi)\n * - VT control sequences (via Node.js util.stripVTControlCharacters)\n * - C0 control chars (0x00-0x1F) except CR/LF which are handled elsewhere\n * - C1 control chars (0x80-0x9F) that can cause display issues\n *\n * Characters preserved:\n * - All printable Unicode including emojis\n * - DEL (0x7F) - handled functionally by applyOperations, not a display issue\n * - CR/LF (0x0D/0x0A) - needed for line breaks\n */\nexport function stripUnsafeCharacters(str: string): string {\n const strippedAnsi = stripAnsi(str);\n const strippedVT = stripVTControlCharacters(strippedAnsi);\n\n return toCodePoints(strippedVT)\n .filter((char) => {\n const code = char.codePointAt(0);\n if (code === undefined) return false;\n\n // Preserve CR/LF for line handling\n if (code === 0x0a || code === 0x0d) return true;\n\n // Remove C0 control chars (except CR/LF) that can break display\n // Examples: BELL(0x07) makes noise, BS(0x08) moves cursor, VT(0x0B), FF(0x0C)\n if (code >= 0x00 && code <= 0x1f) return false;\n\n // Remove C1 control chars (0x80-0x9f) - legacy 8-bit control codes\n if (code >= 0x80 && code <= 0x9f) return false;\n\n // Preserve DEL (0x7f) - it's handled functionally by applyOperations as backspace\n // and doesn't cause rendering issues when displayed\n\n // Preserve all other characters including Unicode/emojis\n return true;\n })\n .join(\"\");\n}\n\n// String width caching for performance optimization\nconst stringWidthCache = new Map<string, number>();\n\n/**\n * Cached version of stringWidth function for better performance\n * Follows Ink's approach with unlimited cache (no eviction)\n */\nexport const getCachedStringWidth = (str: string): number => {\n // ASCII printable chars have width 1\n if (/^[\\x20-\\x7E]*$/.test(str)) {\n return str.length;\n }\n\n if (stringWidthCache.has(str)) {\n return stringWidthCache.get(str)!;\n }\n\n const width = stringWidth(str);\n stringWidthCache.set(str, width);\n\n return width;\n};\n\n/**\n * Clear the string width cache\n */\nexport const clearStringWidthCache = (): void => {\n stringWidthCache.clear();\n};\n\nconst regex = ansiRegex();\n\n/* Recursively traverses a JSON-like structure (objects, arrays, primitives)\n * and escapes all ANSI control characters found in any string values.\n *\n * This function is designed to be robust, handling deeply nested objects and\n * arrays. It applies a regex-based replacement to all string values to\n * safely escape control characters.\n *\n * To optimize performance, this function uses a \"copy-on-write\" strategy.\n * It avoids allocating new objects or arrays if no nested string values\n * required escaping, returning the original object reference in such cases.\n *\n * @param obj The JSON-like value (object, array, string, etc.) to traverse.\n * @returns A new value with all nested string fields escaped, or the\n * original `obj` reference if no changes were necessary.\n */\nexport function escapeAnsiCtrlCodes<T>(obj: T): T {\n if (typeof obj === \"string\") {\n if (obj.search(regex) === -1) {\n return obj; // No changes return original string\n }\n\n regex.lastIndex = 0; // needed for global regex\n return obj.replace(regex, (match) => JSON.stringify(match).slice(1, -1)) as T;\n }\n\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n let newArr: unknown[] | null = null;\n\n for (let i = 0; i < obj.length; i++) {\n const value = obj[i];\n const escapedValue = escapeAnsiCtrlCodes(value);\n if (escapedValue !== value) {\n if (newArr === null) {\n newArr = [...obj];\n }\n newArr[i] = escapedValue;\n }\n }\n return (newArr !== null ? newArr : obj) as T;\n }\n\n let newObj: T | null = null;\n const keys = Object.keys(obj);\n\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n const escapedValue = escapeAnsiCtrlCodes(value);\n\n if (escapedValue !== value) {\n if (newObj === null) {\n newObj = { ...obj };\n }\n (newObj as Record<string, unknown>)[key] = escapedValue;\n }\n }\n\n return newObj !== null ? newObj : obj;\n}\n"],"mappings":";;;;;;;;;;;AAiCA,MAAM,kCAAkB,IAAI,KAAuB;AACnD,MAAM,6BAA6B;AAEnC,SAAgB,aAAa,KAAuB;CAElD,IAAI,UAAU;AACd,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAC9B,KAAI,IAAI,WAAW,EAAE,GAAG,KAAK;AAC3B,YAAU;AACV;;AAGJ,KAAI,QACF,QAAO,IAAI,MAAM,GAAG;AAItB,KAAI,IAAI,UAAU,4BAA4B;EAC5C,MAAM,SAAS,gBAAgB,IAAI,IAAI;AACvC,MAAI,OACF,QAAO;;CAIX,MAAM,SAAS,MAAM,KAAK,IAAI;AAG9B,KAAI,IAAI,UAAU,2BAChB,iBAAgB,IAAI,KAAK,OAAO;AAGlC,QAAO;;AAGT,SAAgB,MAAM,KAAqB;AACzC,QAAO,aAAa,IAAI,CAAC;;AAG3B,SAAgB,QAAQ,KAAa,OAAe,KAAsB;AAGxE,QADY,aAAa,IAAI,CAAC,MAAM,OAAO,IAAI,CACpC,KAAK,GAAG;;;;;;;;;;;;;;;;;;;AAoBrB,SAAgB,sBAAsB,KAAqB;AAIzD,QAAO,aAFY,yBADE,UAAU,IAAI,CACsB,CAE1B,CAC5B,QAAQ,SAAS;EAChB,MAAM,OAAO,KAAK,YAAY,EAAE;AAChC,MAAI,SAAS,OAAW,QAAO;AAG/B,MAAI,SAAS,MAAQ,SAAS,GAAM,QAAO;AAI3C,MAAI,QAAQ,KAAQ,QAAQ,GAAM,QAAO;AAGzC,MAAI,QAAQ,OAAQ,QAAQ,IAAM,QAAO;AAMzC,SAAO;GACP,CACD,KAAK,GAAG;;AAIb,MAAM,mCAAmB,IAAI,KAAqB;;;;;AAMlD,MAAa,wBAAwB,QAAwB;AAE3D,KAAI,iBAAiB,KAAK,IAAI,CAC5B,QAAO,IAAI;AAGb,KAAI,iBAAiB,IAAI,IAAI,CAC3B,QAAO,iBAAiB,IAAI,IAAI;CAGlC,MAAM,QAAQ,YAAY,IAAI;AAC9B,kBAAiB,IAAI,KAAK,MAAM;AAEhC,QAAO;;AAUT,MAAM,QAAQ,WAAW"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let node_path = require("node:path");
|
|
3
|
+
let node_fs_promises = require("node:fs/promises");
|
|
4
|
+
let yaml = require("yaml");
|
|
5
|
+
let glob = require("glob");
|
|
6
|
+
|
|
7
|
+
//#region src/utils/agent-v1.ts
|
|
8
|
+
async function isV1Package(src) {
|
|
9
|
+
return (0, node_fs_promises.stat)((0, node_path.join)(src, "project.yaml")).then((res) => res.isFile()).catch((error) => {
|
|
10
|
+
if (error.code === "ENOENT") return false;
|
|
11
|
+
throw error;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async function toAIGNEPackage(src, dst) {
|
|
15
|
+
const definition = await loadAgentV1Package(src);
|
|
16
|
+
const aigne = {
|
|
17
|
+
chat_model: { name: "gpt-4o-mini" },
|
|
18
|
+
agents: [],
|
|
19
|
+
cli: { agents: [] }
|
|
20
|
+
};
|
|
21
|
+
for (const agent of definition.agents) {
|
|
22
|
+
const { content } = await assistantToAIGNEV2(agent, definition);
|
|
23
|
+
const filename = getAgentFilename(agent);
|
|
24
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(dst, filename), content);
|
|
25
|
+
aigne.agents.push(filename);
|
|
26
|
+
aigne.cli.agents.push(filename);
|
|
27
|
+
}
|
|
28
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(dst, "aigne.yaml"), (0, yaml.stringify)(aigne));
|
|
29
|
+
}
|
|
30
|
+
async function loadAgentV1Package(path) {
|
|
31
|
+
const agentFilePaths = await (0, glob.glob)("prompts/**/*.yaml", { cwd: path });
|
|
32
|
+
const definition = {
|
|
33
|
+
project: (0, yaml.parse)(await (0, node_fs_promises.readFile)((0, node_path.join)(path, "project.yaml"), "utf8")),
|
|
34
|
+
agents: []
|
|
35
|
+
};
|
|
36
|
+
for (const filename of agentFilePaths) {
|
|
37
|
+
const agent = (0, yaml.parse)(await (0, node_fs_promises.readFile)((0, node_path.join)(path, filename), "utf8"));
|
|
38
|
+
definition.agents.push(agent);
|
|
39
|
+
}
|
|
40
|
+
return definition;
|
|
41
|
+
}
|
|
42
|
+
function assistantToAIGNEV2(agent, project) {
|
|
43
|
+
const converter = AGENT_MAP[agent.type];
|
|
44
|
+
if (!converter) throw new Error(`Unsupported agent type: ${agent.type}`);
|
|
45
|
+
return converter(agent, project);
|
|
46
|
+
}
|
|
47
|
+
const AGENT_MAP = {
|
|
48
|
+
prompt: (agent) => {
|
|
49
|
+
if (agent.type !== "prompt") throw new Error(`Expected agent type 'prompt', but got '${agent.type}'`);
|
|
50
|
+
return { content: (0, yaml.stringify)({
|
|
51
|
+
name: agent.name || agent.id,
|
|
52
|
+
description: agent.description,
|
|
53
|
+
input_schema: convertInputSchema(agent),
|
|
54
|
+
output_schema: convertOutputSchema(agent),
|
|
55
|
+
instructions: agent.prompts?.filter((i) => i.visibility !== "hidden" && i.type === "message").map((i) => i.data.content).join("\n")
|
|
56
|
+
}) };
|
|
57
|
+
},
|
|
58
|
+
function: async (agent) => {
|
|
59
|
+
if (agent.type !== "function") throw new Error(`Expected agent type 'function', but got '${agent.type}'`);
|
|
60
|
+
return { content: await formatCode(`\
|
|
61
|
+
export default async function agent({${(agent.parameters?.map((i) => i.key).filter(Boolean) ?? []).join(", ")}}) {
|
|
62
|
+
${agent.code}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
agent.agent_name = ${JSON.stringify(agent.name || agent.id)};
|
|
66
|
+
|
|
67
|
+
agent.description = ${agent.description ? JSON.stringify(agent.description) : "undefined"};
|
|
68
|
+
|
|
69
|
+
agent.input_schema = ${JSON.stringify(convertInputSchema(agent))};
|
|
70
|
+
|
|
71
|
+
agent.output_schema = ${JSON.stringify(convertOutputSchema(agent))};
|
|
72
|
+
`) };
|
|
73
|
+
},
|
|
74
|
+
router: (agent, project) => {
|
|
75
|
+
if (agent.type !== "router") throw new Error(`Expected agent type 'router', but got '${agent.type}'`);
|
|
76
|
+
return { content: (0, yaml.stringify)({
|
|
77
|
+
name: agent.name || agent.id,
|
|
78
|
+
description: agent.description,
|
|
79
|
+
instructions: agent.prompt,
|
|
80
|
+
input_schema: convertInputSchema(agent),
|
|
81
|
+
output_schema: convertOutputSchema(agent),
|
|
82
|
+
skills: agent.routes?.map((i) => {
|
|
83
|
+
const tool = project.agents.find((j) => j.id === i.id);
|
|
84
|
+
if (!tool) throw new Error(`Tool ${i.id} not found in project definition`);
|
|
85
|
+
return getAgentFilename(tool);
|
|
86
|
+
}),
|
|
87
|
+
tool_choice: "router"
|
|
88
|
+
}) };
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
function getAgentFilename(agent) {
|
|
92
|
+
switch (agent.type) {
|
|
93
|
+
case "prompt":
|
|
94
|
+
case "router": return `${agent.name || agent.id}.yaml`;
|
|
95
|
+
case "function": return `${agent.name || agent.id}.js`;
|
|
96
|
+
default: throw new Error(`Unsupported agent type: ${agent.type}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function formatCode(code) {
|
|
100
|
+
const [prettier, typescriptPlugin, estreePlugin] = await Promise.all([
|
|
101
|
+
import("prettier"),
|
|
102
|
+
import("prettier/plugins/typescript"),
|
|
103
|
+
import("prettier/plugins/estree")
|
|
104
|
+
]);
|
|
105
|
+
return prettier.format(code, {
|
|
106
|
+
parser: "typescript",
|
|
107
|
+
plugins: [typescriptPlugin, estreePlugin.default],
|
|
108
|
+
printWidth: 120,
|
|
109
|
+
useTabs: false,
|
|
110
|
+
tabWidth: 2,
|
|
111
|
+
trailingComma: "es5",
|
|
112
|
+
bracketSameLine: true,
|
|
113
|
+
semi: true,
|
|
114
|
+
singleQuote: true
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function convertInputSchema(agent) {
|
|
118
|
+
const parameters = (agent.parameters ?? []).filter((i) => !!i.key && !i.hidden);
|
|
119
|
+
const properties = parameters.map((i) => [i.key, parameterToJsonSchema(i)]);
|
|
120
|
+
return {
|
|
121
|
+
type: "object",
|
|
122
|
+
properties: Object.fromEntries(properties),
|
|
123
|
+
required: parameters.filter((i) => i.required).map((i) => i.key)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function parameterToJsonSchema(parameter) {
|
|
127
|
+
switch (parameter.type) {
|
|
128
|
+
case void 0:
|
|
129
|
+
case "string":
|
|
130
|
+
case "language": return {
|
|
131
|
+
type: "string",
|
|
132
|
+
description: parameter.placeholder
|
|
133
|
+
};
|
|
134
|
+
case "select": return {
|
|
135
|
+
type: "string",
|
|
136
|
+
enum: parameter.options?.map((i) => i.value),
|
|
137
|
+
description: parameter.placeholder
|
|
138
|
+
};
|
|
139
|
+
case "number":
|
|
140
|
+
case "boolean": return {
|
|
141
|
+
type: parameter.type,
|
|
142
|
+
description: parameter.placeholder
|
|
143
|
+
};
|
|
144
|
+
default: throw new Error(`Unsupported parameter type: ${parameter.type}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function convertOutputSchema(agent) {
|
|
148
|
+
const outputs = agent.outputVariables?.filter((i) => !!i.name && !i.hidden) ?? [];
|
|
149
|
+
const properties = outputs.map((i) => [i.name, variableTypeToJsonSchema(i)]).filter((i) => !!i[1]);
|
|
150
|
+
return {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: Object.fromEntries(properties),
|
|
153
|
+
required: outputs.filter((i) => i.required).map((i) => i.name)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function variableTypeToJsonSchema(output) {
|
|
157
|
+
if (output.type === "object") {
|
|
158
|
+
if (!output.properties) return void 0;
|
|
159
|
+
return {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: Object.fromEntries(output.properties.filter((i) => !!i.name).map((i) => [i.name, variableTypeToJsonSchema(i)]).filter((i) => !!i[1])),
|
|
162
|
+
required: output.properties.filter((i) => i.required && i.name).map((i) => i.name)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (output.type === "array") {
|
|
166
|
+
if (!output.element) return void 0;
|
|
167
|
+
return {
|
|
168
|
+
type: "array",
|
|
169
|
+
items: variableTypeToJsonSchema(output.element)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
type: output.type || "string",
|
|
174
|
+
description: output.description
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
exports.isV1Package = isV1Package;
|
|
180
|
+
exports.toAIGNEPackage = toAIGNEPackage;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
//#region src/utils/agent-v1.d.ts
|
|
2
|
+
declare function isV1Package(src: string): Promise<boolean>;
|
|
3
|
+
declare function toAIGNEPackage(src: string, dst: string): Promise<void>;
|
|
4
|
+
type Parameter = {
|
|
5
|
+
id: string;
|
|
6
|
+
key?: string;
|
|
7
|
+
hidden?: boolean;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
} & ({
|
|
11
|
+
type?: "string" | "number" | "boolean" | "language";
|
|
12
|
+
} | {
|
|
13
|
+
type?: "select";
|
|
14
|
+
options?: {
|
|
15
|
+
id: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
value?: string;
|
|
18
|
+
}[];
|
|
19
|
+
});
|
|
20
|
+
interface VariableTypeBase {
|
|
21
|
+
id: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
hidden?: boolean;
|
|
26
|
+
}
|
|
27
|
+
type OutputVariable = VariableTypeBase & ({
|
|
28
|
+
type?: undefined;
|
|
29
|
+
} | {
|
|
30
|
+
type: "string";
|
|
31
|
+
defaultValue?: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "number";
|
|
34
|
+
defaultValue?: number;
|
|
35
|
+
} | {
|
|
36
|
+
type: "boolean";
|
|
37
|
+
defaultValue?: boolean;
|
|
38
|
+
} | {
|
|
39
|
+
type: "object";
|
|
40
|
+
properties?: OutputVariable[];
|
|
41
|
+
} | {
|
|
42
|
+
type: "array";
|
|
43
|
+
element?: OutputVariable;
|
|
44
|
+
});
|
|
45
|
+
type AgentV1 = {
|
|
46
|
+
id: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
parameters?: Parameter[];
|
|
50
|
+
outputVariables?: OutputVariable[];
|
|
51
|
+
} & ({
|
|
52
|
+
type: "prompt";
|
|
53
|
+
prompts?: Prompt[];
|
|
54
|
+
temperature?: number;
|
|
55
|
+
topP?: number;
|
|
56
|
+
presencePenalty?: number;
|
|
57
|
+
frequencyPenalty?: number;
|
|
58
|
+
maxTokens?: number;
|
|
59
|
+
model?: string;
|
|
60
|
+
} | {
|
|
61
|
+
type: "router";
|
|
62
|
+
defaultToolId?: string;
|
|
63
|
+
prompt?: string;
|
|
64
|
+
decisionType?: "ai";
|
|
65
|
+
routes?: Tool[];
|
|
66
|
+
temperature?: number;
|
|
67
|
+
topP?: number;
|
|
68
|
+
presencePenalty?: number;
|
|
69
|
+
frequencyPenalty?: number;
|
|
70
|
+
maxTokens?: number;
|
|
71
|
+
model?: string;
|
|
72
|
+
} | {
|
|
73
|
+
type: "image";
|
|
74
|
+
prompt?: string;
|
|
75
|
+
model?: string;
|
|
76
|
+
n?: number;
|
|
77
|
+
quality?: string;
|
|
78
|
+
style?: string;
|
|
79
|
+
size?: string;
|
|
80
|
+
modelSettings?: {
|
|
81
|
+
[key: string]: unknown;
|
|
82
|
+
};
|
|
83
|
+
} | {
|
|
84
|
+
type: "api";
|
|
85
|
+
requestParameters?: {
|
|
86
|
+
id: string;
|
|
87
|
+
key?: string;
|
|
88
|
+
value?: string;
|
|
89
|
+
}[];
|
|
90
|
+
requestMethod?: string;
|
|
91
|
+
requestUrl?: string;
|
|
92
|
+
requestHeaders: {
|
|
93
|
+
id: string;
|
|
94
|
+
key?: string;
|
|
95
|
+
value?: string;
|
|
96
|
+
}[];
|
|
97
|
+
} | {
|
|
98
|
+
type: "function";
|
|
99
|
+
code?: string;
|
|
100
|
+
} | {
|
|
101
|
+
type: "callAgent";
|
|
102
|
+
agents?: Tool[];
|
|
103
|
+
});
|
|
104
|
+
interface ProjectDefinitionV1 {
|
|
105
|
+
project: {
|
|
106
|
+
name?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
};
|
|
109
|
+
agents: AgentV1[];
|
|
110
|
+
}
|
|
111
|
+
type Prompt = {
|
|
112
|
+
type: "message";
|
|
113
|
+
data: PromptMessage;
|
|
114
|
+
visibility?: "hidden";
|
|
115
|
+
} | {
|
|
116
|
+
type: "executeBlock";
|
|
117
|
+
visibility?: "hidden";
|
|
118
|
+
};
|
|
119
|
+
type PromptMessage = {
|
|
120
|
+
id: string;
|
|
121
|
+
role: Role;
|
|
122
|
+
content?: string;
|
|
123
|
+
name?: string;
|
|
124
|
+
};
|
|
125
|
+
type Role = "system" | "user" | "assistant";
|
|
126
|
+
type Tool = {
|
|
127
|
+
blockletDid?: string;
|
|
128
|
+
projectId?: string;
|
|
129
|
+
id: string;
|
|
130
|
+
from?: "assistant" | "blockletAPI" | "knowledge";
|
|
131
|
+
parameters?: {
|
|
132
|
+
[key: string]: unknown;
|
|
133
|
+
};
|
|
134
|
+
functionName?: string;
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
export { AgentV1, OutputVariable, Parameter, ProjectDefinitionV1, Prompt, PromptMessage, Role, Tool, VariableTypeBase, isV1Package, toAIGNEPackage };
|
|
138
|
+
//# sourceMappingURL=agent-v1.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-v1.d.cts","names":[],"sources":["../../src/utils/agent-v1.ts"],"mappings":";iBAKsB,WAAA,CAAA,GAAA,WAAuB,OAAA;AAAA,iBASvB,cAAA,CAAA,GAAA,UAAA,GAAA,WAAuC,OAAA;AAAA,KA+OjD,SAAA;EAAA,EAAA;EAAA,GAAA;EAAA,MAAA;EAAA,QAAA;EAAA,WAAA;AAAA;EAAA,IAAA;AAAA;EAAA,IAAA;EAAA,OAAA;IAAA,EAAA;IAAA,KAAA;IAAA,KAAA;EAAA;AAAA;AAAA,UAoBK,gBAAA;EAAA,EAAA;EAAA,IAAA;EAAA,WAAA;EAAA,QAAA;EAAA,MAAA;AAAA;AAAA,KAQL,cAAA,GAAiB,gBAAA;EAAA,IAAA;AAAA;EAAA,IAAA;EAAA,YAAA;AAAA;EAAA,IAAA;EAAA,YAAA;AAAA;EAAA,IAAA;EAAA,YAAA;AAAA;EAAA,IAAA;EAAA,UAAA,GAmBR,cAAA;AAAA;EAAA,IAAA;EAAA,OAAA,GAIH,cAAA;AAAA;AAAA,KAIN,OAAA;EAAA,EAAA;EAAA,IAAA;EAAA,WAAA;EAAA,UAAA,GAIG,SAAA;EAAA,eAAA,GACK,cAAA;AAAA;EAAA,IAAA;EAAA,OAAA,GAIJ,MAAA;EAAA,WAAA;EAAA,IAAA;EAAA,eAAA;EAAA,gBAAA;EAAA,SAAA;EAAA,KAAA;AAAA;EAAA,IAAA;EAAA,aAAA;EAAA,MAAA;EAAA,YAAA;EAAA,MAAA,GAaD,IAAA;EAAA,WAAA;EAAA,IAAA;EAAA,eAAA;EAAA,gBAAA;EAAA,SAAA;EAAA,KAAA;AAAA;EAAA,IAAA;EAAA,MAAA;EAAA,KAAA;EAAA,CAAA;EAAA,OAAA;EAAA,KAAA;EAAA,IAAA;EAAA,aAAA;IAAA,CAAA,GAAA;EAAA;AAAA;EAAA,IAAA;EAAA,iBAAA;IAAA,EAAA;IAAA,GAAA;IAAA,KAAA;EAAA;EAAA,aAAA;EAAA,UAAA;EAAA,cAAA;IAAA,EAAA;IAAA,GAAA;IAAA,KAAA;EAAA;AAAA;EAAA,IAAA;EAAA,IAAA;AAAA;EAAA,IAAA;EAAA,MAAA,GAyCA,IAAA;AAAA;AAAA,UAIE,mBAAA;EAAA,OAAA;IAAA,IAAA;IAAA,WAAA;EAAA;EAAA,MAAA,EAKP,OAAA;AAAA;AAAA,KAGE,MAAA;EAAA,IAAA;EAAA,IAAA,EAGA,aAAA;EAAA,UAAA;AAAA;EAAA,IAAA;EAAA,UAAA;AAAA;AAAA,KAQA,aAAA;EAAA,EAAA;EAAA,IAAA,EAEJ,IAAA;EAAA,OAAA;EAAA,IAAA;AAAA;AAAA,KAKI,IAAA;AAAA,KAEA,IAAA;EAAA,WAAA;EAAA,SAAA;EAAA,EAAA;EAAA,IAAA;EAAA,UAAA;IAAA,CAAA,GAAA;EAAA;EAAA,YAAA;AAAA"}
|