@hybridlabor-api/aos 4.13.1 → 4.14.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 (151) hide show
  1. package/.agents/AGENTS.md +8 -0
  2. package/.agents/nodes.json +5 -2
  3. package/.claude/hooks/conventional-commits.mjs +14 -15
  4. package/.claude/hooks/env-file-protection.mjs +14 -15
  5. package/.claude/hooks/go-gate.mjs +157 -13
  6. package/.claude/hooks/go-token.mjs +55 -0
  7. package/.claude/hooks/memb-inject.mjs +75 -62
  8. package/.claude/hooks/trail-autostart.mjs +27 -0
  9. package/.claude/settings.json +18 -0
  10. package/.claude/workflows/startcycle-dispatch.mjs +11 -4
  11. package/.opencode/plugins/bdb-aos.js +98 -121
  12. package/.opencode/plugins/lib/trail-autostart.js +38 -0
  13. package/CLAUDE.md +1 -1
  14. package/README.de.md +6 -10
  15. package/README.md +6 -10
  16. package/README.pt.md +6 -10
  17. package/THIRD_PARTY_NOTICES.md +19 -3
  18. package/assets/header-v5.png +0 -0
  19. package/bin/aos-acp.mjs +211 -0
  20. package/bin/aos-doctor.mjs +1 -1
  21. package/bin/aos-uninstall.mjs +2 -2
  22. package/docs/master-session-acp.md +51 -0
  23. package/installer.js +398 -65
  24. package/mcps/mcsc/packages/mcp/server.js +6 -7
  25. package/package.json +4 -3
  26. package/scripts/validate-skills.mjs +76 -0
  27. package/skills/basic/bdbmediastorm/SKILL.md +1 -1
  28. package/skills/basic/godmode-shipping/SKILL.md +3 -0
  29. package/skills/basic/master-session/SKILL.md +89 -0
  30. package/skills/basic/startcycle/SKILL.md +1 -1
  31. package/skills/basic/startcycle-graph/SKILL.md +2 -2
  32. package/skills/basic/startcycle-graph-user/SKILL.md +1 -1
  33. package/skills/basic/teamwork-preview/SKILL.md +1 -1
  34. package/skills/bdbrainstorm/SKILL.md +7 -1
  35. package/skills/global_config/agentic-harness-patterns/SKILL.md +257 -0
  36. package/skills/global_config/agentic-harness-patterns/metadata.json +10 -0
  37. package/skills/global_config/agentic-harness-patterns/references/agent-orchestration-pattern.md +97 -0
  38. package/skills/global_config/agentic-harness-patterns/references/bootstrap-sequence-pattern.md +106 -0
  39. package/skills/global_config/agentic-harness-patterns/references/context-engineering/compress-pattern.md +78 -0
  40. package/skills/global_config/agentic-harness-patterns/references/context-engineering/isolate-pattern.md +82 -0
  41. package/skills/global_config/agentic-harness-patterns/references/context-engineering/select-pattern.md +86 -0
  42. package/skills/global_config/agentic-harness-patterns/references/context-engineering-pattern.md +29 -0
  43. package/skills/global_config/agentic-harness-patterns/references/hook-lifecycle-pattern.md +111 -0
  44. package/skills/global_config/agentic-harness-patterns/references/memory-persistence-pattern.md +109 -0
  45. package/skills/global_config/agentic-harness-patterns/references/permission-gate-pattern.md +111 -0
  46. package/skills/global_config/agentic-harness-patterns/references/skill-runtime-pattern.md +104 -0
  47. package/skills/global_config/agentic-harness-patterns/references/task-decomposition-pattern.md +92 -0
  48. package/skills/global_config/agentic-harness-patterns/references/tool-registry-pattern.md +101 -0
  49. package/skills/global_config/agenttrail/SKILL.md +8 -0
  50. package/skills/global_config/agenttrail/bin/agenttrail.mjs +14 -0
  51. package/skills/global_config/agenttrail/bin/ensure.mjs +118 -0
  52. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
  53. package/skills/global_config/bdb-memb-mcp/SKILL.md +4 -5
  54. package/skills/global_config/bdb-visual-edit/SKILL.md +51 -0
  55. package/skills/global_config/bdb-visual-edit/references/vite-react-source-attr.md +59 -0
  56. package/skills/global_config/bdb-visual-edit/scripts/pick-snippet.js +27 -0
  57. package/skills/global_config/bdb-visual-edit/scripts/sanitize-element.mjs +123 -0
  58. package/skills/global_config/factory-collect/SKILL.md +74 -0
  59. package/skills/global_config/factory-human-digest/SKILL.md +92 -0
  60. package/skills/global_config/factory-lookback/SKILL.md +95 -0
  61. package/skills/global_config/factory-review-prs/SKILL.md +63 -0
  62. package/skills/global_config/git-pr-review/SKILL.md +3 -0
  63. package/skills/global_config/grilling/SKILL.md +2 -0
  64. package/skills/global_config/mcsc/SKILL.md +1 -1
  65. package/skills/global_config/plan-arbiter/SKILL.md +125 -0
  66. package/skills/global_config/plan-canvas/SKILL.md +63 -9
  67. package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +19 -3
  68. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/README.md +285 -0
  69. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/agent-trail.js +129 -0
  70. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/board-client.js +124 -0
  71. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/canvas.mdx +19 -0
  72. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/plan.mdx +18 -0
  73. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/recap-demo/plan.mdx +72 -0
  74. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/README.md +29 -0
  75. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/architecture.json +30 -0
  76. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/00_architecture.html +14950 -0
  77. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/canvas.mdx +511 -0
  78. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/plan.mdx +208 -0
  79. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/recap/plan.mdx +102 -0
  80. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/standard/plan.md +136 -0
  81. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/canvas.mdx +124 -0
  82. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/plan.mdx +37 -0
  83. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/index.js +188 -0
  84. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/kit.js +123 -0
  85. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/mdx.js +411 -0
  86. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/render.js +1291 -0
  87. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/meta.json +1 -0
  88. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/plan.mdx +195 -0
  89. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/standard.md +95 -0
  90. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/meta.json +1 -0
  91. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/plan.mdx +105 -0
  92. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/standard.md +76 -0
  93. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/canvas.mdx +81 -0
  94. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/meta.json +1 -0
  95. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/plan.mdx +145 -0
  96. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/standard.md +76 -0
  97. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/meta.json +1 -0
  98. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/plan.mdx +172 -0
  99. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/standard.md +100 -0
  100. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/meta.json +1 -0
  101. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/plan.mdx +67 -0
  102. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/standard.md +49 -0
  103. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/canvas.mdx +63 -0
  104. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/meta.json +1 -0
  105. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/plan.mdx +49 -0
  106. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/standard.md +39 -0
  107. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/meta.json +1 -0
  108. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/plan.mdx +118 -0
  109. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/standard.md +57 -0
  110. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/meta.json +1 -0
  111. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/plan.mdx +173 -0
  112. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/standard.md +96 -0
  113. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/meta.json +1 -0
  114. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/plan.mdx +91 -0
  115. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/standard.md +54 -0
  116. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/canvas.mdx +53 -0
  117. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/meta.json +1 -0
  118. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/plan.mdx +225 -0
  119. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/standard.md +111 -0
  120. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/theme.css +472 -0
  121. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/trail.js +216 -0
  122. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +1 -1
  123. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +37 -4
  124. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +125 -29
  125. package/skills/global_config/plan-canvas/scripts/plan-canvas.js +196 -8
  126. package/skills/global_config/pr-recap/SKILL.md +47 -0
  127. package/skills/global_config/pr-recap/scripts/pr-recap.mjs +200 -0
  128. package/skills/global_config/quick-recap/SKILL.md +55 -0
  129. package/skills/global_config/stay-within-limits/SKILL.md +85 -0
  130. package/skills/global_config/triage/SKILL.md +3 -0
  131. package/skills/global_config/visual-edit/README.md +96 -0
  132. package/skills/global_config/visual-edit/SKILL.md +615 -0
  133. package/skills/global_config/visual-plan/README.md +93 -0
  134. package/skills/global_config/visual-plan/SKILL.md +544 -0
  135. package/skills/global_config/visual-plan/references/canvas.md +139 -0
  136. package/skills/global_config/visual-plan/references/connection.md +51 -0
  137. package/skills/global_config/visual-plan/references/document-quality.md +186 -0
  138. package/skills/global_config/visual-plan/references/exemplar.md +62 -0
  139. package/skills/global_config/visual-plan/references/local-files.md +99 -0
  140. package/skills/global_config/visual-plan/references/wireframe.md +319 -0
  141. package/skills/global_config/visual-recap/README.md +103 -0
  142. package/skills/global_config/visual-recap/SKILL.md +560 -0
  143. package/skills/global_config/visual-recap/references/connection.md +51 -0
  144. package/skills/global_config/visual-recap/references/local-files.md +99 -0
  145. package/skills/global_config/visual-recap/references/wireframe.md +319 -0
  146. package/skills/playbooks/pb-ci-fix/SKILL.md +49 -0
  147. package/skills/playbooks/pb-event-tracker/SKILL.md +45 -0
  148. package/skills/playbooks/pb-meeting-actions/SKILL.md +42 -0
  149. package/skills/playbooks/pb-project-new/SKILL.md +48 -0
  150. package/skills/playbooks/pb-week-plan/SKILL.md +45 -0
  151. package/assets/header-v4.jpg +0 -0
