@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.
- package/LICENSE +21 -0
- package/README.md +589 -0
- package/dist/commands/adopt.d.ts +2 -0
- package/dist/commands/adopt.js +26 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/brief.d.ts +2 -0
- package/dist/commands/brief.js +22 -0
- package/dist/commands/brief.js.map +1 -0
- package/dist/commands/card.d.ts +6 -0
- package/dist/commands/card.js +159 -0
- package/dist/commands/card.js.map +1 -0
- package/dist/commands/check.d.ts +4 -0
- package/dist/commands/check.js +76 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/cloud.d.ts +8 -0
- package/dist/commands/cloud.js +123 -0
- package/dist/commands/cloud.js.map +1 -0
- package/dist/commands/guard.d.ts +2 -0
- package/dist/commands/guard.js +26 -0
- package/dist/commands/guard.js.map +1 -0
- package/dist/commands/import.d.ts +2 -0
- package/dist/commands/import.js +24 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/inbox.d.ts +2 -0
- package/dist/commands/inbox.js +48 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +142 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +125 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/lane.d.ts +2 -0
- package/dist/commands/lane.js +100 -0
- package/dist/commands/lane.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +35 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +77 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/mock.d.ts +3 -0
- package/dist/commands/mock.js +22 -0
- package/dist/commands/mock.js.map +1 -0
- package/dist/commands/pack.d.ts +2 -0
- package/dist/commands/pack.js +19 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +125 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.js +31 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/render.d.ts +5 -0
- package/dist/commands/render.js +47 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +45 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.js +26 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/schedule.d.ts +2 -0
- package/dist/commands/schedule.js +51 -0
- package/dist/commands/schedule.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +85 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/serve.d.ts +7 -0
- package/dist/commands/serve.js +126 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/spec.d.ts +3 -0
- package/dist/commands/spec.js +64 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +251 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +83 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +3 -0
- package/dist/commands/verify.js +75 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.js +111 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/wiki.d.ts +3 -0
- package/dist/commands/wiki.js +85 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agent.d.ts +27 -0
- package/dist/lib/agent.js +178 -0
- package/dist/lib/agent.js.map +1 -0
- package/dist/lib/board.d.ts +38 -0
- package/dist/lib/board.js +86 -0
- package/dist/lib/board.js.map +1 -0
- package/dist/lib/cards.d.ts +82 -0
- package/dist/lib/cards.js +107 -0
- package/dist/lib/cards.js.map +1 -0
- package/dist/lib/clock.d.ts +5 -0
- package/dist/lib/clock.js +14 -0
- package/dist/lib/clock.js.map +1 -0
- package/dist/lib/cloud.d.ts +122 -0
- package/dist/lib/cloud.js +580 -0
- package/dist/lib/cloud.js.map +1 -0
- package/dist/lib/competitors.d.ts +28 -0
- package/dist/lib/competitors.js +90 -0
- package/dist/lib/competitors.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +25 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/cron.d.ts +5 -0
- package/dist/lib/cron.js +82 -0
- package/dist/lib/cron.js.map +1 -0
- package/dist/lib/detect.d.ts +13 -0
- package/dist/lib/detect.js +60 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/engine.d.ts +88 -0
- package/dist/lib/engine.js +435 -0
- package/dist/lib/engine.js.map +1 -0
- package/dist/lib/flow.d.ts +44 -0
- package/dist/lib/flow.js +121 -0
- package/dist/lib/flow.js.map +1 -0
- package/dist/lib/glob.d.ts +2 -0
- package/dist/lib/glob.js +10 -0
- package/dist/lib/glob.js.map +1 -0
- package/dist/lib/import.d.ts +13 -0
- package/dist/lib/import.js +127 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/inbox.d.ts +42 -0
- package/dist/lib/inbox.js +65 -0
- package/dist/lib/inbox.js.map +1 -0
- package/dist/lib/lane.d.ts +71 -0
- package/dist/lib/lane.js +105 -0
- package/dist/lib/lane.js.map +1 -0
- package/dist/lib/lock.d.ts +6 -0
- package/dist/lib/lock.js +64 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/mcp.d.ts +2 -0
- package/dist/lib/mcp.js +57 -0
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/mock.d.ts +17 -0
- package/dist/lib/mock.js +137 -0
- package/dist/lib/mock.js.map +1 -0
- package/dist/lib/pack.d.ts +24 -0
- package/dist/lib/pack.js +77 -0
- package/dist/lib/pack.js.map +1 -0
- package/dist/lib/proposals.d.ts +48 -0
- package/dist/lib/proposals.js +240 -0
- package/dist/lib/proposals.js.map +1 -0
- package/dist/lib/render.d.ts +7 -0
- package/dist/lib/render.js +84 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/lib/research.d.ts +8 -0
- package/dist/lib/research.js +39 -0
- package/dist/lib/research.js.map +1 -0
- package/dist/lib/run.d.ts +38 -0
- package/dist/lib/run.js +215 -0
- package/dist/lib/run.js.map +1 -0
- package/dist/lib/scaffold.d.ts +16 -0
- package/dist/lib/scaffold.js +175 -0
- package/dist/lib/scaffold.js.map +1 -0
- package/dist/lib/scan.d.ts +22 -0
- package/dist/lib/scan.js +85 -0
- package/dist/lib/scan.js.map +1 -0
- package/dist/lib/schedule.d.ts +20 -0
- package/dist/lib/schedule.js +66 -0
- package/dist/lib/schedule.js.map +1 -0
- package/dist/lib/server.d.ts +68 -0
- package/dist/lib/server.js +235 -0
- package/dist/lib/server.js.map +1 -0
- package/dist/lib/shell.d.ts +1 -0
- package/dist/lib/shell.js +25 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/skills.d.ts +20 -0
- package/dist/lib/skills.js +92 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/spec.d.ts +24 -0
- package/dist/lib/spec.js +102 -0
- package/dist/lib/spec.js.map +1 -0
- package/dist/lib/stats.d.ts +13 -0
- package/dist/lib/stats.js +43 -0
- package/dist/lib/stats.js.map +1 -0
- package/dist/lib/verify.d.ts +25 -0
- package/dist/lib/verify.js +135 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/version.d.ts +10 -0
- package/dist/lib/version.js +27 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/wiki.d.ts +51 -0
- package/dist/lib/wiki.js +164 -0
- package/dist/lib/wiki.js.map +1 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +8 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/installer.d.ts +30 -0
- package/dist/registry/installer.js +133 -0
- package/dist/registry/installer.js.map +1 -0
- package/dist/registry/local-index.d.ts +32 -0
- package/dist/registry/local-index.js +58 -0
- package/dist/registry/local-index.js.map +1 -0
- package/dist/registry/lockfile.d.ts +40 -0
- package/dist/registry/lockfile.js +85 -0
- package/dist/registry/lockfile.js.map +1 -0
- package/dist/registry/security.d.ts +25 -0
- package/dist/registry/security.js +100 -0
- package/dist/registry/security.js.map +1 -0
- package/dist/registry/skill-schema.d.ts +30 -0
- package/dist/registry/skill-schema.js +95 -0
- package/dist/registry/skill-schema.js.map +1 -0
- package/dist/ui/404.html +1 -0
- package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_buildManifest.js +1 -0
- package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_ssgManifest.js +1 -0
- package/dist/ui/_next/static/chunks/255-54d3085ce94738a4.js +1 -0
- package/dist/ui/_next/static/chunks/423-bb541b7ae2733575.js +1 -0
- package/dist/ui/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
- package/dist/ui/_next/static/chunks/app/_not-found/page-d6bc774f7acb716e.js +1 -0
- package/dist/ui/_next/static/chunks/app/layout-e5fc8e78e1c8da95.js +1 -0
- package/dist/ui/_next/static/chunks/app/page-0c34b6e119cef236.js +1 -0
- package/dist/ui/_next/static/chunks/framework-de98b93a850cfc71.js +1 -0
- package/dist/ui/_next/static/chunks/main-49fd204fc9037ea3.js +1 -0
- package/dist/ui/_next/static/chunks/main-app-c46afa2f48f3aaef.js +1 -0
- package/dist/ui/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
- package/dist/ui/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
- package/dist/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/ui/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
- package/dist/ui/_next/static/css/1bf01240dbfd6088.css +1 -0
- package/dist/ui/index.html +1 -0
- package/dist/ui/index.txt +19 -0
- package/dist/watch/index.d.ts +21 -0
- package/dist/watch/index.js +88 -0
- package/dist/watch/index.js.map +1 -0
- package/dist/watch/reporter.d.ts +11 -0
- package/dist/watch/reporter.js +44 -0
- package/dist/watch/reporter.js.map +1 -0
- package/dist/watch/signals.d.ts +38 -0
- package/dist/watch/signals.js +119 -0
- package/dist/watch/signals.js.map +1 -0
- package/dist/watch/triggers.d.ts +10 -0
- package/dist/watch/triggers.js +67 -0
- package/dist/watch/triggers.js.map +1 -0
- package/package.json +64 -0
- package/registry/index.json +106 -0
- package/starters/generic.yaml +95 -0
- package/starters/go.yaml +99 -0
- package/starters/node-typescript.yaml +108 -0
- package/starters/python.yaml +105 -0
- package/templates/ci/codeloop-pr.yml +29 -0
- package/templates/ci/codeloop-prod.yml +27 -0
- package/templates/ci/codeloop-staging.yml +34 -0
- package/templates/codeloop/board.json +5 -0
- package/templates/codeloop/gotchas.md +13 -0
- package/templates/codeloop/patterns.md +15 -0
- package/templates/codeloop/principles.md +49 -0
- package/templates/codeloop/rules.md +23 -0
- package/templates/commands/commit.md +255 -0
- package/templates/commands/debug.md +142 -0
- package/templates/commands/deploy.md +144 -0
- package/templates/commands/design.md +102 -0
- package/templates/commands/manage.md +77 -0
- package/templates/commands/plan.md +84 -0
- package/templates/commands/qa.md +155 -0
- package/templates/commands/reflect.md +93 -0
- package/templates/commands/ship.md +187 -0
- package/templates/commands/test.md +133 -0
- package/templates/hooks/commit-msg +8 -0
- package/templates/lanes/analyze.yaml +25 -0
- package/templates/lanes/build.yaml +45 -0
- package/templates/lanes/deploy.yaml +24 -0
- package/templates/lanes/learn.yaml +20 -0
- package/templates/lanes/market.yaml +25 -0
- package/templates/lanes/plan.yaml +24 -0
- package/templates/lanes/scan.yaml +11 -0
- package/templates/lanes/triage.yaml +24 -0
- package/templates/mock/template.html +82 -0
- package/templates/seeds/go-gotchas.md +28 -0
- package/templates/seeds/go-patterns.md +22 -0
- package/templates/seeds/node-typescript-gotchas.md +30 -0
- package/templates/seeds/node-typescript-patterns.md +27 -0
- package/templates/seeds/python-gotchas.md +30 -0
- package/templates/seeds/python-patterns.md +19 -0
- package/templates/seeds/universal-gotchas.md +11 -0
- package/templates/seeds/universal-patterns.md +11 -0
- package/templates/spec/plan.md +7 -0
- package/templates/spec/research.md +19 -0
- package/templates/spec/spec.md +14 -0
- package/templates/spec/tasks.md +10 -0
- package/templates/tasks/todo.md +3 -0
package/dist/lib/mcp.js
ADDED
|
@@ -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
|
+
};
|
package/dist/lib/mock.js
ADDED
|
@@ -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 `{` 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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
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 <card> --topic <topic>` 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":"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"}
|
|
@@ -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 {};
|
package/dist/lib/pack.js
ADDED
|
@@ -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
|
+
};
|