@rse/specbook 0.9.4 → 0.9.6

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 (53) hide show
  1. package/README.md +64 -319
  2. package/dst/specbook-api.d.ts +13 -20
  3. package/dst/specbook-api.js +28 -25
  4. package/dst/specbook-cli.js +34 -50
  5. package/dst/specbook-cmd-describe.d.ts +5 -2
  6. package/dst/specbook-cmd-describe.js +32 -91
  7. package/dst/specbook-cmd-export.d.ts +3 -3
  8. package/dst/specbook-cmd-export.js +4 -3
  9. package/dst/specbook-cmd-init.d.ts +2 -2
  10. package/dst/specbook-cmd-init.js +35 -13
  11. package/dst/specbook-cmd-lint.d.ts +6 -6
  12. package/dst/specbook-cmd-lint.js +36 -23
  13. package/dst/specbook-config.d.ts +2 -2
  14. package/dst/specbook-config.js +2 -2
  15. package/dst/specbook-diagram.d.ts +4 -4
  16. package/dst/specbook-diagram.js +21 -15
  17. package/dst/specbook-export-ast.d.ts +3 -3
  18. package/dst/specbook-export-common.d.ts +10 -9
  19. package/dst/specbook-export-common.js +23 -9
  20. package/dst/specbook-export-html.css +13 -3
  21. package/dst/specbook-export-html.d.ts +4 -4
  22. package/dst/specbook-export-html.js +61 -32
  23. package/dst/specbook-export-logo-dark.svg +35 -0
  24. package/dst/specbook-export-logo-light.svg +35 -0
  25. package/dst/specbook-export-md.d.ts +3 -3
  26. package/dst/{specbook-struct-schema.d.ts → specbook-format-schema.d.ts} +3 -2
  27. package/dst/{specbook-struct-schema.js → specbook-format-schema.js} +2 -1
  28. package/dst/specbook-format-spec.d.ts +31 -0
  29. package/dst/{specbook-struct-spec.js → specbook-format-spec.js} +10 -10
  30. package/dst/specbook-format.md +734 -0
  31. package/dst/specbook-link.d.ts +2 -2
  32. package/dst/specbook-mcp.d.ts +2 -1
  33. package/dst/specbook-mcp.js +13 -52
  34. package/dst/specbook-parse-common.d.ts +5 -3
  35. package/dst/specbook-parse-common.js +8 -0
  36. package/dst/specbook-parse-semantic.d.ts +4 -4
  37. package/dst/specbook-parse-semantic.js +4 -65
  38. package/dst/specbook-parse-syntax.d.ts +2 -2
  39. package/dst/specbook-parse-syntax.js +18 -14
  40. package/dst/specbook-parse-value.js +1 -1
  41. package/dst/specbook-parse.d.ts +4 -4
  42. package/dst/specbook-parse.js +3 -3
  43. package/dst/specbook-verbose.d.ts +2 -0
  44. package/dst/specbook-verbose.js +16 -0
  45. package/package.json +6 -11
  46. package/dst/specbook-cmd-edit.d.ts +0 -9
  47. package/dst/specbook-cmd-edit.js +0 -74
  48. package/dst/specbook-cmd-import.d.ts +0 -9
  49. package/dst/specbook-cmd-import.js +0 -78
  50. package/dst/specbook-export-logo.svg +0 -35
  51. package/dst/specbook-llm.d.ts +0 -13
  52. package/dst/specbook-llm.js +0 -51
  53. package/dst/specbook-struct-spec.d.ts +0 -31