@@ -0,0 +1,188 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * BDB Plan Builder — turn an Agent-Native-style plan folder into ONE
5
+ * self-contained HTML file in the BDB look, which `aos-plan-canvas` then opens
6
+ * through the normal `.html` artifact path (annotation, chat and verdict all
7
+ * already work for HTML).
8
+ *
9
+ * No dependencies, no network at build time. Plan content is treated as
10
+ * untrusted input: everything is escaped, and raw HTML only ever reaches a
11
+ * sandboxed iframe without `allow-scripts`.
12
+ *
13
+ * renderPlanFolder('./plans/my-plan') -> { html, warnings, outFile }
14
+ * renderPlanSource({ plan, canvas }) -> { html, warnings }
15
+ * parseMdx(text) -> blocks
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+
21
+ const { parseMdx } = require('./mdx');
22
+ const { renderBoard, renderDocument, prototypeHint, page } = require('./render');
23
+ const { slugify } = require('../plan-canvas/markdown');
24
+
25
+ const PLAN_FILE = 'plan.mdx';
26
+ const OUTPUT_FILE = 'plan.builder.html';
27
+ const OPTIONAL_SOURCES = [
28
+ { key: 'canvas', file: 'canvas.mdx', title: 'Canvas', board: true },
29
+ { key: 'prototype', file: 'prototype.mdx', title: 'Prototype' }
30
+ ];
31
+
32
+ function readIfPresent(dir, file, warnings) {
33
+ const full = path.join(dir, file);
34
+ if (!fs.existsSync(full)) return null;
35
+ try {
36
+ return fs.readFileSync(full, 'utf8');
37
+ } catch (error) {
38
+ warnings.push(`could not read ${file}: ${error.message}`);
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Render one or more MDX sources into a single HTML document.
45
+ *
46
+ * @param {{plan?: string, canvas?: string, prototype?: string, state?: object, title?: string}} source
47
+ * @returns {{html: string, warnings: string[]}}
48
+ */
49
+ function renderPlanSource(source = {}) {
50
+ const warnings = [];
51
+ const ctx = { warnings, headings: [], ids: new Map(), hasMermaid: false, boards: 0, docBlocks: 0, dir: source.dir || null };
52
+ const sections = [];
53
+ const allBlocks = [];
54
+
55
+ const render = (mdx, heading, asBoard, file) => {
56
+ ctx.src = file;
57
+ const blocks = parseMdx(text(mdx));
58
+ allBlocks.push(...blocks);
59
+ for (const warning of blocks.warnings || []) warnings.push(warning);
60
+ if (heading) {
61
+ const id = uniqueHeading(heading, ctx);
62
+ ctx.headings.push({ id, text: heading, level: 2 });
63
+ sections.push(`<h2 class="sec" id="${id}">${heading}</h2>`);
64
+ }
65
+ sections.push(asBoard ? renderBoard(blocks, ctx) : renderDocument(blocks, ctx));
66
+ return blocks.frontmatter || {};
67
+ };
68
+
69
+ const frontmatter = render(source.plan, null, false, PLAN_FILE);
70
+ for (const extra of OPTIONAL_SOURCES) {
71
+ const mdx = source[extra.key];
72
+ if (!text(mdx)) continue;
73
+ render(mdx, extra.title, extra.board, extra.file);
74
+ }
75
+
76
+ sections.push(prototypeHint(allBlocks, frontmatter));
77
+
78
+ const state = source.state && typeof source.state === 'object' ? source.state : {};
79
+ const kind = text(frontmatter.kind) || text(state.kind);
80
+ const title = source.title || frontmatter.title || state.title || 'Plan';
81
+ const status = text(frontmatter.status || state.status || state.kind);
82
+ const meta = [
83
+ kind ? `kind: ${kind}` : '',
84
+ state.localOnly ? 'local-only' : '',
85
+ `${warnings.length} warning(s)`
86
+ ].filter(Boolean).join(' · ');
87
+
88
+ const body = sections.filter(Boolean).join('\n');
89
+ const html = page({
90
+ title: text(title),
91
+ status,
92
+ meta,
93
+ headings: ctx.headings,
94
+ body,
95
+ warnings,
96
+ hasMermaid: ctx.hasMermaid,
97
+ hasBoard: ctx.boards > 0,
98
+ boardOnly: ctx.boards > 0 && ctx.docBlocks === 0,
99
+ recap: kind === 'recap' ? frontmatter : null
100
+ });
101
+ return { html, warnings };
102
+ }
103
+
104
+ function text(value) {
105
+ return typeof value === 'string' ? value : '';
106
+ }
107
+
108
+ function uniqueHeading(raw, ctx) {
109
+ const base = slugify(raw) || 'section';
110
+ const count = ctx.ids.get(base) || 0;
111
+ ctx.ids.set(base, count + 1);
112
+ return count ? `${base}-${count}` : base;
113
+ }
114
+
115
+ /**
116
+ * Build the HTML for a plan folder (or a single plan.mdx path) and write it
117
+ * next to the plan as `plan.builder.html`.
118
+ *
119
+ * A folder without `plan.mdx` is an error, reported — never thrown — so the
120
+ * CLI can turn it into exit code 2 with a clear message.
121
+ *
122
+ * @param {string} dirOrFile
123
+ * @returns {{html?: string, warnings: string[], outFile?: string, error?: string}}
124
+ */
125
+ function renderPlanFolder(dirOrFile) {
126
+ const warnings = [];
127
+ const target = path.resolve(dirOrFile);
128
+
129
+ let dir = target;
130
+ let planPath = path.join(target, PLAN_FILE);
131
+ let stat = null;
132
+ try {
133
+ stat = fs.statSync(target);
134
+ } catch {
135
+ stat = null;
136
+ }
137
+
138
+ if (stat && stat.isFile()) {
139
+ dir = path.dirname(target);
140
+ planPath = target;
141
+ if (path.basename(target) !== PLAN_FILE) {
142
+ return { error: `expected ${PLAN_FILE} (got ${path.basename(target)})`, warnings };
143
+ }
144
+ } else if (!stat) {
145
+ return { error: `plan path not found: ${dirOrFile}`, warnings };
146
+ } else if (!stat.isDirectory()) {
147
+ return { error: `not a plan folder or file: ${dirOrFile}`, warnings };
148
+ }
149
+
150
+ if (!fs.existsSync(planPath)) {
151
+ return { error: `no ${PLAN_FILE} in ${dir}`, warnings };
152
+ }
153
+
154
+ let planText;
155
+ try {
156
+ planText = fs.readFileSync(planPath, 'utf8');
157
+ } catch (error) {
158
+ return { error: `could not read ${planPath}: ${error.message}`, warnings };
159
+ }
160
+
161
+ const source = { plan: planText, dir };
162
+ for (const extra of OPTIONAL_SOURCES) {
163
+ const mdx = readIfPresent(dir, extra.file, warnings);
164
+ if (mdx) source[extra.key] = mdx;
165
+ }
166
+ const statePath = path.join(dir, '.plan-state.json');
167
+ if (fs.existsSync(statePath)) {
168
+ try {
169
+ source.state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
170
+ } catch (error) {
171
+ warnings.push(`could not parse .plan-state.json: ${error.message}`);
172
+ }
173
+ }
174
+
175
+ const result = renderPlanSource(source);
176
+ warnings.push(...result.warnings);
177
+
178
+ const outFile = path.join(dir, OUTPUT_FILE);
179
+ try {
180
+ fs.writeFileSync(outFile, result.html);
181
+ } catch (error) {
182
+ return { html: result.html, warnings, error: `could not write ${outFile}: ${error.message}` };
183
+ }
184
+
185
+ return { html: result.html, warnings, outFile };
186
+ }
187
+
188
+ module.exports = { renderPlanFolder, renderPlanSource, parseMdx, OUTPUT_FILE, PLAN_FILE };
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Low-fidelity wireframe kit: the layout tags authored inside <Screen> /
5
+ * <FrameScreen> (<Col>, <Row>, <Box>, <Lines>, ...) rendered as plain,
6
+ * escaped HTML. Only numbers that were parsed and clamped reach a style
7
+ * attribute; every string goes through escapeHtml.
8
+ */
9
+
10
+ const { escapeHtml: esc } = require('../plan-canvas/markdown');
11
+
12
+ const DEFAULT_WIDTHS = [92, 78, 86, 64, 72];
13
+
14
+ function str(value) {
15
+ if (value === undefined || value === null || value === true || value === false) return '';
16
+ return typeof value === 'object' ? JSON.stringify(value) : String(value);
17
+ }
18
+
19
+ function clamp(value, min, max, fallback) {
20
+ const n = Number(value);
21
+ return Number.isFinite(n) ? Math.min(max, Math.max(min, n)) : fallback;
22
+ }
23
+
24
+ function flag(value) {
25
+ return value === true || value === 'true';
26
+ }
27
+
28
+ function plainChildren(block) {
29
+ return (block.childrenRaw || '').trim();
30
+ }
31
+
32
+ // Inline text for a kit node: explicit props first, then literal children.
33
+ function labelOf(block, ...keys) {
34
+ for (const key of keys) {
35
+ const value = str(block.props[key]);
36
+ if (value) return value;
37
+ }
38
+ return plainChildren(block);
39
+ }
40
+
41
+ function cls(base, ...extra) {
42
+ return [base, ...extra.filter(Boolean)].join(' ');
43
+ }
44
+
45
+ function chips(items) {
46
+ const list = Array.isArray(items) ? items : [];
47
+ return list.map((item) => {
48
+ const obj = item && typeof item === 'object' ? item : { label: str(item) };
49
+ return `<span class="${cls('k-chip', flag(obj.active) && 'on')}">${esc(str(obj.label || obj.text))}</span>`;
50
+ }).join('');
51
+ }
52
+
53
+ const TAGS = {
54
+ FrameScreen: (b, inner) => `<div class="k-frame">${inner}</div>`,
55
+ Main: (b, inner) => `<div class="k-col k-main">${inner}</div>`,
56
+ Col: (b, inner) => `<div class="${cls('k-col', flag(b.props.full) && 'full')}">${inner}</div>`,
57
+ Row: (b, inner) => `<div class="${cls('k-row', flag(b.props.full) && 'full')}">${inner}</div>`,
58
+ Box: (b, inner) => `<div class="${cls('k-box', flag(b.props.dashed) && 'dashed', flag(b.props.full) && 'full')}">${inner}</div>`,
59
+ Card: (b, inner) => `<div class="k-box k-card">${inner}</div>`,
60
+ Lines: (b) => {
61
+ const count = clamp(b.props.n, 1, 40, 3);
62
+ const widths = Array.isArray(b.props.widths) ? b.props.widths : [];
63
+ let html = '';
64
+ for (let i = 0; i < count; i++) {
65
+ const width = clamp(widths[i], 4, 100, DEFAULT_WIDTHS[i % DEFAULT_WIDTHS.length]);
66
+ html += `<i class="k-bar" style="width:${width}%"></i>`;
67
+ }
68
+ return `<div class="k-lines">${html}</div>`;
69
+ },
70
+ IconSquare: (b) => `<i class="${cls('k-icon', flag(b.props.active) && 'on')}"></i>`,
71
+ Divider: () => '<hr class="k-div">',
72
+ StatusBar: () => '<div class="k-status"><i></i><i></i><i></i><b></b></div>',
73
+ TaskRow: (b) => {
74
+ const done = flag(b.props.done);
75
+ const note = str(b.props.note);
76
+ return `<div class="${cls('k-task', done && 'done')}"><i class="k-check"></i>` +
77
+ `<span class="k-text">${esc(labelOf(b, 'title', 'label', 'text'))}</span>` +
78
+ (note ? `<span class="k-text k-muted">${esc(note)}</span>` : '') + '</div>';
79
+ },
80
+ Text: (b) => {
81
+ const tone = str(b.props.tone) === 'muted' ? 'k-muted' : '';
82
+ const weight = str(b.props.weight) === 'bold' ? 'k-bold' : '';
83
+ return `<span class="${cls('k-text', tone, weight)}">${esc(labelOf(b, 'value', 'text', 'label'))}</span>`;
84
+ },
85
+ Title: (b) => `<div class="k-title">${esc(labelOf(b, 'text', 'value', 'label'))}</div>`,
86
+ SectionLabel: (b) => `<div class="k-section-label">${esc(labelOf(b, 'label', 'text', 'value'))}</div>`,
87
+ Btn: (b) => `<span class="${cls('k-btn', flag(b.props.primary) && 'on')}">${esc(labelOf(b, 'label', 'text'))}</span>`,
88
+ Chips: (b) => `<div class="k-chips">${chips(b.props.items)}</div>`,
89
+ Skeleton: (b) => {
90
+ const lines = clamp(b.props.lines, 0, 20, 0);
91
+ if (lines) return TAGS.Lines({ props: { n: lines, widths: b.props.widths } });
92
+ const width = clamp(b.props.width ?? b.props.w, 4, 100, 100);
93
+ const height = clamp(b.props.height ?? b.props.h, 4, 600, 14);
94
+ return `<i class="k-skel" style="width:${width}%;height:${height}px"></i>`;
95
+ }
96
+ };
97
+
98
+ const KIT_TAGS = new Set(Object.keys(TAGS));
99
+
100
+ function renderKit(blocks, ctx) {
101
+ const out = [];
102
+ for (const block of blocks || []) {
103
+ if (block.type === 'tag') {
104
+ const handler = Object.hasOwn(TAGS, block.name) ? TAGS[block.name] : null;
105
+ if (handler) {
106
+ out.push(handler(block, renderKit(block.children, ctx)));
107
+ } else {
108
+ ctx.warnings.push(`unknown wireframe kit tag <${block.name}>`);
109
+ out.push(`<div class="k-unknown">&lt;${esc(block.name)}&gt;</div>`);
110
+ }
111
+ } else if (block.type === 'heading') {
112
+ out.push(`<div class="k-title">${esc(block.text)}</div>`);
113
+ } else if (block.type === 'prose') {
114
+ out.push(`<span class="k-text">${esc(block.text)}</span>`);
115
+ } else if (block.type === 'malformed') {
116
+ ctx.warnings.push(block.message || 'malformed wireframe kit markup');
117
+ out.push(`<div class="k-unknown">${esc(block.message || 'malformed')}</div>`);
118
+ }
119
+ }
120
+ return out.join('');
121
+ }
122
+
123
+ module.exports = { renderKit, KIT_TAGS };