wave-agent-sdk 1.1.5 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/dist/agent.d.ts +128 -28
  2. package/dist/agent.js +201 -49
  3. package/dist/builtin/index.js +2 -0
  4. package/dist/builtin/plugins.js +11 -20
  5. package/dist/builtin/skills/settings.js +7 -20
  6. package/dist/builtin/skills/wave-daemon.d.ts +1 -0
  7. package/dist/builtin/skills/wave-daemon.js +194 -0
  8. package/dist/constants/images.d.ts +26 -0
  9. package/dist/constants/images.js +26 -0
  10. package/dist/constants/index.d.ts +16 -0
  11. package/dist/constants/index.js +16 -0
  12. package/dist/constants/memory.d.ts +26 -0
  13. package/dist/constants/memory.js +34 -0
  14. package/dist/constants/messages.d.ts +11 -0
  15. package/dist/constants/messages.js +11 -0
  16. package/dist/constants/plugins.d.ts +8 -0
  17. package/dist/constants/plugins.js +8 -0
  18. package/dist/constants/tools.d.ts +1 -0
  19. package/dist/constants/tools.js +1 -0
  20. package/dist/core/plugin.d.ts +54 -10
  21. package/dist/core/plugin.js +137 -23
  22. package/dist/core/session.d.ts +1 -1
  23. package/dist/core/session.js +1 -1
  24. package/dist/exec/catalog.d.ts +140 -0
  25. package/dist/exec/catalog.js +470 -0
  26. package/dist/exec/catalogAnnouncement.d.ts +89 -0
  27. package/dist/exec/catalogAnnouncement.js +293 -0
  28. package/dist/exec/constants.d.ts +51 -0
  29. package/dist/exec/constants.js +51 -0
  30. package/dist/exec/execRuntime.d.ts +55 -0
  31. package/dist/exec/execRuntime.js +217 -0
  32. package/dist/exec/workerSource.d.ts +28 -0
  33. package/dist/exec/workerSource.js +299 -0
  34. package/dist/host/index.d.ts +23 -0
  35. package/dist/host/index.js +23 -0
  36. package/dist/index.d.ts +7 -1
  37. package/dist/index.js +8 -1
  38. package/dist/managers/MemoryRuleManager.d.ts +6 -0
  39. package/dist/managers/MemoryRuleManager.js +12 -0
  40. package/dist/managers/aiManager.d.ts +35 -25
  41. package/dist/managers/aiManager.js +204 -202
  42. package/dist/managers/backgroundTaskManager.js +14 -0
  43. package/dist/managers/bashModeManager.d.ts +33 -0
  44. package/dist/managers/bashModeManager.js +110 -0
  45. package/dist/managers/hookManager.d.ts +18 -0
  46. package/dist/managers/hookManager.js +37 -3
  47. package/dist/managers/liveConfigManager.d.ts +33 -0
  48. package/dist/managers/liveConfigManager.js +106 -11
  49. package/dist/managers/lspManager.d.ts +9 -0
  50. package/dist/managers/lspManager.js +47 -18
  51. package/dist/managers/mcpManager.d.ts +68 -10
  52. package/dist/managers/mcpManager.js +265 -15
  53. package/dist/managers/messageManager.d.ts +60 -18
  54. package/dist/managers/messageManager.js +170 -81
  55. package/dist/managers/permissionManager.d.ts +69 -0
  56. package/dist/managers/permissionManager.js +221 -78
  57. package/dist/managers/planManager.d.ts +9 -0
  58. package/dist/managers/planManager.js +19 -1
  59. package/dist/managers/pluginManager.d.ts +46 -2
  60. package/dist/managers/pluginManager.js +117 -11
  61. package/dist/managers/pluginScopeManager.d.ts +15 -2
  62. package/dist/managers/pluginScopeManager.js +20 -1
  63. package/dist/managers/skillManager.d.ts +50 -0
  64. package/dist/managers/skillManager.js +166 -12
  65. package/dist/managers/slashCommandManager.d.ts +10 -0
  66. package/dist/managers/slashCommandManager.js +44 -31
  67. package/dist/managers/subagentManager.d.ts +15 -0
  68. package/dist/managers/subagentManager.js +81 -9
  69. package/dist/managers/toolManager.d.ts +29 -3
  70. package/dist/managers/toolManager.js +87 -13
  71. package/dist/managers/workflowManager.js +6 -0
  72. package/dist/prompts/autoMemory.d.ts +9 -0
  73. package/dist/prompts/autoMemory.js +30 -31
  74. package/dist/prompts/autoMemoryExtraction.d.ts +4 -0
  75. package/dist/prompts/autoMemoryExtraction.js +8 -111
  76. package/dist/prompts/index.d.ts +0 -1
  77. package/dist/prompts/index.js +0 -4
  78. package/dist/prompts/memoryTypes.d.ts +63 -0
  79. package/dist/prompts/memoryTypes.js +191 -0
  80. package/dist/services/GitService.d.ts +7 -0
  81. package/dist/services/GitService.js +23 -0
  82. package/dist/services/MarketplaceService.d.ts +101 -17
  83. package/dist/services/MarketplaceService.js +323 -102
  84. package/dist/services/artifactContent.d.ts +84 -0
  85. package/dist/services/artifactContent.js +204 -0
  86. package/dist/services/artifactSession.d.ts +6 -0
  87. package/dist/services/artifactSession.js +17 -0
  88. package/dist/services/autoMemoryService.js +5 -13
  89. package/dist/services/configurationService.d.ts +92 -9
  90. package/dist/services/configurationService.js +246 -64
  91. package/dist/services/contentSummarizer.d.ts +15 -0
  92. package/dist/services/contentSummarizer.js +45 -0
  93. package/dist/services/execAvailability.d.ts +9 -0
  94. package/dist/services/execAvailability.js +32 -0
  95. package/dist/services/fileWatcher.js +61 -6
  96. package/dist/services/initializationService.js +21 -17
  97. package/dist/services/interactionService.d.ts +9 -1
  98. package/dist/services/interactionService.js +28 -8
  99. package/dist/services/jsonlHandler.d.ts +98 -0
  100. package/dist/services/jsonlHandler.js +250 -12
  101. package/dist/services/memory.d.ts +17 -1
  102. package/dist/services/memory.js +44 -7
  103. package/dist/services/officialMarketplaceMirror.d.ts +85 -0
  104. package/dist/services/officialMarketplaceMirror.js +290 -0
  105. package/dist/services/pluginLoader.d.ts +12 -4
  106. package/dist/services/pluginLoader.js +38 -7
  107. package/dist/services/remoteSettingsService.js +20 -6
  108. package/dist/services/session.d.ts +74 -0
  109. package/dist/services/session.js +174 -16
  110. package/dist/services/sessionEntries.d.ts +2 -0
  111. package/dist/services/sessionEntries.js +20 -0
  112. package/dist/services/worktreeHooks.js +6 -1
  113. package/dist/stdio/index.d.ts +12 -0
  114. package/dist/stdio/index.js +12 -0
  115. package/dist/stdio/notificationRouter.d.ts +38 -0
  116. package/dist/stdio/notificationRouter.js +97 -0
  117. package/dist/stdio/rpcClient.d.ts +18 -0
  118. package/dist/stdio/rpcClient.js +10 -0
  119. package/dist/stdio/stdioAgent.d.ts +229 -0
  120. package/dist/stdio/stdioAgent.js +360 -0
  121. package/dist/tools/artifactTool.js +406 -273
  122. package/dist/tools/bashTool.js +10 -6
  123. package/dist/tools/editTool.js +6 -3
  124. package/dist/tools/execTool.d.ts +2 -0
  125. package/dist/tools/execTool.js +165 -0
  126. package/dist/tools/exitPlanMode.js +10 -2
  127. package/dist/tools/grepTool.js +7 -1
  128. package/dist/tools/readTool.js +30 -2
  129. package/dist/tools/types.d.ts +34 -8
  130. package/dist/tools/webFetchTool.js +15 -166
  131. package/dist/tools/workflowTool.js +40 -8
  132. package/dist/tools/writeTool.js +6 -3
  133. package/dist/types/agent.d.ts +24 -1
  134. package/dist/types/commands.d.ts +7 -0
  135. package/dist/types/configuration.d.ts +45 -2
  136. package/dist/types/hooks.d.ts +1 -0
  137. package/dist/types/hooks.js +19 -0
  138. package/dist/types/marketplace.d.ts +40 -2
  139. package/dist/types/mcp.d.ts +42 -0
  140. package/dist/types/messaging.d.ts +1 -8
  141. package/dist/types/permissions.d.ts +22 -0
  142. package/dist/types/permissions.js +17 -0
  143. package/dist/types/plugins.d.ts +26 -2
  144. package/dist/types/skills.d.ts +26 -0
  145. package/dist/utils/bashParser.d.ts +17 -0
  146. package/dist/utils/bashParser.js +72 -0
  147. package/dist/utils/bashStructure/bashLexer.d.ts +96 -0
  148. package/dist/utils/bashStructure/bashLexer.js +676 -0
  149. package/dist/utils/bashStructure/bashParser.d.ts +144 -0
  150. package/dist/utils/bashStructure/bashParser.js +606 -0
  151. package/dist/utils/bashStructure/bashSemantics.d.ts +70 -0
  152. package/dist/utils/bashStructure/bashSemantics.js +477 -0
  153. package/dist/utils/bashStructure/index.d.ts +26 -0
  154. package/dist/utils/bashStructure/index.js +27 -0
  155. package/dist/utils/bashStructure/types.d.ts +62 -0
  156. package/dist/utils/bashStructure/types.js +47 -0
  157. package/dist/utils/constants.d.ts +10 -0
  158. package/dist/utils/constants.js +10 -0
  159. package/dist/utils/containerSetup.js +48 -6
  160. package/dist/utils/convertMessagesForAPI.d.ts +7 -1
  161. package/dist/utils/convertMessagesForAPI.js +64 -14
  162. package/dist/utils/fileChangeReminder.d.ts +20 -0
  163. package/dist/utils/fileChangeReminder.js +153 -0
  164. package/dist/utils/fileSearch.js +4 -3
  165. package/dist/utils/fileUtils.d.ts +44 -0
  166. package/dist/utils/fileUtils.js +118 -0
  167. package/dist/utils/frontmatterYaml.d.ts +33 -0
  168. package/dist/utils/frontmatterYaml.js +192 -0
  169. package/dist/utils/imageBudget.d.ts +85 -0
  170. package/dist/utils/imageBudget.js +109 -0
  171. package/dist/utils/imageDimensions.d.ts +83 -0
  172. package/dist/utils/imageDimensions.js +232 -0
  173. package/dist/utils/imageProcessor.d.ts +66 -0
  174. package/dist/utils/imageProcessor.js +84 -0
  175. package/dist/utils/imageRewrite.d.ts +29 -0
  176. package/dist/utils/imageRewrite.js +251 -0
  177. package/dist/utils/markdownParser.d.ts +5 -1
  178. package/dist/utils/markdownParser.js +9 -51
  179. package/dist/utils/mcpInstructions.d.ts +61 -0
  180. package/dist/utils/mcpInstructions.js +126 -0
  181. package/dist/utils/mcpUtils.d.ts +7 -0
  182. package/dist/utils/mcpUtils.js +11 -2
  183. package/dist/utils/memoryAge.d.ts +32 -0
  184. package/dist/utils/memoryAge.js +47 -0
  185. package/dist/utils/memoryEntrypoint.d.ts +20 -0
  186. package/dist/utils/memoryEntrypoint.js +49 -0
  187. package/dist/utils/memoryIndex.d.ts +30 -0
  188. package/dist/utils/memoryIndex.js +76 -0
  189. package/dist/utils/messageOperations.d.ts +6 -20
  190. package/dist/utils/messageOperations.js +40 -91
  191. package/dist/utils/nestedMemory.d.ts +22 -0
  192. package/dist/utils/nestedMemory.js +61 -0
  193. package/dist/utils/npmTarball.d.ts +19 -0
  194. package/dist/utils/npmTarball.js +92 -0
  195. package/dist/utils/pluginSource.d.ts +37 -0
  196. package/dist/utils/pluginSource.js +73 -0
  197. package/dist/utils/ripgrep.d.ts +18 -4
  198. package/dist/utils/ripgrep.js +56 -4
  199. package/dist/utils/runtimeDeps.d.ts +35 -0
  200. package/dist/utils/runtimeDeps.js +426 -0
  201. package/dist/utils/skillParser.js +22 -52
  202. package/dist/utils/subagentParser.js +48 -45
  203. package/dist/utils/tokenCalculation.js +0 -8
  204. package/dist/utils/userSettings.d.ts +90 -0
  205. package/dist/utils/userSettings.js +291 -0
  206. package/dist/utils/worktreeUtils.d.ts +2 -1
  207. package/dist/utils/worktreeUtils.js +64 -34
  208. package/package.json +12 -4
  209. package/dist/managers/bangManager.d.ts +0 -26
  210. package/dist/managers/bangManager.js +0 -78
