wave-code 1.2.0 → 1.4.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 (64) hide show
  1. package/dist/bundle/wave.mjs +1738 -893
  2. package/package.json +6 -3
  3. package/src/cli.tsx +9 -0
  4. package/src/commands/plugin/install.ts +6 -7
  5. package/src/commands/plugin/uninstall.ts +11 -5
  6. package/src/commands/update.ts +62 -22
  7. package/src/components/BackgroundTaskManager.tsx +76 -54
  8. package/src/components/ChatInterface.tsx +1 -0
  9. package/src/components/ConfirmationDetails.tsx +51 -16
  10. package/src/components/ConfirmationSelector.tsx +39 -0
  11. package/src/components/InputBox.tsx +41 -2
  12. package/src/components/Markdown.tsx +21 -8
  13. package/src/components/MarketplaceDetail.tsx +10 -27
  14. package/src/components/MarketplaceView.tsx +17 -3
  15. package/src/components/MessageBlockItem.tsx +0 -6
  16. package/src/components/Notifications.tsx +7 -0
  17. package/src/components/PlanView.tsx +22 -17
  18. package/src/components/PluginManagerShell.tsx +3 -3
  19. package/src/components/PluginManagerTypes.ts +2 -1
  20. package/src/components/ResumeCommand.tsx +84 -0
  21. package/src/components/ScrolledContent.tsx +71 -0
  22. package/src/components/SessionSelector.tsx +184 -6
  23. package/src/components/SessionSelectorFlow.tsx +246 -0
  24. package/src/components/WorkflowManager.tsx +38 -138
  25. package/src/components/WorkflowRunDetail.tsx +193 -0
  26. package/src/constants/commands.ts +24 -0
  27. package/src/contexts/useChat.tsx +517 -155
  28. package/src/daemon/commands.ts +582 -50
  29. package/src/daemon-cli.ts +12 -1
  30. package/src/hooks/useInputManager.ts +20 -0
  31. package/src/hooks/usePluginManager.ts +104 -78
  32. package/src/hooks/useRemoteControl.ts +324 -0
  33. package/src/index.ts +97 -8
  34. package/src/managers/inputHandlers.ts +16 -9
  35. package/src/managers/inputReducer.ts +30 -9
  36. package/src/print-cli.ts +5 -0
  37. package/src/reducers/confirmationReducer.ts +20 -1
  38. package/src/reducers/selectorReducer.ts +3 -0
  39. package/src/reducers/workflowManagerReducer.ts +21 -2
  40. package/src/remote/frameBudget.ts +45 -0
  41. package/src/remote/hostIdentity.ts +128 -0
  42. package/src/remote/messageWindow.ts +97 -0
  43. package/src/remote/notificationCoalescer.ts +174 -0
  44. package/src/remote/relayClient.ts +668 -0
  45. package/src/remote/remoteControlCliHost.ts +391 -0
  46. package/src/remote/remoteControlCommands.ts +197 -0
  47. package/src/remote/remoteControlConfig.ts +334 -0
  48. package/src/remote/remoteControlService.ts +799 -0
  49. package/src/remote/remoteControlSink.ts +77 -0
  50. package/src/remote/remoteNotifications.ts +194 -0
  51. package/src/session-selector-cli.tsx +9 -255
  52. package/src/stdio/agentBridge.ts +1001 -165
  53. package/src/stdio/daemonServer.ts +30 -0
  54. package/src/stdio/jsonRpcConnection.ts +11 -2
  55. package/src/stdio/protocol.ts +14 -106
  56. package/src/stdio/stdioServer.ts +33 -2
  57. package/src/stdio-cli.ts +16 -1
  58. package/src/utils/gitCredentialHelper.ts +106 -0
  59. package/src/utils/logger.ts +5 -2
  60. package/src/utils/rewindCheckpoints.ts +2 -4
  61. package/src/utils/sessionOwnership.ts +62 -0
  62. package/src/utils/workspaceDiff.ts +620 -0
  63. package/src/utils/worktree.ts +97 -0
  64. package/src/components/PlanDisplay.tsx +0 -18
@@ -407,6 +407,103 @@ export interface WorktreeChanges {
407
407
  commits: number;
408
408
  }
409
409
 