@@ -1,78 +0,0 @@
1
- /*
2
- ** Specification Book (SpecBook)
3
- ** Copyright (c) 2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
5
- */
6
- import * as fs from "node:fs";
7
- import * as path from "node:path";
8
- import textframe from "textframe";
9
- import { describeConfiguration } from "./specbook-cmd-describe.js";
10
- import { complete, timestamp, renderFileBlock, parseFileBlocks } from "./specbook-llm.js";
11
- /* the LLM instruction for the import command */
12
- const instruction = (description, now) => textframe `
13
- You are the import engine of SpecBook, a Markdown-based specification
14
- format. Import the information of the given foreign sources into the
15
- Markdown specification artifact files of the project, generating or
16
- updating the artifact files so they faithfully reflect the imported
17
- information. Strictly honor the following rules:
18
-
19
- - Faithful reflection: the artifacts must reflect the imported
20
- sources exactly -- no more, no less.
21
- - No fabrication: never invent content the sources do not support;
22
- leave gaps open instead of guessing.
23
- - Surgical updates: when updating an existing artifact, change only
24
- what the imported information actually requires.
25
- - Level-appropriate translation: re-express the imported facts at the
26
- artifact's level of abstraction; do not copy verbatim.
27
- - Format conformance: strictly follow the specification format
28
- described below.
29
- - Markdown generation: emit the Complex Format on levels 1-3
30
- ("#"/"##"/"###") and the Concise Format on level 4 and deeper.
31
- - Timestamps: use "${now}" for the "Created:" and "Modified:"
32
- frontmatter of generated files, and refresh "Modified:" to
33
- "${now}" on updated files.
34
- - Files: generate or update ONLY the configured artifact files listed
35
- in the format description below -- never any other file.
36
- - Output: return ONLY the generated or updated files, each as a block
37
- of the exact form below, and no other text at all:
38
-
39
- <<<FILE: <name>>>>
40
- <content>
41
- <<<END-FILE>>>
42
-
43
- ${description}
44
- `;
45
- /* import foreign sources into the specification artifact files */
46
- export const importSpecification = async (options) => {
47
- const basedir = options.basedir ?? ".";
48
- const files = options.config.map((artifact) => artifact.file).filter((file) => file !== undefined);
49
- /* ensure at least one foreign source was given */
50
- if (options.inputs.length === 0)
51
- throw new Error("no foreign sources given to import");
52
- /* gather the existing artifact files and the foreign sources */
53
- const existing = files
54
- .filter((file) => fs.existsSync(path.join(basedir, file)))
55
- .map((file) => renderFileBlock(file, fs.readFileSync(path.join(basedir, file), "utf8")));
56
- const sources = options.inputs
57
- .map((input) => renderFileBlock(input, fs.readFileSync(input, "utf8")));
58
- /* let the LLM generate or update the artifact files */
59
- options.verbose(`importing ${options.inputs.length} foreign source(s) into "${basedir}"`);
60
- const system = instruction(describeConfiguration(options.config), timestamp());
61
- const prompt = "EXISTING ARTIFACT FILES:\n\n" + (existing.length > 0 ? existing.join("\n\n") : "(none)") +
62
- "\n\nFOREIGN SOURCES TO IMPORT:\n\n" + sources.join("\n\n");
63
- const response = await complete(options, system, prompt);
64
- /* write back all returned artifact files */
65
- const written = new Array();
66
- for (const block of parseFileBlocks(response)) {
67
- if (!files.includes(block.name)) {
68
- options.verbose(`ignoring unconfigured file "${block.name}"`);
69
- continue;
70
- }
71
- const file = path.join(basedir, block.name);
72
- fs.mkdirSync(path.dirname(file), { recursive: true });
73
- fs.writeFileSync(file, block.content, "utf8");
74
- options.verbose(`wrote artifact file "${block.name}"`);
75
- written.push(block.name);
76
- }
77
- return written;
78
- };
@@ -1,35 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 260.81 110.54">
3
- <!-- Generator: Adobe Illustrator 30.7.0, SVG Export Plug-In . SVG Version: 2.1.4 Build 114) -->
4
- <defs>
5
- <style>
6
- .st0 {
7
- fill: none;
8
- }
9
-
10
- .st1 {
11
- fill: #231f20;
12
- }
13
-
14
- .st2 {
15
- fill: #666766;
16
- }
17
- </style>
18
- </defs>
19
- <g>
20
- <rect class="st0" x="128.02" y="5.89" width="297.69" height="245.38"/>
21
- <path class="st1" d="M132.56,41.28c2.62,1.34,6.66,2.69,10.82,2.69,4.48,0,6.85-1.86,6.85-4.67s-2.05-4.22-7.23-6.08c-7.17-2.5-11.84-6.46-11.84-12.73,0-7.36,6.14-12.99,16.32-12.99,4.86,0,8.45,1.02,11.01,2.18l-2.18,7.87c-1.73-.83-4.8-2.05-9.02-2.05s-6.27,1.92-6.27,4.16c0,2.75,2.43,3.97,8,6.08,7.62,2.82,11.2,6.78,11.2,12.86,0,7.23-5.57,13.38-17.41,13.38-4.93,0-9.79-1.28-12.22-2.62l1.98-8.06Z"/>
22
- <path class="st1" d="M163.28,30.53c0-4.1-.13-7.62-.26-10.5h8.45l.45,4.35h.13c2.3-3.33,5.89-5.06,10.43-5.06,6.85,0,12.99,5.95,12.99,15.93,0,11.39-7.23,16.77-14.21,16.77-3.78,0-6.72-1.54-8.13-3.58h-.13v15.55h-9.73V30.53ZM173.01,37.89c0,.77.06,1.47.19,2.05.64,2.62,2.88,4.61,5.7,4.61,4.22,0,6.72-3.52,6.72-8.83,0-4.99-2.24-8.77-6.59-8.77-2.75,0-5.18,2.05-5.82,4.93-.13.51-.19,1.15-.19,1.73v4.29Z"/>
23
- <path class="st1" d="M206.03,38.78c.32,4.03,4.29,5.95,8.83,5.95,3.33,0,6.02-.45,8.64-1.28l1.28,6.59c-3.2,1.28-7.1,1.92-11.33,1.92-10.62,0-16.7-6.14-16.7-15.94,0-7.94,4.93-16.7,15.81-16.7,10.11,0,13.95,7.87,13.95,15.61,0,1.66-.19,3.14-.32,3.84h-20.16ZM217.48,32.13c0-2.37-1.02-6.34-5.5-6.34-4.1,0-5.76,3.71-6.02,6.34h11.52Z"/>
24
- <path class="st1" d="M252.62,50.56c-1.73.77-4.99,1.41-8.7,1.41-10.11,0-16.57-6.14-16.57-16,0-9.15,6.27-16.64,17.92-16.64,2.56,0,5.38.45,7.42,1.22l-1.54,7.23c-1.15-.51-2.88-.96-5.44-.96-5.12,0-8.45,3.65-8.38,8.77,0,5.76,3.84,8.77,8.58,8.77,2.3,0,4.1-.38,5.57-.96l1.15,7.17Z"/>
25
- </g>
26
- <path d="M25.37,18.54h0c-1.03,0-2,.4-2.73,1.13-.74.74-1.15,1.72-1.15,2.77v58.42c0,2.14,1.75,3.89,3.9,3.9,9.07.02,24.26,1.91,34.75,12.88v-61.14c0-.73-.19-1.41-.54-1.97-8.6-13.85-25.14-15.96-34.23-15.98Z"/>
27
- <path d="M104.82,80.86V22.43c0-1.05-.41-2.03-1.15-2.77-.73-.73-1.7-1.13-2.73-1.13h0c-9.09.02-25.62,2.13-34.23,15.98-.35.56-.54,1.25-.54,1.97v61.14c10.48-10.97,25.68-12.86,34.75-12.88,2.15,0,3.9-1.75,3.9-3.89Z"/>
28
- <path class="st2" d="M113.7,32.01h-2.83v48.85c0,5.47-4.46,9.93-9.94,9.94-7.69.02-20.38,1.52-29.36,10.02,15.54-3.8,31.91-1.33,41.25.8,1.17.27,2.37,0,3.3-.75.93-.74,1.46-1.85,1.46-3.04v-61.92c0-2.15-1.75-3.9-3.9-3.9Z"/>
29
- <path class="st2" d="M15.43,80.86v-48.85h-2.83c-2.15,0-3.9,1.75-3.9,3.9v61.92c0,1.19.53,2.3,1.46,3.04.93.74,2.14,1.02,3.3.75,9.33-2.13,25.71-4.6,41.25-.8-8.98-8.5-21.67-10.01-29.36-10.02-5.48-.01-9.94-4.47-9.94-9.94Z"/>
30
- <g>
31
- <path class="st2" d="M131.67,55.5c2.63-.55,6.77-.97,10.99-.97,6.01,0,9.88,1.04,12.78,3.39,2.42,1.8,3.87,4.56,3.87,8.22,0,4.49-2.97,8.43-7.88,10.23v.14c4.42,1.11,9.6,4.77,9.6,11.68,0,4.01-1.59,7.05-3.94,9.33-3.25,2.97-8.5,4.35-16.1,4.35-4.15,0-7.32-.28-9.33-.55v-45.81ZM137.68,74.57h5.46c6.36,0,10.09-3.32,10.09-7.81,0-5.46-4.15-7.6-10.23-7.6-2.76,0-4.35.21-5.32.41v14.99ZM137.68,96.89c1.17.21,2.9.28,5.04.28,6.22,0,11.95-2.28,11.95-9.05,0-6.36-5.46-8.98-12.02-8.98h-4.97v17.76Z"/>
32
- <path class="st2" d="M206.14,66.9c-9.26,0-16.58,6.56-16.58,17.75,0,.12.01.24.01.36h-.04c-.27,7.16-4.51,12.28-10.13,12.28-5.94,0-10.16-5.53-10.16-12.85,0-6.36,3.11-12.99,10.29-12.99,4.29,0,7.02,2.57,8.53,5.85.79-2.15,1.94-3.99,3.37-5.51-2.83-3.1-6.89-4.9-11.76-4.9-9.26,0-16.58,6.56-16.58,17.75,0,10.57,6.98,17.2,16.03,17.2,7.88,0,16.19-5.14,16.61-16.84h0c0-.19-.02-.38-.02-.57,0-6.36,3.11-12.99,10.29-12.99s10.02,7.19,10.02,12.85c0,7.53-4.35,12.99-10.15,12.99-4.05,0-7.29-2.57-8.94-6.51-.75,2.31-1.89,4.24-3.29,5.8,2.9,3.37,7.13,5.27,11.96,5.27,8.08,0,16.65-5.39,16.65-17.75,0-10.22-6.49-17.2-16.1-17.2Z"/>
33
- <path class="st2" d="M230.65,83.76h.14c.83-1.17,2-2.63,2.97-3.8l9.81-11.54h7.32l-12.92,13.75,14.72,19.69h-7.39l-11.54-16.03-3.11,3.45v12.57h-6.01v-49.06h6.01v30.95Z"/>
34
- </g>
35
- </svg>
@@ -1,13 +0,0 @@
1
- import { type LanguageModel } from "ai";
2
- export interface AiOptions {
3
- provider?: string;
4
- model?: string;
5
- }
6
- export declare const resolveModel: (options: AiOptions) => Promise<LanguageModel>;
7
- export declare const complete: (options: AiOptions, system: string, prompt: string) => Promise<string>;
8
- export declare const timestamp: () => string;
9
- export declare const renderFileBlock: (name: string, content: string) => string;
10
- export declare const parseFileBlocks: (text: string) => {
11
- name: string;
12
- content: string;
13
- }[];
@@ -1,51 +0,0 @@
1
- /*
2
- ** Specification Book (SpecBook)
3
- ** Copyright (c) 2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
- ** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
5
- */
6
- /* the supported AI providers */
7
- const providers = {
8
- anthropic: { model: "claude-sonnet-5",
9
- create: async (id) => (await import("@ai-sdk/anthropic")).createAnthropic()(id) },
10
- openai: { model: "gpt-5.6-luna",
11
- create: async (id) => (await import("@ai-sdk/openai")).createOpenAI()(id) },
12
- openrouter: { model: "anthropic/claude-sonnet-5",
13
- create: async (id) => (await import("@openrouter/ai-sdk-provider")).createOpenRouter()(id) },
14
- ollama: { model: "qwen3",
15
- create: async (id) => (await import("ollama-ai-provider-v2")).createOllama()(id) }
16
- };
17
- /* resolve the AI provider and model into a language model handle */
18
- export const resolveModel = async (options) => {
19
- const name = options.provider ?? process.env.SPECBOOK_AI_PROVIDER ?? "anthropic";
20
- const provider = providers[name];
21
- if (provider === undefined)
22
- throw new Error(`unknown AI provider "${name}" (expected ` +
23
- Object.keys(providers).map((n) => `"${n}"`).join(", ") + ")");
24
- const model = options.model ?? process.env.SPECBOOK_AI_MODEL ?? provider.model;
25
- return provider.create(model);
26
- };
27
- /* perform a single LLM completion */
28
- export const complete = async (options, system, prompt) => {
29
- const { generateText } = await import("ai");
30
- const model = await resolveModel(options);
31
- const result = await generateText({ model, system, prompt });
32
- return result.text;
33
- };
34
- /* the current time in the frontmatter timestamp format */
35
- export const timestamp = () => {
36
- const d = new Date();
37
- const pad = (n) => String(n).padStart(2, "0");
38
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
39
- `${pad(d.getHours())}:${pad(d.getMinutes())}`;
40
- };
41
- /* render a named file as a block of the LLM file exchange protocol */
42
- export const renderFileBlock = (name, content) => `<<<FILE: ${name}>>>\n${content.replace(/\n$/, "")}\n<<<END-FILE>>>`;
43
- /* parse all file blocks of the LLM file exchange protocol */
44
- export const parseFileBlocks = (text) => {
45
- const blocks = new Array();
46
- const re = /<<<FILE:\s*([^>]+?)\s*>>>\r?\n([\s\S]*?)<<<END-FILE>>>/g;
47
- let m;
48
- while ((m = re.exec(text)) !== null)
49
- blocks.push({ name: m[1], content: m[2].replace(/\n*$/, "\n") });
50
- return blocks;
51
- };
@@ -1,31 +0,0 @@
1
- import * as v from "valibot";
2
- export type Specification = {
3
- artifacts: Artifact[];
4
- };
5
- export type Artifact = {
6
- created: Date;
7
- modified: Date;
8
- objects: Object[];
9
- };
10
- export type Object = {
11
- kind: string;
12
- id: string;
13
- anchor?: string;
14
- paren?: string;
15
- name: string;
16
- primary?: boolean;
17
- description?: Description;
18
- properties: Property[];
19
- childs: Object[];
20
- };
21
- export type Description = {
22
- description: string;
23
- rationale?: string;
24
- embedding?: string[];
25
- };
26
- export type Property = {
27
- key: string;
28
- value: string;
29
- embedding?: string[];
30
- };
31
- export declare const Specification: v.GenericSchema<Specification>;