@@ -15,6 +15,8 @@ export interface PermissionDecision {
15
15
  newPermissionMode?: PermissionMode;
16
16
  /** Signal to persist a new allowed rule */
17
17
  newPermissionRule?: string;
18
+ /** Signal to add a directory to this session's Safe Zone (not persisted) */
19
+ newAdditionalDirectory?: string;
18
20
  }
19
21
  /** Callback function for custom permission logic */
20
22
  export type PermissionCallback = (context: ToolPermissionContext) => Promise<PermissionDecision>;
@@ -32,6 +34,12 @@ export interface ToolPermissionContext {
32
34
  suggestedPrefix?: string;
33
35
  /** Whether to hide the persistent permission option (e.g., "Don't ask again") in the UI */
34
36
  hidePersistentOption?: boolean;
37
+ /**
38
+ * Absolute path of the directory holding an out-of-Safe-Zone target, set for
39
+ * Edit/Write when the target lies outside the Safe Zone. Lets the confirmation
40
+ * UI offer adding that directory to the session Safe Zone.
41
+ */
42
+ outsideSafeZoneDirectory?: string;
35
43
  /** The ID of the tool call that triggered this permission request */
36
44
  toolCallId?: string;
37
45
  /** The content of the plan being exited from */
@@ -41,6 +49,20 @@ export interface ToolPermissionContext {
41
49
  }
42
50
  /** List of tools that require permission checks in default mode */
43
51
  export declare const RESTRICTED_TOOLS: readonly ["Edit", "Bash", "Write", "EnterPlanMode", "ExitPlanMode", "AskUserQuestion", "Artifact"];
52
+ /**
53
+ * Tools that must still reach the user when permission checks are bypassed
54
+ * (`bypassPermissions` mode, or `plan` mode in a session holding the bypass
55
+ * authorization) — aligned with Claude Code's `requiresUserInteraction`:
56
+ * its permission pipeline returns the tool's own ask result before the
57
+ * bypass step can allow it.
58
+ *
59
+ * - `AskUserQuestion`: the tool *is* the question; bypassing it would strand
60
+ * the agent without an answer.
61
+ * - `ExitPlanMode`: leaving plan mode is the user's approval of the plan, so
62
+ * it stays a user decision even in a "don't ask me" session. This is the
63
+ * one remaining gate on plan mode for such sessions (see plan-mode.md).
64
+ */
65
+ export declare const USER_INTERACTION_REQUIRED_TOOLS: readonly ["AskUserQuestion", "ExitPlanMode"];
44
66
  /** Type for restricted tool names */
45
67
  export type RestrictedTool = (typeof RESTRICTED_TOOLS)[number];
46
68
  export declare const OPERATION_CANCELLED_BY_USER = "Operation cancelled by user";
@@ -13,4 +13,21 @@ export const RESTRICTED_TOOLS = [
13
13
  ASK_USER_QUESTION_TOOL_NAME,
14
14
  ARTIFACT_TOOL_NAME,
15
15
  ];
16
+ /**
17
+ * Tools that must still reach the user when permission checks are bypassed
18
+ * (`bypassPermissions` mode, or `plan` mode in a session holding the bypass
19
+ * authorization) — aligned with Claude Code's `requiresUserInteraction`:
20
+ * its permission pipeline returns the tool's own ask result before the
21
+ * bypass step can allow it.
22
+ *
23
+ * - `AskUserQuestion`: the tool *is* the question; bypassing it would strand
24
+ * the agent without an answer.
25
+ * - `ExitPlanMode`: leaving plan mode is the user's approval of the plan, so
26
+ * it stays a user decision even in a "don't ask me" session. This is the
27
+ * one remaining gate on plan mode for such sessions (see plan-mode.md).
28
+ */
29
+ export const USER_INTERACTION_REQUIRED_TOOLS = [
30
+ ASK_USER_QUESTION_TOOL_NAME,
31
+ EXIT_PLAN_MODE_TOOL_NAME,
32
+ ];
16
33
  export const OPERATION_CANCELLED_BY_USER = "Operation cancelled by user";
@@ -1,7 +1,7 @@
1
1
  import { CustomSlashCommand } from "./commands.js";
2
2
  import { Skill } from "./skills.js";
3
3
  import { LspConfig } from "./lsp.js";
4
- import { McpConfig } from "./mcp.js";
4
+ import { McpConfig, McpServerConfig } from "./mcp.js";
5
5
  import { PartialHookConfiguration } from "./configuration.js";
6
6
  import { SubagentConfiguration } from "../utils/subagentParser.js";
7
7
  /**
@@ -10,10 +10,20 @@ import { SubagentConfiguration } from "../utils/subagentParser.js";
10
10
  export interface PluginManifest {
11
11
  name: string;
12
12
  description: string;
13
- version: string;
13
+ /**
14
+ * Optional: plugins in the Claude Code ecosystem often omit it (spec plugin
15
+ * A-022). Install and load both fall back to `1.0.0`.
16
+ */
17
+ version?: string;
14
18
  author?: {
15
19
  name: string;
16
20
  };
21
+ /**
22
+ * Inline MCP server declarations, equivalent to a sibling `.mcp.json`
23
+ * (spec plugin A-023). Claude Code also allows a path string or array of
24
+ * paths here; only the object form is supported.
25
+ */
26
+ mcpServers?: Record<string, McpServerConfig>;
17
27
  }
