@protoboxai/codeloop 0.3.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 (290) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +589 -0
  3. package/dist/commands/adopt.d.ts +2 -0
  4. package/dist/commands/adopt.js +26 -0
  5. package/dist/commands/adopt.js.map +1 -0
  6. package/dist/commands/brief.d.ts +2 -0
  7. package/dist/commands/brief.js +22 -0
  8. package/dist/commands/brief.js.map +1 -0
  9. package/dist/commands/card.d.ts +6 -0
  10. package/dist/commands/card.js +159 -0
  11. package/dist/commands/card.js.map +1 -0
  12. package/dist/commands/check.d.ts +4 -0
  13. package/dist/commands/check.js +76 -0
  14. package/dist/commands/check.js.map +1 -0
  15. package/dist/commands/cloud.d.ts +8 -0
  16. package/dist/commands/cloud.js +123 -0
  17. package/dist/commands/cloud.js.map +1 -0
  18. package/dist/commands/guard.d.ts +2 -0
  19. package/dist/commands/guard.js +26 -0
  20. package/dist/commands/guard.js.map +1 -0
  21. package/dist/commands/import.d.ts +2 -0
  22. package/dist/commands/import.js +24 -0
  23. package/dist/commands/import.js.map +1 -0
  24. package/dist/commands/inbox.d.ts +2 -0
  25. package/dist/commands/inbox.js +48 -0
  26. package/dist/commands/inbox.js.map +1 -0
  27. package/dist/commands/init.d.ts +2 -0
  28. package/dist/commands/init.js +142 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/install.d.ts +2 -0
  31. package/dist/commands/install.js +125 -0
  32. package/dist/commands/install.js.map +1 -0
  33. package/dist/commands/lane.d.ts +2 -0
  34. package/dist/commands/lane.js +100 -0
  35. package/dist/commands/lane.js.map +1 -0
  36. package/dist/commands/list.d.ts +2 -0
  37. package/dist/commands/list.js +35 -0
  38. package/dist/commands/list.js.map +1 -0
  39. package/dist/commands/login.d.ts +2 -0
  40. package/dist/commands/login.js +77 -0
  41. package/dist/commands/login.js.map +1 -0
  42. package/dist/commands/mock.d.ts +3 -0
  43. package/dist/commands/mock.js +22 -0
  44. package/dist/commands/mock.js.map +1 -0
  45. package/dist/commands/pack.d.ts +2 -0
  46. package/dist/commands/pack.js +19 -0
  47. package/dist/commands/pack.js.map +1 -0
  48. package/dist/commands/publish.d.ts +2 -0
  49. package/dist/commands/publish.js +125 -0
  50. package/dist/commands/publish.js.map +1 -0
  51. package/dist/commands/remove.d.ts +2 -0
  52. package/dist/commands/remove.js +31 -0
  53. package/dist/commands/remove.js.map +1 -0
  54. package/dist/commands/render.d.ts +5 -0
  55. package/dist/commands/render.js +47 -0
  56. package/dist/commands/render.js.map +1 -0
  57. package/dist/commands/run.d.ts +2 -0
  58. package/dist/commands/run.js +45 -0
  59. package/dist/commands/run.js.map +1 -0
  60. package/dist/commands/scan.d.ts +2 -0
  61. package/dist/commands/scan.js +26 -0
  62. package/dist/commands/scan.js.map +1 -0
  63. package/dist/commands/schedule.d.ts +2 -0
  64. package/dist/commands/schedule.js +51 -0
  65. package/dist/commands/schedule.js.map +1 -0
  66. package/dist/commands/search.d.ts +2 -0
  67. package/dist/commands/search.js +85 -0
  68. package/dist/commands/search.js.map +1 -0
  69. package/dist/commands/serve.d.ts +7 -0
  70. package/dist/commands/serve.js +126 -0
  71. package/dist/commands/serve.js.map +1 -0
  72. package/dist/commands/spec.d.ts +3 -0
  73. package/dist/commands/spec.js +64 -0
  74. package/dist/commands/spec.js.map +1 -0
  75. package/dist/commands/status.d.ts +3 -0
  76. package/dist/commands/status.js +251 -0
  77. package/dist/commands/status.js.map +1 -0
  78. package/dist/commands/update.d.ts +2 -0
  79. package/dist/commands/update.js +83 -0
  80. package/dist/commands/update.js.map +1 -0
  81. package/dist/commands/verify.d.ts +3 -0
  82. package/dist/commands/verify.js +75 -0
  83. package/dist/commands/verify.js.map +1 -0
  84. package/dist/commands/watch.d.ts +6 -0
  85. package/dist/commands/watch.js +111 -0
  86. package/dist/commands/watch.js.map +1 -0
  87. package/dist/commands/wiki.d.ts +3 -0
  88. package/dist/commands/wiki.js +85 -0
  89. package/dist/commands/wiki.js.map +1 -0
  90. package/dist/index.d.ts +2 -0
  91. package/dist/index.js +86 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/lib/agent.d.ts +27 -0
  94. package/dist/lib/agent.js +178 -0
  95. package/dist/lib/agent.js.map +1 -0
  96. package/dist/lib/board.d.ts +38 -0
  97. package/dist/lib/board.js +86 -0
  98. package/dist/lib/board.js.map +1 -0
  99. package/dist/lib/cards.d.ts +82 -0
  100. package/dist/lib/cards.js +107 -0
  101. package/dist/lib/cards.js.map +1 -0
  102. package/dist/lib/clock.d.ts +5 -0
  103. package/dist/lib/clock.js +14 -0
  104. package/dist/lib/clock.js.map +1 -0
  105. package/dist/lib/cloud.d.ts +122 -0
  106. package/dist/lib/cloud.js +580 -0
  107. package/dist/lib/cloud.js.map +1 -0
  108. package/dist/lib/competitors.d.ts +28 -0
  109. package/dist/lib/competitors.js +90 -0
  110. package/dist/lib/competitors.js.map +1 -0
  111. package/dist/lib/config.d.ts +7 -0
  112. package/dist/lib/config.js +25 -0
  113. package/dist/lib/config.js.map +1 -0
  114. package/dist/lib/cron.d.ts +5 -0
  115. package/dist/lib/cron.js +82 -0
  116. package/dist/lib/cron.js.map +1 -0
  117. package/dist/lib/detect.d.ts +13 -0
  118. package/dist/lib/detect.js +60 -0
  119. package/dist/lib/detect.js.map +1 -0
  120. package/dist/lib/engine.d.ts +88 -0
  121. package/dist/lib/engine.js +435 -0
  122. package/dist/lib/engine.js.map +1 -0
  123. package/dist/lib/flow.d.ts +44 -0
  124. package/dist/lib/flow.js +121 -0
  125. package/dist/lib/flow.js.map +1 -0
  126. package/dist/lib/glob.d.ts +2 -0
  127. package/dist/lib/glob.js +10 -0
  128. package/dist/lib/glob.js.map +1 -0
  129. package/dist/lib/import.d.ts +13 -0
  130. package/dist/lib/import.js +127 -0
  131. package/dist/lib/import.js.map +1 -0
  132. package/dist/lib/inbox.d.ts +42 -0
  133. package/dist/lib/inbox.js +65 -0
  134. package/dist/lib/inbox.js.map +1 -0
  135. package/dist/lib/lane.d.ts +71 -0
  136. package/dist/lib/lane.js +105 -0
  137. package/dist/lib/lane.js.map +1 -0
  138. package/dist/lib/lock.d.ts +6 -0
  139. package/dist/lib/lock.js +64 -0
  140. package/dist/lib/lock.js.map +1 -0
  141. package/dist/lib/mcp.d.ts +2 -0
  142. package/dist/lib/mcp.js +57 -0
  143. package/dist/lib/mcp.js.map +1 -0
  144. package/dist/lib/mock.d.ts +17 -0
  145. package/dist/lib/mock.js +137 -0
  146. package/dist/lib/mock.js.map +1 -0
  147. package/dist/lib/pack.d.ts +24 -0
  148. package/dist/lib/pack.js +77 -0
  149. package/dist/lib/pack.js.map +1 -0
  150. package/dist/lib/proposals.d.ts +48 -0
  151. package/dist/lib/proposals.js +240 -0
  152. package/dist/lib/proposals.js.map +1 -0
  153. package/dist/lib/render.d.ts +7 -0
  154. package/dist/lib/render.js +84 -0
  155. package/dist/lib/render.js.map +1 -0
  156. package/dist/lib/research.d.ts +8 -0
  157. package/dist/lib/research.js +39 -0
  158. package/dist/lib/research.js.map +1 -0
  159. package/dist/lib/run.d.ts +38 -0
  160. package/dist/lib/run.js +215 -0
  161. package/dist/lib/run.js.map +1 -0
  162. package/dist/lib/scaffold.d.ts +16 -0
  163. package/dist/lib/scaffold.js +175 -0
  164. package/dist/lib/scaffold.js.map +1 -0
  165. package/dist/lib/scan.d.ts +22 -0
  166. package/dist/lib/scan.js +85 -0
  167. package/dist/lib/scan.js.map +1 -0
  168. package/dist/lib/schedule.d.ts +20 -0
  169. package/dist/lib/schedule.js +66 -0
  170. package/dist/lib/schedule.js.map +1 -0
  171. package/dist/lib/server.d.ts +68 -0
  172. package/dist/lib/server.js +235 -0
  173. package/dist/lib/server.js.map +1 -0
  174. package/dist/lib/shell.d.ts +1 -0
  175. package/dist/lib/shell.js +25 -0
  176. package/dist/lib/shell.js.map +1 -0
  177. package/dist/lib/skills.d.ts +20 -0
  178. package/dist/lib/skills.js +92 -0
  179. package/dist/lib/skills.js.map +1 -0
  180. package/dist/lib/spec.d.ts +24 -0
  181. package/dist/lib/spec.js +102 -0
  182. package/dist/lib/spec.js.map +1 -0
  183. package/dist/lib/stats.d.ts +13 -0
  184. package/dist/lib/stats.js +43 -0
  185. package/dist/lib/stats.js.map +1 -0
  186. package/dist/lib/verify.d.ts +25 -0
  187. package/dist/lib/verify.js +135 -0
  188. package/dist/lib/verify.js.map +1 -0
  189. package/dist/lib/version.d.ts +10 -0
  190. package/dist/lib/version.js +27 -0
  191. package/dist/lib/version.js.map +1 -0
  192. package/dist/lib/wiki.d.ts +51 -0
  193. package/dist/lib/wiki.js +164 -0
  194. package/dist/lib/wiki.js.map +1 -0
  195. package/dist/registry/index.d.ts +7 -0
  196. package/dist/registry/index.js +8 -0
  197. package/dist/registry/index.js.map +1 -0
  198. package/dist/registry/installer.d.ts +30 -0
  199. package/dist/registry/installer.js +133 -0
  200. package/dist/registry/installer.js.map +1 -0
  201. package/dist/registry/local-index.d.ts +32 -0
  202. package/dist/registry/local-index.js +58 -0
  203. package/dist/registry/local-index.js.map +1 -0
  204. package/dist/registry/lockfile.d.ts +40 -0
  205. package/dist/registry/lockfile.js +85 -0
  206. package/dist/registry/lockfile.js.map +1 -0
  207. package/dist/registry/security.d.ts +25 -0
  208. package/dist/registry/security.js +100 -0
  209. package/dist/registry/security.js.map +1 -0
  210. package/dist/registry/skill-schema.d.ts +30 -0
  211. package/dist/registry/skill-schema.js +95 -0
  212. package/dist/registry/skill-schema.js.map +1 -0
  213. package/dist/ui/404.html +1 -0
  214. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_buildManifest.js +1 -0
  215. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_ssgManifest.js +1 -0
  216. package/dist/ui/_next/static/chunks/255-54d3085ce94738a4.js +1 -0
  217. package/dist/ui/_next/static/chunks/423-bb541b7ae2733575.js +1 -0
  218. package/dist/ui/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  219. package/dist/ui/_next/static/chunks/app/_not-found/page-d6bc774f7acb716e.js +1 -0
  220. package/dist/ui/_next/static/chunks/app/layout-e5fc8e78e1c8da95.js +1 -0
  221. package/dist/ui/_next/static/chunks/app/page-0c34b6e119cef236.js +1 -0
  222. package/dist/ui/_next/static/chunks/framework-de98b93a850cfc71.js +1 -0
  223. package/dist/ui/_next/static/chunks/main-49fd204fc9037ea3.js +1 -0
  224. package/dist/ui/_next/static/chunks/main-app-c46afa2f48f3aaef.js +1 -0
  225. package/dist/ui/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  226. package/dist/ui/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  227. package/dist/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  228. package/dist/ui/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
  229. package/dist/ui/_next/static/css/1bf01240dbfd6088.css +1 -0
  230. package/dist/ui/index.html +1 -0
  231. package/dist/ui/index.txt +19 -0
  232. package/dist/watch/index.d.ts +21 -0
  233. package/dist/watch/index.js +88 -0
  234. package/dist/watch/index.js.map +1 -0
  235. package/dist/watch/reporter.d.ts +11 -0
  236. package/dist/watch/reporter.js +44 -0
  237. package/dist/watch/reporter.js.map +1 -0
  238. package/dist/watch/signals.d.ts +38 -0
  239. package/dist/watch/signals.js +119 -0
  240. package/dist/watch/signals.js.map +1 -0
  241. package/dist/watch/triggers.d.ts +10 -0
  242. package/dist/watch/triggers.js +67 -0
  243. package/dist/watch/triggers.js.map +1 -0
  244. package/package.json +64 -0
  245. package/registry/index.json +106 -0
  246. package/starters/generic.yaml +95 -0
  247. package/starters/go.yaml +99 -0
  248. package/starters/node-typescript.yaml +108 -0
  249. package/starters/python.yaml +105 -0
  250. package/templates/ci/codeloop-pr.yml +29 -0
  251. package/templates/ci/codeloop-prod.yml +27 -0
  252. package/templates/ci/codeloop-staging.yml +34 -0
  253. package/templates/codeloop/board.json +5 -0
  254. package/templates/codeloop/gotchas.md +13 -0
  255. package/templates/codeloop/patterns.md +15 -0
  256. package/templates/codeloop/principles.md +49 -0
  257. package/templates/codeloop/rules.md +23 -0
  258. package/templates/commands/commit.md +255 -0
  259. package/templates/commands/debug.md +142 -0
  260. package/templates/commands/deploy.md +144 -0
  261. package/templates/commands/design.md +102 -0
  262. package/templates/commands/manage.md +77 -0
  263. package/templates/commands/plan.md +84 -0
  264. package/templates/commands/qa.md +155 -0
  265. package/templates/commands/reflect.md +93 -0
  266. package/templates/commands/ship.md +187 -0
  267. package/templates/commands/test.md +133 -0
  268. package/templates/hooks/commit-msg +8 -0
  269. package/templates/lanes/analyze.yaml +25 -0
  270. package/templates/lanes/build.yaml +45 -0
  271. package/templates/lanes/deploy.yaml +24 -0
  272. package/templates/lanes/learn.yaml +20 -0
  273. package/templates/lanes/market.yaml +25 -0
  274. package/templates/lanes/plan.yaml +24 -0
  275. package/templates/lanes/scan.yaml +11 -0
  276. package/templates/lanes/triage.yaml +24 -0
  277. package/templates/mock/template.html +82 -0
  278. package/templates/seeds/go-gotchas.md +28 -0
  279. package/templates/seeds/go-patterns.md +22 -0
  280. package/templates/seeds/node-typescript-gotchas.md +30 -0
  281. package/templates/seeds/node-typescript-patterns.md +27 -0
  282. package/templates/seeds/python-gotchas.md +30 -0
  283. package/templates/seeds/python-patterns.md +19 -0
  284. package/templates/seeds/universal-gotchas.md +11 -0
  285. package/templates/seeds/universal-patterns.md +11 -0
  286. package/templates/spec/plan.md +7 -0
  287. package/templates/spec/research.md +19 -0
  288. package/templates/spec/spec.md +14 -0
  289. package/templates/spec/tasks.md +10 -0
  290. package/templates/tasks/todo.md +3 -0