410
+ /**
411
+ * The linked worktree a directory sits in, derived from the filesystem only.
412
+ * Same field semantics as `createWorktree`'s result, so a caller can hand it
413
+ * straight to `removeWorktree`.
414
+ */
415
+ export interface DerivedWorktree {
416
+ path: string;
417
+ branch: string;
418
+ repoRoot: string;
419
+ hookBased: boolean;
420
+ }
421
+
422
+ /**
423
+ * Work out whether `sessionDir` **is** a linked git worktree — and which one —
424
+ * without running git.
425
+ *
426
+ * Two callers need this and both need it cheap: `listDaemonSessions` embeds the
427
+ * answer in every session row (the remote page decides from it whether deleting
428
+ * a session also deletes a worktree), and `destroy --removeWorktree` needs the
429
+ * path/branch/repoRoot that `removeWorktree` takes. Shelling out per row is not
430
+ * an option — `listDaemonSessions` runs on every reconnect, snapshot and page
431
+ * open, and a synchronous git call in this process freezes every session it
432
+ * serves (see the note at the top of this file). So the whole derivation is
433
+ * plain fs reads:
434
+ *
435
+ * - `.git` a **directory** in `sessionDir` ⇒ it is the main working tree, not a
436
+ * worktree ⇒ `undefined` (removing it would be removing the repository).
437
+ * - `.git` a **file** ⇒ a linked worktree; the file holds `gitdir: <path>`,
438
+ * which is where that worktree's own HEAD lives.
439
+ * - branch = `<gitdir>/HEAD` (`ref: refs/heads/<name>`); a detached HEAD has no
440
+ * branch, which returns `""` — the same thing `git branch --show-current`
441
+ * says, and `removeWorktree` skips a branch it cannot name.
442
+ * - repoRoot = the main repository root, i.e. the directory *above* the common
443
+ * git dir that `<gitdir>/commondir` points at (`<repoRoot>/.git`).
444
+ *
445
+ * `sessionDir` must be the worktree root itself (the directory a session was
446
+ * created in) — a subdirectory of a worktree has no `.git` of its own, and this
447
+ * returns `undefined` for it rather than guessing. Every failure path returns
448
+ * `undefined`: "not a worktree / cannot tell" is a legitimate answer and must
449
+ * never throw into a caller that is only decorating a list.
450
+ */
451
+ export function deriveWorktreeInfo(
452
+ sessionDir: string,
453
+ ): DerivedWorktree | undefined {
454
+ try {
455
+ if (!sessionDir) return undefined;
456
+ const dir = path.resolve(sessionDir);
457
+ const gitEntry = path.join(dir, ".git");
458
+ if (!fs.statSync(gitEntry).isFile()) return undefined;
459
+
460
+ const prefix = "gitdir: ";
461
+ const content = fs.readFileSync(gitEntry, "utf8").trim();
462
+ if (!content.startsWith(prefix)) return undefined;
463
+ const gitDir = path.resolve(dir, content.substring(prefix.length).trim());
464
+
465
+ let branch = "";
466
+ try {
467
+ const head = fs.readFileSync(path.join(gitDir, "HEAD"), "utf8").trim();
468
+ const refPrefix = "ref: refs/heads/";
469
+ if (head.startsWith(refPrefix)) {
470
+ branch = head.substring(refPrefix.length);
471
+ }
472
+ } catch {
473
+ // Detached/unreadable HEAD: no branch to delete, the worktree is still
474
+ // identifiable.
475
+ }
476
+
477
+ let repoRoot = "";
478
+ try {
479
+ const common = fs
480
+ .readFileSync(path.join(gitDir, "commondir"), "utf8")
481
+ .trim();
482
+ const commonDir = path.resolve(gitDir, common);
483
+ repoRoot =
484
+ path.basename(commonDir) === ".git"
485
+ ? path.dirname(commonDir)
486
+ : commonDir;
487
+ } catch {
488
+ return undefined;
489
+ }
490
+ if (!repoRoot) return undefined;
491
+
492
+ // Hook-based worktrees are removed by the WorktreeRemove hook, never by
493
+ // `git worktree remove` — mirror createWorktree's own hookBased decision
494
+ // (same test `wave daemon destroy --remove-worktree` uses).
495
+ const config = loadMergedWaveConfig(repoRoot);
496
+ return {
497
+ path: dir,
498
+ branch,
499
+ repoRoot,
500
+ hookBased: hasWorktreeCreateHook(config?.hooks),
501
+ };
502
+ } catch {
503
+ return undefined;
504
+ }
505
+ }
506
+
410
507
  /**
411
508
  * Count what deleting a worktree would throw away, so the caller can warn
412
509
  * before it happens. Both counts are best-effort: an unknown base branch (never
@@ -1,18 +0,0 @@
1
- import React from "react";
2
- import { Box } from "ink";
3
- import { Markdown } from "./Markdown.js";
4
-
5
- interface PlanDisplayProps {
6
- plan: string;
7
- isExpanded?: boolean;
8
- }
9
-
10
- export const PlanDisplay: React.FC<PlanDisplayProps> = ({ plan }) => {
11
- return (
12
- <Box flexDirection="column" marginTop={1}>
13
- <Box flexDirection="column">
14
- <Markdown>{plan}</Markdown>
15
- </Box>
16
- </Box>
17
- );
18
- };