18
28
  /**
19
29
  * Plugin configuration in AgentOptions or wave.settings.json
@@ -22,10 +32,24 @@ export interface PluginConfig {
22
32
  type: "local";
23
33
  path: string;
24
34
  }
35
+ /** A plugin root that failed to load during the most recent load/reload. */
36
+ export interface PluginLoadFailure {
37
+ path: string;
38
+ error: string;
39
+ }
40
+ /** Result of `Agent.reloadPlugins()` / `PluginManager.reloadAllPlugins()`. */
41
+ export interface PluginReloadResult {
42
+ /** Plugin names loaded after the reload. */
43
+ plugins: string[];
44
+ /** Plugins that could not be loaded; the reload does not roll back. */
45
+ failures: PluginLoadFailure[];
46
+ }
25
47
  /**
26
48
  * Represents a loaded plugin in the system
27
49
  */
28
50
  export interface Plugin extends PluginManifest {
51
+ /** Always resolved on load: a missing manifest version becomes `1.0.0` (A-022). */
52
+ version: string;
29
53
  path: string;
30
54
  commands: CustomSlashCommand[];
31
55
  skills: Skill[];
@@ -6,6 +6,17 @@ export interface SkillMetadata {
6
6
  name: string;
7
7
  description: string;
8
8
  type: "personal" | "project" | "builtin";
9
+ /**
10
+ * Path to the skill **directory** (the folder containing SKILL.md), never
11
+ * to SKILL.md itself. Directory-level contract — all consumers rely on it:
12
+ * - `SkillManager.prepareSkillContent` injects this value for
13
+ * `${WAVE_SKILL_DIR}` / `${CLAUDE_SKILL_DIR}` substitutions and reports it
14
+ * as the "Base directory for this skill";
15
+ * - `SkillManager.deleteSkill` removes this path with `rm(recursive)`.
16
+ * Callers that need the file itself must `join(skillPath, "SKILL.md")`
17
+ * (misreading this as the file path broke the desktop "Edit" action,
18
+ * bug 3466438649392128).
19
+ */
9
20
  skillPath: string;
10
21
  allowedTools?: string[];
11
22
  context?: "fork";
@@ -80,6 +91,21 @@ export interface SkillParseOptions {
80
91
  validateMetadata?: boolean;
81
92
  basePath?: string;
82
93
  }
94
+ /**
95
+ * A skill invocation recorded for context restoration (post-compaction
96
+ * re-injection, spec core/message-compact 场景 4).
97
+ */
98
+ export interface InvokedSkillRecord {
99
+ skillName: string;
100
+ timestamp: number;
101
+ /**
102
+ * The content the model actually saw when the skill was invoked — directory
103
+ * placeholders already substituted, prefixed with
104
+ * `Base directory for this skill: <path>`. Re-injecting the raw SKILL.md
105
+ * instead would hand the model a literal `${WAVE_SKILL_DIR}`.
106
+ */
107
+ content?: string;
108
+ }
83
109
  export declare const SKILL_DEFAULTS: {
84
110
  readonly PERSONAL_SKILLS_DIR: ".wave/skills";
85
111
  readonly PROJECT_SKILLS_DIR: ".wave/skills";
@@ -37,6 +37,23 @@ export declare const DANGEROUS_COMMANDS: string[];
37
37
  * FR-019.2 through FR-019.7 in tool-permission-system.md.
38
38
  */
39
39
  export declare const READ_ONLY_COMMANDS: string[];
40
+ /**
41
+ * Subset of READ_ONLY_COMMANDS whose arguments are file paths (as opposed to
42
+ * strings, names, or flags, e.g. echo, pwd, which, basename). These commands
43
+ * must stay within the Safe Zone: a read-only command accessing a path outside
44
+ * the working directory / additional directories requires confirmation.
45
+ * Aligned with Claude Code's PathCommand list.
46
+ */
47
+ export declare const PATH_COMMANDS: string[];
48
+ /**
49
+ * Extract file path arguments from a command's argument string.
50
+ * Tokens starting with "-" are treated as flags and skipped; everything after
51
+ * a "--" separator counts as a path. Quoted path arguments are unquoted.
52
+ * Non-path tokens (e.g. a grep pattern) are harmless: they resolve against the
53
+ * working directory and typically do not exist, so isPathInside falls back to
54
+ * the nearest existing parent (the workdir itself) and stays inside.
55
+ */
56
+ export declare function extractPathArgs(args: string): string[];
40
57
  /**
41
58
  * Registry of commands and their expected subcommand depth for smart prefix extraction.
42
59
  * For example, 'git: 2' means 'git commit' is a valid prefix, but 'git' alone is not.
@@ -500,6 +500,78 @@ export const READ_ONLY_COMMANDS = [
500
500
  "bc",
501
501
  "sleep",
502
502
  ];
503
+ /**
504
+ * Subset of READ_ONLY_COMMANDS whose arguments are file paths (as opposed to
505
+ * strings, names, or flags, e.g. echo, pwd, which, basename). These commands
506
+ * must stay within the Safe Zone: a read-only command accessing a path outside
507
+ * the working directory / additional directories requires confirmation.
508
+ * Aligned with Claude Code's PathCommand list.
509
+ */
510
+ export const PATH_COMMANDS = [
511
+ "ls",
512
+ "find",
513
+ "cat",
514
+ "head",
515
+ "tail",
516
+ "wc",
517
+ "sort",
518
+ "uniq",
519
+ "grep",
520
+ "egrep",
521
+ "fgrep",
522
+ "rg",
523
+ "file",
524
+ "stat",
525
+ "du",
526
+ "df",
527
+ "tree",
528
+ "diff",
529
+ "cmp",
530
+ "md5sum",
531
+ "sha256sum",
532
+ "sha1sum",
533
+ "xxd",
534
+ "od",
535
+ "hexdump",
536
+ "strings",
537
+ "readlink",
538
+ "realpath",
539
+ "jq",
540
+ "yq",
541
+ "cut",
542
+ "paste",
543
+ "column",
544
+ "tr",
545
+ "awk",
546
+ "sed",
547
+ ];
548
+ /**
549
+ * Extract file path arguments from a command's argument string.
550
+ * Tokens starting with "-" are treated as flags and skipped; everything after
551
+ * a "--" separator counts as a path. Quoted path arguments are unquoted.
552
+ * Non-path tokens (e.g. a grep pattern) are harmless: they resolve against the
553
+ * working directory and typically do not exist, so isPathInside falls back to
554
+ * the nearest existing parent (the workdir itself) and stays inside.
555
+ */
556
+ export function extractPathArgs(args) {
557
+ const tokens = args.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
558
+ const pathArgs = [];
559
+ let afterDoubleDash = false;
560
+ for (const token of tokens) {
561
+ if (afterDoubleDash) {
562
+ pathArgs.push(token);
563
+ continue;
564
+ }
565
+ if (token === "--") {
566
+ afterDoubleDash = true;
567
+ continue;
568
+ }
569
+ if (!token.startsWith("-")) {
570
+ pathArgs.push(token);
571
+ }
572
+ }
573
+ return pathArgs.map((p) => p.replace(/^['"](.*)['"]$/, "$1"));
574
+ }
503
575
  /**
504
576
  * Global scope flags for git that only change the target repository or
505
577
  * configuration, not the subcommand being run. Shared by TOOL_RULES (smart
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Tokenizer for the structure-aware bash parser.
3
+ *
4
+ * Unlike `bashParser.ts`'s text-based heuristics, this tokenizer understands
5
+ * bash quoting so that structural tokens (;, &&, ||, |, &, ( ), do/done/fi…)
6
+ * are only recognized OUTSIDE quotes/substitutions, and words keep enough
7
+ * internal structure for the semantic layer to tell quoted `"$f"` from bare
8
+ * `$f`.
9
+ *
10
+ * Words are tokenized into parts:
11
+ * - lit literal text (single-quoted or plain)
12
+ * - var `$name` / `${name}` expansion (name kept raw, unexpanded)
13
+ * - special `$@` `$*` `$?` `$$` `$!` `$#` `$-` `$0`..`$9`
14
+ * - cmdsub `$(...)` or backtick command substitution (text = inner)
15
+ * - arith `$((...))` — unsupported (dynamic), fail closed
16
+ * - brace `{a,b}` brace expansion — unsupported (dynamic)
17
+ * - process `<(cmd)` / `>(cmd)` process substitution — unsupported
18
+ * Each part records whether it appeared inside double quotes (`q: 'double'`)
19
+ * or bare (`q: 'none'`); single-quoted text is fully literal.
20
+ *
21
+ * The tokenizer FAILS (returns null) on any construct it cannot safely delimit
22
+ * (unterminated quotes / $( / backticks / heredocs). Failures are surfaced by
23
+ * the caller as a fail-closed `unsupported` parse result.
24
+ */
25
+ export type QuoteCtx = "none" | "single" | "double";
26
+ export type WordPart = {
27
+ t: "lit";
28
+ v: string;
29
+ q: QuoteCtx;
30
+ } | {
31
+ t: "var";
32
+ name: string;
33
+ q: "none" | "double";
34
+ } | {
35
+ t: "special";
36
+ name: string;
37
+ q: "none" | "double";
38
+ } | {
39
+ t: "cmdsub";
40
+ text: string;
41
+ q: "none" | "double";
42
+ } | {
43
+ t: "arith";
44
+ q: "none" | "double";
45
+ } | {
46
+ t: "brace";
47
+ v: string;
48
+ q: "none" | "double";
49
+ } | {
50
+ t: "process";
51
+ text: string;
52
+ q: "none" | "double";
53
+ };
54
+ export interface WordToken {
55
+ t: "word";
56
+ /** Raw word text as written (quotes and $ references preserved). */
57
+ raw: string;
58
+ /** Inner structure for the semantic layer. */
59
+ parts: WordPart[];
60
+ }
61
+ export type OpToken = "&&" | "||" | "|" | "|&" | ";" | ";;" | ";&" | ";;&" | "&" | "(" | ")" | "newline" | "{" | "}";
62
+ export interface OpTok {
63
+ t: "op";
64
+ op: OpToken;
65
+ }
66
+ export interface NlTok {
67
+ t: "nl";
68
+ }
69
+ export type Token = WordToken | OpTok | NlTok | {
70
+ t: "eof";
71
+ };
72
+ /** Raw tokenizer failure: a construct we cannot model → ask (fail closed). */
73
+ export type LexFailureReason = "heredoc" | "unterminated" | "unexpected-char" | "length-limit";
74
+ export declare function isVariableNameStart(ch: string): boolean;
75
+ /**
76
+ * Classify a redirection operator word emitted by the tokenizer.
77
+ * Returns "plain" when the operator still needs a separate following target
78
+ * word (`>`, `2>`, `>>`, `&>`, `>&` …), "folded" when the target is already
79
+ * part of the operator token (`2>&1`, `>&-`), or null when the word is not a
80
+ * redirection operator.
81
+ *
82
+ * The raw word may carry an optional file-descriptor digit prefix (`2>`) and
83
+ * the dup operators `<&`/`>&` may fold their fd/- target when it directly
84
+ * touches the operator (`2>&1` must stay one token so the reconstructed text
85
+ * remains faithful — legacy `2>& 1` text checks would mis-read the target).
86
+ */
87
+ export declare function redirectOpKind(raw: string): "plain" | "folded" | null;
88
+ /** True when the raw text is a redirection operator (fd prefix allowed). */
89
+ export declare function isRedirectRaw(raw: string): boolean;
90
+ /** Whether a word token is a redirection operator (raw literal, no quoting). */
91
+ export declare function isRedirectWord(w: WordToken): boolean;
92
+ /**
93
+ * Tokenize a bash command string. Returns tokens or null on a lexical
94
+ * construct we deliberately do not support (fail closed).
95
+ */
96
+ export declare function tokenize(input: string): Token[] | null;