@@ -0,0 +1,57 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { DONE, findCard, inLane, readCards } from './cards.js';
5
+ import { advanceCard, rejectCard, resolveRole } from './engine.js';
6
+ import { approveFlow } from './flow.js';
7
+ import { buildInbox } from './inbox.js';
8
+ import { loadLane, substitute } from './lane.js';
9
+ import { resolveSpecDir, tickTask } from './spec.js';
10
+ import { capture, inject } from './wiki.js';
11
+ function card(projectDir, id) {
12
+ const found = findCard(readCards(projectDir).cards, id);
13
+ const stage = found.stage === DONE ? undefined : loadLane(projectDir, found.lane).stages.find(s => s.id === found.stage);
14
+ return {
15
+ ...found,
16
+ brief: stage && {
17
+ skill: stage.skill,
18
+ output: stage.output && substitute(stage.output, found),
19
+ done: stage.done?.cmd ? substitute(stage.done.cmd, found, { shell: true }) : stage.done?.event,
20
+ notes: stage.notes ?? [],
21
+ rejections: found.events.filter(e => e.action === 'reject' && e.stage === stage.id).map(e => e.note),
22
+ },
23
+ };
24
+ }
25
+ /** Same engine as the CLI. The role comes from CODELOOP_ROLE in the server's environment, never from a tool argument. */
26
+ export async function serveMcp(projectDir) {
27
+ const server = new McpServer({ name: 'codeloop', version: '0.2.0' });
28
+ const id = { id: z.string().describe('Card id, e.g. c-001') };
29
+ const tool = (name, description, inputSchema, run) => server.registerTool(name, { description, inputSchema }, (async (args) => {
30
+ try {
31
+ return { content: [{ type: 'text', text: JSON.stringify(run(args), null, 2) }] };
32
+ }
33
+ catch (e) {
34
+ return { isError: true, content: [{ type: 'text', text: `${e.name}: ${e.message}` }] };
35
+ }
36
+ }));
37
+ tool('inbox', 'Gates waiting on a person, what shipped, and numbers per lane.', {}, () => buildInbox(projectDir));
38
+ tool('next_up', 'Cards an agent can work now: unfinished and not waiting at a gate, oldest first.', {}, () => readCards(projectDir).cards.filter(c => inLane(c) && !c.gate).sort((a, b) => a.createdAt.localeCompare(b.createdAt)).map(c => card(projectDir, c.id)));
39
+ tool('get_card', 'A card with its current stage brief: skill, output path, done check, notes, earlier rejections.', id, a => card(projectDir, a.id));
40
+ tool('advance', "Run the current stage's done check and move the card if it passes.", id, a => {
41
+ const r = advanceCard(projectDir, a.id);
42
+ return { outcome: r.outcome, stage: r.card.stage, gate: r.card.gate, awaiting: r.card.awaiting, output: r.output, started: r.started.map(s => s.id) };
43
+ });
44
+ tool('approve', 'Approve the gate a card is waiting at, then advance it once. Refused unless the server runs with CODELOOP_ROLE=owner or reviewer.', { ...id, note: z.string().optional() }, a => {
45
+ const r = approveFlow(projectDir, a.id, resolveRole(), a.note);
46
+ return { approved: r.gate, stage: (r.advanced?.card ?? r.card).stage, outcome: r.advanced?.outcome };
47
+ });
48
+ tool('reject', 'Reject the gate with a note. Refused unless the server runs with CODELOOP_ROLE=owner or reviewer.', { ...id, note: z.string() }, a => rejectCard(projectDir, a.id, resolveRole(), a.note));
49
+ tool('task_done', 'Tick a task in the card spec folder.', { ...id, task: z.string().describe('Task id, e.g. T003') }, a => {
50
+ tickTask(projectDir, resolveSpecDir(projectDir, a.id), a.task);
51
+ return { done: a.task };
52
+ });
53
+ tool('wiki_inject', 'Wiki pages whose scope matches these files.', { files: z.array(z.string()) }, a => inject(projectDir, a.files));
54
+ tool('wiki_capture', 'Write a wiki page; an existing title raises its frequency.', { title: z.string(), scope: z.array(z.string()), body: z.string(), kind: z.enum(['gotcha', 'decision', 'concept']).optional(), card: z.string().optional() }, a => capture(projectDir, a));
55
+ await server.connect(new StdioServerTransport());
56
+ }
57
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/lib/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export declare const MOCKS_DIR = "docs/mocks";
2
+ /** The card's mock, wherever its project and topic folders put it. */
3
+ export declare function findMock(projectDir: string, cardId: string): string | undefined;
4
+ /** Creates the card's mock from the shared template. A mock that exists is never overwritten. */
5
+ export declare function newMock(projectDir: string, ref: string, topic: string): {
6
+ path: string;
7
+ created: boolean;
8
+ };
9
+ /** The names under `screens:` in a spec, or 'none' when the spec says the card has nothing to draw. */
10
+ export declare function specScreens(spec: string): string[] | 'none';
11
+ /** Why the card's mock does not pass, one line each. Empty when it passes. */
12
+ export declare function checkMock(projectDir: string, ref: string): string[];
13
+ /** Writes docs/mocks/index.html: projects, then topics, then cards, each newest first. */
14
+ export declare function writeMocksIndex(projectDir: string): {
15
+ path: string;
16
+ mocks: number;
17
+ };
@@ -0,0 +1,137 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs';
2
+ import { basename, dirname, join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { findCard, findCardOrNone, readCards, safeName } from './cards.js';
5
+ import { loadConfig } from './config.js';
6
+ import { resolveSpecDir, slugify } from './spec.js';
7
+ const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
8
+ const TEMPLATE = 'templates/mock/template.html';
9
+ export const MOCKS_DIR = 'docs/mocks';
10
+ const MARKER = '<!-- codeloop-mock-template: 1 -->';
11
+ const TOKENS = /\/\* codeloop-tokens:start \*\/[\s\S]*?\/\* codeloop-tokens:end \*\//;
12
+ // Hex colours and colour functions. `href="#fff"` is a link to an anchor, and `&#123;` an entity.
13
+ const COLOUR = /(?<![&\w]|href=["'])#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{3,4})\b|\b(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch)\(/g;
14
+ const template = () => readFileSync(join(PACKAGE_ROOT, TEMPLATE), 'utf-8');
15
+ const escape = (text) => text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
16
+ function projectName(projectDir) {
17
+ return slugify(String(loadConfig(projectDir).project?.name ?? '')) || slugify(basename(projectDir)) || 'project';
18
+ }
19
+ /** The card's mock, wherever its project and topic folders put it. */
20
+ export function findMock(projectDir, cardId) {
21
+ const root = join(projectDir, MOCKS_DIR);
22
+ if (!existsSync(root))
23
+ return undefined;
24
+ for (const project of dirs(root)) {
25
+ for (const topic of dirs(join(root, project))) {
26
+ if (existsSync(join(root, project, topic, `${cardId}.html`)))
27
+ return `${MOCKS_DIR}/${project}/${topic}/${cardId}.html`;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ const dirs = (path) => readdirSync(path).filter(d => statSync(join(path, d)).isDirectory()).sort();
33
+ /** Creates the card's mock from the shared template. A mock that exists is never overwritten. */
34
+ export function newMock(projectDir, ref, topic) {
35
+ const card = findCard(readCards(projectDir).cards, ref);
36
+ const folder = safeName(topic, 'topic');
37
+ const existing = findMock(projectDir, card.id);
38
+ if (existing)
39
+ return { path: existing, created: false };
40
+ const project = projectName(projectDir);
41
+ const path = `${MOCKS_DIR}/${project}/${folder}/${card.id}.html`;
42
+ const values = { id: card.id, title: escape(card.title), project, topic };
43
+ mkdirSync(dirname(join(projectDir, path)), { recursive: true });
44
+ writeFileSync(join(projectDir, path), template().replace(/\{\{(id|title|project|topic)\}\}/g, (_, key) => values[key]));
45
+ return { path, created: true };
46
+ }
47
+ /** The names under `screens:` in a spec, or 'none' when the spec says the card has nothing to draw. */
48
+ export function specScreens(spec) {
49
+ const lines = spec.split('\n');
50
+ const at = lines.findIndex(l => /^screens:/.test(l));
51
+ if (at < 0)
52
+ return [];
53
+ const inline = lines[at].replace(/^screens:/, '').trim();
54
+ if (inline.toLowerCase() === 'none')
55
+ return 'none';
56
+ if (inline)
57
+ return inline.replace(/^\[|\]$/g, '').split(',').map(s => s.trim()).filter(Boolean);
58
+ const names = [];
59
+ for (const line of lines.slice(at + 1)) {
60
+ const item = /^\s*-\s+(\S.*)$/.exec(line);
61
+ if (!item) {
62
+ if (line.trim() === '')
63
+ continue;
64
+ break;
65
+ }
66
+ names.push(item[1].trim());
67
+ }
68
+ return names;
69
+ }
70
+ /** Why the card's mock does not pass, one line each. Empty when it passes. */
71
+ export function checkMock(projectDir, ref) {
72
+ const card = findCardOrNone(readCards(projectDir).cards, ref);
73
+ const specDir = resolveSpecDir(projectDir, ref);
74
+ const specFile = join(projectDir, specDir, 'spec.md');
75
+ const screens = existsSync(specFile) ? specScreens(readFileSync(specFile, 'utf-8')) : [];
76
+ if (screens === 'none')
77
+ return [];
78
+ // An untouched spec template names nothing, so it cannot pass.
79
+ if (screens.length === 0)
80
+ return [`${specDir}/spec.md names no screens under \`screens:\` (write \`screens: none\` for a card with nothing to draw)`];
81
+ const id = card?.id ?? ref;
82
+ const path = findMock(projectDir, id);
83
+ if (!path)
84
+ return [`no mock for ${id} under ${MOCKS_DIR}; run \`codeloop mock new ${id} --topic <topic>\``];
85
+ const html = readFileSync(join(projectDir, path), 'utf-8').replace(/\r\n/g, '\n');
86
+ if (!html.includes(MARKER))
87
+ return [`${path} does not carry the template marker ${MARKER}`];
88
+ if (TOKENS.exec(html)?.[0] !== TOKENS.exec(template())[0])
89
+ return [`${path}: the tokens block differs from ${TEMPLATE}`];
90
+ const errors = [];
91
+ const literals = [...new Set(html.replace(TOKENS, '').match(COLOUR) ?? [])];
92
+ if (literals.length)
93
+ errors.push(`${path} uses colours outside the tokens block: ${literals.join(', ')}`);
94
+ for (const screen of screens) {
95
+ if (!new RegExp(`<section[^>]*\\sdata-screen=["']${screen.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}["']`).test(html)) {
96
+ errors.push(`${path} has no <section data-screen="${screen}"> for a screen named in the spec`);
97
+ }
98
+ }
99
+ return errors;
100
+ }
101
+ /** Writes docs/mocks/index.html: projects, then topics, then cards, each newest first. */
102
+ export function writeMocksIndex(projectDir) {
103
+ const root = join(projectDir, MOCKS_DIR);
104
+ const { cards } = readCards(projectDir);
105
+ const found = (existsSync(root) ? dirs(root) : []).flatMap(project => dirs(join(root, project)).flatMap(topic => readdirSync(join(root, project, topic)).filter(f => f.endsWith('.html')).map(file => {
106
+ const full = join(root, project, topic, file);
107
+ const id = file.replace(/\.html$/, '');
108
+ const title = cards.find(c => c.id === id)?.title ?? /<title>([^<]*)<\/title>/.exec(readFileSync(full, 'utf-8'))?.[1] ?? id;
109
+ return { project, topic, id, title, href: `${project}/${topic}/${file}`, at: statSync(full).mtimeMs };
110
+ })));
111
+ const newest = (items) => Math.max(...items.map(i => i.at));
112
+ const group = (items, key) => [...new Set(items.map(i => i[key]))].map(name => ({ name, items: items.filter(i => i[key] === name) })).sort((a, b) => newest(b.items) - newest(a.items));
113
+ const body = group(found, 'project').map(project => [
114
+ `<section data-screen="${escape(project.name)}">`,
115
+ ` <h2>${escape(project.name)}</h2>`,
116
+ ...group(project.items, 'topic').map(topic => [
117
+ ' <div class="frame">',
118
+ ` <strong>${escape(topic.name)}</strong>`,
119
+ ' <table>',
120
+ ...topic.items.sort((a, b) => b.at - a.at).map(m => ` <tr><td><a href="${escape(m.href)}">${escape(m.id)}</a></td><td>${escape(m.title)}</td><td class="muted">${new Date(m.at).toISOString().slice(0, 10)}</td></tr>`),
121
+ ' </table>',
122
+ ' </div>',
123
+ ].join('\n')),
124
+ '</section>',
125
+ ].join('\n')).join('\n');
126
+ // The gallery is the same page shell as every mock, with the list where the screens go.
127
+ const html = template()
128
+ .replace('<title>{{id}} {{title}}</title>', '<title>Mocks</title>')
129
+ .replace('<h1>{{title}}</h1>', '<h1>Mocks</h1>')
130
+ .replace('{{id}} · {{project}} · {{topic}}', `${found.length} ${found.length === 1 ? 'mock' : 'mocks'}, newest first`)
131
+ .replace(/<main class="screens">[\s\S]*<\/main>/, `<main class="screens">\n${body || '<p class="muted">No mocks yet. `codeloop mock new &lt;card&gt; --topic &lt;topic&gt;` creates one.</p>'}\n</main>`);
132
+ const path = `${MOCKS_DIR}/index.html`;
133
+ mkdirSync(root, { recursive: true });
134
+ writeFileSync(join(projectDir, path), html);
135
+ return { path, mocks: found.length };
136
+ }
137
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/lib/mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC/F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC/E,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AAChD,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC;AACtC,MAAM,MAAM,GAAG,oCAAoC,CAAC;AACpD,MAAM,MAAM,GAAG,sEAAsE,CAAC;AACtF,kGAAkG;AAClG,MAAM,MAAM,GAAG,wHAAwH,CAAC;AAExI,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3E,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEjI,SAAS,WAAW,CAAC,UAAkB;IACrC,OAAO,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,SAAS,CAAC;AACnH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,UAAkB,EAAE,MAAc;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;YAC9C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;gBAAE,OAAO,GAAG,SAAS,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM,OAAO,CAAC;QACzH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAE3G,iGAAiG;AACjG,MAAM,UAAU,OAAO,CAAC,UAAkB,EAAE,GAAW,EAAE,KAAa;IACpE,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,IAAI,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACxD,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,GAAG,SAAS,IAAI,OAAO,IAAI,MAAM,IAAI,IAAI,CAAC,EAAE,OAAO,CAAC;IACjE,MAAM,MAAM,GAA2B,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAClG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAChI,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnD,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChG,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAS;YACjC,MAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAE,GAAW;IACvD,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAClC,+DAA+D;IAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,OAAO,wGAAwG,CAAC,CAAC;IAEtJ,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,GAAG,CAAC;IAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,eAAe,EAAE,UAAU,SAAS,6BAA6B,EAAE,oBAAoB,CAAC,CAAC;IAC5G,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,GAAG,IAAI,uCAAuC,MAAM,EAAE,CAAC,CAAC;IAC5F,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAE,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,GAAG,IAAI,mCAAmC,QAAQ,EAAE,CAAC,CAAC;IAE1H,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5E,IAAI,QAAQ,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,2CAA2C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1G,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,MAAM,CAAC,mCAAmC,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnH,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,iCAAiC,MAAM,mCAAmC,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACzC,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CACnE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CACxC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,yBAAyB,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5H,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,IAAI,KAAK,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IACxG,CAAC,CAAC,CACH,CACF,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,KAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,CAAgC,KAAmB,EAAE,GAAM,EAAE,EAAE,CAC3E,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAE5J,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAClD,yBAAyB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;QACjD,SAAS,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO;QACpC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,uBAAuB;YACvB,eAAe,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW;YAC5C,aAAa;YACb,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,0BAA0B,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC;YAC5N,cAAc;YACd,UAAU;SACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,YAAY;KACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEzB,wFAAwF;IACxF,MAAM,IAAI,GAAG,QAAQ,EAAE;SACpB,OAAO,CAAC,iCAAiC,EAAE,sBAAsB,CAAC;SAClE,OAAO,CAAC,oBAAoB,EAAE,gBAAgB,CAAC;SAC/C,OAAO,CAAC,kCAAkC,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,gBAAgB,CAAC;SACrH,OAAO,CAAC,uCAAuC,EAAE,2BAA2B,IAAI,IAAI,wGAAwG,WAAW,CAAC,CAAC;IAC5M,MAAM,IAAI,GAAG,GAAG,SAAS,aAAa,CAAC;IACvC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,24 @@
1
+ interface PackSkill {
2
+ skillId: string;
3
+ title: string;
4
+ description: string;
5
+ content: string;
6
+ toolDeps: string[];
7
+ }
8
+ export declare function skillIdFor(name: string): string;
9
+ export declare function buildPack(projectDir: string, version?: string): {
10
+ id: string;
11
+ version: string;
12
+ 'x-source-sha256': string;
13
+ kind: string;
14
+ display: {
15
+ name: string;
16
+ description: string;
17
+ };
18
+ auth: {
19
+ type: string;
20
+ }[];
21
+ availability: string;
22
+ skills: PackSkill[];
23
+ };
24
+ export {};
@@ -0,0 +1,77 @@
1
+ import { createHash } from 'crypto';
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { resolve } from 'path';
4
+ import { RefusalError } from './engine.js';
5
+ import { loadLanes, loadSkillsIndex, SKILLS_INDEX } from './lane.js';
6
+ import { parseFrontmatter } from './skills.js';
7
+ // The Protobox manifest validator requires lower_snake skill ids.
8
+ export function skillIdFor(name) {
9
+ const id = name.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
10
+ if (!/^[a-z][a-z0-9_]*$/.test(id))
11
+ throw new RefusalError(`skill name "${name}" does not yield a lower_snake skillId`);
12
+ return id;
13
+ }
14
+ function titleFor(name, title, body) {
15
+ if (typeof title === 'string' && title.trim())
16
+ return title.trim();
17
+ const h1 = /^#\s+(.+?)\s*$/m.exec(body);
18
+ if (h1)
19
+ return h1[1].trim();
20
+ return name.split(/[-_:]/).map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
21
+ }
22
+ function guide(lanes) {
23
+ const lines = ['# Codeloop guide', '', 'Each lane moves a card through its stages in order. A stage runs the named skill and is finished when its done check passes; a gate waits for a person. A gate on a public step is asked first: approve before the stage runs. Other gates are approved after the check passes.', ''];
24
+ for (const lane of lanes) {
25
+ lines.push(`## ${lane.id} (v${lane.version})`, '', '| Stage | Skill | Output | Done check | Gate |', '|---|---|---|---|---|');
26
+ for (const s of lane.stages) {
27
+ const who = s.skill ? skillIdFor(s.skill) : [s.role ?? ''].flat().join(', ');
28
+ const gate = s.gate ? `${s.gate.name} (${s.gate.approver}, ${s.gate.outward ? 'public step: approve before the stage runs' : 'approve after the check passes'})` : '';
29
+ lines.push(`| ${s.id} | ${who} | ${s.output ?? ''} | ${(s.done?.cmd ?? s.done?.event ?? '').replace(/\|/g, '\\|')} | ${gate} |`);
30
+ }
31
+ lines.push('');
32
+ }
33
+ return lines.join('\n');
34
+ }
35
+ export function buildPack(projectDir, version = '1.0.0') {
36
+ const lanes = loadLanes(projectDir);
37
+ if (lanes.length === 0)
38
+ throw new RefusalError('no lanes found; nothing to pack');
39
+ const index = loadSkillsIndex(projectDir);
40
+ if (!index)
41
+ throw new RefusalError(`${SKILLS_INDEX} not found; run \`codeloop adopt\` first`);
42
+ const names = [...new Set(lanes.flatMap(l => l.stages.map(s => s.skill).filter((s) => !!s)))].sort();
43
+ const missing = names.filter(n => !index.some(e => e.name === n));
44
+ if (missing.length)
45
+ throw new RefusalError(`lanes reference skills that are not in ${SKILLS_INDEX}: ${missing.join(', ')}`);
46
+ const skills = names.map(name => {
47
+ const found = index.find(e => e.name === name);
48
+ const file = resolve(projectDir, found.source);
49
+ if (!existsSync(file))
50
+ throw new RefusalError(`skill ${name}: source ${found.source} no longer exists; re-run \`codeloop adopt\``);
51
+ const { data, body } = parseFrontmatter(readFileSync(file, 'utf-8'));
52
+ const title = titleFor(name, data.title, body);
53
+ return { skillId: skillIdFor(name), title, description: found.description || title || `${name} skill`, content: body.trim(), toolDeps: [] };
54
+ });
55
+ skills.push({
56
+ skillId: 'codeloop_guide',
57
+ title: 'Codeloop guide',
58
+ description: 'Which lane runs which skill at which stage, what each stage must produce, and how it is checked.',
59
+ content: guide(lanes),
60
+ toolDeps: [],
61
+ });
62
+ const hash = createHash('sha256');
63
+ for (const s of skills)
64
+ hash.update(s.skillId).update('\0').update(s.content).update('\0');
65
+ return {
66
+ id: 'codeloop',
67
+ version,
68
+ 'x-source-sha256': hash.digest('hex'),
69
+ // 'platform' with no platform block is the manifest validator's skills-only case.
70
+ kind: 'platform',
71
+ display: { name: 'Codeloop', description: 'Lanes for building, shipping and marketing, with the skills each stage runs.' },
72
+ auth: [{ type: 'none' }],
73
+ availability: 'available',
74
+ skills,
75
+ };
76
+ }
77
+ //# sourceMappingURL=pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/lib/pack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { type Role } from './engine.js';
2
+ export declare const PROPOSALS_DIR = ".codeloop/proposals";
3
+ export declare const LANE_CHANGES = ".codeloop/state/lane-changes.json";
4
+ export interface EvalResult {
5
+ proposal: string;
6
+ lane: string;
7
+ version: number;
8
+ at: string;
9
+ laneSha: string;
10
+ lint: string[];
11
+ fixtures: {
12
+ stage: string;
13
+ fixture: string;
14
+ expect: string;
15
+ got: string;
16
+ ok: boolean;
17
+ }[];
18
+ vacuous: string[];
19
+ replay: string[];
20
+ replayed: {
21
+ card: string;
22
+ stage: string;
23
+ passed: boolean;
24
+ accepted: boolean;
25
+ }[];
26
+ /** Ways the proposal makes the lane less strict. Each needs a reason under accept_weakening in eval.yaml. */
27
+ weakening: {
28
+ change: string;
29
+ detail: string;
30
+ accepted: boolean;
31
+ reason?: string;
32
+ }[];
33
+ green: boolean;
34
+ exitCode: number;
35
+ }
36
+ export declare function propose(projectDir: string, now?: Date): string[];
37
+ export declare function evalProposal(projectDir: string, id: string, now?: Date): EvalResult;
38
+ export declare function promote(projectDir: string, id: string, role: Role, now?: Date): {
39
+ lane: string;
40
+ from: number | null;
41
+ to: number;
42
+ weakening: EvalResult['weakening'];
43
+ };
44
+ export declare function rollback(projectDir: string, laneId: string, role: Role, now?: Date): {
45
+ lane: string;
46
+ from: number;
47
+ to: number;
48
+ };