@namzu/cli 8.3.0 → 8.5.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.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/login.d.ts +44 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +185 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js +24 -0
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/integrations/providers/oauth.d.ts +14 -3
- package/dist/integrations/providers/oauth.d.ts.map +1 -1
- package/dist/integrations/providers/oauth.js +14 -3
- package/dist/integrations/providers/oauth.js.map +1 -1
- package/dist/tui/App.d.ts +1 -17
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +133 -48
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Markdown.d.ts +14 -0
- package/dist/tui/Markdown.d.ts.map +1 -1
- package/dist/tui/Markdown.js +31 -4
- package/dist/tui/Markdown.js.map +1 -1
- package/dist/tui/Picker.d.ts +14 -1
- package/dist/tui/Picker.d.ts.map +1 -1
- package/dist/tui/Picker.js +12 -3
- package/dist/tui/Picker.js.map +1 -1
- package/dist/tui/Transcript.d.ts +18 -2
- package/dist/tui/Transcript.d.ts.map +1 -1
- package/dist/tui/Transcript.js +48 -13
- package/dist/tui/Transcript.js.map +1 -1
- package/dist/tui/bottom-spacer.d.ts +22 -8
- package/dist/tui/bottom-spacer.d.ts.map +1 -1
- package/dist/tui/bottom-spacer.js.map +1 -1
- package/dist/tui/live-window.d.ts +97 -0
- package/dist/tui/live-window.d.ts.map +1 -0
- package/dist/tui/live-window.js +140 -0
- package/dist/tui/live-window.js.map +1 -0
- package/dist/tui/login-prompt.d.ts +26 -2
- package/dist/tui/login-prompt.d.ts.map +1 -1
- package/dist/tui/login-prompt.js +16 -7
- package/dist/tui/login-prompt.js.map +1 -1
- package/dist/tui/markdown-block-cache.d.ts +57 -0
- package/dist/tui/markdown-block-cache.d.ts.map +1 -0
- package/dist/tui/markdown-block-cache.js +74 -0
- package/dist/tui/markdown-block-cache.js.map +1 -0
- package/dist/tui/markdownParser.d.ts +33 -0
- package/dist/tui/markdownParser.d.ts.map +1 -1
- package/dist/tui/markdownParser.js +124 -54
- package/dist/tui/markdownParser.js.map +1 -1
- package/package.json +3 -3
|
@@ -25,9 +25,33 @@ export declare function describeLoginStart(start: {
|
|
|
25
25
|
readonly url: string;
|
|
26
26
|
readonly loopback: boolean;
|
|
27
27
|
readonly browserOpened: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* How the operator hands the result back HERE, in the surface they are
|
|
30
|
+
* looking at.
|
|
31
|
+
*
|
|
32
|
+
* A parameter because the answer is different in each one — a slash command
|
|
33
|
+
* in the chat, a keypress at the picker, a line of standard input at a bare
|
|
34
|
+
* terminal — and this sentence is the one an operator with no browser
|
|
35
|
+
* follows. Printing the chat's answer on the picker would send them to a
|
|
36
|
+
* composer that is not on screen, which is the defect that made a shipped
|
|
37
|
+
* sign-in unreachable.
|
|
38
|
+
*/
|
|
39
|
+
readonly completionHint?: string;
|
|
40
|
+
}): string;
|
|
41
|
+
/**
|
|
42
|
+
* What the operator reads when the attempt ends, either way.
|
|
43
|
+
*
|
|
44
|
+
* `retryHint` and `removeHint` name the commands as THIS surface spells them,
|
|
45
|
+
* for the same reason `completionHint` exists above. A failed sign-in run from
|
|
46
|
+
* a bare terminal used to end with "Run /login to try again" — a slash command,
|
|
47
|
+
* in a shell, where the thing to type is `namzu login`. Instructions that name
|
|
48
|
+
* another surface's spelling are the defect that made the sign-in unreachable
|
|
49
|
+
* from the picker; it is not any better in an error message.
|
|
50
|
+
*/
|
|
51
|
+
export declare function describeLoginOutcome(outcome: LoginOutcome, hints?: {
|
|
52
|
+
readonly retry?: string;
|
|
53
|
+
readonly remove?: string;
|
|
28
54
|
}): string;
|
|
29
|
-
/** What the operator reads when the attempt ends, either way. */
|
|
30
|
-
export declare function describeLoginOutcome(outcome: LoginOutcome): string;
|
|
31
55
|
/** What the operator reads after asking namzu to forget the credential. */
|
|
32
56
|
export declare function describeLogout(path: string, removed: boolean): string;
|
|
33
57
|
/**
|
|
@@ -1 +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;
|
|
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;IAC/B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAChC,GAAG,MAAM,CAmBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,YAAY,EACrB,KAAK,GAAE;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,MAAM,CAUR;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"}
|
package/dist/tui/login-prompt.js
CHANGED
|
@@ -30,24 +30,33 @@ export function describeLoginStart(start) {
|
|
|
30
30
|
'',
|
|
31
31
|
];
|
|
32
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
|
|
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:'
|
|
34
34
|
: // Said plainly. The listener is what makes the automatic path work,
|
|
35
35
|
// and an operator who is not told it is missing will sit waiting for
|
|
36
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
|
|
38
|
-
lines.push('', '
|
|
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:');
|
|
38
|
+
lines.push('', ` ${start.completionHint ?? '/login <the address, or just the code>'}`);
|
|
39
39
|
return lines.join('\n');
|
|
40
40
|
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
41
|
+
/**
|
|
42
|
+
* What the operator reads when the attempt ends, either way.
|
|
43
|
+
*
|
|
44
|
+
* `retryHint` and `removeHint` name the commands as THIS surface spells them,
|
|
45
|
+
* for the same reason `completionHint` exists above. A failed sign-in run from
|
|
46
|
+
* a bare terminal used to end with "Run /login to try again" — a slash command,
|
|
47
|
+
* in a shell, where the thing to type is `namzu login`. Instructions that name
|
|
48
|
+
* another surface's spelling are the defect that made the sign-in unreachable
|
|
49
|
+
* from the picker; it is not any better in an error message.
|
|
50
|
+
*/
|
|
51
|
+
export function describeLoginOutcome(outcome, hints = {}) {
|
|
43
52
|
if (!outcome.ok) {
|
|
44
|
-
return `${outcome.reason}\n\nRun /login to try again.`;
|
|
53
|
+
return `${outcome.reason}\n\nRun ${hints.retry ?? '/login'} to try again.`;
|
|
45
54
|
}
|
|
46
55
|
return [
|
|
47
56
|
'Signed in. The credential is stored on this machine, readable only by your account:',
|
|
48
57
|
` ${outcome.storedAt}`,
|
|
49
58
|
'',
|
|
50
|
-
|
|
59
|
+
`namzu will refresh it as it expires, and will find it again next time it starts. Run ${hints.remove ?? '/logout'} to remove it.`,
|
|
51
60
|
].join('\n');
|
|
52
61
|
}
|
|
53
62
|
/** What the operator reads after asking namzu to forget the credential. */
|
|
@@ -1 +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,
|
|
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,KAgBlC;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,6LAA6L;QAC/L,CAAC,CAAC,oEAAoE;YACrE,qEAAqE;YACrE,2CAA2C;YAC3C,2LAA2L,CAC7L,CAAA;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC,cAAc,IAAI,wCAAwC,EAAE,CAAC,CAAA;IACvF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACxB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CACnC,OAAqB,EACrB,QAA+D,EAAE;IAEjE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,CAAC,MAAM,WAAW,KAAK,CAAC,KAAK,IAAI,QAAQ,gBAAgB,CAAA;IAC3E,CAAC;IACD,OAAO;QACN,qFAAqF;QACrF,KAAK,OAAO,CAAC,QAAQ,EAAE;QACvB,EAAE;QACF,wFAAwF,KAAK,CAAC,MAAM,IAAI,SAAS,gBAAgB;KACjI,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"}
|
|
@@ -8,6 +8,28 @@
|
|
|
8
8
|
* use), not a full CommonMark implementation. Syntax highlighting inside
|
|
9
9
|
* code blocks is intentionally out of scope; code is shown in one code
|
|
10
10
|
* color, which reads cleanly without a highlighter dependency.
|
|
11
|
+
*
|
|
12
|
+
* ## Two halves, because a streaming reply is re-parsed on every token
|
|
13
|
+
*
|
|
14
|
+
* {@link parseMarkdown} is {@link scanBlocks} followed by {@link parseBlock}
|
|
15
|
+
* per segment, and the split is what makes the per-block cache in
|
|
16
|
+
* `markdown-block-cache.ts` possible: scanning finds where each top-level
|
|
17
|
+
* block starts and ends, and parsing turns one block's raw text into one
|
|
18
|
+
* {@link MdBlock}. The cache can then skip the second half for text it has
|
|
19
|
+
* already seen.
|
|
20
|
+
*
|
|
21
|
+
* **{@link parseBlock} is a pure function of the segment handed to it** —
|
|
22
|
+
* nothing about a block's meaning depends on another block. That is what makes
|
|
23
|
+
* a cache keyed on raw text sound rather than merely convenient, and it is a
|
|
24
|
+
* property to preserve: reference-style link definitions (`[a]: http://…`),
|
|
25
|
+
* for instance, would make one block's rendering depend on another's presence
|
|
26
|
+
* and would have to be either implemented across the whole document or not at
|
|
27
|
+
* all. This subset has no such construct, and nothing here should acquire one
|
|
28
|
+
* without revisiting the cache.
|
|
29
|
+
*
|
|
30
|
+
* There is one classifier, {@link classify}. The scanner uses it to find
|
|
31
|
+
* boundaries and {@link parseBlock} uses it to dispatch, so "what is this
|
|
32
|
+
* line" is decided in a single place rather than once per half.
|
|
11
33
|
*/
|
|
12
34
|
export interface InlineSpan {
|
|
13
35
|
readonly text: string;
|
|
@@ -38,6 +60,17 @@ export type MdBlock = {
|
|
|
38
60
|
readonly headers: readonly string[];
|
|
39
61
|
readonly rows: readonly string[][];
|
|
40
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Split markdown source into the raw text of each top-level block, in order.
|
|
65
|
+
*
|
|
66
|
+
* Blank lines separate blocks and belong to none, so they appear in no segment.
|
|
67
|
+
* Every other line lands in exactly one, which is what lets a segment be used
|
|
68
|
+
* as a cache key: two runs that produce the same segment produce the same
|
|
69
|
+
* block, because {@link parseBlock} reads nothing else.
|
|
70
|
+
*/
|
|
71
|
+
export declare function scanBlocks(src: string): string[];
|
|
72
|
+
/** Parse one block's raw text — a segment from {@link scanBlocks} — into a block. */
|
|
73
|
+
export declare function parseBlock(raw: string): MdBlock;
|
|
41
74
|
/** Parse markdown source into a flat list of block elements. */
|
|
42
75
|
export declare function parseMarkdown(src: string): MdBlock[];
|
|
43
76
|
/** Parse a single line of text into styled inline spans. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/tui/markdownParser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../../src/tui/markdownParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,OAAO,GAChB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3E;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACpB,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACpF;IACA,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,CAAA;CACjC,CAAA;AAsCJ;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA4ChD;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAyC/C;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE,CAEpD;AAKD,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CA0BtD"}
|
|
@@ -8,6 +8,28 @@
|
|
|
8
8
|
* use), not a full CommonMark implementation. Syntax highlighting inside
|
|
9
9
|
* code blocks is intentionally out of scope; code is shown in one code
|
|
10
10
|
* color, which reads cleanly without a highlighter dependency.
|
|
11
|
+
*
|
|
12
|
+
* ## Two halves, because a streaming reply is re-parsed on every token
|
|
13
|
+
*
|
|
14
|
+
* {@link parseMarkdown} is {@link scanBlocks} followed by {@link parseBlock}
|
|
15
|
+
* per segment, and the split is what makes the per-block cache in
|
|
16
|
+
* `markdown-block-cache.ts` possible: scanning finds where each top-level
|
|
17
|
+
* block starts and ends, and parsing turns one block's raw text into one
|
|
18
|
+
* {@link MdBlock}. The cache can then skip the second half for text it has
|
|
19
|
+
* already seen.
|
|
20
|
+
*
|
|
21
|
+
* **{@link parseBlock} is a pure function of the segment handed to it** —
|
|
22
|
+
* nothing about a block's meaning depends on another block. That is what makes
|
|
23
|
+
* a cache keyed on raw text sound rather than merely convenient, and it is a
|
|
24
|
+
* property to preserve: reference-style link definitions (`[a]: http://…`),
|
|
25
|
+
* for instance, would make one block's rendering depend on another's presence
|
|
26
|
+
* and would have to be either implemented across the whole document or not at
|
|
27
|
+
* all. This subset has no such construct, and nothing here should acquire one
|
|
28
|
+
* without revisiting the cache.
|
|
29
|
+
*
|
|
30
|
+
* There is one classifier, {@link classify}. The scanner uses it to find
|
|
31
|
+
* boundaries and {@link parseBlock} uses it to dispatch, so "what is this
|
|
32
|
+
* line" is decided in a single place rather than once per half.
|
|
11
33
|
*/
|
|
12
34
|
const FENCE = /^```(\w*)\s*$/;
|
|
13
35
|
const HEADING = /^(#{1,6})\s+(.+?)\s*#*$/;
|
|
@@ -22,74 +44,122 @@ function tableCells(line) {
|
|
|
22
44
|
.split('|')
|
|
23
45
|
.map((c) => c.trim());
|
|
24
46
|
}
|
|
25
|
-
|
|
26
|
-
|
|
47
|
+
function classify(line, next) {
|
|
48
|
+
if (FENCE.test(line))
|
|
49
|
+
return 'code';
|
|
50
|
+
// Table: a `| … |` header row immediately followed by a `|---|` separator.
|
|
51
|
+
if (TABLE_ROW.test(line) && next !== undefined && TABLE_SEP.test(next))
|
|
52
|
+
return 'table';
|
|
53
|
+
if (HEADING.test(line))
|
|
54
|
+
return 'heading';
|
|
55
|
+
if (BULLET.test(line))
|
|
56
|
+
return 'bullet';
|
|
57
|
+
if (line.trim().length === 0)
|
|
58
|
+
return 'blank';
|
|
59
|
+
return 'text';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Split markdown source into the raw text of each top-level block, in order.
|
|
63
|
+
*
|
|
64
|
+
* Blank lines separate blocks and belong to none, so they appear in no segment.
|
|
65
|
+
* Every other line lands in exactly one, which is what lets a segment be used
|
|
66
|
+
* as a cache key: two runs that produce the same segment produce the same
|
|
67
|
+
* block, because {@link parseBlock} reads nothing else.
|
|
68
|
+
*/
|
|
69
|
+
export function scanBlocks(src) {
|
|
27
70
|
const lines = src.split('\n');
|
|
28
|
-
const
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
if (para.length > 0) {
|
|
32
|
-
blocks.push({ type: 'paragraph', text: para.join(' ') });
|
|
33
|
-
para = [];
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
for (let i = 0; i < lines.length; i++) {
|
|
71
|
+
const segments = [];
|
|
72
|
+
let i = 0;
|
|
73
|
+
while (i < lines.length) {
|
|
37
74
|
const line = lines[i] ?? '';
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
flushPara();
|
|
41
|
-
const lang = fence[1] ? fence[1] : undefined;
|
|
42
|
-
const codeLines = [];
|
|
43
|
-
i++;
|
|
44
|
-
while (i < lines.length && !FENCE.test(lines[i] ?? '')) {
|
|
45
|
-
codeLines.push(lines[i] ?? '');
|
|
75
|
+
switch (classify(line, lines[i + 1])) {
|
|
76
|
+
case 'blank':
|
|
46
77
|
i++;
|
|
78
|
+
break;
|
|
79
|
+
case 'code': {
|
|
80
|
+
// Run to the closing fence, or to the end of the text — a reply
|
|
81
|
+
// still streaming in has an open fence for as long as it is inside
|
|
82
|
+
// one, and that is a code block with what has arrived so far.
|
|
83
|
+
let end = i + 1;
|
|
84
|
+
while (end < lines.length && !FENCE.test(lines[end] ?? ''))
|
|
85
|
+
end++;
|
|
86
|
+
const last = Math.min(end, lines.length - 1);
|
|
87
|
+
segments.push(lines.slice(i, last + 1).join('\n'));
|
|
88
|
+
i = end + 1;
|
|
89
|
+
break;
|
|
47
90
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
rows.push(tableCells(lines[i] ?? ''));
|
|
91
|
+
case 'table': {
|
|
92
|
+
let end = i + 2; // header + separator
|
|
93
|
+
while (end < lines.length && TABLE_ROW.test(lines[end] ?? ''))
|
|
94
|
+
end++;
|
|
95
|
+
segments.push(lines.slice(i, end).join('\n'));
|
|
96
|
+
i = end;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case 'heading':
|
|
100
|
+
case 'bullet':
|
|
101
|
+
segments.push(line);
|
|
60
102
|
i++;
|
|
103
|
+
break;
|
|
104
|
+
default: {
|
|
105
|
+
// A paragraph is every following line that begins nothing else.
|
|
106
|
+
let end = i;
|
|
107
|
+
while (end < lines.length && classify(lines[end] ?? '', lines[end + 1]) === 'text')
|
|
108
|
+
end++;
|
|
109
|
+
segments.push(lines.slice(i, end).join('\n'));
|
|
110
|
+
i = end;
|
|
111
|
+
break;
|
|
61
112
|
}
|
|
62
|
-
i--; // for-loop ++ will re-advance past the last consumed row
|
|
63
|
-
blocks.push({ type: 'table', headers, rows });
|
|
64
|
-
continue;
|
|
65
113
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
114
|
+
}
|
|
115
|
+
return segments;
|
|
116
|
+
}
|
|
117
|
+
/** Parse one block's raw text — a segment from {@link scanBlocks} — into a block. */
|
|
118
|
+
export function parseBlock(raw) {
|
|
119
|
+
const lines = raw.split('\n');
|
|
120
|
+
const first = lines[0] ?? '';
|
|
121
|
+
switch (classify(first, lines[1])) {
|
|
122
|
+
case 'code': {
|
|
123
|
+
const lang = FENCE.exec(first)?.[1];
|
|
124
|
+
// The closing fence is part of the segment when the block is closed and
|
|
125
|
+
// absent while it is still arriving, so it is dropped only if present.
|
|
126
|
+
// A segment that is nothing but its opening fence reads as closed and
|
|
127
|
+
// is right either way: there is no body to drop a line from.
|
|
128
|
+
const closed = FENCE.test(lines[lines.length - 1] ?? '');
|
|
129
|
+
return {
|
|
130
|
+
type: 'code',
|
|
131
|
+
...(lang ? { lang } : {}),
|
|
132
|
+
lines: closed ? lines.slice(1, -1) : lines.slice(1),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
case 'table':
|
|
136
|
+
return {
|
|
137
|
+
type: 'table',
|
|
138
|
+
headers: tableCells(first),
|
|
139
|
+
rows: lines.slice(2).map(tableCells),
|
|
140
|
+
};
|
|
141
|
+
case 'heading': {
|
|
142
|
+
const heading = HEADING.exec(first);
|
|
143
|
+
return { type: 'heading', level: heading?.[1]?.length ?? 1, text: heading?.[2] ?? '' };
|
|
71
144
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const rawMarker = bullet[2] ?? '-';
|
|
145
|
+
case 'bullet': {
|
|
146
|
+
const bullet = BULLET.exec(first);
|
|
147
|
+
const rawMarker = bullet?.[2] ?? '-';
|
|
76
148
|
const ordered = /\d/.test(rawMarker);
|
|
77
|
-
|
|
149
|
+
return {
|
|
78
150
|
type: 'bullet',
|
|
79
151
|
ordered,
|
|
80
152
|
marker: ordered ? rawMarker.replace(/[.)]$/, '') : '•',
|
|
81
|
-
text: bullet[3] ?? '',
|
|
82
|
-
}
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (line.trim().length === 0) {
|
|
86
|
-
flushPara();
|
|
87
|
-
continue;
|
|
153
|
+
text: bullet?.[3] ?? '',
|
|
154
|
+
};
|
|
88
155
|
}
|
|
89
|
-
|
|
156
|
+
default:
|
|
157
|
+
return { type: 'paragraph', text: lines.map((l) => l.trim()).join(' ') };
|
|
90
158
|
}
|
|
91
|
-
|
|
92
|
-
|
|
159
|
+
}
|
|
160
|
+
/** Parse markdown source into a flat list of block elements. */
|
|
161
|
+
export function parseMarkdown(src) {
|
|
162
|
+
return scanBlocks(src).map(parseBlock);
|
|
93
163
|
}
|
|
94
164
|
const INLINE = /(`[^`]+`)|(\[[^\]]+\]\([^)]+\))|(\*\*[^*]+\*\*)|(__[^_]+__)|(\*[^*]+\*)|(_[^_]+_)/;
|
|
95
165
|
const LINK = /^\[([^\]]+)\]\(([^)]+)\)$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdownParser.js","sourceRoot":"","sources":["../../src/tui/markdownParser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"markdownParser.js","sourceRoot":"","sources":["../../src/tui/markdownParser.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namzu/cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.0",
|
|
4
4
|
"description": "Operator CLI for the Namzu agent platform — namzu doctor + future commands. Dual-purpose: standalone bin (`namzu doctor`) and library (`import { runDoctor } from '@namzu/cli'`).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"namzu",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"@namzu/anthropic": "3.2.0",
|
|
48
48
|
"@namzu/openai": "1.2.0",
|
|
49
49
|
"@namzu/sdk": "^21.1.0",
|
|
50
|
-
"@namzu/
|
|
51
|
-
"@namzu/
|
|
50
|
+
"@namzu/ollama": "2.1.0",
|
|
51
|
+
"@namzu/openrouter": "2.1.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@biomejs/biome": "^1.9.4",
|