dsh-better-display 0.3.7 → 0.3.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.
Files changed (208) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/DESIGN.md +43 -3
  3. package/README.en.md +9 -1
  4. package/README.md +9 -1
  5. package/docs/dependency-update-policy.md +9 -0
  6. package/docs/extension-points.md +172 -0
  7. package/docs/official-rendering-bridge.md +59 -18
  8. package/docs/openapi.yaml +147 -0
  9. package/docs/runbooks/blank-reader.md +39 -0
  10. package/lib/client.js +1629 -586
  11. package/lib/client.js.map +1 -1
  12. package/lib/dsh-better-display.js +535 -57
  13. package/lib/types/client/AssistantNode.d.ts +20 -0
  14. package/lib/types/client/AssistantNode.d.ts.map +1 -0
  15. package/lib/types/client/AssistantNode.js +46 -0
  16. package/lib/types/client/AssistantNode.js.map +1 -0
  17. package/lib/types/client/Blocks.d.ts.map +1 -1
  18. package/lib/types/client/Blocks.js +33 -10
  19. package/lib/types/client/Blocks.js.map +1 -1
  20. package/lib/types/client/ChoreographedFlow.d.ts.map +1 -1
  21. package/lib/types/client/ChoreographedFlow.js +2 -0
  22. package/lib/types/client/ChoreographedFlow.js.map +1 -1
  23. package/lib/types/client/ClosedProcessSummary.d.ts.map +1 -1
  24. package/lib/types/client/ClosedProcessSummary.js +3 -1
  25. package/lib/types/client/ClosedProcessSummary.js.map +1 -1
  26. package/lib/types/client/McpAppFrame.d.ts.map +1 -1
  27. package/lib/types/client/McpAppFrame.js +5 -11
  28. package/lib/types/client/McpAppFrame.js.map +1 -1
  29. package/lib/types/client/OfficialContent.d.ts +17 -3
  30. package/lib/types/client/OfficialContent.d.ts.map +1 -1
  31. package/lib/types/client/OfficialContent.js +33 -7
  32. package/lib/types/client/OfficialContent.js.map +1 -1
  33. package/lib/types/client/Reader.d.ts.map +1 -1
  34. package/lib/types/client/Reader.js +76 -73
  35. package/lib/types/client/Reader.js.map +1 -1
  36. package/lib/types/client/SettingsSection.d.ts.map +1 -1
  37. package/lib/types/client/SettingsSection.js +0 -5
  38. package/lib/types/client/SettingsSection.js.map +1 -1
  39. package/lib/types/client/StickyLane.d.ts +12 -0
  40. package/lib/types/client/StickyLane.d.ts.map +1 -1
  41. package/lib/types/client/StickyLane.js +78 -2
  42. package/lib/types/client/StickyLane.js.map +1 -1
  43. package/lib/types/client/ToolActivity.d.ts.map +1 -1
  44. package/lib/types/client/ToolActivity.js +10 -5
  45. package/lib/types/client/ToolActivity.js.map +1 -1
  46. package/lib/types/client/deliverables.d.ts.map +1 -1
  47. package/lib/types/client/deliverables.js +2 -0
  48. package/lib/types/client/deliverables.js.map +1 -1
  49. package/lib/types/client/index.d.ts +3 -1
  50. package/lib/types/client/index.d.ts.map +1 -1
  51. package/lib/types/client/index.js +15 -1
  52. package/lib/types/client/index.js.map +1 -1
  53. package/lib/types/client/live-turn.d.ts +17 -5
  54. package/lib/types/client/live-turn.d.ts.map +1 -1
  55. package/lib/types/client/live-turn.js +106 -76
  56. package/lib/types/client/live-turn.js.map +1 -1
  57. package/lib/types/client/motion.d.ts +26 -2
  58. package/lib/types/client/motion.d.ts.map +1 -1
  59. package/lib/types/client/motion.js +144 -10
  60. package/lib/types/client/motion.js.map +1 -1
  61. package/lib/types/client/official-slots.d.ts +9 -0
  62. package/lib/types/client/official-slots.d.ts.map +1 -1
  63. package/lib/types/client/official-slots.js +22 -4
  64. package/lib/types/client/official-slots.js.map +1 -1
  65. package/lib/types/client/open-file.d.ts.map +1 -1
  66. package/lib/types/client/open-file.js +1 -6
  67. package/lib/types/client/open-file.js.map +1 -1
  68. package/lib/types/client/projection.d.ts +15 -2
  69. package/lib/types/client/projection.d.ts.map +1 -1
  70. package/lib/types/client/projection.js +16 -4
  71. package/lib/types/client/projection.js.map +1 -1
  72. package/lib/types/client/rewind-cut.d.ts +131 -0
  73. package/lib/types/client/rewind-cut.d.ts.map +1 -0
  74. package/lib/types/client/rewind-cut.js +321 -0
  75. package/lib/types/client/rewind-cut.js.map +1 -0
  76. package/lib/types/client/styles.d.ts +3 -0
  77. package/lib/types/client/styles.d.ts.map +1 -0
  78. package/lib/types/client/styles.js +25 -0
  79. package/lib/types/client/styles.js.map +1 -0
  80. package/lib/types/client/text-transform.d.ts +93 -0
  81. package/lib/types/client/text-transform.d.ts.map +1 -0
  82. package/lib/types/client/text-transform.js +183 -0
  83. package/lib/types/client/text-transform.js.map +1 -0
  84. package/lib/types/client/timeline.d.ts.map +1 -1
  85. package/lib/types/client/timeline.js.map +1 -1
  86. package/lib/types/client/tool-activity.d.ts +11 -4
  87. package/lib/types/client/tool-activity.d.ts.map +1 -1
  88. package/lib/types/client/tool-activity.js +54 -9
  89. package/lib/types/client/tool-activity.js.map +1 -1
  90. package/lib/types/client/turn-slots.d.ts +29 -0
  91. package/lib/types/client/turn-slots.d.ts.map +1 -0
  92. package/lib/types/client/turn-slots.js +62 -0
  93. package/lib/types/client/turn-slots.js.map +1 -0
  94. package/lib/types/client/types.d.ts +18 -0
  95. package/lib/types/client/types.d.ts.map +1 -1
  96. package/lib/types/dsh-better-display.d.ts +4 -1
  97. package/lib/types/dsh-better-display.d.ts.map +1 -1
  98. package/lib/types/dsh-better-display.js +55 -43
  99. package/lib/types/dsh-better-display.js.map +1 -1
  100. package/lib/types/flags.d.ts +7 -0
  101. package/lib/types/flags.d.ts.map +1 -0
  102. package/lib/types/flags.js +37 -0
  103. package/lib/types/flags.js.map +1 -0
  104. package/lib/types/log.d.ts +17 -0
  105. package/lib/types/log.d.ts.map +1 -0
  106. package/lib/types/log.js +122 -0
  107. package/lib/types/log.js.map +1 -0
  108. package/lib/types/metrics.d.ts +18 -0
  109. package/lib/types/metrics.d.ts.map +1 -0
  110. package/lib/types/metrics.js +35 -0
  111. package/lib/types/metrics.js.map +1 -0
  112. package/lib/types/reveal.d.ts +12 -0
  113. package/lib/types/reveal.d.ts.map +1 -0
  114. package/lib/types/reveal.js +147 -0
  115. package/lib/types/reveal.js.map +1 -0
  116. package/lib/types/workspace-path.d.ts +3 -0
  117. package/lib/types/workspace-path.d.ts.map +1 -0
  118. package/lib/types/workspace-path.js +5 -0
  119. package/lib/types/workspace-path.js.map +1 -0
  120. package/package.json +36 -5
  121. package/scripts/changelog.mjs +20 -0
  122. package/scripts/check-agents-md.mjs +67 -0
  123. package/scripts/check-bundle-size.mjs +38 -0
  124. package/scripts/check-dead-flags.mjs +55 -0
  125. package/scripts/check-todo-debt.mjs +69 -0
  126. package/scripts/security-audit-report.mjs +92 -0
  127. package/scripts/verify-commentary-visible.mjs +627 -0
  128. package/src/client/AssistantNode.tsx +72 -0
  129. package/src/client/Blocks.tsx +49 -10
  130. package/src/client/ChoreographedFlow.tsx +3 -1
  131. package/src/client/ClosedProcessSummary.tsx +3 -1
  132. package/src/client/McpAppFrame.tsx +5 -13
  133. package/src/client/OfficialContent.tsx +47 -9
  134. package/src/client/Reader.module.css +103 -21
  135. package/src/client/Reader.tsx +83 -88
  136. package/src/client/SettingsSection.tsx +1 -7
  137. package/src/client/StickyLane.tsx +81 -2
  138. package/src/client/ToolActivity.tsx +10 -6
  139. package/src/client/deliverables.ts +1 -0
  140. package/src/client/index.tsx +18 -2
  141. package/src/client/live-turn.ts +100 -69
  142. package/src/client/motion.tsx +142 -7
  143. package/src/client/official-slots.tsx +23 -4
  144. package/src/client/open-file.ts +2 -8
  145. package/src/client/projection.ts +16 -4
  146. package/src/client/rewind-cut.ts +340 -0
  147. package/src/client/styles.ts +22 -0
  148. package/src/client/text-transform.ts +265 -0
  149. package/src/client/timeline.ts +0 -2
  150. package/src/client/tool-activity.ts +67 -9
  151. package/src/client/turn-slots.ts +80 -0
  152. package/src/client/types.ts +19 -0
  153. package/src/dsh-better-display.ts +57 -42
  154. package/src/flags.ts +40 -0
  155. package/src/log.ts +137 -0
  156. package/src/metrics.ts +50 -0
  157. package/src/reveal.ts +90 -0
  158. package/src/workspace-path.ts +4 -0
  159. package/tests/browser-commentary.tsx +191 -0
  160. package/tests/chat-flow-hook.test.ts +1 -1
  161. package/tests/cloud-gate.test.ts +1 -1
  162. package/tests/context-tool-update.test.ts +1 -1
  163. package/tests/conversation-scroll.test.ts +1 -1
  164. package/tests/deliverables.test.ts +1 -1
  165. package/tests/entry.test.ts +1 -1
  166. package/tests/fixtures/reader-lane-owners.tsx +46 -0
  167. package/tests/fixtures/reader-official-users.tsx +234 -0
  168. package/tests/fixtures/reader-theme-overlap.html +80 -0
  169. package/tests/fixtures/reader-user-bubble.tsx +222 -0
  170. package/tests/flags.test.ts +66 -0
  171. package/tests/fold-choreography.test.ts +32 -8
  172. package/tests/fold-intensity.test.ts +11 -6
  173. package/tests/footer-precedence.test.ts +9 -1
  174. package/tests/history-word-regression.test.ts +1 -1
  175. package/tests/live-turn.test.ts +125 -54
  176. package/tests/log.test.ts +99 -0
  177. package/tests/mcp-apps.test.ts +1 -1
  178. package/tests/message-chrome.test.ts +1 -1
  179. package/tests/metrics.test.ts +52 -0
  180. package/tests/official-slots.test.ts +41 -2
  181. package/tests/open-file.test.ts +1 -1
  182. package/tests/pending-submission.test.ts +12 -1
  183. package/tests/pinned-selection.test.ts +16 -0
  184. package/tests/platform-media.test.ts +1 -1
  185. package/tests/projection.test.ts +66 -3
  186. package/tests/reader-glass-css.test.ts +28 -0
  187. package/tests/reader-official-users.test.ts +91 -0
  188. package/tests/reader-sticky-surface.test.ts +377 -0
  189. package/tests/reader-theme-lanes.test.ts +54 -0
  190. package/tests/reader-theme-overlap.test.ts +151 -0
  191. package/tests/reader-user-bubble.test.ts +137 -0
  192. package/tests/reasoning-follow.test.ts +1 -1
  193. package/tests/retiring-content.test.ts +229 -0
  194. package/tests/reveal.test.ts +128 -0
  195. package/tests/rewind-cut.test.ts +1090 -0
  196. package/tests/settings-copy.test.ts +1 -1
  197. package/tests/skill-status.test.ts +1 -1
  198. package/tests/stock-install.test.ts +9 -1
  199. package/tests/stream-buffer.test.ts +1 -1
  200. package/tests/styles.test.ts +75 -0
  201. package/tests/terminal-input-preview.test.ts +113 -0
  202. package/tests/text-transform.test.ts +272 -0
  203. package/tests/timeline.test.ts +1 -1
  204. package/tests/tool-clock.test.ts +1 -1
  205. package/tests/tool-diff.test.ts +1 -1
  206. package/tests/waiting-clock.test.ts +1 -1
  207. package/tests/word-timeline.test.ts +1 -1
  208. package/tsdown.config.ts +49 -1
