@namzu/cli 8.2.0 → 8.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 (76) hide show
  1. package/dist/doctor/checks/credentials.d.ts.map +1 -1
  2. package/dist/doctor/checks/credentials.js +2 -0
  3. package/dist/doctor/checks/credentials.js.map +1 -1
  4. package/dist/integrations/providers/credential-store.d.ts +118 -0
  5. package/dist/integrations/providers/credential-store.d.ts.map +1 -0
  6. package/dist/integrations/providers/credential-store.js +322 -0
  7. package/dist/integrations/providers/credential-store.js.map +1 -0
  8. package/dist/integrations/providers/discover.d.ts +37 -10
  9. package/dist/integrations/providers/discover.d.ts.map +1 -1
  10. package/dist/integrations/providers/discover.js +67 -13
  11. package/dist/integrations/providers/discover.js.map +1 -1
  12. package/dist/integrations/providers/identity.d.ts +75 -0
  13. package/dist/integrations/providers/identity.d.ts.map +1 -0
  14. package/dist/integrations/providers/identity.js +75 -0
  15. package/dist/integrations/providers/identity.js.map +1 -0
  16. package/dist/integrations/providers/index.d.ts +4 -1
  17. package/dist/integrations/providers/index.d.ts.map +1 -1
  18. package/dist/integrations/providers/index.js +4 -1
  19. package/dist/integrations/providers/index.js.map +1 -1
  20. package/dist/integrations/providers/oauth.d.ts +48 -7
  21. package/dist/integrations/providers/oauth.d.ts.map +1 -1
  22. package/dist/integrations/providers/oauth.js +73 -17
  23. package/dist/integrations/providers/oauth.js.map +1 -1
  24. package/dist/integrations/providers/subscription-login.d.ts +123 -0
  25. package/dist/integrations/providers/subscription-login.d.ts.map +1 -0
  26. package/dist/integrations/providers/subscription-login.js +348 -0
  27. package/dist/integrations/providers/subscription-login.js.map +1 -0
  28. package/dist/tui/App.d.ts +1 -17
  29. package/dist/tui/App.d.ts.map +1 -1
  30. package/dist/tui/App.js +185 -49
  31. package/dist/tui/App.js.map +1 -1
  32. package/dist/tui/Markdown.d.ts +14 -0
  33. package/dist/tui/Markdown.d.ts.map +1 -1
  34. package/dist/tui/Markdown.js +31 -4
  35. package/dist/tui/Markdown.js.map +1 -1
  36. package/dist/tui/Picker.js +4 -0
  37. package/dist/tui/Picker.js.map +1 -1
  38. package/dist/tui/Transcript.d.ts +18 -2
  39. package/dist/tui/Transcript.d.ts.map +1 -1
  40. package/dist/tui/Transcript.js +48 -13
  41. package/dist/tui/Transcript.js.map +1 -1
  42. package/dist/tui/agent.d.ts.map +1 -1
  43. package/dist/tui/agent.js +15 -7
  44. package/dist/tui/agent.js.map +1 -1
  45. package/dist/tui/bottom-spacer.d.ts +22 -8
  46. package/dist/tui/bottom-spacer.d.ts.map +1 -1
  47. package/dist/tui/bottom-spacer.js.map +1 -1
  48. package/dist/tui/credential-entry.d.ts +16 -12
  49. package/dist/tui/credential-entry.d.ts.map +1 -1
  50. package/dist/tui/credential-entry.js +16 -12
  51. package/dist/tui/credential-entry.js.map +1 -1
  52. package/dist/tui/live-window.d.ts +97 -0
  53. package/dist/tui/live-window.d.ts.map +1 -0
  54. package/dist/tui/live-window.js +140 -0
  55. package/dist/tui/live-window.js.map +1 -0
  56. package/dist/tui/login-prompt.d.ts +41 -0
  57. package/dist/tui/login-prompt.d.ts.map +1 -0
  58. package/dist/tui/login-prompt.js +69 -0
  59. package/dist/tui/login-prompt.js.map +1 -0
  60. package/dist/tui/markdown-block-cache.d.ts +57 -0
  61. package/dist/tui/markdown-block-cache.d.ts.map +1 -0
  62. package/dist/tui/markdown-block-cache.js +74 -0
  63. package/dist/tui/markdown-block-cache.js.map +1 -0
  64. package/dist/tui/markdownParser.d.ts +33 -0
  65. package/dist/tui/markdownParser.d.ts.map +1 -1
  66. package/dist/tui/markdownParser.js +124 -54
  67. package/dist/tui/markdownParser.js.map +1 -1
  68. package/dist/tui/open-browser.d.ts +24 -0
  69. package/dist/tui/open-browser.d.ts.map +1 -0
  70. package/dist/tui/open-browser.js +57 -0
  71. package/dist/tui/open-browser.js.map +1 -0
  72. package/dist/tui/slashCommands.d.ts +16 -0
  73. package/dist/tui/slashCommands.d.ts.map +1 -1
  74. package/dist/tui/slashCommands.js +13 -0
  75. package/dist/tui/slashCommands.js.map +1 -1
  76. package/package.json +3 -3
