@zhuk/spego 0.1.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 +190 -0
- package/README.md +49 -0
- package/dist/artifacts/engine.d.ts +45 -0
- package/dist/artifacts/engine.js +209 -0
- package/dist/artifacts/engine.js.map +1 -0
- package/dist/artifacts/schemas.d.ts +4 -0
- package/dist/artifacts/schemas.js +79 -0
- package/dist/artifacts/schemas.js.map +1 -0
- package/dist/artifacts/slug.d.ts +9 -0
- package/dist/artifacts/slug.js +24 -0
- package/dist/artifacts/slug.js.map +1 -0
- package/dist/artifacts/storage.d.ts +18 -0
- package/dist/artifacts/storage.js +94 -0
- package/dist/artifacts/storage.js.map +1 -0
- package/dist/artifacts/types.d.ts +52 -0
- package/dist/artifacts/types.js +42 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/validation.d.ts +46 -0
- package/dist/artifacts/validation.js +72 -0
- package/dist/artifacts/validation.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +461 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/registry.d.ts +18 -0
- package/dist/commands/registry.js +127 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/delivery/index.d.ts +2 -0
- package/dist/delivery/index.js +2 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/delivery/openspec-adapter.d.ts +2 -0
- package/dist/delivery/openspec-adapter.js +86 -0
- package/dist/delivery/openspec-adapter.js.map +1 -0
- package/dist/delivery/openspec-discover.d.ts +8 -0
- package/dist/delivery/openspec-discover.js +80 -0
- package/dist/delivery/openspec-discover.js.map +1 -0
- package/dist/delivery/openspec-parse.d.ts +9 -0
- package/dist/delivery/openspec-parse.js +63 -0
- package/dist/delivery/openspec-parse.js.map +1 -0
- package/dist/delivery/resolve.d.ts +3 -0
- package/dist/delivery/resolve.js +14 -0
- package/dist/delivery/resolve.js.map +1 -0
- package/dist/delivery/types.d.ts +27 -0
- package/dist/delivery/types.js +2 -0
- package/dist/delivery/types.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -0
- package/dist/export/view.d.ts +54 -0
- package/dist/export/view.js +74 -0
- package/dist/export/view.js.map +1 -0
- package/dist/generator/claude.d.ts +5 -0
- package/dist/generator/claude.js +85 -0
- package/dist/generator/claude.js.map +1 -0
- package/dist/generator/index.d.ts +5 -0
- package/dist/generator/index.js +23 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/markers.d.ts +3 -0
- package/dist/generator/markers.js +8 -0
- package/dist/generator/markers.js.map +1 -0
- package/dist/generator/types.d.ts +15 -0
- package/dist/generator/types.js +2 -0
- package/dist/generator/types.js.map +1 -0
- package/dist/generator/write.d.ts +2 -0
- package/dist/generator/write.js +28 -0
- package/dist/generator/write.js.map +1 -0
- package/dist/index/db.d.ts +17 -0
- package/dist/index/db.js +95 -0
- package/dist/index/db.js.map +1 -0
- package/dist/index/indexer.d.ts +42 -0
- package/dist/index/indexer.js +219 -0
- package/dist/index/indexer.js.map +1 -0
- package/dist/index/revisions.d.ts +13 -0
- package/dist/index/revisions.js +31 -0
- package/dist/index/revisions.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/workspace/config.d.ts +47 -0
- package/dist/workspace/config.js +64 -0
- package/dist/workspace/config.js.map +1 -0
- package/dist/workspace/init.d.ts +37 -0
- package/dist/workspace/init.js +114 -0
- package/dist/workspace/init.js.map +1 -0
- package/dist/workspace/paths.d.ts +30 -0
- package/dist/workspace/paths.js +34 -0
- package/dist/workspace/paths.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,UAAU,GAAiC,IAAI,GAAG,EAAE,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAoB;IACpD,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,iBAAiB,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,OAAiB;IAEjB,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const SPEGO_GENERATED_MARKER = '<!-- spego-generated';
|
|
2
|
+
export function wrapWithMarker(content, version = 1) {
|
|
3
|
+
return `${SPEGO_GENERATED_MARKER} v${version} -->\n${content}`;
|
|
4
|
+
}
|
|
5
|
+
export function isSpegoGenerated(fileContent) {
|
|
6
|
+
return fileContent.startsWith(SPEGO_GENERATED_MARKER);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=markers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/generator/markers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAE7D,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,UAAkB,CAAC;IACjE,OAAO,GAAG,sBAAsB,KAAK,OAAO,SAAS,OAAO,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,OAAO,WAAW,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const GENERATOR_VERSION = 1;
|
|
2
|
+
export type FileAction = 'created' | 'updated' | 'unchanged' | 'skipped';
|
|
3
|
+
export interface GeneratedFile {
|
|
4
|
+
path: string;
|
|
5
|
+
action: FileAction;
|
|
6
|
+
}
|
|
7
|
+
export interface GenerationReport {
|
|
8
|
+
target: string;
|
|
9
|
+
files: GeneratedFile[];
|
|
10
|
+
version: number;
|
|
11
|
+
}
|
|
12
|
+
export interface TargetGenerator {
|
|
13
|
+
readonly targetName: string;
|
|
14
|
+
generate(projectRoot: string): Promise<GenerationReport>;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/generator/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isSpegoGenerated, wrapWithMarker } from './markers.js';
|
|
4
|
+
import { GENERATOR_VERSION } from './types.js';
|
|
5
|
+
export async function writeGeneratedFile(absPath, content) {
|
|
6
|
+
const marked = wrapWithMarker(content, GENERATOR_VERSION);
|
|
7
|
+
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
8
|
+
let existing = null;
|
|
9
|
+
try {
|
|
10
|
+
existing = await fs.readFile(absPath, 'utf8');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// file does not exist — will create
|
|
14
|
+
}
|
|
15
|
+
if (existing !== null) {
|
|
16
|
+
if (!isSpegoGenerated(existing)) {
|
|
17
|
+
return 'skipped';
|
|
18
|
+
}
|
|
19
|
+
if (marked.trim() === existing.trim()) {
|
|
20
|
+
return 'unchanged';
|
|
21
|
+
}
|
|
22
|
+
await fs.writeFile(absPath, marked, 'utf8');
|
|
23
|
+
return 'updated';
|
|
24
|
+
}
|
|
25
|
+
await fs.writeFile(absPath, marked, 'utf8');
|
|
26
|
+
return 'created';
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/generator/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,OAAe;IAEf,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC1D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3D,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACtC,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare const DatabaseSync: typeof import("node:sqlite").DatabaseSync;
|
|
2
|
+
export type Db = InstanceType<typeof DatabaseSync>;
|
|
3
|
+
/** Open (or create) the SQLite index database with safe pragmas. */
|
|
4
|
+
export declare function openIndexDb(dbPath: string): Db;
|
|
5
|
+
export declare function closeIndexDb(db: Db): void;
|
|
6
|
+
/** Run `fn` inside a SQLite transaction. Rolls back on throw. */
|
|
7
|
+
export declare function transaction<T>(db: Db, fn: () => T): T;
|
|
8
|
+
/**
|
|
9
|
+
* Create or migrate the index schema. Idempotent.
|
|
10
|
+
*
|
|
11
|
+
* Tables:
|
|
12
|
+
* - artifacts: one row per logical artifact (latest snapshot mirror)
|
|
13
|
+
* - revisions: one row per saved revision
|
|
14
|
+
* - index_meta: key/value (schema version, last rebuild, etc.)
|
|
15
|
+
*/
|
|
16
|
+
export declare function ensureIndexSchema(db: Db): void;
|
|
17
|
+
export {};
|
package/dist/index/db.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
// `node:sqlite` is a Node built-in, but bundlers (Vite/Rollup) trip over the
|
|
5
|
+
// `node:` prefix because their built-in lists lag behind Node releases.
|
|
6
|
+
// Loading via createRequire keeps the import opaque to static analyzers.
|
|
7
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
8
|
+
const { DatabaseSync } = requireFromHere('node:sqlite');
|
|
9
|
+
/** Open (or create) the SQLite index database with safe pragmas. */
|
|
10
|
+
export function openIndexDb(dbPath) {
|
|
11
|
+
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
12
|
+
const db = new DatabaseSync(dbPath);
|
|
13
|
+
db.exec('PRAGMA journal_mode = WAL');
|
|
14
|
+
db.exec('PRAGMA synchronous = NORMAL');
|
|
15
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
16
|
+
return db;
|
|
17
|
+
}
|
|
18
|
+
export function closeIndexDb(db) {
|
|
19
|
+
db.close();
|
|
20
|
+
}
|
|
21
|
+
/** Run `fn` inside a SQLite transaction. Rolls back on throw. */
|
|
22
|
+
export function transaction(db, fn) {
|
|
23
|
+
db.exec('BEGIN');
|
|
24
|
+
try {
|
|
25
|
+
const result = fn();
|
|
26
|
+
db.exec('COMMIT');
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
try {
|
|
31
|
+
db.exec('ROLLBACK');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// ignore secondary rollback failures
|
|
35
|
+
}
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create or migrate the index schema. Idempotent.
|
|
41
|
+
*
|
|
42
|
+
* Tables:
|
|
43
|
+
* - artifacts: one row per logical artifact (latest snapshot mirror)
|
|
44
|
+
* - revisions: one row per saved revision
|
|
45
|
+
* - index_meta: key/value (schema version, last rebuild, etc.)
|
|
46
|
+
*/
|
|
47
|
+
export function ensureIndexSchema(db) {
|
|
48
|
+
db.exec(`
|
|
49
|
+
CREATE TABLE IF NOT EXISTS index_meta (
|
|
50
|
+
key TEXT PRIMARY KEY,
|
|
51
|
+
value TEXT NOT NULL
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE TABLE IF NOT EXISTS artifacts (
|
|
55
|
+
id TEXT PRIMARY KEY,
|
|
56
|
+
type TEXT NOT NULL,
|
|
57
|
+
slug TEXT NOT NULL,
|
|
58
|
+
title TEXT NOT NULL,
|
|
59
|
+
revision INTEGER NOT NULL,
|
|
60
|
+
path TEXT NOT NULL,
|
|
61
|
+
created_at TEXT NOT NULL,
|
|
62
|
+
updated_at TEXT NOT NULL,
|
|
63
|
+
deleted_at TEXT,
|
|
64
|
+
meta_json TEXT NOT NULL DEFAULT '{}'
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_artifacts_type_slug
|
|
68
|
+
ON artifacts (type, slug);
|
|
69
|
+
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_type
|
|
71
|
+
ON artifacts (type);
|
|
72
|
+
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_artifacts_deleted
|
|
74
|
+
ON artifacts (deleted_at);
|
|
75
|
+
|
|
76
|
+
CREATE TABLE IF NOT EXISTS revisions (
|
|
77
|
+
artifact_id TEXT NOT NULL,
|
|
78
|
+
revision INTEGER NOT NULL,
|
|
79
|
+
type TEXT NOT NULL,
|
|
80
|
+
slug TEXT NOT NULL,
|
|
81
|
+
title TEXT NOT NULL,
|
|
82
|
+
path TEXT NOT NULL,
|
|
83
|
+
created_at TEXT NOT NULL,
|
|
84
|
+
meta_json TEXT NOT NULL DEFAULT '{}',
|
|
85
|
+
PRIMARY KEY (artifact_id, revision),
|
|
86
|
+
FOREIGN KEY (artifact_id) REFERENCES artifacts(id) ON DELETE CASCADE
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
CREATE INDEX IF NOT EXISTS idx_revisions_artifact
|
|
90
|
+
ON revisions (artifact_id);
|
|
91
|
+
`);
|
|
92
|
+
db.prepare(`INSERT INTO index_meta (key, value) VALUES ('schema_version', '1')
|
|
93
|
+
ON CONFLICT(key) DO NOTHING`).run();
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/index/db.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,6EAA6E;AAC7E,wEAAwE;AACxE,yEAAyE;AACzE,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvD,MAAM,EAAE,YAAY,EAAE,GAAG,eAAe,CAAC,aAAa,CAAiC,CAAC;AAIxF,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACrC,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACvC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACpC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAM;IACjC,EAAE,CAAC,KAAK,EAAE,CAAC;AACb,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,WAAW,CAAI,EAAM,EAAE,EAAW;IAChD,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,EAAE,EAAE,CAAC;QACpB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAM;IACtC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CP,CAAC,CAAC;IAEH,EAAE,CAAC,OAAO,CACR;iCAC6B,CAC9B,CAAC,GAAG,EAAE,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type WorkspacePaths } from '../workspace/paths.js';
|
|
2
|
+
import type { ArtifactFrontmatter } from '../artifacts/types.js';
|
|
3
|
+
import type { Db } from './db.js';
|
|
4
|
+
export interface IndexedArtifact {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
title: string;
|
|
9
|
+
revision: number;
|
|
10
|
+
path: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
deletedAt: string | null;
|
|
14
|
+
meta: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
/** Upsert the artifact mirror row + revision row in a single transaction. */
|
|
17
|
+
export declare function upsertArtifact(db: Db, fm: ArtifactFrontmatter, filePath: string, revisionPath?: string): void;
|
|
18
|
+
export interface ListOptions {
|
|
19
|
+
type?: string;
|
|
20
|
+
includeDeleted?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function listArtifacts(db: Db, opts?: ListOptions): IndexedArtifact[];
|
|
23
|
+
export declare function getArtifactById(db: Db, id: string): IndexedArtifact | null;
|
|
24
|
+
export declare function getArtifactByTypeSlug(db: Db, type: string, slug: string): IndexedArtifact | null;
|
|
25
|
+
export declare function listRevisions(db: Db, artifactId: string): Array<{
|
|
26
|
+
revision: number;
|
|
27
|
+
path: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
}>;
|
|
30
|
+
export interface RebuildReport {
|
|
31
|
+
scannedFiles: number;
|
|
32
|
+
indexedArtifacts: number;
|
|
33
|
+
invalidFiles: Array<{
|
|
34
|
+
path: string;
|
|
35
|
+
error: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Walk `.spego/artifacts/**\/*.md`, drop the index tables, and rebuild from
|
|
40
|
+
* the markdown files. Invalid files are reported but do not abort the rebuild.
|
|
41
|
+
*/
|
|
42
|
+
export declare function rebuildIndex(db: Db, paths: WorkspacePaths, knownTypes?: ReadonlySet<string>): Promise<RebuildReport>;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { artifactFilePath, } from '../workspace/paths.js';
|
|
4
|
+
import { parseArtifactFile, } from '../artifacts/storage.js';
|
|
5
|
+
import { ensureIndexSchema, transaction } from './db.js';
|
|
6
|
+
import { SpegoError } from '../errors.js';
|
|
7
|
+
function rowToArtifact(row) {
|
|
8
|
+
return {
|
|
9
|
+
id: row.id,
|
|
10
|
+
type: row.type,
|
|
11
|
+
slug: row.slug,
|
|
12
|
+
title: row.title,
|
|
13
|
+
revision: row.revision,
|
|
14
|
+
path: row.path,
|
|
15
|
+
createdAt: row.created_at,
|
|
16
|
+
updatedAt: row.updated_at,
|
|
17
|
+
deletedAt: row.deleted_at ?? null,
|
|
18
|
+
meta: JSON.parse(row.meta_json ?? '{}'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Upsert the artifact mirror row + revision row in a single transaction. */
|
|
22
|
+
export function upsertArtifact(db, fm, filePath, revisionPath) {
|
|
23
|
+
transaction(db, () => {
|
|
24
|
+
db.prepare(`INSERT INTO artifacts
|
|
25
|
+
(id, type, slug, title, revision, path, created_at, updated_at, deleted_at, meta_json)
|
|
26
|
+
VALUES
|
|
27
|
+
(@id, @type, @slug, @title, @revision, @path, @created_at, @updated_at, @deleted_at, @meta_json)
|
|
28
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
29
|
+
type = excluded.type,
|
|
30
|
+
slug = excluded.slug,
|
|
31
|
+
title = excluded.title,
|
|
32
|
+
revision = excluded.revision,
|
|
33
|
+
path = excluded.path,
|
|
34
|
+
updated_at = excluded.updated_at,
|
|
35
|
+
deleted_at = excluded.deleted_at,
|
|
36
|
+
meta_json = excluded.meta_json`).run({
|
|
37
|
+
id: fm.id,
|
|
38
|
+
type: fm.type,
|
|
39
|
+
slug: fm.slug,
|
|
40
|
+
title: fm.title,
|
|
41
|
+
revision: fm.revision,
|
|
42
|
+
path: filePath,
|
|
43
|
+
created_at: fm.createdAt,
|
|
44
|
+
updated_at: fm.updatedAt,
|
|
45
|
+
deleted_at: fm.deletedAt ?? null,
|
|
46
|
+
meta_json: JSON.stringify(fm.meta ?? {}),
|
|
47
|
+
});
|
|
48
|
+
db.prepare(`INSERT INTO revisions
|
|
49
|
+
(artifact_id, revision, type, slug, title, path, created_at, meta_json)
|
|
50
|
+
VALUES
|
|
51
|
+
(@id, @revision, @type, @slug, @title, @path, @created_at, @meta_json)
|
|
52
|
+
ON CONFLICT(artifact_id, revision) DO UPDATE SET
|
|
53
|
+
title = excluded.title,
|
|
54
|
+
path = excluded.path,
|
|
55
|
+
meta_json = excluded.meta_json`).run({
|
|
56
|
+
id: fm.id,
|
|
57
|
+
revision: fm.revision,
|
|
58
|
+
type: fm.type,
|
|
59
|
+
slug: fm.slug,
|
|
60
|
+
title: fm.title,
|
|
61
|
+
path: revisionPath ?? filePath,
|
|
62
|
+
created_at: fm.updatedAt,
|
|
63
|
+
meta_json: JSON.stringify(fm.meta ?? {}),
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function listArtifacts(db, opts = {}) {
|
|
68
|
+
const where = [];
|
|
69
|
+
const params = {};
|
|
70
|
+
if (opts.type) {
|
|
71
|
+
where.push('type = @type');
|
|
72
|
+
params.type = opts.type;
|
|
73
|
+
}
|
|
74
|
+
if (!opts.includeDeleted) {
|
|
75
|
+
where.push('deleted_at IS NULL');
|
|
76
|
+
}
|
|
77
|
+
const sql = `SELECT * FROM artifacts` +
|
|
78
|
+
(where.length ? ` WHERE ${where.join(' AND ')}` : '') +
|
|
79
|
+
` ORDER BY type ASC, updated_at DESC`;
|
|
80
|
+
const stmt = db.prepare(sql);
|
|
81
|
+
const rows = where.length ? stmt.all(params) : stmt.all();
|
|
82
|
+
return rows.map((r) => rowToArtifact(r));
|
|
83
|
+
}
|
|
84
|
+
export function getArtifactById(db, id) {
|
|
85
|
+
const row = db.prepare(`SELECT * FROM artifacts WHERE id = ?`).get(id);
|
|
86
|
+
return row ? rowToArtifact(row) : null;
|
|
87
|
+
}
|
|
88
|
+
export function getArtifactByTypeSlug(db, type, slug) {
|
|
89
|
+
const row = db
|
|
90
|
+
.prepare(`SELECT * FROM artifacts WHERE type = ? AND slug = ?`)
|
|
91
|
+
.get(type, slug);
|
|
92
|
+
return row ? rowToArtifact(row) : null;
|
|
93
|
+
}
|
|
94
|
+
export function listRevisions(db, artifactId) {
|
|
95
|
+
const rows = db
|
|
96
|
+
.prepare(`SELECT revision, path, created_at FROM revisions WHERE artifact_id = ? ORDER BY revision ASC`)
|
|
97
|
+
.all(artifactId);
|
|
98
|
+
return rows.map((r) => ({
|
|
99
|
+
revision: r.revision,
|
|
100
|
+
path: r.path,
|
|
101
|
+
createdAt: r.created_at,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Walk `.spego/artifacts/**\/*.md`, drop the index tables, and rebuild from
|
|
106
|
+
* the markdown files. Invalid files are reported but do not abort the rebuild.
|
|
107
|
+
*/
|
|
108
|
+
export async function rebuildIndex(db, paths, knownTypes) {
|
|
109
|
+
const report = {
|
|
110
|
+
scannedFiles: 0,
|
|
111
|
+
indexedArtifacts: 0,
|
|
112
|
+
invalidFiles: [],
|
|
113
|
+
};
|
|
114
|
+
// Reset tables; recreate schema for safety.
|
|
115
|
+
db.exec(`DROP TABLE IF EXISTS revisions; DROP TABLE IF EXISTS artifacts;`);
|
|
116
|
+
ensureIndexSchema(db);
|
|
117
|
+
let typeDirs = [];
|
|
118
|
+
try {
|
|
119
|
+
typeDirs = await fs.readdir(paths.artifactsRoot);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (err.code === 'ENOENT') {
|
|
123
|
+
return report;
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
for (const type of typeDirs) {
|
|
128
|
+
const typeDir = path.join(paths.artifactsRoot, type);
|
|
129
|
+
let stat;
|
|
130
|
+
try {
|
|
131
|
+
stat = await fs.stat(typeDir);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (!stat.isDirectory())
|
|
137
|
+
continue;
|
|
138
|
+
const entries = await fs.readdir(typeDir);
|
|
139
|
+
for (const entry of entries) {
|
|
140
|
+
if (!entry.endsWith('.md'))
|
|
141
|
+
continue;
|
|
142
|
+
const file = path.join(typeDir, entry);
|
|
143
|
+
report.scannedFiles += 1;
|
|
144
|
+
try {
|
|
145
|
+
const text = await fs.readFile(file, 'utf8');
|
|
146
|
+
const { frontmatter } = parseArtifactFile(text, file);
|
|
147
|
+
if (knownTypes && !knownTypes.has(frontmatter.type)) {
|
|
148
|
+
throw new SpegoError('INVALID_ARTIFACT_TYPE', `Unsupported artifact type: ${frontmatter.type}`, {
|
|
149
|
+
type: frontmatter.type,
|
|
150
|
+
path: file,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const expectedName = `${frontmatter.slug}.md`;
|
|
154
|
+
if (entry !== expectedName) {
|
|
155
|
+
throw new SpegoError('VALIDATION_FAILED', `File name "${entry}" does not match slug "${frontmatter.slug}" in frontmatter`, { path: file, expectedSlug: frontmatter.slug, fileName: entry });
|
|
156
|
+
}
|
|
157
|
+
// Use the canonical computed path so reads from any cwd resolve.
|
|
158
|
+
const canonical = artifactFilePath(paths, frontmatter.type, frontmatter.slug);
|
|
159
|
+
upsertArtifact(db, frontmatter, canonical);
|
|
160
|
+
// Discover revision snapshots and reattach.
|
|
161
|
+
await reindexRevisions(db, paths, frontmatter, report);
|
|
162
|
+
report.indexedArtifacts += 1;
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
const message = err instanceof SpegoError ? `${err.code}: ${err.message}` : err.message;
|
|
166
|
+
report.invalidFiles.push({ path: file, error: message });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
db.prepare(`INSERT INTO index_meta (key, value) VALUES ('last_rebuild', @value)
|
|
171
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run({ value: new Date().toISOString() });
|
|
172
|
+
return report;
|
|
173
|
+
}
|
|
174
|
+
async function reindexRevisions(db, paths, fm, report) {
|
|
175
|
+
const revDir = path.join(paths.revisionsRoot, fm.type);
|
|
176
|
+
let entries;
|
|
177
|
+
try {
|
|
178
|
+
entries = await fs.readdir(revDir);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
if (err.code === 'ENOENT')
|
|
182
|
+
return;
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
185
|
+
const prefix = `${fm.slug}.r`;
|
|
186
|
+
for (const entry of entries) {
|
|
187
|
+
if (!entry.startsWith(prefix) || !entry.endsWith('.md'))
|
|
188
|
+
continue;
|
|
189
|
+
const file = path.join(revDir, entry);
|
|
190
|
+
try {
|
|
191
|
+
const text = await fs.readFile(file, 'utf8');
|
|
192
|
+
const { frontmatter } = parseArtifactFile(text, file);
|
|
193
|
+
if (frontmatter.id !== fm.id)
|
|
194
|
+
continue;
|
|
195
|
+
db.prepare(`INSERT INTO revisions
|
|
196
|
+
(artifact_id, revision, type, slug, title, path, created_at, meta_json)
|
|
197
|
+
VALUES
|
|
198
|
+
(@id, @revision, @type, @slug, @title, @path, @created_at, @meta_json)
|
|
199
|
+
ON CONFLICT(artifact_id, revision) DO UPDATE SET
|
|
200
|
+
title = excluded.title,
|
|
201
|
+
path = excluded.path,
|
|
202
|
+
meta_json = excluded.meta_json`).run({
|
|
203
|
+
id: frontmatter.id,
|
|
204
|
+
revision: frontmatter.revision,
|
|
205
|
+
type: frontmatter.type,
|
|
206
|
+
slug: frontmatter.slug,
|
|
207
|
+
title: frontmatter.title,
|
|
208
|
+
path: file,
|
|
209
|
+
created_at: frontmatter.updatedAt,
|
|
210
|
+
meta_json: JSON.stringify(frontmatter.meta ?? {}),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
const message = err instanceof SpegoError ? `${err.code}: ${err.message}` : err.message;
|
|
215
|
+
report.invalidFiles.push({ path: file, error: message });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/index/indexer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type WorkspacePaths } from '../workspace/paths.js';
|
|
2
|
+
import type { ArtifactFrontmatter } from '../artifacts/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Persist a snapshot of an artifact at the given revision under
|
|
5
|
+
* `.spego/revisions/<type>/<slug>.r<n>.md`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeRevisionSnapshot(paths: WorkspacePaths, frontmatter: ArtifactFrontmatter, body: string): Promise<string>;
|
|
8
|
+
/** Read a previously snapshotted revision. */
|
|
9
|
+
export declare function readRevisionSnapshot(paths: WorkspacePaths, type: string, slug: string, revision: number): Promise<{
|
|
10
|
+
frontmatter: ArtifactFrontmatter;
|
|
11
|
+
body: string;
|
|
12
|
+
path: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { revisionFilePath } from '../workspace/paths.js';
|
|
3
|
+
import { atomicWriteFile, parseArtifactFile } from '../artifacts/storage.js';
|
|
4
|
+
import { renderArtifactFile } from '../artifacts/storage.js';
|
|
5
|
+
import { SpegoError } from '../errors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Persist a snapshot of an artifact at the given revision under
|
|
8
|
+
* `.spego/revisions/<type>/<slug>.r<n>.md`.
|
|
9
|
+
*/
|
|
10
|
+
export async function writeRevisionSnapshot(paths, frontmatter, body) {
|
|
11
|
+
const dest = revisionFilePath(paths, frontmatter.type, frontmatter.slug, frontmatter.revision);
|
|
12
|
+
await atomicWriteFile(dest, renderArtifactFile(frontmatter, body));
|
|
13
|
+
return dest;
|
|
14
|
+
}
|
|
15
|
+
/** Read a previously snapshotted revision. */
|
|
16
|
+
export async function readRevisionSnapshot(paths, type, slug, revision) {
|
|
17
|
+
const file = revisionFilePath(paths, type, slug, revision);
|
|
18
|
+
let raw;
|
|
19
|
+
try {
|
|
20
|
+
raw = await fs.readFile(file, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err.code === 'ENOENT') {
|
|
24
|
+
throw new SpegoError('REVISION_NOT_FOUND', `Revision ${revision} not found for ${type}/${slug}`, { type, slug, revision, path: file });
|
|
25
|
+
}
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
const parsed = parseArtifactFile(raw, file);
|
|
29
|
+
return { ...parsed, path: file };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=revisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revisions.js","sourceRoot":"","sources":["../../src/index/revisions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAuB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAqB,EACrB,WAAgC,EAChC,IAAY;IAEZ,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC/F,MAAM,eAAe,CAAC,IAAI,EAAE,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAqB,EACrB,IAAY,EACZ,IAAY,EACZ,QAAgB;IAEhB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,UAAU,CAClB,oBAAoB,EACpB,YAAY,QAAQ,kBAAkB,IAAI,IAAI,IAAI,EAAE,EACpD,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CACrC,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACnC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for embedding the spego artifact engine in other tools.
|
|
3
|
+
* The CLI in `cli.ts` is built on top of these exports.
|
|
4
|
+
*/
|
|
5
|
+
export { ArtifactEngine } from './artifacts/engine.js';
|
|
6
|
+
export type { EngineOptions } from './artifacts/engine.js';
|
|
7
|
+
export { artifactFrontmatterSchema, BUILTIN_ARTIFACT_TYPES, } from './artifacts/types.js';
|
|
8
|
+
export type { ArtifactFrontmatter, ArtifactRecord, ArtifactType, BuiltinArtifactType, } from './artifacts/types.js';
|
|
9
|
+
export { initWorkspace, workspaceStatus, } from './workspace/init.js';
|
|
10
|
+
export type { InitOptions, InitSummary, WorkspaceStatus } from './workspace/init.js';
|
|
11
|
+
export { resolveWorkspacePaths, artifactFilePath, artifactTypeDir, revisionFilePath, WORKSPACE_DIR_NAME, ARTIFACTS_DIR_NAME, REVISIONS_DIR_NAME, INDEX_DIR_NAME, CONFIG_FILE_NAME, INDEX_DB_FILE_NAME, } from './workspace/paths.js';
|
|
12
|
+
export type { WorkspacePaths } from './workspace/paths.js';
|
|
13
|
+
export { defaultConfig, knownArtifactTypes, readConfig, writeConfig, workspaceConfigSchema, } from './workspace/config.js';
|
|
14
|
+
export type { WorkspaceConfig, SupportedAgent } from './workspace/config.js';
|
|
15
|
+
export type { CreateArtifactInput, UpdateArtifactInput } from './artifacts/validation.js';
|
|
16
|
+
export type { IndexedArtifact, RebuildReport } from './index/indexer.js';
|
|
17
|
+
export { viewArtifacts, renderMarkdownBundle, renderJsonBundle } from './export/view.js';
|
|
18
|
+
export type { ViewOptions, ViewResult, MarkdownBundle, JsonBundle, JsonArtifact, } from './export/view.js';
|
|
19
|
+
export { SpegoError } from './errors.js';
|
|
20
|
+
export type { SpegoErrorCode } from './errors.js';
|
|
21
|
+
export { validateMetaForType, hasTypeSchema, ARTIFACT_META_SCHEMAS } from './artifacts/schemas.js';
|
|
22
|
+
export { COMMAND_REGISTRY, getCommandByName } from './commands/registry.js';
|
|
23
|
+
export type { CommandMeta, InputField } from './commands/registry.js';
|
|
24
|
+
export { generateAll, registerGenerator, getGenerator, availableTargets } from './generator/index.js';
|
|
25
|
+
export { ClaudeGenerator } from './generator/claude.js';
|
|
26
|
+
export type { TargetGenerator, GenerationReport, GeneratedFile, FileAction } from './generator/types.js';
|
|
27
|
+
export { SPEGO_GENERATED_MARKER, isSpegoGenerated, wrapWithMarker } from './generator/markers.js';
|
|
28
|
+
export { resolveAdapter } from './delivery/index.js';
|
|
29
|
+
export type { DeliveryAdapter, DeliveryEpicLink, DeliveryItemStatus, DeliveryStatus, DeliveryTaskSummary, } from './delivery/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for embedding the spego artifact engine in other tools.
|
|
3
|
+
* The CLI in `cli.ts` is built on top of these exports.
|
|
4
|
+
*/
|
|
5
|
+
export { ArtifactEngine } from './artifacts/engine.js';
|
|
6
|
+
export { artifactFrontmatterSchema, BUILTIN_ARTIFACT_TYPES, } from './artifacts/types.js';
|
|
7
|
+
export { initWorkspace, workspaceStatus, } from './workspace/init.js';
|
|
8
|
+
export { resolveWorkspacePaths, artifactFilePath, artifactTypeDir, revisionFilePath, WORKSPACE_DIR_NAME, ARTIFACTS_DIR_NAME, REVISIONS_DIR_NAME, INDEX_DIR_NAME, CONFIG_FILE_NAME, INDEX_DB_FILE_NAME, } from './workspace/paths.js';
|
|
9
|
+
export { defaultConfig, knownArtifactTypes, readConfig, writeConfig, workspaceConfigSchema, } from './workspace/config.js';
|
|
10
|
+
export { viewArtifacts, renderMarkdownBundle, renderJsonBundle } from './export/view.js';
|
|
11
|
+
export { SpegoError } from './errors.js';
|
|
12
|
+
export { validateMetaForType, hasTypeSchema, ARTIFACT_META_SCHEMAS } from './artifacts/schemas.js';
|
|
13
|
+
export { COMMAND_REGISTRY, getCommandByName } from './commands/registry.js';
|
|
14
|
+
export { generateAll, registerGenerator, getGenerator, availableTargets } from './generator/index.js';
|
|
15
|
+
export { ClaudeGenerator } from './generator/claude.js';
|
|
16
|
+
export { SPEGO_GENERATED_MARKER, isSpegoGenerated, wrapWithMarker } from './generator/markers.js';
|
|
17
|
+
export { resolveAdapter } from './delivery/index.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EACL,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EACL,aAAa,EACb,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAQzF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACtG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SUPPORTED_AGENTS: readonly ["claude", "cursor", "opencode", "amp"];
|
|
3
|
+
export type SupportedAgent = (typeof SUPPORTED_AGENTS)[number];
|
|
4
|
+
export declare const workspaceConfigSchema: z.ZodObject<{
|
|
5
|
+
/** Schema version. Bump when config layout changes. */
|
|
6
|
+
version: z.ZodDefault<z.ZodLiteral<1>>;
|
|
7
|
+
/** Agent toolchains the workspace targets. */
|
|
8
|
+
agents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
9
|
+
/** Whether init seeded demo artifacts. */
|
|
10
|
+
demo: z.ZodDefault<z.ZodBoolean>;
|
|
11
|
+
/** Built-in types are always allowed; this list extends them. */
|
|
12
|
+
extraArtifactTypes: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
deliveryAdapter: z.ZodDefault<z.ZodObject<{
|
|
14
|
+
name: z.ZodDefault<z.ZodString>;
|
|
15
|
+
options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
options: Record<string, unknown>;
|
|
18
|
+
name: string;
|
|
19
|
+
}, {
|
|
20
|
+
options?: Record<string, unknown> | undefined;
|
|
21
|
+
name?: string | undefined;
|
|
22
|
+
}>>;
|
|
23
|
+
}, "strict", z.ZodTypeAny, {
|
|
24
|
+
version: 1;
|
|
25
|
+
agents: string[];
|
|
26
|
+
demo: boolean;
|
|
27
|
+
extraArtifactTypes: string[];
|
|
28
|
+
deliveryAdapter: {
|
|
29
|
+
options: Record<string, unknown>;
|
|
30
|
+
name: string;
|
|
31
|
+
};
|
|
32
|
+
}, {
|
|
33
|
+
version?: 1 | undefined;
|
|
34
|
+
agents?: string[] | undefined;
|
|
35
|
+
demo?: boolean | undefined;
|
|
36
|
+
extraArtifactTypes?: string[] | undefined;
|
|
37
|
+
deliveryAdapter?: {
|
|
38
|
+
options?: Record<string, unknown> | undefined;
|
|
39
|
+
name?: string | undefined;
|
|
40
|
+
} | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;
|
|
43
|
+
export declare function defaultConfig(overrides?: Partial<WorkspaceConfig>): WorkspaceConfig;
|
|
44
|
+
export declare function readConfig(configPath: string): Promise<WorkspaceConfig>;
|
|
45
|
+
export declare function writeConfig(configPath: string, config: WorkspaceConfig): Promise<void>;
|
|
46
|
+
/** Returns the union of built-in and user-extended artifact types. */
|
|
47
|
+
export declare function knownArtifactTypes(config: WorkspaceConfig): Set<string>;
|