@agimon-ai/doompi-git 0.0.1-alpha.7 → 0.0.1-alpha.9
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/dist/_virtual/_rolldown/runtime.cjs +23 -1
- package/dist/api-contracts.cjs +7 -1
- package/dist/api-contracts.d.cts +1 -1
- package/dist/api-contracts.d.mts +1 -1
- package/dist/api-contracts.mjs +2 -1
- package/dist/extensions/pi.cjs +38 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.cts +5 -4
- package/dist/extensions/pi.d.cts.map +1 -1
- package/dist/extensions/pi.d.mts +5 -4
- package/dist/extensions/pi.d.mts.map +1 -1
- package/dist/extensions/pi.mjs +33 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +72 -1
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.cts +3 -3
- package/dist/extensions/server.d.cts.map +1 -1
- package/dist/extensions/server.d.mts +3 -3
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +67 -1
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +485 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +5 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -1
- package/dist/src/constants/git.cjs +8 -0
- package/dist/src/constants/git.cjs.map +1 -0
- package/dist/src/constants/git.mjs +7 -0
- package/dist/src/constants/git.mjs.map +1 -0
- package/dist/src/extensions/(backend)/api/_lib/route.server.cjs +93 -0
- package/dist/src/extensions/(backend)/api/_lib/route.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/api/_lib/route.server.mjs +92 -0
- package/dist/src/extensions/(backend)/api/_lib/route.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/api/route.server.cjs +7 -0
- package/dist/src/extensions/(backend)/api/route.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/api/route.server.mjs +8 -0
- package/dist/src/extensions/(backend)/api/route.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/_lib/git-worktrees.server.cjs +195 -0
- package/dist/src/extensions/(backend)/channel/_lib/git-worktrees.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/_lib/git-worktrees.server.mjs +194 -0
- package/dist/src/extensions/(backend)/channel/_lib/git-worktrees.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/git-worktrees.server.cjs +7 -0
- package/dist/src/extensions/(backend)/channel/git-worktrees.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/git-worktrees.server.mjs +8 -0
- package/dist/src/extensions/(backend)/channel/git-worktrees.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.server.cjs +71 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.server.mjs +70 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/root.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/_lib/git.cli.cjs +17 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/_lib/git.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/_lib/git.cli.mjs +16 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/_lib/git.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/git.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/git.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/git.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/git.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompi-use-git.cli.cjs +15 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompi-use-git.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompi-use-git.cli.mjs +15 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompi-use-git.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.mjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGit.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.mjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiGitReadme.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.mjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/_lib/doompiUseGit.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-git.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-git.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-git.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-git.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGit.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiGitReadme.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompiUseGit.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/_lib/runWorktree.cli.cjs +38 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/_lib/runWorktree.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/_lib/runWorktree.cli.mjs +36 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/_lib/runWorktree.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/runWorktree.server.mjs.map +1 -0
- package/dist/src/schemas/apiContracts.cjs +138 -0
- package/dist/src/schemas/apiContracts.cjs.map +1 -0
- package/dist/{schemas → src/schemas}/apiContracts.d.cts +2 -2
- package/dist/{schemas → src/schemas}/apiContracts.d.cts.map +1 -1
- package/dist/{schemas → src/schemas}/apiContracts.d.mts +2 -2
- package/dist/{schemas → src/schemas}/apiContracts.d.mts.map +1 -1
- package/dist/src/schemas/apiContracts.mjs +135 -0
- package/dist/src/schemas/apiContracts.mjs.map +1 -0
- package/dist/src/schemas/runWorktreeTool.cjs +152 -0
- package/dist/src/schemas/runWorktreeTool.cjs.map +1 -0
- package/dist/src/schemas/runWorktreeTool.mjs +150 -0
- package/dist/src/schemas/runWorktreeTool.mjs.map +1 -0
- package/dist/src/services/atomicJson/index.cjs +42 -0
- package/dist/src/services/atomicJson/index.cjs.map +1 -0
- package/dist/src/services/atomicJson/index.mjs +38 -0
- package/dist/src/services/atomicJson/index.mjs.map +1 -0
- package/dist/src/services/compositionMirror/index.cjs +119 -0
- package/dist/src/services/compositionMirror/index.cjs.map +1 -0
- package/dist/src/services/compositionMirror/index.mjs +116 -0
- package/dist/src/services/compositionMirror/index.mjs.map +1 -0
- package/dist/src/services/errors/index.cjs +29 -0
- package/dist/src/services/errors/index.cjs.map +1 -0
- package/dist/src/services/errors/index.mjs +27 -0
- package/dist/src/services/errors/index.mjs.map +1 -0
- package/dist/src/services/extensionService/index.cjs +13 -0
- package/dist/src/services/extensionService/index.cjs.map +1 -0
- package/dist/{services → src/services}/extensionService/index.d.cts +1 -2
- package/dist/src/services/extensionService/index.d.cts.map +1 -0
- package/dist/{services → src/services}/extensionService/index.d.mts +1 -2
- package/dist/src/services/extensionService/index.d.mts.map +1 -0
- package/dist/src/services/extensionService/index.mjs +13 -0
- package/dist/src/services/extensionService/index.mjs.map +1 -0
- package/dist/src/services/gitCli/index.cjs +144 -0
- package/dist/src/services/gitCli/index.cjs.map +1 -0
- package/dist/src/services/gitCli/index.mjs +142 -0
- package/dist/src/services/gitCli/index.mjs.map +1 -0
- package/dist/src/services/gitDependencies/index.cjs +14 -0
- package/dist/src/services/gitDependencies/index.cjs.map +1 -0
- package/dist/src/services/gitDependencies/index.d.cts +5 -0
- package/dist/src/services/gitDependencies/index.d.cts.map +1 -0
- package/dist/src/services/gitDependencies/index.d.mts +5 -0
- package/dist/src/services/gitDependencies/index.d.mts.map +1 -0
- package/dist/src/services/gitDependencies/index.mjs +14 -0
- package/dist/src/services/gitDependencies/index.mjs.map +1 -0
- package/dist/src/services/paths/index.cjs +35 -0
- package/dist/src/services/paths/index.cjs.map +1 -0
- package/dist/src/services/paths/index.mjs +30 -0
- package/dist/src/services/paths/index.mjs.map +1 -0
- package/dist/src/services/repositoryIdentity/index.cjs +71 -0
- package/dist/src/services/repositoryIdentity/index.cjs.map +1 -0
- package/dist/src/services/repositoryIdentity/index.mjs +65 -0
- package/dist/src/services/repositoryIdentity/index.mjs.map +1 -0
- package/dist/src/services/runWorktree/index.cjs +145 -0
- package/dist/src/services/runWorktree/index.cjs.map +1 -0
- package/dist/src/services/runWorktree/index.mjs +142 -0
- package/dist/src/services/runWorktree/index.mjs.map +1 -0
- package/dist/src/services/worktreeEvents/index.cjs +64 -0
- package/dist/src/services/worktreeEvents/index.cjs.map +1 -0
- package/dist/{services → src/services}/worktreeEvents/index.d.cts +3 -4
- package/dist/src/services/worktreeEvents/index.d.cts.map +1 -0
- package/dist/{services → src/services}/worktreeEvents/index.d.mts +3 -4
- package/dist/src/services/worktreeEvents/index.d.mts.map +1 -0
- package/dist/src/services/worktreeEvents/index.mjs +60 -0
- package/dist/src/services/worktreeEvents/index.mjs.map +1 -0
- package/dist/src/services/worktreeNaming/index.cjs +99 -0
- package/dist/src/services/worktreeNaming/index.cjs.map +1 -0
- package/dist/{services → src/services}/worktreeNaming/index.d.cts +2 -3
- package/dist/src/services/worktreeNaming/index.d.cts.map +1 -0
- package/dist/{services → src/services}/worktreeNaming/index.d.mts +2 -3
- package/dist/src/services/worktreeNaming/index.d.mts.map +1 -0
- package/dist/src/services/worktreeNaming/index.mjs +94 -0
- package/dist/src/services/worktreeNaming/index.mjs.map +1 -0
- package/dist/src/services/worktreeOperations/index.cjs +263 -0
- package/dist/src/services/worktreeOperations/index.cjs.map +1 -0
- package/dist/{services → src/services}/worktreeOperations/index.d.cts +4 -5
- package/dist/src/services/worktreeOperations/index.d.cts.map +1 -0
- package/dist/{services → src/services}/worktreeOperations/index.d.mts +4 -5
- package/dist/src/services/worktreeOperations/index.d.mts.map +1 -0
- package/dist/src/services/worktreeOperations/index.mjs +261 -0
- package/dist/src/services/worktreeOperations/index.mjs.map +1 -0
- package/dist/src/services/worktreeRegistry/index.cjs +38 -0
- package/dist/src/services/worktreeRegistry/index.cjs.map +1 -0
- package/dist/src/services/worktreeRegistry/index.mjs +38 -0
- package/dist/src/services/worktreeRegistry/index.mjs.map +1 -0
- package/dist/{types → src/types}/extension.d.cts +4 -5
- package/dist/src/types/extension.d.cts.map +1 -0
- package/dist/{types → src/types}/extension.d.mts +4 -5
- package/dist/src/types/extension.d.mts.map +1 -0
- package/dist/src/types/webWorktrees.cjs +20 -0
- package/dist/src/types/webWorktrees.cjs.map +1 -0
- package/dist/src/types/webWorktrees.mjs +20 -0
- package/dist/src/types/webWorktrees.mjs.map +1 -0
- package/dist/{types → src/types}/worktreeRegistry.d.cts +3 -4
- package/dist/src/types/worktreeRegistry.d.cts.map +1 -0
- package/dist/{types → src/types}/worktreeRegistry.d.mts +3 -4
- package/dist/src/types/worktreeRegistry.d.mts.map +1 -0
- package/package.json +31 -26
- package/dist/constants/git.cjs +0 -2
- package/dist/constants/git.cjs.map +0 -1
- package/dist/constants/git.mjs +0 -2
- package/dist/constants/git.mjs.map +0 -1
- package/dist/controllers/gitCommand.cjs +0 -2
- package/dist/controllers/gitCommand.cjs.map +0 -1
- package/dist/controllers/gitCommand.mjs +0 -2
- package/dist/controllers/gitCommand.mjs.map +0 -1
- package/dist/controllers/gitSession.cjs +0 -2
- package/dist/controllers/gitSession.cjs.map +0 -1
- package/dist/controllers/gitSession.mjs +0 -2
- package/dist/controllers/gitSession.mjs.map +0 -1
- package/dist/controllers/hubApi.cjs +0 -2
- package/dist/controllers/hubApi.cjs.map +0 -1
- package/dist/controllers/hubApi.mjs +0 -2
- package/dist/controllers/hubApi.mjs.map +0 -1
- package/dist/controllers/worktreesChannel.cjs +0 -2
- package/dist/controllers/worktreesChannel.cjs.map +0 -1
- package/dist/controllers/worktreesChannel.mjs +0 -2
- package/dist/controllers/worktreesChannel.mjs.map +0 -1
- package/dist/schemas/apiContracts.cjs +0 -2
- package/dist/schemas/apiContracts.cjs.map +0 -1
- package/dist/schemas/apiContracts.mjs +0 -2
- package/dist/schemas/apiContracts.mjs.map +0 -1
- package/dist/schemas/runWorktreeTool.cjs +0 -2
- package/dist/schemas/runWorktreeTool.cjs.map +0 -1
- package/dist/schemas/runWorktreeTool.mjs +0 -2
- package/dist/schemas/runWorktreeTool.mjs.map +0 -1
- package/dist/services/atomicJson/index.cjs +0 -2
- package/dist/services/atomicJson/index.cjs.map +0 -1
- package/dist/services/atomicJson/index.mjs +0 -2
- package/dist/services/atomicJson/index.mjs.map +0 -1
- package/dist/services/compositionMirror/index.cjs +0 -2
- package/dist/services/compositionMirror/index.cjs.map +0 -1
- package/dist/services/compositionMirror/index.mjs +0 -2
- package/dist/services/compositionMirror/index.mjs.map +0 -1
- package/dist/services/errors/index.cjs +0 -2
- package/dist/services/errors/index.cjs.map +0 -1
- package/dist/services/errors/index.mjs +0 -2
- package/dist/services/errors/index.mjs.map +0 -1
- package/dist/services/extensionService/index.cjs +0 -2
- package/dist/services/extensionService/index.cjs.map +0 -1
- package/dist/services/extensionService/index.d.cts.map +0 -1
- package/dist/services/extensionService/index.d.mts.map +0 -1
- package/dist/services/extensionService/index.mjs +0 -2
- package/dist/services/extensionService/index.mjs.map +0 -1
- package/dist/services/gitCli/index.cjs +0 -4
- package/dist/services/gitCli/index.cjs.map +0 -1
- package/dist/services/gitCli/index.mjs +0 -4
- package/dist/services/gitCli/index.mjs.map +0 -1
- package/dist/services/gitDependencies/index.cjs +0 -2
- package/dist/services/gitDependencies/index.cjs.map +0 -1
- package/dist/services/gitDependencies/index.d.cts +0 -6
- package/dist/services/gitDependencies/index.d.cts.map +0 -1
- package/dist/services/gitDependencies/index.d.mts +0 -6
- package/dist/services/gitDependencies/index.d.mts.map +0 -1
- package/dist/services/gitDependencies/index.mjs +0 -2
- package/dist/services/gitDependencies/index.mjs.map +0 -1
- package/dist/services/paths/index.cjs +0 -2
- package/dist/services/paths/index.cjs.map +0 -1
- package/dist/services/paths/index.mjs +0 -2
- package/dist/services/paths/index.mjs.map +0 -1
- package/dist/services/repositoryIdentity/index.cjs +0 -2
- package/dist/services/repositoryIdentity/index.cjs.map +0 -1
- package/dist/services/repositoryIdentity/index.mjs +0 -2
- package/dist/services/repositoryIdentity/index.mjs.map +0 -1
- package/dist/services/runWorktree/index.cjs +0 -15
- package/dist/services/runWorktree/index.cjs.map +0 -1
- package/dist/services/runWorktree/index.mjs +0 -15
- package/dist/services/runWorktree/index.mjs.map +0 -1
- package/dist/services/worktreeEvents/index.cjs +0 -2
- package/dist/services/worktreeEvents/index.cjs.map +0 -1
- package/dist/services/worktreeEvents/index.d.cts.map +0 -1
- package/dist/services/worktreeEvents/index.d.mts.map +0 -1
- package/dist/services/worktreeEvents/index.mjs +0 -2
- package/dist/services/worktreeEvents/index.mjs.map +0 -1
- package/dist/services/worktreeNaming/index.cjs +0 -2
- package/dist/services/worktreeNaming/index.cjs.map +0 -1
- package/dist/services/worktreeNaming/index.d.cts.map +0 -1
- package/dist/services/worktreeNaming/index.d.mts.map +0 -1
- package/dist/services/worktreeNaming/index.mjs +0 -2
- package/dist/services/worktreeNaming/index.mjs.map +0 -1
- package/dist/services/worktreeOperations/index.cjs +0 -2
- package/dist/services/worktreeOperations/index.cjs.map +0 -1
- package/dist/services/worktreeOperations/index.d.cts.map +0 -1
- package/dist/services/worktreeOperations/index.d.mts.map +0 -1
- package/dist/services/worktreeOperations/index.mjs +0 -2
- package/dist/services/worktreeOperations/index.mjs.map +0 -1
- package/dist/services/worktreeRegistry/index.cjs +0 -2
- package/dist/services/worktreeRegistry/index.cjs.map +0 -1
- package/dist/services/worktreeRegistry/index.mjs +0 -2
- package/dist/services/worktreeRegistry/index.mjs.map +0 -1
- package/dist/tools/runWorktree.cjs +0 -2
- package/dist/tools/runWorktree.cjs.map +0 -1
- package/dist/tools/runWorktree.mjs +0 -2
- package/dist/tools/runWorktree.mjs.map +0 -1
- package/dist/types/extension.d.cts.map +0 -1
- package/dist/types/extension.d.mts.map +0 -1
- package/dist/types/webWorktrees.cjs +0 -2
- package/dist/types/webWorktrees.cjs.map +0 -1
- package/dist/types/webWorktrees.mjs +0 -2
- package/dist/types/webWorktrees.mjs.map +0 -1
- package/dist/types/worktreeRegistry.d.cts.map +0 -1
- package/dist/types/worktreeRegistry.d.mts.map +0 -1
- package/src/extensions/web.ts +0 -33
- package/src/types/webWorktrees.ts +0 -55
- package/src/types/worktreeRegistry.ts +0 -78
- package/src/web/components/RunWorktreeToolMessage.tsx +0 -45
- package/src/web/components/WorktreesActivitySection.tsx +0 -80
- package/src/web/components/WorktreesPanel.tsx +0 -175
- package/src/web/components/toolRenderers.ts +0 -8
- package/src/web/stores/worktreesActivityStore.ts +0 -125
- package/src/web/tsconfig.json +0 -22
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["WORKTREE_ACTIONS","invalidRequest","WORKTREE_ACTION_FIELDS"],"sources":["../../../../src/services/runWorktree/index.ts"],"sourcesContent":["import {\n RunWorktreeParams,\n WORKTREE_ACTION_FIELDS,\n WORKTREE_ACTIONS,\n type WorktreeAction,\n type RunWorktreeToolParams,\n} from '../../schemas/runWorktreeTool';\nimport type { WorktreeRecord } from '../../types/worktreeRegistry';\nimport { invalidRequest } from '../errors';\nimport type { WorktreeOperations } from '../worktreeOperations';\n\nexport { RunWorktreeParams };\nexport type { RunWorktreeToolParams, WorktreeAction };\n\nexport const RUN_WORKTREE_TOOL_NAME = 'run_worktree';\n\nconst IMPLEMENTED_ACTIONS: ReadonlySet<string> = new Set(Object.values(WORKTREE_ACTIONS));\n\nexport const RUN_WORKTREE_DESCRIPTION = `Create and manage git worktrees, each with its own DoomPi session nested under this one.\n\nActions:\n- spawn_worktree: create a worktree on a new branch and start a session in it. Requires 'branch'. Optional 'baseRef' (defaults to the current branch), 'name' for the rail, 'task' as the first message.\n- close_worktree: stop a worktree's session and delete its directory. Requires 'id'. Refuses a dirty tree unless 'force' is true.\n- list: every worktree for this repository, with status.\n- status: one worktree and its uncommitted files. Requires 'id'.\n- merge: merge a worktree's branch into this checkout. Requires 'id'. Refuses when this checkout is dirty.\n- prune: remove orphaned worktrees. Pass 'dryRun' to see the plan without destroying anything.\n- send: send a message to the other side of a worktree. Requires 'id' and 'message'.\n- messages: read messages waiting for you from a worktree. Requires 'id'.\n\nWorktrees live outside the repository, under ~/.pi/.doom/git/worktrees.`;\n\nexport interface RunWorktreeToolDetails {\n action: WorktreeAction;\n records?: WorktreeRecord[];\n}\n\nexport interface RunWorktreeToolResult {\n content: [{ type: 'text'; text: string }];\n details: RunWorktreeToolDetails;\n}\n\nexport interface RunWorktreeExecutionContext {\n readonly cwd: string;\n readonly sessionId: string;\n}\n\nexport interface RunWorktreeExecutionOptions {\n readonly signal?: AbortSignal;\n readonly onProgress?: (label: string) => void;\n}\n\n/** Rejects calls that do not match one documented action shape. */\nexport function validateParams(input: unknown): RunWorktreeToolParams {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw invalidRequest('run_worktree parameters must be an object.', 'Call it with one documented action shape.');\n }\n const record = input as Record<string, unknown>;\n const action = record.action;\n if (typeof action !== 'string' || !IMPLEMENTED_ACTIONS.has(action)) {\n throw invalidRequest(\n `Unknown action ${typeof action === 'string' ? `'${action}'` : 'value'}.`,\n `Use one of: ${[...IMPLEMENTED_ACTIONS].join(', ')}.`,\n );\n }\n const allowed = WORKTREE_ACTION_FIELDS[action as WorktreeAction];\n const unexpected = Object.keys(record).filter((key) => !allowed.includes(key));\n if (unexpected.length > 0) {\n throw invalidRequest(\n `action='${action}' does not accept: ${unexpected.join(', ')}.`,\n `Fields for '${action}': ${allowed.join(', ')}.`,\n );\n }\n for (const field of ['branch', 'id'] as const) {\n if (allowed.includes(field) && field in record) {\n const value = record[field];\n if (typeof value !== 'string' || value.trim() === '') {\n throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);\n }\n }\n }\n const stringFields = ['baseRef', 'name', 'task', 'message'] as const;\n for (const field of stringFields) {\n if (field in record && (typeof record[field] !== 'string' || record[field].trim() === '')) {\n throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);\n }\n }\n for (const field of ['force', 'dryRun'] as const) {\n if (field in record && typeof record[field] !== 'boolean') {\n throw invalidRequest(`action='${action}' requires boolean '${field}'.`, `Pass true or false for ${field}.`);\n }\n }\n if (action === WORKTREE_ACTIONS.send && typeof record.message !== 'string') {\n throw invalidRequest(\"action='send' requires 'message'.\", 'Pass the message to send.');\n }\n if (action === WORKTREE_ACTIONS.spawn_worktree && typeof record.branch !== 'string') {\n throw invalidRequest(\"action='spawn_worktree' requires 'branch'.\", 'Name the branch to create.');\n }\n if (\n (action === WORKTREE_ACTIONS.close_worktree ||\n action === WORKTREE_ACTIONS.status ||\n action === WORKTREE_ACTIONS.merge ||\n action === WORKTREE_ACTIONS.send ||\n action === WORKTREE_ACTIONS.messages) &&\n typeof record.id !== 'string'\n ) {\n throw invalidRequest(`action='${action}' requires 'id'.`, 'Call list to see the current ids.');\n }\n return record as RunWorktreeToolParams;\n}\n\nfunction describe(record: WorktreeRecord): string {\n return `${record.id} ${record.branch} ${record.status} ${record.path}`;\n}\n\nfunction text(...lines: readonly string[]): [{ type: 'text'; text: string }] {\n return [{ type: 'text', text: lines.join('\\n') }];\n}\n\nexport async function executeRunWorktreeTool(\n params: RunWorktreeToolParams,\n operations: WorktreeOperations,\n context: RunWorktreeExecutionContext,\n options: RunWorktreeExecutionOptions = {},\n): Promise<RunWorktreeToolResult> {\n switch (params.action) {\n case WORKTREE_ACTIONS.spawn_worktree: {\n const record = await operations.spawn(\n context,\n {\n branch: params.branch,\n ...(params.baseRef === undefined ? {} : { baseRef: params.baseRef }),\n ...(params.name === undefined ? {} : { name: params.name }),\n },\n options,\n );\n return {\n content: text(\n `Worktree ${record.id} created on ${record.branch} from ${record.baseRef}.`,\n `Path: ${record.path}`,\n `Session ${record.sessionId} is starting; it appears nested under this one in the rail.`,\n ),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.close_worktree: {\n const record = await operations.close(context, params.id, params.force ?? false);\n return {\n content: text(`Worktree ${record.id} (${record.branch}) closed and removed.`),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.list: {\n const records = await operations.list(context);\n return {\n content:\n records.length === 0\n ? text('No worktrees for this repository.')\n : text(`${String(records.length)} worktree(s):`, ...records.map(describe)),\n details: { action: params.action, records },\n };\n }\n case WORKTREE_ACTIONS.status: {\n const { record, dirtyFiles } = await operations.status(context, params.id);\n return {\n content: text(\n describe(record),\n `Session: ${record.sessionId}`,\n dirtyFiles.length === 0\n ? 'Clean.'\n : `${String(dirtyFiles.length)} uncommitted file(s): ${dirtyFiles.slice(0, 20).join(', ')}`,\n ),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.merge: {\n const record = await operations.merge(\n context,\n params.id,\n ...(params.message === undefined ? [] : ([params.message] as const)),\n );\n return {\n content: text(`Merged ${record.branch} into this checkout.`),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.send: {\n await operations.send(context, params.id, params.message);\n return { content: text(`Message sent to worktree ${params.id}.`), details: { action: params.action } };\n }\n case WORKTREE_ACTIONS.messages: {\n const waiting = await operations.messages(context, params.id);\n return {\n content:\n waiting.length === 0\n ? text('No messages.')\n : text(\n `${String(waiting.length)} message(s):`,\n ...waiting.map((entry) => `[${entry.sentAt}] ${entry.from}: ${entry.text}`),\n ),\n details: { action: params.action },\n };\n }\n case WORKTREE_ACTIONS.prune: {\n const dryRun = params.dryRun ?? false;\n const plan = await operations.prune(context, dryRun);\n const lines = [\n dryRun ? 'Prune plan (nothing was changed):' : 'Pruned:',\n `Remove: ${plan.remove.length === 0 ? 'none' : plan.remove.map((record) => record.id).join(', ')}`,\n `Forget: ${plan.forget.length === 0 ? 'none' : plan.forget.map((record) => record.id).join(', ')}`,\n `Kept, uncommitted work: ${plan.keptDirty.length === 0 ? 'none' : plan.keptDirty.map((record) => record.id).join(', ')}`,\n `Untracked directories, left alone: ${plan.untracked.length === 0 ? 'none' : plan.untracked.join(', ')}`,\n ...(plan.keptBranches.length === 0\n ? []\n : [`Branches kept, they hold commits: ${plan.keptBranches.join(', ')}`]),\n ];\n return { content: text(...lines), details: { action: params.action } };\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { invalidRequest } from "../errors/index.mjs";
|
|
2
|
+
import { WORKTREE_ACTIONS, WORKTREE_ACTION_FIELDS } from "../../schemas/runWorktreeTool.mjs";
|
|
3
|
+
//#region src/services/runWorktree/index.ts
|
|
4
|
+
const RUN_WORKTREE_TOOL_NAME = "run_worktree";
|
|
5
|
+
const IMPLEMENTED_ACTIONS = new Set(Object.values(WORKTREE_ACTIONS));
|
|
6
|
+
const RUN_WORKTREE_DESCRIPTION = `Create and manage git worktrees, each with its own DoomPi session nested under this one.
|
|
7
|
+
|
|
8
|
+
Actions:
|
|
9
|
+
- spawn_worktree: create a worktree on a new branch and start a session in it. Requires 'branch'. Optional 'baseRef' (defaults to the current branch), 'name' for the rail, 'task' as the first message.
|
|
10
|
+
- close_worktree: stop a worktree's session and delete its directory. Requires 'id'. Refuses a dirty tree unless 'force' is true.
|
|
11
|
+
- list: every worktree for this repository, with status.
|
|
12
|
+
- status: one worktree and its uncommitted files. Requires 'id'.
|
|
13
|
+
- merge: merge a worktree's branch into this checkout. Requires 'id'. Refuses when this checkout is dirty.
|
|
14
|
+
- prune: remove orphaned worktrees. Pass 'dryRun' to see the plan without destroying anything.
|
|
15
|
+
- send: send a message to the other side of a worktree. Requires 'id' and 'message'.
|
|
16
|
+
- messages: read messages waiting for you from a worktree. Requires 'id'.
|
|
17
|
+
|
|
18
|
+
Worktrees live outside the repository, under ~/.pi/.doom/git/worktrees.`;
|
|
19
|
+
/** Rejects calls that do not match one documented action shape. */
|
|
20
|
+
function validateParams(input) {
|
|
21
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) throw invalidRequest("run_worktree parameters must be an object.", "Call it with one documented action shape.");
|
|
22
|
+
const record = input;
|
|
23
|
+
const action = record.action;
|
|
24
|
+
if (typeof action !== "string" || !IMPLEMENTED_ACTIONS.has(action)) throw invalidRequest(`Unknown action ${typeof action === "string" ? `'${action}'` : "value"}.`, `Use one of: ${[...IMPLEMENTED_ACTIONS].join(", ")}.`);
|
|
25
|
+
const allowed = WORKTREE_ACTION_FIELDS[action];
|
|
26
|
+
const unexpected = Object.keys(record).filter((key) => !allowed.includes(key));
|
|
27
|
+
if (unexpected.length > 0) throw invalidRequest(`action='${action}' does not accept: ${unexpected.join(", ")}.`, `Fields for '${action}': ${allowed.join(", ")}.`);
|
|
28
|
+
for (const field of ["branch", "id"]) if (allowed.includes(field) && field in record) {
|
|
29
|
+
const value = record[field];
|
|
30
|
+
if (typeof value !== "string" || value.trim() === "") throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);
|
|
31
|
+
}
|
|
32
|
+
for (const field of [
|
|
33
|
+
"baseRef",
|
|
34
|
+
"name",
|
|
35
|
+
"task",
|
|
36
|
+
"message"
|
|
37
|
+
]) if (field in record && (typeof record[field] !== "string" || record[field].trim() === "")) throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);
|
|
38
|
+
for (const field of ["force", "dryRun"]) if (field in record && typeof record[field] !== "boolean") throw invalidRequest(`action='${action}' requires boolean '${field}'.`, `Pass true or false for ${field}.`);
|
|
39
|
+
if (action === WORKTREE_ACTIONS.send && typeof record.message !== "string") throw invalidRequest("action='send' requires 'message'.", "Pass the message to send.");
|
|
40
|
+
if (action === WORKTREE_ACTIONS.spawn_worktree && typeof record.branch !== "string") throw invalidRequest("action='spawn_worktree' requires 'branch'.", "Name the branch to create.");
|
|
41
|
+
if ((action === WORKTREE_ACTIONS.close_worktree || action === WORKTREE_ACTIONS.status || action === WORKTREE_ACTIONS.merge || action === WORKTREE_ACTIONS.send || action === WORKTREE_ACTIONS.messages) && typeof record.id !== "string") throw invalidRequest(`action='${action}' requires 'id'.`, "Call list to see the current ids.");
|
|
42
|
+
return record;
|
|
43
|
+
}
|
|
44
|
+
function describe(record) {
|
|
45
|
+
return `${record.id} ${record.branch} ${record.status} ${record.path}`;
|
|
46
|
+
}
|
|
47
|
+
function text(...lines) {
|
|
48
|
+
return [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: lines.join("\n")
|
|
51
|
+
}];
|
|
52
|
+
}
|
|
53
|
+
async function executeRunWorktreeTool(params, operations, context, options = {}) {
|
|
54
|
+
switch (params.action) {
|
|
55
|
+
case WORKTREE_ACTIONS.spawn_worktree: {
|
|
56
|
+
const record = await operations.spawn(context, {
|
|
57
|
+
branch: params.branch,
|
|
58
|
+
...params.baseRef === void 0 ? {} : { baseRef: params.baseRef },
|
|
59
|
+
...params.name === void 0 ? {} : { name: params.name }
|
|
60
|
+
}, options);
|
|
61
|
+
return {
|
|
62
|
+
content: text(`Worktree ${record.id} created on ${record.branch} from ${record.baseRef}.`, `Path: ${record.path}`, `Session ${record.sessionId} is starting; it appears nested under this one in the rail.`),
|
|
63
|
+
details: {
|
|
64
|
+
action: params.action,
|
|
65
|
+
records: [record]
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
case WORKTREE_ACTIONS.close_worktree: {
|
|
70
|
+
const record = await operations.close(context, params.id, params.force ?? false);
|
|
71
|
+
return {
|
|
72
|
+
content: text(`Worktree ${record.id} (${record.branch}) closed and removed.`),
|
|
73
|
+
details: {
|
|
74
|
+
action: params.action,
|
|
75
|
+
records: [record]
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
case WORKTREE_ACTIONS.list: {
|
|
80
|
+
const records = await operations.list(context);
|
|
81
|
+
return {
|
|
82
|
+
content: records.length === 0 ? text("No worktrees for this repository.") : text(`${String(records.length)} worktree(s):`, ...records.map(describe)),
|
|
83
|
+
details: {
|
|
84
|
+
action: params.action,
|
|
85
|
+
records
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
case WORKTREE_ACTIONS.status: {
|
|
90
|
+
const { record, dirtyFiles } = await operations.status(context, params.id);
|
|
91
|
+
return {
|
|
92
|
+
content: text(describe(record), `Session: ${record.sessionId}`, dirtyFiles.length === 0 ? "Clean." : `${String(dirtyFiles.length)} uncommitted file(s): ${dirtyFiles.slice(0, 20).join(", ")}`),
|
|
93
|
+
details: {
|
|
94
|
+
action: params.action,
|
|
95
|
+
records: [record]
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
case WORKTREE_ACTIONS.merge: {
|
|
100
|
+
const record = await operations.merge(context, params.id, ...params.message === void 0 ? [] : [params.message]);
|
|
101
|
+
return {
|
|
102
|
+
content: text(`Merged ${record.branch} into this checkout.`),
|
|
103
|
+
details: {
|
|
104
|
+
action: params.action,
|
|
105
|
+
records: [record]
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
case WORKTREE_ACTIONS.send:
|
|
110
|
+
await operations.send(context, params.id, params.message);
|
|
111
|
+
return {
|
|
112
|
+
content: text(`Message sent to worktree ${params.id}.`),
|
|
113
|
+
details: { action: params.action }
|
|
114
|
+
};
|
|
115
|
+
case WORKTREE_ACTIONS.messages: {
|
|
116
|
+
const waiting = await operations.messages(context, params.id);
|
|
117
|
+
return {
|
|
118
|
+
content: waiting.length === 0 ? text("No messages.") : text(`${String(waiting.length)} message(s):`, ...waiting.map((entry) => `[${entry.sentAt}] ${entry.from}: ${entry.text}`)),
|
|
119
|
+
details: { action: params.action }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
case WORKTREE_ACTIONS.prune: {
|
|
123
|
+
const dryRun = params.dryRun ?? false;
|
|
124
|
+
const plan = await operations.prune(context, dryRun);
|
|
125
|
+
return {
|
|
126
|
+
content: text(...[
|
|
127
|
+
dryRun ? "Prune plan (nothing was changed):" : "Pruned:",
|
|
128
|
+
`Remove: ${plan.remove.length === 0 ? "none" : plan.remove.map((record) => record.id).join(", ")}`,
|
|
129
|
+
`Forget: ${plan.forget.length === 0 ? "none" : plan.forget.map((record) => record.id).join(", ")}`,
|
|
130
|
+
`Kept, uncommitted work: ${plan.keptDirty.length === 0 ? "none" : plan.keptDirty.map((record) => record.id).join(", ")}`,
|
|
131
|
+
`Untracked directories, left alone: ${plan.untracked.length === 0 ? "none" : plan.untracked.join(", ")}`,
|
|
132
|
+
...plan.keptBranches.length === 0 ? [] : [`Branches kept, they hold commits: ${plan.keptBranches.join(", ")}`]
|
|
133
|
+
]),
|
|
134
|
+
details: { action: params.action }
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
export { RUN_WORKTREE_DESCRIPTION, RUN_WORKTREE_TOOL_NAME, executeRunWorktreeTool, validateParams };
|
|
141
|
+
|
|
142
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/runWorktree/index.ts"],"sourcesContent":["import {\n RunWorktreeParams,\n WORKTREE_ACTION_FIELDS,\n WORKTREE_ACTIONS,\n type WorktreeAction,\n type RunWorktreeToolParams,\n} from '../../schemas/runWorktreeTool';\nimport type { WorktreeRecord } from '../../types/worktreeRegistry';\nimport { invalidRequest } from '../errors';\nimport type { WorktreeOperations } from '../worktreeOperations';\n\nexport { RunWorktreeParams };\nexport type { RunWorktreeToolParams, WorktreeAction };\n\nexport const RUN_WORKTREE_TOOL_NAME = 'run_worktree';\n\nconst IMPLEMENTED_ACTIONS: ReadonlySet<string> = new Set(Object.values(WORKTREE_ACTIONS));\n\nexport const RUN_WORKTREE_DESCRIPTION = `Create and manage git worktrees, each with its own DoomPi session nested under this one.\n\nActions:\n- spawn_worktree: create a worktree on a new branch and start a session in it. Requires 'branch'. Optional 'baseRef' (defaults to the current branch), 'name' for the rail, 'task' as the first message.\n- close_worktree: stop a worktree's session and delete its directory. Requires 'id'. Refuses a dirty tree unless 'force' is true.\n- list: every worktree for this repository, with status.\n- status: one worktree and its uncommitted files. Requires 'id'.\n- merge: merge a worktree's branch into this checkout. Requires 'id'. Refuses when this checkout is dirty.\n- prune: remove orphaned worktrees. Pass 'dryRun' to see the plan without destroying anything.\n- send: send a message to the other side of a worktree. Requires 'id' and 'message'.\n- messages: read messages waiting for you from a worktree. Requires 'id'.\n\nWorktrees live outside the repository, under ~/.pi/.doom/git/worktrees.`;\n\nexport interface RunWorktreeToolDetails {\n action: WorktreeAction;\n records?: WorktreeRecord[];\n}\n\nexport interface RunWorktreeToolResult {\n content: [{ type: 'text'; text: string }];\n details: RunWorktreeToolDetails;\n}\n\nexport interface RunWorktreeExecutionContext {\n readonly cwd: string;\n readonly sessionId: string;\n}\n\nexport interface RunWorktreeExecutionOptions {\n readonly signal?: AbortSignal;\n readonly onProgress?: (label: string) => void;\n}\n\n/** Rejects calls that do not match one documented action shape. */\nexport function validateParams(input: unknown): RunWorktreeToolParams {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw invalidRequest('run_worktree parameters must be an object.', 'Call it with one documented action shape.');\n }\n const record = input as Record<string, unknown>;\n const action = record.action;\n if (typeof action !== 'string' || !IMPLEMENTED_ACTIONS.has(action)) {\n throw invalidRequest(\n `Unknown action ${typeof action === 'string' ? `'${action}'` : 'value'}.`,\n `Use one of: ${[...IMPLEMENTED_ACTIONS].join(', ')}.`,\n );\n }\n const allowed = WORKTREE_ACTION_FIELDS[action as WorktreeAction];\n const unexpected = Object.keys(record).filter((key) => !allowed.includes(key));\n if (unexpected.length > 0) {\n throw invalidRequest(\n `action='${action}' does not accept: ${unexpected.join(', ')}.`,\n `Fields for '${action}': ${allowed.join(', ')}.`,\n );\n }\n for (const field of ['branch', 'id'] as const) {\n if (allowed.includes(field) && field in record) {\n const value = record[field];\n if (typeof value !== 'string' || value.trim() === '') {\n throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);\n }\n }\n }\n const stringFields = ['baseRef', 'name', 'task', 'message'] as const;\n for (const field of stringFields) {\n if (field in record && (typeof record[field] !== 'string' || record[field].trim() === '')) {\n throw invalidRequest(`action='${action}' requires a nonblank '${field}'.`, `Pass a ${field}.`);\n }\n }\n for (const field of ['force', 'dryRun'] as const) {\n if (field in record && typeof record[field] !== 'boolean') {\n throw invalidRequest(`action='${action}' requires boolean '${field}'.`, `Pass true or false for ${field}.`);\n }\n }\n if (action === WORKTREE_ACTIONS.send && typeof record.message !== 'string') {\n throw invalidRequest(\"action='send' requires 'message'.\", 'Pass the message to send.');\n }\n if (action === WORKTREE_ACTIONS.spawn_worktree && typeof record.branch !== 'string') {\n throw invalidRequest(\"action='spawn_worktree' requires 'branch'.\", 'Name the branch to create.');\n }\n if (\n (action === WORKTREE_ACTIONS.close_worktree ||\n action === WORKTREE_ACTIONS.status ||\n action === WORKTREE_ACTIONS.merge ||\n action === WORKTREE_ACTIONS.send ||\n action === WORKTREE_ACTIONS.messages) &&\n typeof record.id !== 'string'\n ) {\n throw invalidRequest(`action='${action}' requires 'id'.`, 'Call list to see the current ids.');\n }\n return record as RunWorktreeToolParams;\n}\n\nfunction describe(record: WorktreeRecord): string {\n return `${record.id} ${record.branch} ${record.status} ${record.path}`;\n}\n\nfunction text(...lines: readonly string[]): [{ type: 'text'; text: string }] {\n return [{ type: 'text', text: lines.join('\\n') }];\n}\n\nexport async function executeRunWorktreeTool(\n params: RunWorktreeToolParams,\n operations: WorktreeOperations,\n context: RunWorktreeExecutionContext,\n options: RunWorktreeExecutionOptions = {},\n): Promise<RunWorktreeToolResult> {\n switch (params.action) {\n case WORKTREE_ACTIONS.spawn_worktree: {\n const record = await operations.spawn(\n context,\n {\n branch: params.branch,\n ...(params.baseRef === undefined ? {} : { baseRef: params.baseRef }),\n ...(params.name === undefined ? {} : { name: params.name }),\n },\n options,\n );\n return {\n content: text(\n `Worktree ${record.id} created on ${record.branch} from ${record.baseRef}.`,\n `Path: ${record.path}`,\n `Session ${record.sessionId} is starting; it appears nested under this one in the rail.`,\n ),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.close_worktree: {\n const record = await operations.close(context, params.id, params.force ?? false);\n return {\n content: text(`Worktree ${record.id} (${record.branch}) closed and removed.`),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.list: {\n const records = await operations.list(context);\n return {\n content:\n records.length === 0\n ? text('No worktrees for this repository.')\n : text(`${String(records.length)} worktree(s):`, ...records.map(describe)),\n details: { action: params.action, records },\n };\n }\n case WORKTREE_ACTIONS.status: {\n const { record, dirtyFiles } = await operations.status(context, params.id);\n return {\n content: text(\n describe(record),\n `Session: ${record.sessionId}`,\n dirtyFiles.length === 0\n ? 'Clean.'\n : `${String(dirtyFiles.length)} uncommitted file(s): ${dirtyFiles.slice(0, 20).join(', ')}`,\n ),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.merge: {\n const record = await operations.merge(\n context,\n params.id,\n ...(params.message === undefined ? [] : ([params.message] as const)),\n );\n return {\n content: text(`Merged ${record.branch} into this checkout.`),\n details: { action: params.action, records: [record] },\n };\n }\n case WORKTREE_ACTIONS.send: {\n await operations.send(context, params.id, params.message);\n return { content: text(`Message sent to worktree ${params.id}.`), details: { action: params.action } };\n }\n case WORKTREE_ACTIONS.messages: {\n const waiting = await operations.messages(context, params.id);\n return {\n content:\n waiting.length === 0\n ? text('No messages.')\n : text(\n `${String(waiting.length)} message(s):`,\n ...waiting.map((entry) => `[${entry.sentAt}] ${entry.from}: ${entry.text}`),\n ),\n details: { action: params.action },\n };\n }\n case WORKTREE_ACTIONS.prune: {\n const dryRun = params.dryRun ?? false;\n const plan = await operations.prune(context, dryRun);\n const lines = [\n dryRun ? 'Prune plan (nothing was changed):' : 'Pruned:',\n `Remove: ${plan.remove.length === 0 ? 'none' : plan.remove.map((record) => record.id).join(', ')}`,\n `Forget: ${plan.forget.length === 0 ? 'none' : plan.forget.map((record) => record.id).join(', ')}`,\n `Kept, uncommitted work: ${plan.keptDirty.length === 0 ? 'none' : plan.keptDirty.map((record) => record.id).join(', ')}`,\n `Untracked directories, left alone: ${plan.untracked.length === 0 ? 'none' : plan.untracked.join(', ')}`,\n ...(plan.keptBranches.length === 0\n ? []\n : [`Branches kept, they hold commits: ${plan.keptBranches.join(', ')}`]),\n ];\n return { content: text(...lines), details: { action: params.action } };\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/services/worktreeEvents/index.ts
|
|
2
|
+
const GIT_WORKTREE_LIFECYCLE_EVENT = "git_worktree_lifecycle";
|
|
3
|
+
const GIT_WORKTREE_MESSAGE_EVENT = "git_worktree_message";
|
|
4
|
+
const MAX_WORKTREE_MESSAGE_BYTES = 65536;
|
|
5
|
+
function isMessageParty(value) {
|
|
6
|
+
return value === "parent" || value === "child";
|
|
7
|
+
}
|
|
8
|
+
function parseMessage(value) {
|
|
9
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
10
|
+
const record = value;
|
|
11
|
+
if (record.version !== 1) return void 0;
|
|
12
|
+
if (typeof record.worktreeId !== "string" || record.worktreeId === "") return void 0;
|
|
13
|
+
if (typeof record.fromSessionId !== "string" || record.fromSessionId === "") return void 0;
|
|
14
|
+
if (!isMessageParty(record.from)) return void 0;
|
|
15
|
+
if (typeof record.text !== "string" || record.text === "") return void 0;
|
|
16
|
+
if (Buffer.byteLength(record.text, "utf8") > 65536) return void 0;
|
|
17
|
+
if (typeof record.sentAt !== "string" || record.sentAt === "") return void 0;
|
|
18
|
+
return record;
|
|
19
|
+
}
|
|
20
|
+
function createWorktreeMessageInbox(directEvents, sessionId) {
|
|
21
|
+
if (sessionId === "") throw new Error("The Git message service requires a session identity.");
|
|
22
|
+
const messages = /* @__PURE__ */ new Map();
|
|
23
|
+
const unsubscribe = directEvents.subscribe(GIT_WORKTREE_MESSAGE_EVENT, sessionId, (payload) => {
|
|
24
|
+
const message = parseMessage(payload);
|
|
25
|
+
if (message === void 0) return;
|
|
26
|
+
const inbox = messages.get(message.worktreeId) ?? [];
|
|
27
|
+
if (inbox.length >= 100) inbox.shift();
|
|
28
|
+
inbox.push(message);
|
|
29
|
+
messages.set(message.worktreeId, inbox);
|
|
30
|
+
});
|
|
31
|
+
let closed = false;
|
|
32
|
+
return {
|
|
33
|
+
send(targetSessionId, message) {
|
|
34
|
+
if (closed) throw new Error("The Git message service is closed.");
|
|
35
|
+
directEvents.publish(GIT_WORKTREE_MESSAGE_EVENT, targetSessionId, message);
|
|
36
|
+
},
|
|
37
|
+
receive(worktreeId) {
|
|
38
|
+
if (closed) return [];
|
|
39
|
+
const inbox = messages.get(worktreeId);
|
|
40
|
+
if (inbox === void 0) return [];
|
|
41
|
+
messages.delete(worktreeId);
|
|
42
|
+
return inbox;
|
|
43
|
+
},
|
|
44
|
+
close() {
|
|
45
|
+
if (closed) return;
|
|
46
|
+
closed = true;
|
|
47
|
+
unsubscribe();
|
|
48
|
+
messages.clear();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function isWorktreeLifecycleEvent(value) {
|
|
53
|
+
if (typeof value !== "object" || value === null) return false;
|
|
54
|
+
const record = value;
|
|
55
|
+
return record.version === 1 && typeof record.repositoryRoot === "string" && record.repositoryRoot !== "";
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
exports.GIT_WORKTREE_LIFECYCLE_EVENT = GIT_WORKTREE_LIFECYCLE_EVENT;
|
|
59
|
+
exports.GIT_WORKTREE_MESSAGE_EVENT = GIT_WORKTREE_MESSAGE_EVENT;
|
|
60
|
+
exports.MAX_WORKTREE_MESSAGE_BYTES = MAX_WORKTREE_MESSAGE_BYTES;
|
|
61
|
+
exports.createWorktreeMessageInbox = createWorktreeMessageInbox;
|
|
62
|
+
exports.isWorktreeLifecycleEvent = isWorktreeLifecycleEvent;
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/services/worktreeEvents/index.ts"],"sourcesContent":["import type { DoomDirectEventBus } from '@agimon-ai/doompi-core/hub-channel';\n\nexport const GIT_WORKTREE_LIFECYCLE_EVENT = 'git_worktree_lifecycle';\nexport const GIT_WORKTREE_MESSAGE_EVENT = 'git_worktree_message';\nexport const WORKTREE_MESSAGE_VERSION = 1 as const;\nexport const MAX_WORKTREE_MESSAGE_BYTES = 64 * 1024;\nexport const MAX_WORKTREE_INBOX_MESSAGES = 100;\n\nexport interface WorktreeLifecycleEvent {\n readonly version: typeof WORKTREE_MESSAGE_VERSION;\n readonly repositoryRoot: string;\n}\n\nexport type WorktreeMessageParty = 'parent' | 'child';\n\nexport interface WorktreeMessage {\n readonly version: typeof WORKTREE_MESSAGE_VERSION;\n readonly worktreeId: string;\n readonly fromSessionId: string;\n readonly from: WorktreeMessageParty;\n readonly text: string;\n readonly sentAt: string;\n}\n\nexport interface WorktreeMessageInbox {\n send(targetSessionId: string, message: WorktreeMessage): void;\n receive(worktreeId: string): WorktreeMessage[];\n close(): void;\n}\n\nfunction isMessageParty(value: unknown): value is WorktreeMessageParty {\n return value === 'parent' || value === 'child';\n}\n\nfunction parseMessage(value: unknown): WorktreeMessage | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const record = value as Partial<WorktreeMessage>;\n if (record.version !== WORKTREE_MESSAGE_VERSION) return undefined;\n if (typeof record.worktreeId !== 'string' || record.worktreeId === '') return undefined;\n if (typeof record.fromSessionId !== 'string' || record.fromSessionId === '') return undefined;\n if (!isMessageParty(record.from)) return undefined;\n if (typeof record.text !== 'string' || record.text === '') return undefined;\n if (Buffer.byteLength(record.text, 'utf8') > MAX_WORKTREE_MESSAGE_BYTES) return undefined;\n if (typeof record.sentAt !== 'string' || record.sentAt === '') return undefined;\n return record as WorktreeMessage;\n}\n\nexport function createWorktreeMessageInbox(directEvents: DoomDirectEventBus, sessionId: string): WorktreeMessageInbox {\n if (sessionId === '') throw new Error('The Git message service requires a session identity.');\n const messages = new Map<string, WorktreeMessage[]>();\n const unsubscribe = directEvents.subscribe(GIT_WORKTREE_MESSAGE_EVENT, sessionId, (payload) => {\n const message = parseMessage(payload);\n if (message === undefined) return;\n const inbox = messages.get(message.worktreeId) ?? [];\n if (inbox.length >= MAX_WORKTREE_INBOX_MESSAGES) inbox.shift();\n inbox.push(message);\n messages.set(message.worktreeId, inbox);\n });\n let closed = false;\n return {\n send(targetSessionId, message) {\n if (closed) throw new Error('The Git message service is closed.');\n directEvents.publish(GIT_WORKTREE_MESSAGE_EVENT, targetSessionId, message);\n },\n receive(worktreeId) {\n if (closed) return [];\n const inbox = messages.get(worktreeId);\n if (inbox === undefined) return [];\n messages.delete(worktreeId);\n return inbox;\n },\n close() {\n if (closed) return;\n closed = true;\n unsubscribe();\n messages.clear();\n },\n };\n}\n\nexport function isWorktreeLifecycleEvent(value: unknown): value is WorktreeLifecycleEvent {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Partial<WorktreeLifecycleEvent>;\n return (\n record.version === WORKTREE_MESSAGE_VERSION &&\n typeof record.repositoryRoot === 'string' &&\n record.repositoryRoot !== ''\n );\n}\n"],"mappings":";AAEA,MAAa,+BAA+B;AAC5C,MAAa,6BAA6B;AAE1C,MAAa,6BAA6B;AAyB1C,SAAS,eAAe,OAA+C;CACrE,OAAO,UAAU,YAAY,UAAU;AACzC;AAEA,SAAS,aAAa,OAA6C;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO,KAAA;CACxD,MAAM,SAAS;CACf,IAAI,OAAO,YAAA,GAAsC,OAAO,KAAA;CACxD,IAAI,OAAO,OAAO,eAAe,YAAY,OAAO,eAAe,IAAI,OAAO,KAAA;CAC9E,IAAI,OAAO,OAAO,kBAAkB,YAAY,OAAO,kBAAkB,IAAI,OAAO,KAAA;CACpF,IAAI,CAAC,eAAe,OAAO,IAAI,GAAG,OAAO,KAAA;CACzC,IAAI,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,IAAI,OAAO,KAAA;CAClE,IAAI,OAAO,WAAW,OAAO,MAAM,MAAM,IAAA,OAAgC,OAAO,KAAA;CAChF,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,WAAW,IAAI,OAAO,KAAA;CACtE,OAAO;AACT;AAEA,SAAgB,2BAA2B,cAAkC,WAAyC;CACpH,IAAI,cAAc,IAAI,MAAM,IAAI,MAAM,sDAAsD;CAC5F,MAAM,2BAAW,IAAI,IAA+B;CACpD,MAAM,cAAc,aAAa,UAAU,4BAA4B,YAAY,YAAY;EAC7F,MAAM,UAAU,aAAa,OAAO;EACpC,IAAI,YAAY,KAAA,GAAW;EAC3B,MAAM,QAAQ,SAAS,IAAI,QAAQ,UAAU,KAAK,CAAC;EACnD,IAAI,MAAM,UAAA,KAAuC,MAAM,MAAM;EAC7D,MAAM,KAAK,OAAO;EAClB,SAAS,IAAI,QAAQ,YAAY,KAAK;CACxC,CAAC;CACD,IAAI,SAAS;CACb,OAAO;EACL,KAAK,iBAAiB,SAAS;GAC7B,IAAI,QAAQ,MAAM,IAAI,MAAM,oCAAoC;GAChE,aAAa,QAAQ,4BAA4B,iBAAiB,OAAO;EAC3E;EACA,QAAQ,YAAY;GAClB,IAAI,QAAQ,OAAO,CAAC;GACpB,MAAM,QAAQ,SAAS,IAAI,UAAU;GACrC,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;GACjC,SAAS,OAAO,UAAU;GAC1B,OAAO;EACT;EACA,QAAQ;GACN,IAAI,QAAQ;GACZ,SAAS;GACT,YAAY;GACZ,SAAS,MAAM;EACjB;CACF;AACF;AAEA,SAAgB,yBAAyB,OAAiD;CACxF,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,SAAS;CACf,OACE,OAAO,YAAA,KACP,OAAO,OAAO,mBAAmB,YACjC,OAAO,mBAAmB;AAE9B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "@agimon-ai/doompi-core/hub-channel";
|
|
2
2
|
//#region src/services/worktreeEvents/index.d.ts
|
|
3
|
-
declare const WORKTREE_MESSAGE_VERSION: 1;
|
|
4
|
-
type WorktreeMessageParty = 'parent' | 'child';
|
|
5
|
-
interface WorktreeMessage {
|
|
3
|
+
export declare const WORKTREE_MESSAGE_VERSION: 1;
|
|
4
|
+
export type WorktreeMessageParty = 'parent' | 'child';
|
|
5
|
+
export interface WorktreeMessage {
|
|
6
6
|
readonly version: typeof WORKTREE_MESSAGE_VERSION;
|
|
7
7
|
readonly worktreeId: string;
|
|
8
8
|
readonly fromSessionId: string;
|
|
@@ -11,5 +11,4 @@ interface WorktreeMessage {
|
|
|
11
11
|
readonly sentAt: string;
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
|
-
export { WORKTREE_MESSAGE_VERSION, WorktreeMessage, WorktreeMessageParty };
|
|
15
14
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../../src/services/worktreeEvents/index.ts"],"mappings":";;qBAIa;YASD;iBAEK;WACN,gBAAgB;WAChB;WACA;WACA,MAAM;WACN;WACA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "@agimon-ai/doompi-core/hub-channel";
|
|
2
2
|
//#region src/services/worktreeEvents/index.d.ts
|
|
3
|
-
declare const WORKTREE_MESSAGE_VERSION: 1;
|
|
4
|
-
type WorktreeMessageParty = 'parent' | 'child';
|
|
5
|
-
interface WorktreeMessage {
|
|
3
|
+
export declare const WORKTREE_MESSAGE_VERSION: 1;
|
|
4
|
+
export type WorktreeMessageParty = 'parent' | 'child';
|
|
5
|
+
export interface WorktreeMessage {
|
|
6
6
|
readonly version: typeof WORKTREE_MESSAGE_VERSION;
|
|
7
7
|
readonly worktreeId: string;
|
|
8
8
|
readonly fromSessionId: string;
|
|
@@ -11,5 +11,4 @@ interface WorktreeMessage {
|
|
|
11
11
|
readonly sentAt: string;
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
|
-
export { WORKTREE_MESSAGE_VERSION, WorktreeMessage, WorktreeMessageParty };
|
|
15
14
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/services/worktreeEvents/index.ts"],"mappings":";;qBAIa;YASD;iBAEK;WACN,gBAAgB;WAChB;WACA;WACA,MAAM;WACN;WACA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//#region src/services/worktreeEvents/index.ts
|
|
2
|
+
const GIT_WORKTREE_LIFECYCLE_EVENT = "git_worktree_lifecycle";
|
|
3
|
+
const GIT_WORKTREE_MESSAGE_EVENT = "git_worktree_message";
|
|
4
|
+
const MAX_WORKTREE_MESSAGE_BYTES = 65536;
|
|
5
|
+
function isMessageParty(value) {
|
|
6
|
+
return value === "parent" || value === "child";
|
|
7
|
+
}
|
|
8
|
+
function parseMessage(value) {
|
|
9
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
10
|
+
const record = value;
|
|
11
|
+
if (record.version !== 1) return void 0;
|
|
12
|
+
if (typeof record.worktreeId !== "string" || record.worktreeId === "") return void 0;
|
|
13
|
+
if (typeof record.fromSessionId !== "string" || record.fromSessionId === "") return void 0;
|
|
14
|
+
if (!isMessageParty(record.from)) return void 0;
|
|
15
|
+
if (typeof record.text !== "string" || record.text === "") return void 0;
|
|
16
|
+
if (Buffer.byteLength(record.text, "utf8") > 65536) return void 0;
|
|
17
|
+
if (typeof record.sentAt !== "string" || record.sentAt === "") return void 0;
|
|
18
|
+
return record;
|
|
19
|
+
}
|
|
20
|
+
function createWorktreeMessageInbox(directEvents, sessionId) {
|
|
21
|
+
if (sessionId === "") throw new Error("The Git message service requires a session identity.");
|
|
22
|
+
const messages = /* @__PURE__ */ new Map();
|
|
23
|
+
const unsubscribe = directEvents.subscribe(GIT_WORKTREE_MESSAGE_EVENT, sessionId, (payload) => {
|
|
24
|
+
const message = parseMessage(payload);
|
|
25
|
+
if (message === void 0) return;
|
|
26
|
+
const inbox = messages.get(message.worktreeId) ?? [];
|
|
27
|
+
if (inbox.length >= 100) inbox.shift();
|
|
28
|
+
inbox.push(message);
|
|
29
|
+
messages.set(message.worktreeId, inbox);
|
|
30
|
+
});
|
|
31
|
+
let closed = false;
|
|
32
|
+
return {
|
|
33
|
+
send(targetSessionId, message) {
|
|
34
|
+
if (closed) throw new Error("The Git message service is closed.");
|
|
35
|
+
directEvents.publish(GIT_WORKTREE_MESSAGE_EVENT, targetSessionId, message);
|
|
36
|
+
},
|
|
37
|
+
receive(worktreeId) {
|
|
38
|
+
if (closed) return [];
|
|
39
|
+
const inbox = messages.get(worktreeId);
|
|
40
|
+
if (inbox === void 0) return [];
|
|
41
|
+
messages.delete(worktreeId);
|
|
42
|
+
return inbox;
|
|
43
|
+
},
|
|
44
|
+
close() {
|
|
45
|
+
if (closed) return;
|
|
46
|
+
closed = true;
|
|
47
|
+
unsubscribe();
|
|
48
|
+
messages.clear();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function isWorktreeLifecycleEvent(value) {
|
|
53
|
+
if (typeof value !== "object" || value === null) return false;
|
|
54
|
+
const record = value;
|
|
55
|
+
return record.version === 1 && typeof record.repositoryRoot === "string" && record.repositoryRoot !== "";
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { GIT_WORKTREE_LIFECYCLE_EVENT, GIT_WORKTREE_MESSAGE_EVENT, MAX_WORKTREE_MESSAGE_BYTES, createWorktreeMessageInbox, isWorktreeLifecycleEvent };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/worktreeEvents/index.ts"],"sourcesContent":["import type { DoomDirectEventBus } from '@agimon-ai/doompi-core/hub-channel';\n\nexport const GIT_WORKTREE_LIFECYCLE_EVENT = 'git_worktree_lifecycle';\nexport const GIT_WORKTREE_MESSAGE_EVENT = 'git_worktree_message';\nexport const WORKTREE_MESSAGE_VERSION = 1 as const;\nexport const MAX_WORKTREE_MESSAGE_BYTES = 64 * 1024;\nexport const MAX_WORKTREE_INBOX_MESSAGES = 100;\n\nexport interface WorktreeLifecycleEvent {\n readonly version: typeof WORKTREE_MESSAGE_VERSION;\n readonly repositoryRoot: string;\n}\n\nexport type WorktreeMessageParty = 'parent' | 'child';\n\nexport interface WorktreeMessage {\n readonly version: typeof WORKTREE_MESSAGE_VERSION;\n readonly worktreeId: string;\n readonly fromSessionId: string;\n readonly from: WorktreeMessageParty;\n readonly text: string;\n readonly sentAt: string;\n}\n\nexport interface WorktreeMessageInbox {\n send(targetSessionId: string, message: WorktreeMessage): void;\n receive(worktreeId: string): WorktreeMessage[];\n close(): void;\n}\n\nfunction isMessageParty(value: unknown): value is WorktreeMessageParty {\n return value === 'parent' || value === 'child';\n}\n\nfunction parseMessage(value: unknown): WorktreeMessage | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const record = value as Partial<WorktreeMessage>;\n if (record.version !== WORKTREE_MESSAGE_VERSION) return undefined;\n if (typeof record.worktreeId !== 'string' || record.worktreeId === '') return undefined;\n if (typeof record.fromSessionId !== 'string' || record.fromSessionId === '') return undefined;\n if (!isMessageParty(record.from)) return undefined;\n if (typeof record.text !== 'string' || record.text === '') return undefined;\n if (Buffer.byteLength(record.text, 'utf8') > MAX_WORKTREE_MESSAGE_BYTES) return undefined;\n if (typeof record.sentAt !== 'string' || record.sentAt === '') return undefined;\n return record as WorktreeMessage;\n}\n\nexport function createWorktreeMessageInbox(directEvents: DoomDirectEventBus, sessionId: string): WorktreeMessageInbox {\n if (sessionId === '') throw new Error('The Git message service requires a session identity.');\n const messages = new Map<string, WorktreeMessage[]>();\n const unsubscribe = directEvents.subscribe(GIT_WORKTREE_MESSAGE_EVENT, sessionId, (payload) => {\n const message = parseMessage(payload);\n if (message === undefined) return;\n const inbox = messages.get(message.worktreeId) ?? [];\n if (inbox.length >= MAX_WORKTREE_INBOX_MESSAGES) inbox.shift();\n inbox.push(message);\n messages.set(message.worktreeId, inbox);\n });\n let closed = false;\n return {\n send(targetSessionId, message) {\n if (closed) throw new Error('The Git message service is closed.');\n directEvents.publish(GIT_WORKTREE_MESSAGE_EVENT, targetSessionId, message);\n },\n receive(worktreeId) {\n if (closed) return [];\n const inbox = messages.get(worktreeId);\n if (inbox === undefined) return [];\n messages.delete(worktreeId);\n return inbox;\n },\n close() {\n if (closed) return;\n closed = true;\n unsubscribe();\n messages.clear();\n },\n };\n}\n\nexport function isWorktreeLifecycleEvent(value: unknown): value is WorktreeLifecycleEvent {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Partial<WorktreeLifecycleEvent>;\n return (\n record.version === WORKTREE_MESSAGE_VERSION &&\n typeof record.repositoryRoot === 'string' &&\n record.repositoryRoot !== ''\n );\n}\n"],"mappings":";AAEA,MAAa,+BAA+B;AAC5C,MAAa,6BAA6B;AAE1C,MAAa,6BAA6B;AAyB1C,SAAS,eAAe,OAA+C;CACrE,OAAO,UAAU,YAAY,UAAU;AACzC;AAEA,SAAS,aAAa,OAA6C;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO,KAAA;CACxD,MAAM,SAAS;CACf,IAAI,OAAO,YAAA,GAAsC,OAAO,KAAA;CACxD,IAAI,OAAO,OAAO,eAAe,YAAY,OAAO,eAAe,IAAI,OAAO,KAAA;CAC9E,IAAI,OAAO,OAAO,kBAAkB,YAAY,OAAO,kBAAkB,IAAI,OAAO,KAAA;CACpF,IAAI,CAAC,eAAe,OAAO,IAAI,GAAG,OAAO,KAAA;CACzC,IAAI,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,IAAI,OAAO,KAAA;CAClE,IAAI,OAAO,WAAW,OAAO,MAAM,MAAM,IAAA,OAAgC,OAAO,KAAA;CAChF,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,WAAW,IAAI,OAAO,KAAA;CACtE,OAAO;AACT;AAEA,SAAgB,2BAA2B,cAAkC,WAAyC;CACpH,IAAI,cAAc,IAAI,MAAM,IAAI,MAAM,sDAAsD;CAC5F,MAAM,2BAAW,IAAI,IAA+B;CACpD,MAAM,cAAc,aAAa,UAAU,4BAA4B,YAAY,YAAY;EAC7F,MAAM,UAAU,aAAa,OAAO;EACpC,IAAI,YAAY,KAAA,GAAW;EAC3B,MAAM,QAAQ,SAAS,IAAI,QAAQ,UAAU,KAAK,CAAC;EACnD,IAAI,MAAM,UAAA,KAAuC,MAAM,MAAM;EAC7D,MAAM,KAAK,OAAO;EAClB,SAAS,IAAI,QAAQ,YAAY,KAAK;CACxC,CAAC;CACD,IAAI,SAAS;CACb,OAAO;EACL,KAAK,iBAAiB,SAAS;GAC7B,IAAI,QAAQ,MAAM,IAAI,MAAM,oCAAoC;GAChE,aAAa,QAAQ,4BAA4B,iBAAiB,OAAO;EAC3E;EACA,QAAQ,YAAY;GAClB,IAAI,QAAQ,OAAO,CAAC;GACpB,MAAM,QAAQ,SAAS,IAAI,UAAU;GACrC,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;GACjC,SAAS,OAAO,UAAU;GAC1B,OAAO;EACT;EACA,QAAQ;GACN,IAAI,QAAQ;GACZ,SAAS;GACT,YAAY;GACZ,SAAS,MAAM;EACjB;CACF;AACF;AAEA,SAAgB,yBAAyB,OAAiD;CACxF,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,SAAS;CACf,OACE,OAAO,YAAA,KACP,OAAO,OAAO,mBAAmB,YACjC,OAAO,mBAAmB;AAE9B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//#region src/services/worktreeNaming/index.ts
|
|
2
|
+
const MAX_SLUG_LENGTH = 64;
|
|
3
|
+
/**
|
|
4
|
+
* A branch name reduced to one safe path segment.
|
|
5
|
+
*
|
|
6
|
+
* Slashes are the point: `wt/fix-auth` is a perfectly good branch and a
|
|
7
|
+
* terrible directory name, because the nested directory it implies is not the
|
|
8
|
+
* one the worktree lives in.
|
|
9
|
+
*/
|
|
10
|
+
function branchSlug(branch) {
|
|
11
|
+
const slug = branch.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, MAX_SLUG_LENGTH).replace(/-+$/gu, "");
|
|
12
|
+
return slug === "" ? "worktree" : slug;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The directory for one worktree.
|
|
16
|
+
*
|
|
17
|
+
* The short id disambiguates two branches whose slugs collide, such as
|
|
18
|
+
* `feature/x` and `feature_x`, which would otherwise want the same directory.
|
|
19
|
+
*/
|
|
20
|
+
function worktreeDirectory(input) {
|
|
21
|
+
const repository = `${input.repositoryLabel}--${input.repositoryId}`;
|
|
22
|
+
return `${input.worktreesRoot}/${repository}/${branchSlug(input.branch)}--${input.shortId}`;
|
|
23
|
+
}
|
|
24
|
+
/** Why a worktree cannot be created, or undefined when it can. */
|
|
25
|
+
function refuseSpawn(input) {
|
|
26
|
+
if (input.branch.trim() === "") return "A branch name is required.";
|
|
27
|
+
const live = input.existing.find((record) => record.branch === input.branch && record.status !== "orphaned");
|
|
28
|
+
if (live) return `Branch ${input.branch} already has a worktree (${live.id}).`;
|
|
29
|
+
}
|
|
30
|
+
/** Why a worktree cannot be closed, or undefined when it can. */
|
|
31
|
+
function refuseClose(input) {
|
|
32
|
+
if (!input.record) return "No worktree with that id. Call list to see the current ids.";
|
|
33
|
+
if (input.dirtyFiles.length === 0 || input.force) return void 0;
|
|
34
|
+
const names = input.dirtyFiles.slice(0, 10).join(", ");
|
|
35
|
+
const more = input.dirtyFiles.length > 10 ? `, and ${String(input.dirtyFiles.length - 10)} more` : "";
|
|
36
|
+
return `${String(input.dirtyFiles.length)} uncommitted file(s): ${names}${more}. Pass force: true to discard them.`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Marks records whose process or directory is gone as orphaned.
|
|
40
|
+
*
|
|
41
|
+
* Nothing is deleted here. A doompi-git orphan owns a directory that may hold
|
|
42
|
+
* uncommitted work, so losing the record would lose the only pointer to it.
|
|
43
|
+
* Deletion is always a separate, named decision.
|
|
44
|
+
*/
|
|
45
|
+
function reconcile(records, probe) {
|
|
46
|
+
const changed = [];
|
|
47
|
+
return {
|
|
48
|
+
records: records.map((record) => {
|
|
49
|
+
if (record.status === "orphaned") return record;
|
|
50
|
+
if (!(!probe.exists(record.path) || !probe.alive(record))) return record;
|
|
51
|
+
changed.push(record.id);
|
|
52
|
+
return {
|
|
53
|
+
...record,
|
|
54
|
+
status: "orphaned"
|
|
55
|
+
};
|
|
56
|
+
}),
|
|
57
|
+
changed
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What a prune would do, decided before anything is destroyed.
|
|
62
|
+
*
|
|
63
|
+
* Separating the plan from the execution is what makes dryRun honest and lets
|
|
64
|
+
* the destructive half be reviewed on its own.
|
|
65
|
+
*/
|
|
66
|
+
function planPrune(input) {
|
|
67
|
+
const plan = {
|
|
68
|
+
remove: [],
|
|
69
|
+
forget: [],
|
|
70
|
+
untracked: [],
|
|
71
|
+
keptDirty: [],
|
|
72
|
+
keptBranches: []
|
|
73
|
+
};
|
|
74
|
+
const known = new Set(input.records.map((record) => record.path));
|
|
75
|
+
const listed = new Set(input.gitPaths);
|
|
76
|
+
for (const record of input.records) {
|
|
77
|
+
if (record.status !== "orphaned") continue;
|
|
78
|
+
if (!listed.has(record.path)) {
|
|
79
|
+
plan.forget.push(record);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if ((input.dirtyByPath.get(record.path) ?? []).length > 0) {
|
|
83
|
+
plan.keptDirty.push(record);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
plan.remove.push(record);
|
|
87
|
+
}
|
|
88
|
+
for (const path of input.gitPaths) if (path.startsWith(`${input.worktreesRoot}/`) && !known.has(path)) plan.untracked.push(path);
|
|
89
|
+
return plan;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
exports.branchSlug = branchSlug;
|
|
93
|
+
exports.planPrune = planPrune;
|
|
94
|
+
exports.reconcile = reconcile;
|
|
95
|
+
exports.refuseClose = refuseClose;
|
|
96
|
+
exports.refuseSpawn = refuseSpawn;
|
|
97
|
+
exports.worktreeDirectory = worktreeDirectory;
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/services/worktreeNaming/index.ts"],"sourcesContent":["/**\n * Naming and reconciliation rules for worktrees, as pure functions.\n *\n * Everything here is a function of its arguments so the interesting decisions,\n * which are the ones about destroying work, can be tested without a repository\n * or a filesystem.\n */\n\nimport type { WorktreeRecord } from '../../types/worktreeRegistry';\n\nconst MAX_SLUG_LENGTH = 64;\n\n/**\n * A branch name reduced to one safe path segment.\n *\n * Slashes are the point: `wt/fix-auth` is a perfectly good branch and a\n * terrible directory name, because the nested directory it implies is not the\n * one the worktree lives in.\n */\nexport function branchSlug(branch: string): string {\n const slug = branch\n .toLowerCase()\n .replace(/[^a-z0-9]+/gu, '-')\n .replace(/^-+|-+$/gu, '')\n .slice(0, MAX_SLUG_LENGTH)\n .replace(/-+$/gu, '');\n return slug === '' ? 'worktree' : slug;\n}\n\n/**\n * The directory for one worktree.\n *\n * The short id disambiguates two branches whose slugs collide, such as\n * `feature/x` and `feature_x`, which would otherwise want the same directory.\n */\nexport function worktreeDirectory(input: {\n worktreesRoot: string;\n repositoryLabel: string;\n repositoryId: string;\n branch: string;\n shortId: string;\n}): string {\n const repository = `${input.repositoryLabel}--${input.repositoryId}`;\n return `${input.worktreesRoot}/${repository}/${branchSlug(input.branch)}--${input.shortId}`;\n}\n\n/** Why a worktree cannot be created, or undefined when it can. */\nexport function refuseSpawn(input: { branch: string; existing: readonly WorktreeRecord[] }): string | undefined {\n if (input.branch.trim() === '') return 'A branch name is required.';\n // Git refuses a second worktree on one branch, but its message names a path\n // the caller never chose, so this says it in the caller's own terms first.\n const live = input.existing.find((record) => record.branch === input.branch && record.status !== 'orphaned');\n if (live) return `Branch ${input.branch} already has a worktree (${live.id}).`;\n return undefined;\n}\n\n/** Why a worktree cannot be closed, or undefined when it can. */\nexport function refuseClose(input: {\n record: WorktreeRecord | undefined;\n dirtyFiles: readonly string[];\n force: boolean;\n}): string | undefined {\n if (!input.record) return 'No worktree with that id. Call list to see the current ids.';\n if (input.dirtyFiles.length === 0 || input.force) return undefined;\n // Naming the files is the point: \"the tree is dirty\" sends the reader to go\n // look, and the answer is usually a file they forgot rather than one they\n // meant to keep.\n const names = input.dirtyFiles.slice(0, 10).join(', ');\n const more = input.dirtyFiles.length > 10 ? `, and ${String(input.dirtyFiles.length - 10)} more` : '';\n return `${String(input.dirtyFiles.length)} uncommitted file(s): ${names}${more}. Pass force: true to discard them.`;\n}\n\nexport interface Reconciliation {\n records: WorktreeRecord[];\n /** Ids whose status changed, so a caller can report what it noticed. */\n changed: string[];\n}\n\n/**\n * Marks records whose process or directory is gone as orphaned.\n *\n * Nothing is deleted here. A doompi-git orphan owns a directory that may hold\n * uncommitted work, so losing the record would lose the only pointer to it.\n * Deletion is always a separate, named decision.\n */\nexport function reconcile(\n records: readonly WorktreeRecord[],\n probe: { alive: (record: WorktreeRecord) => boolean; exists: (path: string) => boolean },\n): Reconciliation {\n const changed: string[] = [];\n const next = records.map((record) => {\n if (record.status === 'orphaned') return record;\n const gone = !probe.exists(record.path) || !probe.alive(record);\n if (!gone) return record;\n changed.push(record.id);\n return { ...record, status: 'orphaned' as const };\n });\n return { records: next, changed };\n}\n\nexport interface PrunePlan {\n /** Orphans whose directory git still lists, safe to remove. */\n remove: WorktreeRecord[];\n /** Orphans whose directory is already gone; drop the record only. */\n forget: WorktreeRecord[];\n /** Paths git lists under our root that we have no record of; report, never touch. */\n untracked: string[];\n /** Orphans left alone because they still hold uncommitted work. */\n keptDirty: WorktreeRecord[];\n /**\n * Branches git refused to delete because they hold commits.\n *\n * Filled by the prune itself, not by the plan: a dry run destroys nothing, so\n * it has nothing to report here and leaves it empty.\n */\n keptBranches: string[];\n}\n\n/**\n * What a prune would do, decided before anything is destroyed.\n *\n * Separating the plan from the execution is what makes dryRun honest and lets\n * the destructive half be reviewed on its own.\n */\nexport function planPrune(input: {\n records: readonly WorktreeRecord[];\n gitPaths: readonly string[];\n worktreesRoot: string;\n dirtyByPath: ReadonlyMap<string, readonly string[]>;\n}): PrunePlan {\n const plan: PrunePlan = { remove: [], forget: [], untracked: [], keptDirty: [], keptBranches: [] };\n const known = new Set(input.records.map((record) => record.path));\n const listed = new Set(input.gitPaths);\n for (const record of input.records) {\n if (record.status !== 'orphaned') continue;\n if (!listed.has(record.path)) {\n plan.forget.push(record);\n continue;\n }\n if ((input.dirtyByPath.get(record.path) ?? []).length > 0) {\n plan.keptDirty.push(record);\n continue;\n }\n plan.remove.push(record);\n }\n for (const path of input.gitPaths) {\n // Only ever inside our own root: a worktree the user made by hand is none\n // of this package's business, even when it looks abandoned.\n if (path.startsWith(`${input.worktreesRoot}/`) && !known.has(path)) plan.untracked.push(path);\n }\n return plan;\n}\n"],"mappings":";AAUA,MAAM,kBAAkB;;;;;;;;AASxB,SAAgB,WAAW,QAAwB;CACjD,MAAM,OAAO,OACV,YAAY,CAAC,CACb,QAAQ,gBAAgB,GAAG,CAAC,CAC5B,QAAQ,aAAa,EAAE,CAAC,CACxB,MAAM,GAAG,eAAe,CAAC,CACzB,QAAQ,SAAS,EAAE;CACtB,OAAO,SAAS,KAAK,aAAa;AACpC;;;;;;;AAQA,SAAgB,kBAAkB,OAMvB;CACT,MAAM,aAAa,GAAG,MAAM,gBAAgB,IAAI,MAAM;CACtD,OAAO,GAAG,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,MAAM,MAAM,EAAE,IAAI,MAAM;AACpF;;AAGA,SAAgB,YAAY,OAAoF;CAC9G,IAAI,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO;CAGvC,MAAM,OAAO,MAAM,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM,UAAU,OAAO,WAAW,UAAU;CAC3G,IAAI,MAAM,OAAO,UAAU,MAAM,OAAO,2BAA2B,KAAK,GAAG;AAE7E;;AAGA,SAAgB,YAAY,OAIL;CACrB,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,IAAI,MAAM,WAAW,WAAW,KAAK,MAAM,OAAO,OAAO,KAAA;CAIzD,MAAM,QAAQ,MAAM,WAAW,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,IAAI;CACrD,MAAM,OAAO,MAAM,WAAW,SAAS,KAAK,SAAS,OAAO,MAAM,WAAW,SAAS,EAAE,EAAE,SAAS;CACnG,OAAO,GAAG,OAAO,MAAM,WAAW,MAAM,EAAE,wBAAwB,QAAQ,KAAK;AACjF;;;;;;;;AAeA,SAAgB,UACd,SACA,OACgB;CAChB,MAAM,UAAoB,CAAC;CAQ3B,OAAO;EAAE,SAPI,QAAQ,KAAK,WAAW;GACnC,IAAI,OAAO,WAAW,YAAY,OAAO;GAEzC,IAAI,EADS,CAAC,MAAM,OAAO,OAAO,IAAI,KAAK,CAAC,MAAM,MAAM,MAAM,IACnD,OAAO;GAClB,QAAQ,KAAK,OAAO,EAAE;GACtB,OAAO;IAAE,GAAG;IAAQ,QAAQ;GAAoB;EAClD,CACqB;EAAG;CAAQ;AAClC;;;;;;;AA0BA,SAAgB,UAAU,OAKZ;CACZ,MAAM,OAAkB;EAAE,QAAQ,CAAC;EAAG,QAAQ,CAAC;EAAG,WAAW,CAAC;EAAG,WAAW,CAAC;EAAG,cAAc,CAAC;CAAE;CACjG,MAAM,QAAQ,IAAI,IAAI,MAAM,QAAQ,KAAK,WAAW,OAAO,IAAI,CAAC;CAChE,MAAM,SAAS,IAAI,IAAI,MAAM,QAAQ;CACrC,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,IAAI,OAAO,WAAW,YAAY;EAClC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,GAAG;GAC5B,KAAK,OAAO,KAAK,MAAM;GACvB;EACF;EACA,KAAK,MAAM,YAAY,IAAI,OAAO,IAAI,KAAK,CAAC,EAAA,CAAG,SAAS,GAAG;GACzD,KAAK,UAAU,KAAK,MAAM;GAC1B;EACF;EACA,KAAK,OAAO,KAAK,MAAM;CACzB;CACA,KAAK,MAAM,QAAQ,MAAM,UAGvB,IAAI,KAAK,WAAW,GAAG,MAAM,cAAc,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI,GAAG,KAAK,UAAU,KAAK,IAAI;CAE9F,OAAO;AACT"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorktreeRecord } from "../../types/worktreeRegistry.cjs";
|
|
2
2
|
//#region src/services/worktreeNaming/index.d.ts
|
|
3
|
-
interface PrunePlan {
|
|
3
|
+
export interface PrunePlan {
|
|
4
4
|
/** Orphans whose directory git still lists, safe to remove. */
|
|
5
5
|
remove: WorktreeRecord[];
|
|
6
6
|
/** Orphans whose directory is already gone; drop the record only. */
|
|
@@ -23,12 +23,11 @@ interface PrunePlan {
|
|
|
23
23
|
* Separating the plan from the execution is what makes dryRun honest and lets
|
|
24
24
|
* the destructive half be reviewed on its own.
|
|
25
25
|
*/
|
|
26
|
-
declare function planPrune(input: {
|
|
26
|
+
export declare function planPrune(input: {
|
|
27
27
|
records: readonly WorktreeRecord[];
|
|
28
28
|
gitPaths: readonly string[];
|
|
29
29
|
worktreesRoot: string;
|
|
30
30
|
dirtyByPath: ReadonlyMap<string, readonly string[]>;
|
|
31
31
|
}): PrunePlan;
|
|
32
32
|
//#endregion
|
|
33
|
-
export { PrunePlan, planPrune };
|
|
34
33
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../../src/services/worktreeNaming/index.ts"],"mappings":";;iBAoGiB;;EAEf,QAAQ;;EAER,QAAQ;;EAER;;EAEA,WAAW;;;;;;;EAOX;;;;;;;;wBASc,UAAU;EACxB,kBAAkB;EAClB;EACA;EACA,aAAa;IACX"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorktreeRecord } from "../../types/worktreeRegistry.mjs";
|
|
2
2
|
//#region src/services/worktreeNaming/index.d.ts
|
|
3
|
-
interface PrunePlan {
|
|
3
|
+
export interface PrunePlan {
|
|
4
4
|
/** Orphans whose directory git still lists, safe to remove. */
|
|
5
5
|
remove: WorktreeRecord[];
|
|
6
6
|
/** Orphans whose directory is already gone; drop the record only. */
|
|
@@ -23,12 +23,11 @@ interface PrunePlan {
|
|
|
23
23
|
* Separating the plan from the execution is what makes dryRun honest and lets
|
|
24
24
|
* the destructive half be reviewed on its own.
|
|
25
25
|
*/
|
|
26
|
-
declare function planPrune(input: {
|
|
26
|
+
export declare function planPrune(input: {
|
|
27
27
|
records: readonly WorktreeRecord[];
|
|
28
28
|
gitPaths: readonly string[];
|
|
29
29
|
worktreesRoot: string;
|
|
30
30
|
dirtyByPath: ReadonlyMap<string, readonly string[]>;
|
|
31
31
|
}): PrunePlan;
|
|
32
32
|
//#endregion
|
|
33
|
-
export { PrunePlan, planPrune };
|
|
34
33
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/services/worktreeNaming/index.ts"],"mappings":";;iBAoGiB;;EAEf,QAAQ;;EAER,QAAQ;;EAER;;EAEA,WAAW;;;;;;;EAOX;;;;;;;;wBASc,UAAU;EACxB,kBAAkB;EAClB;EACA;EACA,aAAa;IACX"}
|