@@ -7,19 +7,23 @@
7
7
  *
8
8
  * ## Why session-only, stated as a decision rather than a limitation
9
9
  *
10
- * The obvious durable home is the OS keychain, and here it does not exist. The
11
- * keychain helper in this package is macOS-only, and it reads and writes a
12
- * DIFFERENT product's credential store — namzu borrows an OAuth token from it.
13
- * Writing a namzu key into that envelope would put our secret under their name.
14
- * On Windows, which is where this was asked for, there is no keychain path at
15
- * all.
10
+ * A durable store now exists next door (`credential-store.ts`), and this path
11
+ * still does not use it — which is the interesting part, because the original
12
+ * reason for session-only was that no such store had been written.
16
13
  *
17
- * So the durable options were a plaintext file or a per-platform credential
18
- * store nobody has written. Keeping the key in memory for the session is the
19
- * honest third answer: nothing lands on disk, it works everywhere, and the
20
- * screen names the environment variable that makes it durable. A secret at rest
21
- * should be something the operator chose, not something that arrived because
22
- * they typed into a text field.
14
+ * That reason is gone; the decision is not, and it rests on the one thing the
15
+ * two paths do not share. `/login` OBTAINS a credential: the operator asked for
16
+ * one, namzu got it, and namzu can refresh it, name where it came from, and
17
+ * remove it again. A key typed here arrived from somewhere namzu had no part
18
+ * in — there is nothing to refresh it with, no origin to report, and no
19
+ * meaningful way to revoke it on the operator's behalf. Writing that to disk
20
+ * uninvited would be namzu deciding, for someone else, that their secret should
21
+ * persist.
22
+ *
23
+ * So the key stays in memory: nothing lands on disk, it works everywhere, and
24
+ * the screen names the environment variable that makes it durable. A secret at
25
+ * rest should be something the operator chose, not something that arrived
26
+ * because they typed into a text field — and now there are two ways to choose.
23
27
  *
24
28
  * Everything decidable lives here rather than in the component, because this
25
29
  * package has no component tests and a secret is the worst thing to leave
@@ -1 +1 @@
1
- {"version":3,"file":"credential-entry.d.ts","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAE1B,MAAM,oCAAoC,CAAA;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,oBAAoB,CAAA;AAE7D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAG5F;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAmBxF;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,qBAAqB,EAC5B,YAAY,EAAE,YAAY,EAC1B,IAAI,GAAE,cAA0B,GAC9B,MAAM,CAmCR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAQ7F"}
1
+ {"version":3,"file":"credential-entry.d.ts","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAE1B,MAAM,oCAAoC,CAAA;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,oBAAoB,CAAA;AAE7D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAG5F;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAmBxF;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,qBAAqB,EAC5B,YAAY,EAAE,YAAY,EAC1B,IAAI,GAAE,cAA0B,GAC9B,MAAM,CAmCR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAQ7F"}
@@ -7,19 +7,23 @@
7
7
  *
8
8
  * ## Why session-only, stated as a decision rather than a limitation
9
9
  *
10
- * The obvious durable home is the OS keychain, and here it does not exist. The
11
- * keychain helper in this package is macOS-only, and it reads and writes a
12
- * DIFFERENT product's credential store — namzu borrows an OAuth token from it.
13
- * Writing a namzu key into that envelope would put our secret under their name.
14
- * On Windows, which is where this was asked for, there is no keychain path at
15
- * all.
10
+ * A durable store now exists next door (`credential-store.ts`), and this path
11
+ * still does not use it — which is the interesting part, because the original
12
+ * reason for session-only was that no such store had been written.
16
13
  *
17
- * So the durable options were a plaintext file or a per-platform credential
18
- * store nobody has written. Keeping the key in memory for the session is the
19
- * honest third answer: nothing lands on disk, it works everywhere, and the
20
- * screen names the environment variable that makes it durable. A secret at rest
21
- * should be something the operator chose, not something that arrived because
22
- * they typed into a text field.
14
+ * That reason is gone; the decision is not, and it rests on the one thing the
15
+ * two paths do not share. `/login` OBTAINS a credential: the operator asked for
16
+ * one, namzu got it, and namzu can refresh it, name where it came from, and
17
+ * remove it again. A key typed here arrived from somewhere namzu had no part
18
+ * in — there is nothing to refresh it with, no origin to report, and no
19
+ * meaningful way to revoke it on the operator's behalf. Writing that to disk
20
+ * uninvited would be namzu deciding, for someone else, that their secret should
21
+ * persist.
22
+ *
23
+ * So the key stays in memory: nothing lands on disk, it works everywhere, and
24
+ * the screen names the environment variable that makes it durable. A secret at
25
+ * rest should be something the operator chose, not something that arrived
26
+ * because they typed into a text field — and now there are two ways to choose.
23
27
  *