@@ -0,0 +1,38 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+
4
+ /**
5
+ * Fresh tsdown host bundle. The previously committed file omitted flags, log,
6
+ * and metrics, which the entry already imports, so CI's rebuild is this size.
7
+ */
8
+ export const BASELINE_BYTES = 18503;
9
+ export const BUDGET_BYTES = Math.floor(BASELINE_BYTES * 1.1);
10
+
11
+ export function judgeBundle(size, budget = BUDGET_BYTES) {
12
+ if (size > budget) return { code: 1, message: `bundle exceeds budget: ${size} > ${budget}` };
13
+ return { code: 0, message: `lib/dsh-better-display.js ${size} bytes; budget ${budget} (baseline ${BASELINE_BYTES} + 10%).` };
14
+ }
15
+
16
+ export function reportBundle(file) {
17
+ if (!existsSync(file)) {
18
+ return { code: 0, message: `skip: ${file} is absent. Run npm run build before measuring the bundle.` };
19
+ }
20
+ return judgeBundle(statSync(file).size);
21
+ }
22
+
23
+ function selfTest() {
24
+ const over = judgeBundle(BUDGET_BYTES + 1);
25
+ const under = judgeBundle(BASELINE_BYTES);
26
+ const skipped = reportBundle(resolve(import.meta.dirname, 'no-such-bundle.js'));
27
+ if (BUDGET_BYTES !== 20353 || over.code !== 1 || under.code !== 0 || skipped.code !== 0 || !skipped.message.startsWith('skip:')) {
28
+ console.error('check-bundle-size self-test failed', { over, under, skipped, BUDGET_BYTES });
29
+ process.exit(1);
30
+ }
31
+ console.log('check-bundle-size self-test passed');
32
+ }
33
+
34
+ if (process.argv.includes('--self-test')) selfTest();
35
+
36
+ const result = reportBundle(resolve(import.meta.dirname, '../lib/dsh-better-display.js'));
37
+ console.log(result.message);
38
+ process.exit(result.code);
@@ -0,0 +1,55 @@
1
+ /** Fail when a flags.json key never appears under src. FLAGS_JSON and FLAGS_SRC override paths. */
2
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
4
+
5
+ const root = resolve(import.meta.dirname, '..');
6
+ const flagsPath = process.env.FLAGS_JSON ? resolve(process.env.FLAGS_JSON) : join(root, 'flags.json');
7
+ const srcDir = process.env.FLAGS_SRC ? resolve(process.env.FLAGS_SRC) : join(root, 'src');
8
+
9
+ function fail(message) {
10
+ console.error(message);
11
+ process.exit(1);
12
+ }
13
+
14
+ function sourceFiles(dir) {
15
+ const found = [];
16
+ for (const entry of readdirSync(dir)) {
17
+ if (entry === 'node_modules' || entry === 'lib') continue;
18
+ const path = join(dir, entry);
19
+ const stat = statSync(path);
20
+ if (stat.isDirectory()) found.push(...sourceFiles(path));
21
+ else if (/\.(?:[cm]?[jt]s|tsx|jsx)$/.test(entry)) found.push(path);
22
+ }
23
+ return found;
24
+ }
25
+
26
+ function referenced(haystack, key) {
27
+ const pattern = new RegExp(`\\b${key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
28
+ return pattern.test(haystack);
29
+ }
30
+
31
+ let flags;
32
+ try {
33
+ flags = JSON.parse(readFileSync(flagsPath, 'utf8'));
34
+ } catch (err) {
35
+ fail(`Cannot read feature flags from ${flagsPath}: ${err instanceof Error ? err.message : String(err)}`);
36
+ }
37
+
38
+ if (flags === null || typeof flags !== 'object' || Array.isArray(flags)) {
39
+ fail('flags.json must be an object of feature flags');
40
+ }
41
+
42
+ const keys = Object.keys(flags);
43
+ if (keys.length === 0 || keys.some(key => key.trim() === '')) fail('flags.json has no usable keys');
44
+
45
+ let sources;
46
+ try {
47
+ sources = sourceFiles(srcDir).map(path => readFileSync(path, 'utf8')).join('\n');
48
+ } catch (err) {
49
+ fail(`Cannot scan ${srcDir} for feature flag usage: ${err instanceof Error ? err.message : String(err)}`);
50
+ }
51
+
52
+ const unused = keys.filter(key => !referenced(sources, key));
53
+ if (unused.length > 0) fail(`Unused feature flags: ${unused.join(', ')}`);
54
+
55
+ console.log(`All ${keys.length} flags.json keys are referenced under src.`);
@@ -0,0 +1,69 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ const root = path.resolve(process.argv[2] ?? process.cwd());
5
+ const skipDirs = new Set([
6
+ 'node_modules',
7
+ 'lib',
8
+ '.git',
9
+ 'artifacts',
10
+ '.evidence',
11
+ '.delivery',
12
+ 'coverage',
13
+ 'report',
14
+ 'dist'
15
+ ]);
16
+ const extensions = new Set([
17
+ '.ts',
18
+ '.tsx',
19
+ '.mts',
20
+ '.cts',
21
+ '.mjs',
22
+ '.cjs',
23
+ '.js',
24
+ '.jsx',
25
+ '.md',
26
+ '.yml',
27
+ '.yaml',
28
+ '.css',
29
+ '.json',
30
+ '.html'
31
+ ]);
32
+
33
+ const marker = new RegExp(String.raw`\b(?:${'TO' + 'DO'}|${'FIX' + 'ME'})\b`);
34
+ const issueId = /#\d+/;
35
+
36
+ async function walk(directory, hits) {
37
+ const entries = await readdir(directory, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ if (entry.isDirectory()) {
40
+ if (skipDirs.has(entry.name)) continue;
41
+ if (entry.name.startsWith('.') && entry.name !== '.github') continue;
42
+ await walk(path.join(directory, entry.name), hits);
43
+ continue;
44
+ }
45
+ if (!entry.isFile() || !extensions.has(path.extname(entry.name))) continue;
46
+ const file = path.join(directory, entry.name);
47
+ let text;
48
+ try {
49
+ text = await readFile(file, 'utf8');
50
+ } catch {
51
+ continue;
52
+ }
53
+ const lines = text.split(/\r?\n/);
54
+ for (let index = 0; index < lines.length; index += 1) {
55
+ const line = lines[index];
56
+ if (!marker.test(line) || issueId.test(line)) continue;
57
+ hits.push(`${path.relative(root, file)}:${index + 1}: ${line.trim()}`);
58
+ }
59
+ }
60
+ }
61
+
62
+ const hits = [];
63
+ await walk(root, hits);
64
+ if (hits.length > 0) {
65
+ console.error(`TODO/FIXME without an issue id (#123): ${hits.length}`);
66
+ for (const hit of hits) console.error(hit);
67
+ process.exit(1);
68
+ }
69
+ console.log('todo debt: ok');
@@ -0,0 +1,92 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { appendFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ export function isAuditReport(report) {
6
+ return Boolean(report && !report.error && report.metadata?.vulnerabilities);
7
+ }
8
+
9
+ export function formatAuditError(report, stderr) {
10
+ const summary = report?.error?.summary || report?.error?.detail || stderr || 'npm audit failed';
11
+ return [
12
+ '## npm audit',
13
+ '',
14
+ 'npm audit did not return a vulnerability report. Nothing was filled in as a clean result.',
15
+ '',
16
+ '```',
17
+ String(summary).slice(0, 8000),
18
+ '```',
19
+ ].join('\n');
20
+ }
21
+
22
+ export function formatAudit(report) {
23
+ const counts = report?.metadata?.vulnerabilities ?? {};
24
+ const vulns = report?.vulnerabilities ?? {};
25
+ const lines = [
26
+ '## npm audit',
27
+ '',
28
+ `Total ${counts.total ?? 'unknown'}: critical ${counts.critical ?? 0}, high ${counts.high ?? 0}, moderate ${counts.moderate ?? 0}, low ${counts.low ?? 0}, info ${counts.info ?? 0}.`,
29
+ '',
30
+ '| Package | Severity | Fix |',
31
+ '| --- | --- | --- |',
32
+ ];
33
+ for (const [name, info] of Object.entries(vulns)) {
34
+ const fix = info?.fixAvailable === true ? 'yes' : info?.fixAvailable ? 'yes' : 'no';
35
+ lines.push(`| ${name} | ${info?.severity ?? 'unknown'} | ${fix} |`);
36
+ }
37
+ if (Object.keys(vulns).length === 0) lines.push('| (none) | | |');
38
+ lines.push('', '<details>', '<summary>npm audit JSON</summary>', '', '```json');
39
+ const json = JSON.stringify(report, null, 2);
40
+ lines.push(json.length > 100000 ? `${json.slice(0, 100000)}\n… truncated` : json);
41
+ lines.push('```', '', '</details>');
42
+ return lines.join('\n');
43
+ }
44
+
45
+ function writeSummary(text) {
46
+ const summary = process.env.GITHUB_STEP_SUMMARY;
47
+ if (!summary) {
48
+ console.log('GITHUB_STEP_SUMMARY is unset; the report was printed here only.');
49
+ return;
50
+ }
51
+ appendFileSync(summary, `${text}\n`);
52
+ console.log(`Wrote the npm audit report to ${summary}`);
53
+ }
54
+
55
+ function selfTest() {
56
+ const text = formatAudit({
57
+ metadata: { vulnerabilities: { info: 0, low: 1, moderate: 0, high: 0, critical: 0, total: 1 } },
58
+ vulnerabilities: { example: { severity: 'low', fixAvailable: false } },
59
+ });
60
+ const enolock = { error: { code: 'ENOLOCK', summary: 'This command requires an existing lockfile.' } };
61
+ if (!text.includes('| example | low | no |') || !text.includes('```json') || isAuditReport(enolock) || !isAuditReport({ metadata: { vulnerabilities: { total: 0 } } })) {
62
+ console.error('security-audit-report self-test failed');
63
+ process.exit(1);
64
+ }
65
+ console.log('security-audit-report self-test passed');
66
+ }
67
+
68
+ if (process.argv.includes('--self-test')) selfTest();
69
+
70
+ const root = fileURLToPath(new URL('..', import.meta.url));
71
+ const result = spawnSync('npm', ['audit', '--json'], {
72
+ cwd: root,
73
+ encoding: 'utf8',
74
+ maxBuffer: 32 * 1024 * 1024,
75
+ });
76
+ const stdout = result.stdout ?? '';
77
+ let report;
78
+ try {
79
+ report = JSON.parse(stdout);
80
+ } catch {
81
+ report = undefined;
82
+ }
83
+ if (!isAuditReport(report)) {
84
+ const failure = formatAuditError(report, result.stderr || stdout || result.error?.message || 'npm audit produced no output');
85
+ console.log(failure);
86
+ writeSummary(failure);
87
+ process.exit(1);
88
+ }
89
+
90
+ const text = formatAudit(report);
91
+ console.log(text);
92
+ writeSummary(text);