24
28
  * Everything decidable lives here rather than in the component, because this
25
29
  * package has no component tests and a secret is the worst thing to leave
@@ -1 +1 @@
1
- {"version":3,"file":"credential-entry.js","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"credential-entry.js","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * How much of the transcript is still ALIVE — redrawable — and how much has
3
+ * already been handed to the terminal's own scrollback.
4
+ *
5
+ * ## Why there is a window at all
6
+ *
7
+ * Every finalized row used to go straight into `<Static>`, which prints a row
8
+ * once and never redraws it. That kept per-frame work bounded, and it also made
9
+ * changing a row that is already on screen impossible by construction: an
10
+ * expand key could not reopen a collapsed body, so expansion had to become a
11
+ * command that appends a second copy of the output further down.
12
+ *
13
+ * A small window of the most recent rows is kept live instead. Inside it a row
14
+ * can be redrawn in place, so expansion works where an operator actually looks;
15
+ * `/expand <n>` remains the way to reach anything older, and the hint under a
16
+ * collapsed body already degrades correctly when a row has no number.
17
+ *
18
+ * ## Why the window is bounded by HEIGHT, not by a count of rows
19
+ *
20
+ * This is the constraint the whole design turns on, and it is a property of the
21
+ * renderer rather than a preference. When the live region's height reaches the
22
+ * viewport's, ink stops doing an incremental repaint and instead writes
23
+ * `clearTerminal` followed by **the entire static output it has accumulated
24
+ * this session** plus the frame. On a long session that is the whole transcript,
25
+ * re-serialized on every spinner tick — which is the allocation churn that
26
+ * pushed `<Static>` to swallow everything in the first place.
27
+ *
28
+ * So the window takes rows from the end only while their estimated height fits
29
+ * a budget the live furniture and a safety margin are already subtracted from.
30
+ * A single row taller than the budget leaves the window empty, and an empty
31
+ * window is exactly the previous behaviour — the failure direction is "no
32
+ * retroactive expansion", never "repaint the session".
33
+ *
34
+ * ## Why it only ever moves one way
35
+ *
36
+ * `settled` is a floor the caller carries between renders. `<Static>` keeps an
37
+ * index of how many items it has emitted and renders only what is past it, so a
38
+ * shrinking item list would leave rows unprinted; and a row that has already
39
+ * been drawn live must not be handed back to a mechanism that would print it
40
+ * again. Rows therefore leave the window in one direction, oldest first, and a
41
+ * row that has settled never comes back.
42
+ */
43
+ import type { TranscriptMessage } from './types.js';
44
+ /**
45
+ * The most rows the window will ever hold, whatever the terminal's height.
46
+ *
47
+ * A cap on top of the height budget, because the budget alone would put thirty
48
+ * short rows in the live region on a tall terminal — thirty rows re-laid-out
49
+ * per spinner tick to make retroactive expansion available on output nobody is
50
+ * still looking at. Six covers what an operator is working with: a tool call,
51
+ * its result, and the exchange around them.
52
+ */
53
+ export declare const MAX_LIVE_ROWS = 6;
54
+ export interface LiveWindowInput {
55
+ /** Finalized rows, oldest first. The pending row is not one of these. */
56
+ readonly messages: readonly TranscriptMessage[];
57
+ /** Terminal height. `undefined` when not a TTY. */
58
+ readonly rows: number | undefined;
59
+ /** Terminal width, for wrapping. `undefined` falls back to 80. */
60
+ readonly columns: number | undefined;
61
+ /** Rows the live region occupies apart from the window: activity, composer, status bar. */
62
+ readonly furnitureRows: number;
63
+ /** How many rows have already settled into scrollback. The window never reaches back past this. */
64
+ readonly settled: number;
65
+ }
66
+ export interface LiveWindow {
67
+ /** `messages[0, settled)` are in scrollback; the rest are drawn live. */
68
+ readonly settled: number;
69
+ /** The live rows' estimated height, for the bottom spacer to account for. */
70
+ readonly rows: number;
71
+ }
72
+ /**
73
+ * Every line the finalized transcript will print, for a height estimate.
74
+ *
75
+ * Exported so the wiring is testable rather than only typecheckable. The
76
+ * spacer's own docblock states the asymmetry it depends on: over-count the
77
+ * content and the composer merely floats, under-count it and the composer is
78
+ * pushed off the bottom. The caller used to pass each row's `content` alone,
79
+ * which counted a six-line collapsed tool body as nothing at all — the estimate
80
+ * ran low by six per tool call, in the direction that costs the usability
81
+ * rather than the feature. `/expand` makes it acute: a row whose entire
82
+ * substance is a two-hundred-line body would have been handed over as one line.
83
+ *
84
+ * A pending row is excluded because it is not in the static log yet; the
85
+ * spacer's `liveRows` covers the live region.
86
+ */
87
+ export declare function transcriptLines(messages: readonly TranscriptMessage[]): readonly string[];
88
+ /**
89
+ * How much of the transcript stays live, given the room there is for it.
90
+ *
91
+ * Returns `settled === messages.length` — everything in scrollback, nothing
92
+ * redrawable — whenever the answer is not knowable: no TTY, an implausible
93
+ * height, or a most-recent row too tall to hold. That is the previous
94
+ * behaviour, and it is the safe direction.
95
+ */
96
+ export declare function liveWindow(input: LiveWindowInput): LiveWindow;
97
+ //# sourceMappingURL=live-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-window.d.ts","sourceRoot":"","sources":["../../src/tui/live-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B,MAAM,WAAW,eAAe;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,mGAAmG;IACnG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,UAAU;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACrB;AAmBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,SAAS,MAAM,EAAE,CAGzF;AA4BD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CAmB7D"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * How much of the transcript is still ALIVE — redrawable — and how much has
3
+ * already been handed to the terminal's own scrollback.
4
+ *
5
+ * ## Why there is a window at all
6
+ *
7
+ * Every finalized row used to go straight into `<Static>`, which prints a row
8
+ * once and never redraws it. That kept per-frame work bounded, and it also made
9
+ * changing a row that is already on screen impossible by construction: an
10
+ * expand key could not reopen a collapsed body, so expansion had to become a
11
+ * command that appends a second copy of the output further down.
12
+ *
13
+ * A small window of the most recent rows is kept live instead. Inside it a row
14
+ * can be redrawn in place, so expansion works where an operator actually looks;
15
+ * `/expand <n>` remains the way to reach anything older, and the hint under a
16
+ * collapsed body already degrades correctly when a row has no number.
17
+ *
18
+ * ## Why the window is bounded by HEIGHT, not by a count of rows
19
+ *
20
+ * This is the constraint the whole design turns on, and it is a property of the
21
+ * renderer rather than a preference. When the live region's height reaches the
22
+ * viewport's, ink stops doing an incremental repaint and instead writes
23
+ * `clearTerminal` followed by **the entire static output it has accumulated
24
+ * this session** plus the frame. On a long session that is the whole transcript,
25
+ * re-serialized on every spinner tick — which is the allocation churn that
26
+ * pushed `<Static>` to swallow everything in the first place.
27
+ *
28
+ * So the window takes rows from the end only while their estimated height fits
29
+ * a budget the live furniture and a safety margin are already subtracted from.
30
+ * A single row taller than the budget leaves the window empty, and an empty
31
+ * window is exactly the previous behaviour — the failure direction is "no
32
+ * retroactive expansion", never "repaint the session".
33
+ *
34
+ * ## Why it only ever moves one way
35
+ *
36
+ * `settled` is a floor the caller carries between renders. `<Static>` keeps an
37
+ * index of how many items it has emitted and renders only what is past it, so a
38
+ * shrinking item list would leave rows unprinted; and a row that has already
39
+ * been drawn live must not be handed back to a mechanism that would print it
40
+ * again. Rows therefore leave the window in one direction, oldest first, and a
41
+ * row that has settled never comes back.
42
+ */
43
+ import { renderedDetailLines } from './Transcript.js';
44
+ import { SAFETY_ROWS, estimateRenderedLines } from './bottom-spacer.js';
45
+ /**
46
+ * The most rows the window will ever hold, whatever the terminal's height.
47
+ *
48
+ * A cap on top of the height budget, because the budget alone would put thirty
49
+ * short rows in the live region on a tall terminal — thirty rows re-laid-out
50
+ * per spinner tick to make retroactive expansion available on output nobody is
51
+ * still looking at. Six covers what an operator is working with: a tool call,
52
+ * its result, and the exchange around them.
53
+ */
54
+ export const MAX_LIVE_ROWS = 6;
55
+ /**
56
+ * Every line one row will print, including the body under a tool call.
57
+ *
58
+ * The blank row `MessageRow` puts above every entry but the first and the `⎿`
59
+ * result rows is counted, because one row per entry is not negligible: forty
60
+ * entries is forty rows, which on most terminals is the whole viewport. The
61
+ * content is indented by the two-column glyph gutter it renders beside, so a
62
+ * long line is measured against the width it actually has.
63
+ */
64
+ function messageLines(message, hasPrev) {
65
+ return [
66
+ ...(hasPrev && message.glyph !== '⎿' ? [''] : []),
67
+ ` ${message.content}`,
68
+ ...renderedDetailLines(message),
69
+ ];
70
+ }
71
+ /**
72
+ * Every line the finalized transcript will print, for a height estimate.
73
+ *
74
+ * Exported so the wiring is testable rather than only typecheckable. The
75
+ * spacer's own docblock states the asymmetry it depends on: over-count the
76
+ * content and the composer merely floats, under-count it and the composer is
77
+ * pushed off the bottom. The caller used to pass each row's `content` alone,
78
+ * which counted a six-line collapsed tool body as nothing at all — the estimate
79
+ * ran low by six per tool call, in the direction that costs the usability
80
+ * rather than the feature. `/expand` makes it acute: a row whose entire
81
+ * substance is a two-hundred-line body would have been handed over as one line.
82
+ *
83
+ * A pending row is excluded because it is not in the static log yet; the
84
+ * spacer's `liveRows` covers the live region.
85
+ */
86
+ export function transcriptLines(messages) {
87
+ const finalized = messages.filter((m) => !m.pending);
88
+ return finalized.flatMap((message, i) => messageLines(message, i > 0));
89
+ }
90
+ /**
91
+ * Rows added to each windowed row's estimate.
92
+ *
93
+ * `estimateRenderedLines` is deliberately an UNDER-count, because for the
94
+ * bottom spacer counting low leaves more apparent room and the safety margin
95
+ * absorbs the difference. Here the asymmetry runs the other way: under-count a
96
+ * live row and the window takes more of the viewport than it was budgeted, and
97
+ * the price of exceeding the viewport is the whole-session repaint this window
98
+ * exists to stay clear of. Over-count and the window merely holds one row
99
+ * fewer.
100
+ *
101
+ * Two per row covers what the line estimate cannot see — the rule a code block
102
+ * draws around itself, the blank line markdown puts between blocks — without
103
+ * needing to model any of it.
104
+ */
105
+ const ROW_HEIGHT_ALLOWANCE = 2;
106
+ /** How tall one row is expected to render, rounded UP. */
107
+ function messageHeight(message, hasPrev, columns) {
108
+ return estimateRenderedLines(messageLines(message, hasPrev), columns) + ROW_HEIGHT_ALLOWANCE;
109
+ }
110
+ /**
111
+ * How much of the transcript stays live, given the room there is for it.
112
+ *
113
+ * Returns `settled === messages.length` — everything in scrollback, nothing
114
+ * redrawable — whenever the answer is not knowable: no TTY, an implausible
115
+ * height, or a most-recent row too tall to hold. That is the previous
116
+ * behaviour, and it is the safe direction.
117
+ */
118
+ export function liveWindow(input) {
119
+ const { messages, rows, columns, furnitureRows, settled } = input;
120
+ const floor = Math.min(Math.max(settled, 0), messages.length);
121
+ if (rows === undefined || !Number.isFinite(rows))
122
+ return { settled: messages.length, rows: 0 };
123
+ const budget = rows - furnitureRows - SAFETY_ROWS;
124
+ if (budget < 1)
125
+ return { settled: messages.length, rows: 0 };
126
+ let height = 0;
127
+ let held = 0;
128
+ for (let i = messages.length - 1; i >= floor && held < MAX_LIVE_ROWS; i--) {
129
+ const message = messages[i];
130
+ if (!message)
131
+ break;
132
+ const next = height + messageHeight(message, i > 0, columns);
133
+ if (next > budget)
134
+ break;
135
+ height = next;
136
+ held += 1;
137
+ }
138
+ return { settled: messages.length - held, rows: height };
139
+ }
140
+ //# sourceMappingURL=live-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-window.js","sourceRoot":"","sources":["../../src/tui/live-window.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * What namzu says while an operator signs in to their subscription.
3
+ *
4
+ * Every decidable thing lives here rather than in the component, for the
5
+ * reason `credential-entry.ts` gives next door: this package has no component
6
+ * tests, and wording that handles a credential is the worst thing to leave
7
+ * unverifiable. What the component does with these strings is print them.
8
+ *
9
+ * The one rule these functions exist to keep: **an outcome is described by
10
+ * what happened, never by quoting what came back.** A refusal from a token
11
+ * endpoint arrives in a document that can contain a token, so no function
12
+ * here ever receives one — `LoginOutcome.reason` is already sanitised at the
13
+ * protocol layer, and the success arm is handed a path, not a credential.
14
+ */
15
+ import type { LoginOutcome } from '../integrations/providers/index.js';
16
+ /**
17
+ * The screen the operator reads when a sign-in starts.
18
+ *
19
+ * The URL is printed WHATEVER happened with the browser. A launcher that
20
+ * started is not a browser that appeared — no platform reports that — and a
21
+ * message that says "your browser is opening" and nothing else leaves someone
22
+ * on a machine with no browser staring at a line that is simply false.
23
+ */
24
+ export declare function describeLoginStart(start: {
25
+ readonly url: string;
26
+ readonly loopback: boolean;
27
+ readonly browserOpened: boolean;
28
+ }): string;
29
+ /** What the operator reads when the attempt ends, either way. */
30
+ export declare function describeLoginOutcome(outcome: LoginOutcome): string;
31
+ /** What the operator reads after asking namzu to forget the credential. */
32
+ export declare function describeLogout(path: string, removed: boolean): string;
33
+ /**
34
+ * Whether a `/login` argument is an attempt to finish, rather than to start.
35
+ *
36
+ * Bare `/login` starts an attempt; `/login <something>` finishes one. Drawn
37
+ * here rather than in the command so the rule is testable and so the command
38
+ * cannot quietly grow a third meaning.
39
+ */
40
+ export declare function isCompletionArgument(args: readonly string[]): boolean;
41
+ //# sourceMappingURL=login-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-prompt.d.ts","sourceRoot":"","sources":["../../src/tui/login-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEtE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAC/B,GAAG,MAAM,CAmBT;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAUlE;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAIrE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAErE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * What namzu says while an operator signs in to their subscription.
3
+ *
4
+ * Every decidable thing lives here rather than in the component, for the
5
+ * reason `credential-entry.ts` gives next door: this package has no component
6
+ * tests, and wording that handles a credential is the worst thing to leave
7
+ * unverifiable. What the component does with these strings is print them.
8
+ *
9
+ * The one rule these functions exist to keep: **an outcome is described by
10
+ * what happened, never by quoting what came back.** A refusal from a token
11
+ * endpoint arrives in a document that can contain a token, so no function
12
+ * here ever receives one — `LoginOutcome.reason` is already sanitised at the
13
+ * protocol layer, and the success arm is handed a path, not a credential.
14
+ */
15
+ /**
16
+ * The screen the operator reads when a sign-in starts.
17
+ *
18
+ * The URL is printed WHATEVER happened with the browser. A launcher that
19
+ * started is not a browser that appeared — no platform reports that — and a
20
+ * message that says "your browser is opening" and nothing else leaves someone
21
+ * on a machine with no browser staring at a line that is simply false.
22
+ */
23
+ export function describeLoginStart(start) {
24
+ const lines = [
25
+ start.browserOpened
26
+ ? 'Opening your browser to sign in. If nothing opened, or the browser is on another machine, use this address:'
27
+ : 'Open this address to sign in — on this machine, or on any machine you can reach it from:',
28
+ '',
29
+ start.url,
30
+ '',
31
+ ];
32
+ lines.push(start.loopback
33
+ ? 'When the page finishes, namzu will pick it up automatically. If your browser is somewhere this machine cannot be reached from — a container, a remote shell — copy the address it lands on and run:'
34
+ : // Said plainly. The listener is what makes the automatic path work,
35
+ // and an operator who is not told it is missing will sit waiting for
36
+ // something that is never going to happen.
37
+ 'The automatic hand-back is not available in this session (the port is in use, or this environment does not allow listening), so finish it by hand. Copy the address the browser lands on and run:');
38
+ lines.push('', ' /login <the address, or just the code>');
39
+ return lines.join('\n');
40
+ }
41
+ /** What the operator reads when the attempt ends, either way. */
42
+ export function describeLoginOutcome(outcome) {
43
+ if (!outcome.ok) {
44
+ return `${outcome.reason}\n\nRun /login to try again.`;
45
+ }
46
+ return [
47
+ 'Signed in. The credential is stored on this machine, readable only by your account:',
48
+ ` ${outcome.storedAt}`,
49
+ '',
50
+ 'namzu will refresh it as it expires, and will find it again next time it starts. Run /logout to remove it.',
51
+ ].join('\n');
52
+ }
53
+ /** What the operator reads after asking namzu to forget the credential. */
54
+ export function describeLogout(path, removed) {
55
+ return removed
56
+ ? `Removed the stored credential at ${path}. This session keeps working until it ends; the next one will ask you to sign in again.\n\nSigning out here does not revoke anything at the provider — do that in your account settings if you need to.`
57
+ : "There was no stored credential to remove. If namzu is using one, it came from your environment or from another tool on this machine, and neither is namzu's to delete.";
58
+ }
59
+ /**
60
+ * Whether a `/login` argument is an attempt to finish, rather than to start.
61
+ *
62
+ * Bare `/login` starts an attempt; `/login <something>` finishes one. Drawn
63
+ * here rather than in the command so the rule is testable and so the command
64
+ * cannot quietly grow a third meaning.
65
+ */
66
+ export function isCompletionArgument(args) {
67
+ return args.join(' ').trim().length > 0;
68
+ }
69
+ //# sourceMappingURL=login-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-prompt.js","sourceRoot":"","sources":["../../src/tui/login-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAIlC;IACA,MAAM,KAAK,GAAG;QACb,KAAK,CAAC,aAAa;YAClB,CAAC,CAAC,6GAA6G;YAC/G,CAAC,CAAC,0FAA0F;QAC7F,EAAE;QACF,KAAK,CAAC,GAAG;QACT,EAAE;KACF,CAAA;IACD,KAAK,CAAC,IAAI,CACT,KAAK,CAAC,QAAQ;QACb,CAAC,CAAC,qMAAqM;QACvM,CAAC,CAAC,oEAAoE;YACrE,qEAAqE;YACrE,2CAA2C;YAC3C,mMAAmM,CACrM,CAAA;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,0CAA0C,CAAC,CAAA;IAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACxB,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,oBAAoB,CAAC,OAAqB;IACzD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,CAAC,MAAM,8BAA8B,CAAA;IACvD,CAAC;IACD,OAAO;QACN,qFAAqF;QACrF,KAAK,OAAO,CAAC,QAAQ,EAAE;QACvB,EAAE;QACF,4GAA4G;KAC5G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACb,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAgB;IAC5D,OAAO,OAAO;QACb,CAAC,CAAC,oCAAoC,IAAI,yMAAyM;QACnP,CAAC,CAAC,wKAAwK,CAAA;AAC5K,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAuB;IAC3D,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Parse a growing markdown document without re-parsing what has not changed.
3
+ *
4
+ * ## The cost this removes
5
+ *
6
+ * A streaming assistant reply is one message whose text grows by a token at a
7
+ * time, and the row rendering it re-renders on every one of them. Parsing the
8
+ * whole message each time makes the work quadratic in the reply's length: a
9
+ * forty-block answer is parsed forty blocks deep on every token, when
10
+ * thirty-nine of those blocks are byte-for-byte what they were a token ago.
11
+ *
12
+ * So the document is scanned into top-level blocks — cheap, one pass over the
13
+ * lines — and only the blocks that are new are parsed. The rest come back as
14
+ * **the same objects**, which is the half that matters to the renderer:
15
+ * `BlockView` is memoised, so an unchanged block is not re-rendered, not
16
+ * re-split into inline spans, and not turned into fresh elements either.
17
+ *
18
+ * ## Why raw text is a sound key
19
+ *
20
+ * `parseBlock` reads only the segment it is given: nothing in this markdown
21
+ * subset makes one block's meaning depend on another (there are no
22
+ * reference-style link definitions, which is the construct that would). Same
23
+ * segment ⇒ same block, so a hit cannot differ from a fresh parse. The
24
+ * `markdownParser` docblock states that property; it is the contract this file
25
+ * depends on, and it is why there is no "give up on caching when the document
26
+ * contains X" escape hatch here. There is no such X.
27
+ *
28
+ * ## Why the last two blocks are never cached
29
+ *
30
+ * Not for correctness — a key is a whole segment, so a block whose text grows
31
+ * simply misses under its new text and is parsed. It is to keep the cache from
32
+ * accumulating garbage: a block that is still being written passes through
33
+ * every one of its own prefixes, and storing them would put an entry per TOKEN
34
+ * into a structure meant to hold an entry per block. That is the memory the
35
+ * quadratic parse was costing, moved rather than removed.
36
+ *
37
+ * Two, not one, because the block still being written is not always the last
38
+ * segment. A half-typed table row is not yet a table row — `| 1 | 2` has no
39
+ * closing pipe — so it scans as a paragraph of its own, and the table above it
40
+ * becomes the second-to-last segment while still growing a row at a time. One
41
+ * excluded segment would have cached that table once per row, at increasing
42
+ * size. The line being typed can reach back exactly one segment and no further:
43
+ * it can be absorbed by the block above it, and that block is maximal, so there
44
+ * is nothing for it to reach past.
45
+ *
46
+ * The cost of the wider exclusion is one extra parse per block over the life of
47
+ * the message, against a saving of one per block per token.
48
+ */
49
+ import { type MdBlock } from './markdownParser.js';
50
+ export interface BlockCache {
51
+ /** Blocks of `src`, reusing the block objects of unchanged segments. */
52
+ parse(src: string): MdBlock[];
53
+ /** How many segments are being held. One per completed block. */
54
+ readonly size: number;
55
+ }
56
+ export declare function createBlockCache(): BlockCache;
57
+ //# sourceMappingURL=markdown-block-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-block-cache.d.ts","sourceRoot":"","sources":["../../src/tui/markdown-block-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAAE,KAAK,OAAO,EAA0B,MAAM,qBAAqB,CAAA;AAE1E,MAAM,WAAW,UAAU;IAC1B,wEAAwE;IACxE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAqB7C"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Parse a growing markdown document without re-parsing what has not changed.
3
+ *
4
+ * ## The cost this removes
5
+ *
6
+ * A streaming assistant reply is one message whose text grows by a token at a
7
+ * time, and the row rendering it re-renders on every one of them. Parsing the
8
+ * whole message each time makes the work quadratic in the reply's length: a
9
+ * forty-block answer is parsed forty blocks deep on every token, when
10
+ * thirty-nine of those blocks are byte-for-byte what they were a token ago.
11
+ *
12
+ * So the document is scanned into top-level blocks — cheap, one pass over the
13
+ * lines — and only the blocks that are new are parsed. The rest come back as
14
+ * **the same objects**, which is the half that matters to the renderer:
15
+ * `BlockView` is memoised, so an unchanged block is not re-rendered, not
16
+ * re-split into inline spans, and not turned into fresh elements either.
17
+ *
18
+ * ## Why raw text is a sound key
19
+ *
20
+ * `parseBlock` reads only the segment it is given: nothing in this markdown
21
+ * subset makes one block's meaning depend on another (there are no
22
+ * reference-style link definitions, which is the construct that would). Same
23
+ * segment ⇒ same block, so a hit cannot differ from a fresh parse. The
24
+ * `markdownParser` docblock states that property; it is the contract this file
25
+ * depends on, and it is why there is no "give up on caching when the document
26
+ * contains X" escape hatch here. There is no such X.
27
+ *
28
+ * ## Why the last two blocks are never cached
29
+ *
30
+ * Not for correctness — a key is a whole segment, so a block whose text grows
31
+ * simply misses under its new text and is parsed. It is to keep the cache from
32
+ * accumulating garbage: a block that is still being written passes through
33
+ * every one of its own prefixes, and storing them would put an entry per TOKEN
34
+ * into a structure meant to hold an entry per block. That is the memory the
35
+ * quadratic parse was costing, moved rather than removed.
36
+ *
37
+ * Two, not one, because the block still being written is not always the last
38
+ * segment. A half-typed table row is not yet a table row — `| 1 | 2` has no
39
+ * closing pipe — so it scans as a paragraph of its own, and the table above it
40
+ * becomes the second-to-last segment while still growing a row at a time. One
41
+ * excluded segment would have cached that table once per row, at increasing
42
+ * size. The line being typed can reach back exactly one segment and no further:
43
+ * it can be absorbed by the block above it, and that block is maximal, so there
44
+ * is nothing for it to reach past.
45
+ *
46
+ * The cost of the wider exclusion is one extra parse per block over the life of
47
+ * the message, against a saving of one per block per token.
48
+ */
49
+ import { parseBlock, scanBlocks } from './markdownParser.js';
50
+ export function createBlockCache() {
51
+ const blocks = new Map();
52
+ return {
53
+ parse(src) {
54
+ const segments = scanBlocks(src);
55
+ const settled = segments.length - 2;
56
+ return segments.map((segment, i) => {
57
+ // The tail is where the text is still being written, so it is parsed
58
+ // every time and stored never.
59
+ if (i >= settled)
60
+ return parseBlock(segment);
61
+ const hit = blocks.get(segment);
62
+ if (hit)
63
+ return hit;
64
+ const parsed = parseBlock(segment);
65
+ blocks.set(segment, parsed);
66
+ return parsed;
67
+ });
68
+ },
69
+ get size() {
70
+ return blocks.size;
71
+ },
72
+ };
73
+ }
74
+ //# sourceMappingURL=markdown-block-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-block-cache.js","sourceRoot":"","sources":["../../src/tui/markdown-block-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAAgB,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAS1E,MAAM,UAAU,gBAAgB;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAA;IACzC,OAAO;QACN,KAAK,CAAC,GAAW;YAChB,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;YAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;YACnC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;gBAClC,qEAAqE;gBACrE,+BAA+B;gBAC/B,IAAI,CAAC,IAAI,OAAO;oBAAE,OAAO,UAAU,CAAC,OAAO,CAAC,CAAA;gBAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC/B,IAAI,GAAG;oBAAE,OAAO,GAAG,CAAA;gBACnB,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;gBAClC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;gBAC3B,OAAO,MAAM,CAAA;YACd,CAAC,CAAC,CAAA;QACH,CAAC;QACD,IAAI,IAAI;YACP,OAAO,MAAM,CAAC,IAAI,CAAA;QACnB,CAAC;KACD,CAAA;AACF,CAAC"}