@sudocode-ai/cli 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.
Files changed (41) hide show
  1. package/README.md +330 -0
  2. package/dist/cli/feedback-commands.d.ts +53 -0
  3. package/dist/cli/init-commands.d.ts +22 -0
  4. package/dist/cli/issue-commands.d.ts +45 -0
  5. package/dist/cli/query-commands.d.ts +18 -0
  6. package/dist/cli/reference-commands.d.ts +22 -0
  7. package/dist/cli/relationship-commands.d.ts +14 -0
  8. package/dist/cli/server-commands.d.ts +17 -0
  9. package/dist/cli/spec-commands.d.ts +38 -0
  10. package/dist/cli/status-commands.d.ts +17 -0
  11. package/dist/cli/sync-commands.d.ts +24 -0
  12. package/dist/cli/update-commands.d.ts +12 -0
  13. package/dist/cli.d.ts +6 -0
  14. package/dist/cli.js +196 -0
  15. package/dist/db.d.ts +21 -0
  16. package/dist/export.d.ts +79 -0
  17. package/dist/filename-generator.d.ts +30 -0
  18. package/dist/id-generator.d.ts +26 -0
  19. package/dist/import.d.ts +118 -0
  20. package/dist/index.d.ts +13 -0
  21. package/dist/index.js +189 -0
  22. package/dist/jsonl.d.ts +69 -0
  23. package/dist/markdown.d.ts +146 -0
  24. package/dist/migrations.d.ts +23 -0
  25. package/dist/operations/events.d.ts +53 -0
  26. package/dist/operations/feedback-anchors.d.ts +92 -0
  27. package/dist/operations/feedback.d.ts +76 -0
  28. package/dist/operations/index.d.ts +10 -0
  29. package/dist/operations/issues.d.ts +82 -0
  30. package/dist/operations/references.d.ts +34 -0
  31. package/dist/operations/relationships.d.ts +57 -0
  32. package/dist/operations/specs.d.ts +64 -0
  33. package/dist/operations/tags.d.ts +42 -0
  34. package/dist/operations/transactions.d.ts +41 -0
  35. package/dist/sync.d.ts +47 -0
  36. package/dist/test-schema.d.ts +5 -0
  37. package/dist/types.d.ts +7 -0
  38. package/dist/update-checker.d.ts +24 -0
  39. package/dist/version.d.ts +12 -0
  40. package/dist/watcher.d.ts +63 -0
  41. package/package.json +68 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Import JSONL data to SQLite with collision resolution
3
+ */
4
+ import type Database from "better-sqlite3";
5
+ import type { SpecJSONL, IssueJSONL } from "@sudocode-ai/types";
6
+ export interface ImportOptions {
7
+ /**
8
+ * Input directory for JSONL files
9
+ */
10
+ inputDir?: string;
11
+ /**
12
+ * Custom file names
13
+ */
14
+ specsFile?: string;
15
+ issuesFile?: string;
16
+ /**
17
+ * Dry run - detect changes but don't apply
18
+ */
19
+ dryRun?: boolean;
20
+ /**
21
+ * Automatically resolve collisions
22
+ */
23
+ resolveCollisions?: boolean;
24
+ /**
25
+ * Path to meta.json for collision logging
26
+ */
27
+ metaPath?: string;
28
+ }
29
+ export interface ImportResult {
30
+ specs: {
31
+ added: number;
32
+ updated: number;
33
+ deleted: number;
34
+ };
35
+ issues: {
36
+ added: number;
37
+ updated: number;
38
+ deleted: number;
39
+ };
40
+ collisions: CollisionInfo[];
41
+ }
42
+ export interface CollisionInfo {
43
+ id: string;
44
+ uuid: string;
45
+ type: "spec" | "issue";
46
+ reason: string;
47
+ localContent: string;
48
+ incomingContent: string;
49
+ localCreatedAt?: string;
50
+ incomingCreatedAt: string;
51
+ resolution?: "keep-local" | "use-incoming" | "renumber";
52
+ newId?: string;
53
+ }
54
+ export interface ChangeDetection {
55
+ added: string[];
56
+ updated: string[];
57
+ deleted: string[];
58
+ unchanged: string[];
59
+ }
60
+ /**
61
+ * Detect changes between existing and incoming entities
62
+ * Uses UUID as the source of truth for entity identity
63
+ */
64
+ export declare function detectChanges<T extends {
65
+ id: string;
66
+ uuid: string;
67
+ updated_at: string;
68
+ }>(existing: T[], incoming: T[]): ChangeDetection;
69
+ /**
70
+ * Detect ID collisions (same ID, different UUID)
71
+ * UUIDs are the source of truth for entity identity
72
+ */
73
+ export declare function detectCollisions<T extends {
74
+ id: string;
75
+ uuid: string;
76
+ title: string;
77
+ created_at: string;
78
+ }>(existing: T[], incoming: T[]): CollisionInfo[];
79
+ /**
80
+ * Count references to an entity ID in content fields
81
+ */
82
+ export declare function countReferences(db: Database.Database, entityId: string, entityType: "spec" | "issue"): number;
83
+ /**
84
+ * Resolve collisions using timestamp-based deterministic strategy
85
+ *
86
+ * The entity with the NEWER (more recent) created_at timestamp logically
87
+ * should be renumbered, while the OLDER entity keeps the original ID.
88
+ *
89
+ * For practical reasons (entities already in DB can't be easily renamed),
90
+ * incoming entities are always the ones that get new IDs. However, we
91
+ * deterministically decide which UUID gets which new ID based on timestamps.
92
+ */
93
+ export declare function resolveCollisions(db: Database.Database, collisions: CollisionInfo[]): CollisionInfo[];
94
+ /**
95
+ * Update text references when an ID is renumbered
96
+ */
97
+ export declare function updateTextReferences(db: Database.Database, oldId: string, newId: string): number;
98
+ /**
99
+ * Import specs from JSONL
100
+ */
101
+ export declare function importSpecs(db: Database.Database, specs: SpecJSONL[], changes: ChangeDetection, dryRun?: boolean, skipRelationships?: boolean): {
102
+ added: number;
103
+ updated: number;
104
+ deleted: number;
105
+ };
106
+ /**
107
+ * Import issues from JSONL
108
+ */
109
+ export declare function importIssues(db: Database.Database, issues: IssueJSONL[], changes: ChangeDetection, dryRun?: boolean, skipRelationships?: boolean): {
110
+ added: number;
111
+ updated: number;
112
+ deleted: number;
113
+ };
114
+ /**
115
+ * Import both specs and issues from JSONL files
116
+ */
117
+ export declare function importFromJSONL(db: Database.Database, options?: ImportOptions): Promise<ImportResult>;
118
+ //# sourceMappingURL=import.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Main entry point for sudocode
3
+ */
4
+ export * from "@sudocode-ai/types";
5
+ export * from "./db.js";
6
+ export * from "./operations/index.js";
7
+ export * from "./operations/transactions.js";
8
+ export * from "./jsonl.js";
9
+ export * from "./export.js";
10
+ export * from "./import.js";
11
+ export * from "./markdown.js";
12
+ export * from "./sync.js";
13
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,189 @@
1
+ var Ye=Object.defineProperty;var K=(n,e)=>()=>(n&&(e=n(n=0)),e);var ze=(n,e)=>{for(var t in e)Ye(n,t,{get:e[t],enumerable:!0})};import*as _e from"fs";import*as Z from"path";import{fileURLToPath as Xe}from"url";function nt(){let n=Z.join(tt,"..","package.json");return JSON.parse(_e.readFileSync(n,"utf8")).version}var et,tt,he,ye=K(()=>{"use strict";et=Xe(import.meta.url),tt=Z.dirname(et);he=nt()});import*as C from"fs";import*as se from"path";import*as Ee from"crypto";function be(n,e){let t=ie(e),s=st(n);return`${t.id_prefix.spec}-${String(s).padStart(3,"0")}`}function Se(n,e){let t=ie(e),s=it(n);return`${t.id_prefix.issue}-${String(s).padStart(3,"0")}`}function st(n){let t=n.prepare(`
2
+ SELECT id FROM specs
3
+ ORDER BY created_at DESC
4
+ LIMIT 1
5
+ `).get();if(t){let r=t.id.match(/(\d+)$/);if(r)return parseInt(r[1],10)+1}return n.prepare("SELECT COUNT(*) as count FROM specs").get().count+1}function it(n){let t=n.prepare(`
6
+ SELECT id FROM issues
7
+ ORDER BY created_at DESC
8
+ LIMIT 1
9
+ `).get();if(t){let r=t.id.match(/(\d+)$/);if(r)return parseInt(r[1],10)+1}return n.prepare("SELECT COUNT(*) as count FROM issues").get().count+1}function ie(n){let e=se.join(n,"config.json");if(!C.existsSync(e)){let s={version:he,id_prefix:{spec:"SPEC",issue:"ISSUE"}};return rt(n,s),s}let t=C.readFileSync(e,"utf8");return JSON.parse(t)}function rt(n,e){let t=se.join(n,"config.json");C.writeFileSync(t,JSON.stringify(e,null,2),"utf8")}function De(n){return ie(n)}function G(){return Ee.randomUUID()}var B=K(()=>{"use strict";ye()});var re={};ze(re,{addRelationship:()=>I,getAllRelationships:()=>lt,getDependencies:()=>ut,getDependents:()=>pt,getIncomingRelationships:()=>H,getOutgoingRelationships:()=>k,getRelationship:()=>ee,relationshipExists:()=>ft,removeAllRelationships:()=>A,removeRelationship:()=>ot});function I(n,e){let t=e.from_type==="spec"?"specs":"issues",s=n.prepare(`SELECT id, uuid FROM ${t} WHERE id = ?`).get(e.from_id);if(!s)throw new Error(`${e.from_type==="spec"?"Spec":"Issue"} not found: ${e.from_id}`);let i=e.to_type==="spec"?"specs":"issues",r=n.prepare(`SELECT id, uuid FROM ${i} WHERE id = ?`).get(e.to_id);if(!r)throw new Error(`${e.to_type==="spec"?"Spec":"Issue"} not found: ${e.to_id}`);let c=ee(n,e.from_id,e.from_type,e.to_id,e.to_type,e.relationship_type);if(c)return c;let o=n.prepare(`
10
+ INSERT INTO relationships (
11
+ from_id, from_uuid, from_type, to_id, to_uuid, to_type, relationship_type, metadata
12
+ ) VALUES (
13
+ @from_id, @from_uuid, @from_type, @to_id, @to_uuid, @to_type, @relationship_type, @metadata
14
+ )
15
+ `);try{o.run({from_id:e.from_id,from_uuid:s.uuid,from_type:e.from_type,to_id:e.to_id,to_uuid:r.uuid,to_type:e.to_type,relationship_type:e.relationship_type,metadata:e.metadata??null});let d=ee(n,e.from_id,e.from_type,e.to_id,e.to_type,e.relationship_type);if(!d)throw new Error("Failed to create relationship");return e.relationship_type==="blocks"&&e.from_type==="issue"&&e.to_type==="issue"&&at(n,e.from_id,e.to_id),d}catch(d){throw d.code&&d.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Relationship already exists: ${e.from_id} (${e.from_type}) --[${e.relationship_type}]--> ${e.to_id} (${e.to_type})`):d}}function at(n,e,t){let s=E(n,t);if(s&&s.status!=="closed"){let i=E(n,e);i&&(i.status==="open"||i.status==="in_progress")&&n.prepare(`
16
+ UPDATE issues
17
+ SET status = 'blocked', updated_at = CURRENT_TIMESTAMP
18
+ WHERE id = ?
19
+ `).run(e)}}function ee(n,e,t,s,i,r){return n.prepare(`
20
+ SELECT * FROM relationships
21
+ WHERE from_id = ? AND from_type = ?
22
+ AND to_id = ? AND to_type = ?
23
+ AND relationship_type = ?
24
+ `).get(e,t,s,i,r)??null}function ot(n,e,t,s,i,r){let d=n.prepare(`
25
+ DELETE FROM relationships
26
+ WHERE from_id = ? AND from_type = ?
27
+ AND to_id = ? AND to_type = ?
28
+ AND relationship_type = ?
29
+ `).run(e,t,s,i,r).changes>0;return d&&r==="blocks"&&t==="issue"&&i==="issue"&&ct(n,e),d}function ct(n,e){let t=E(n,e);t&&t.status==="blocked"&&(dt(n,e)||n.prepare(`
30
+ UPDATE issues
31
+ SET status = 'open', updated_at = CURRENT_TIMESTAMP
32
+ WHERE id = ?
33
+ `).run(e))}function dt(n,e){return n.prepare(`
34
+ SELECT COUNT(*) as count
35
+ FROM relationships r
36
+ JOIN issues blocker ON r.to_id = blocker.id AND r.to_type = 'issue'
37
+ WHERE r.from_id = ?
38
+ AND r.from_type = 'issue'
39
+ AND r.relationship_type = 'blocks'
40
+ AND blocker.status IN ('open', 'in_progress', 'blocked')
41
+ `).get(e).count>0}function k(n,e,t,s){let i=`
42
+ SELECT * FROM relationships
43
+ WHERE from_id = @entity_id AND from_type = @entity_type
44
+ `,r={entity_id:e,entity_type:t};return s!==void 0&&(i+=" AND relationship_type = @relationship_type",r.relationship_type=s),i+=" ORDER BY created_at DESC",n.prepare(i).all(r)}function H(n,e,t,s){let i=`
45
+ SELECT * FROM relationships
46
+ WHERE to_id = @entity_id AND to_type = @entity_type
47
+ `,r={entity_id:e,entity_type:t};return s!==void 0&&(i+=" AND relationship_type = @relationship_type",r.relationship_type=s),i+=" ORDER BY created_at DESC",n.prepare(i).all(r)}function ut(n,e,t){return k(n,e,t,"blocks")}function pt(n,e,t){return H(n,e,t,"blocks")}function lt(n,e,t){return{outgoing:k(n,e,t),incoming:H(n,e,t)}}function ft(n,e,t,s,i,r){return ee(n,e,t,s,i,r)!==null}function A(n,e,t){return n.prepare(`
48
+ DELETE FROM relationships
49
+ WHERE (from_id = ? AND from_type = ?)
50
+ OR (to_id = ? AND to_type = ?)
51
+ `).run(e,t,e,t).changes}var v=K(()=>{"use strict";w()});function te(n,e){let t=null;if(e.parent_id){let o=E(n,e.parent_id);if(!o)throw new Error(`Parent issue not found: ${e.parent_id}`);t=o.uuid}let s=e.uuid||G(),i=["id","uuid","title","content","status","priority","assignee","parent_id","parent_uuid","archived"],r=["@id","@uuid","@title","@content","@status","@priority","@assignee","@parent_id","@parent_uuid","@archived"];e.created_at&&(i.push("created_at"),r.push("@created_at")),e.updated_at&&(i.push("updated_at"),r.push("@updated_at")),e.closed_at!==void 0&&(i.push("closed_at"),r.push("@closed_at")),e.archived_at!==void 0&&(i.push("archived_at"),r.push("@archived_at"));let c=n.prepare(`
52
+ INSERT INTO issues (
53
+ ${i.join(", ")}
54
+ ) VALUES (
55
+ ${r.join(", ")}
56
+ )
57
+ ON CONFLICT(id) DO UPDATE SET
58
+ uuid = excluded.uuid,
59
+ title = excluded.title,
60
+ content = excluded.content,
61
+ status = excluded.status,
62
+ priority = excluded.priority,
63
+ assignee = excluded.assignee,
64
+ parent_id = excluded.parent_id,
65
+ parent_uuid = excluded.parent_uuid,
66
+ archived = excluded.archived,
67
+ archived_at = excluded.archived_at,
68
+ ${e.created_at?"created_at = excluded.created_at,":""}
69
+ ${e.updated_at?"updated_at = excluded.updated_at":"updated_at = CURRENT_TIMESTAMP"}
70
+ `);try{let o={id:e.id,uuid:s,title:e.title,content:e.content||"",status:e.status||"open",priority:e.priority??2,assignee:e.assignee??null,parent_id:e.parent_id??null,parent_uuid:t,archived:e.archived?1:0};e.created_at&&(o.created_at=e.created_at),e.updated_at&&(o.updated_at=e.updated_at),e.closed_at!==void 0&&(o.closed_at=e.closed_at),e.archived_at!==void 0&&(o.archived_at=e.archived_at),c.run(o);let d=E(n,e.id);if(!d)throw new Error(`Failed to create issue ${e.id}`);return d}catch(o){throw o.code&&o.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${o.message}`):o}}function E(n,e){return n.prepare(`
71
+ SELECT * FROM issues WHERE id = ?
72
+ `).get(e)??null}function L(n,e,t){let s=E(n,e);if(!s)throw new Error(`Issue not found: ${e}`);if(t.parent_id&&!E(n,t.parent_id))throw new Error(`Parent issue not found: ${t.parent_id}`);let i=[],r={id:e};if(t.title!==void 0&&t.title!==s.title&&(i.push("title = @title"),r.title=t.title),t.content!==void 0&&t.content!==s.content&&(i.push("content = @content"),r.content=t.content),t.status!==void 0&&t.status!==s.status?(i.push("status = @status"),r.status=t.status,t.closed_at!==void 0?(i.push("closed_at = @closed_at"),r.closed_at=t.closed_at):t.status==="closed"&&s.status!=="closed"?i.push("closed_at = CURRENT_TIMESTAMP"):t.status!=="closed"&&s.status==="closed"&&i.push("closed_at = NULL")):t.closed_at!==void 0&&t.closed_at!==s.closed_at&&(i.push("closed_at = @closed_at"),r.closed_at=t.closed_at),t.priority!==void 0&&t.priority!==s.priority&&(i.push("priority = @priority"),r.priority=t.priority),t.assignee!==void 0&&t.assignee!==s.assignee&&(i.push("assignee = @assignee"),r.assignee=t.assignee),t.parent_id!==void 0&&t.parent_id!==s.parent_id&&(i.push("parent_id = @parent_id"),r.parent_id=t.parent_id),t.archived!==void 0&&(t.archived?1:0)!==s.archived?(i.push("archived = @archived"),r.archived=t.archived?1:0,t.archived_at!==void 0?(i.push("archived_at = @archived_at"),r.archived_at=t.archived_at):t.archived&&!s.archived?i.push("archived_at = CURRENT_TIMESTAMP"):!t.archived&&s.archived&&i.push("archived_at = NULL")):t.archived_at!==void 0&&t.archived_at!==s.archived_at&&(i.push("archived_at = @archived_at"),r.archived_at=t.archived_at),t.updated_at!==void 0?(i.push("updated_at = @updated_at"),r.updated_at=t.updated_at):i.length>0&&i.push("updated_at = CURRENT_TIMESTAMP"),i.length===0)return s;let c=n.prepare(`
73
+ UPDATE issues SET ${i.join(", ")} WHERE id = @id
74
+ `);try{c.run(r);let o=E(n,e);if(!o)throw new Error(`Failed to update issue ${e}`);return t.status==="closed"&&s.status!=="closed"&&gt(n,e),o}catch(o){throw o.code&&o.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${o.message}`):o}}function gt(n,e){let t=H(n,e,"issue","blocks");for(let s of t){let i=s.from_id,r=E(n,i);if(!r||r.status!=="blocked")continue;mt(n,i,e)||n.prepare(`
75
+ UPDATE issues
76
+ SET status = 'open', updated_at = CURRENT_TIMESTAMP
77
+ WHERE id = ?
78
+ `).run(i)}}function mt(n,e,t){let s=n.prepare(`
79
+ SELECT COUNT(*) as count
80
+ FROM relationships r
81
+ JOIN issues blocker ON r.to_id = blocker.id AND r.to_type = 'issue'
82
+ WHERE r.from_id = ?
83
+ AND r.from_type = 'issue'
84
+ AND r.relationship_type = 'blocks'
85
+ AND blocker.status IN ('open', 'in_progress', 'blocked')
86
+ ${t?"AND blocker.id != ?":""}
87
+ `),i=t?[e,t]:[e];return s.get(...i).count>0}function Ie(n,e){return n.prepare("DELETE FROM issues WHERE id = ?").run(e).changes>0}function gn(n,e){return L(n,e,{status:"closed"})}function mn(n,e){return L(n,e,{status:"open"})}function $(n,e={}){let t=[],s={};e.status!==void 0&&(t.push("status = @status"),s.status=e.status),e.priority!==void 0&&(t.push("priority = @priority"),s.priority=e.priority),e.assignee!==void 0&&(t.push("assignee = @assignee"),s.assignee=e.assignee),e.parent_id!==void 0&&(t.push("parent_id = @parent_id"),s.parent_id=e.parent_id),e.archived!==void 0&&(t.push("archived = @archived"),s.archived=e.archived?1:0);let i="SELECT * FROM issues";return t.length>0&&(i+=" WHERE "+t.join(" AND ")),i+=" ORDER BY priority DESC, created_at DESC",e.limit!==void 0&&(i+=" LIMIT @limit",s.limit=e.limit),e.offset!==void 0&&(i+=" OFFSET @offset",s.offset=e.offset),n.prepare(i).all(s)}function _n(n){return n.prepare("SELECT * FROM ready_issues ORDER BY priority DESC, created_at DESC").all()}function hn(n){return n.prepare("SELECT * FROM blocked_issues ORDER BY priority DESC, created_at DESC").all()}function yn(n,e,t={}){let s=["(title LIKE @query OR content LIKE @query)"],i={query:`%${e}%`};t.status!==void 0&&(s.push("status = @status"),i.status=t.status),t.priority!==void 0&&(s.push("priority = @priority"),i.priority=t.priority),t.assignee!==void 0&&(s.push("assignee = @assignee"),i.assignee=t.assignee),t.parent_id!==void 0&&(s.push("parent_id = @parent_id"),i.parent_id=t.parent_id),t.archived!==void 0&&(s.push("archived = @archived"),i.archived=t.archived?1:0);let r=`SELECT * FROM issues WHERE ${s.join(" AND ")} ORDER BY priority DESC, created_at DESC`;return t.limit!==void 0?(r+=" LIMIT @limit",i.limit=t.limit):r+=" LIMIT 50",n.prepare(r).all(i)}var w=K(()=>{"use strict";B();v()});export*from"@sudocode-ai/types";import Ze from"better-sqlite3";import*as R from"@sudocode-ai/types/schema";var Ve=[];function Qe(n){return n.exec(`
88
+ CREATE TABLE IF NOT EXISTS migrations (
89
+ version INTEGER PRIMARY KEY,
90
+ name TEXT NOT NULL,
91
+ applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
92
+ )
93
+ `),n.prepare("SELECT MAX(version) as version FROM migrations").get().version??0}function Ke(n,e){n.prepare(`
94
+ INSERT OR REPLACE INTO migrations (version, name)
95
+ VALUES (?, ?)
96
+ `).run(e.version,e.name)}function me(n){let e=Qe(n),t=Ve.filter(s=>s.version>e);if(t.length!==0){console.log(`Running ${t.length} pending migration(s)...`);for(let s of t){console.log(` Applying migration ${s.version}: ${s.name}`);try{s.up(n),Ke(n,s),console.log(` \u2713 Migration ${s.version} applied successfully`)}catch(i){throw console.error(` \u2717 Migration ${s.version} failed:`,i),i}}}}function Ge(n){let e=new Ze(n.path,{verbose:n.verbose?console.log:void 0});e.exec(R.DB_CONFIG);for(let t of R.ALL_TABLES)e.exec(t);for(let t of R.ALL_INDEXES)e.exec(t);for(let t of R.ALL_VIEWS)e.exec(t);return me(e),e}function en(n){return Ge({path:n})}function tn(n,e){let t=`sp_${Date.now()}`;try{n.exec(`SAVEPOINT ${t}`);let s=e(n);return n.exec(`RELEASE ${t}`),s}catch(s){throw n.exec(`ROLLBACK TO ${t}`),s}}B();function X(n,e){let t=null;if(e.parent_id){let o=T(n,e.parent_id);if(!o)throw new Error(`Parent spec not found: ${e.parent_id}`);t=o.uuid}let s=e.uuid||G(),i=["id","uuid","title","file_path","content","priority","parent_id","parent_uuid","archived"],r=["@id","@uuid","@title","@file_path","@content","@priority","@parent_id","@parent_uuid","@archived"];e.created_at&&(i.push("created_at"),r.push("@created_at")),e.updated_at&&(i.push("updated_at"),r.push("@updated_at")),e.archived_at!==void 0&&(i.push("archived_at"),r.push("@archived_at"));let c=n.prepare(`
97
+ INSERT INTO specs (
98
+ ${i.join(", ")}
99
+ ) VALUES (
100
+ ${r.join(", ")}
101
+ )
102
+ ON CONFLICT(id) DO UPDATE SET
103
+ uuid = excluded.uuid,
104
+ title = excluded.title,
105
+ file_path = excluded.file_path,
106
+ content = excluded.content,
107
+ priority = excluded.priority,
108
+ parent_id = excluded.parent_id,
109
+ parent_uuid = excluded.parent_uuid,
110
+ archived = excluded.archived,
111
+ archived_at = excluded.archived_at,
112
+ ${e.created_at?"created_at = excluded.created_at,":""}
113
+ ${e.updated_at?"updated_at = excluded.updated_at":"updated_at = CURRENT_TIMESTAMP"}
114
+ `);try{let o={id:e.id,uuid:s,title:e.title,file_path:e.file_path,content:e.content||"",priority:e.priority??2,parent_id:e.parent_id??null,parent_uuid:t,archived:e.archived?1:0};e.created_at&&(o.created_at=e.created_at),e.updated_at&&(o.updated_at=e.updated_at),e.archived_at!==void 0&&(o.archived_at=e.archived_at),c.run(o);let d=T(n,e.id);if(!d)throw new Error(`Failed to create spec ${e.id}`);return d}catch(o){throw o.code&&o.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${o.message}`):o}}function T(n,e){return n.prepare(`
115
+ SELECT * FROM specs WHERE id = ?
116
+ `).get(e)??null}function xe(n,e){return n.prepare(`
117
+ SELECT * FROM specs WHERE file_path = ?
118
+ `).get(e)??null}function P(n,e,t){let s=T(n,e);if(!s)throw new Error(`Spec not found: ${e}`);if(t.parent_id&&!T(n,t.parent_id))throw new Error(`Parent spec not found: ${t.parent_id}`);let i=[],r={id:e};if(t.title!==void 0&&t.title!==s.title&&(i.push("title = @title"),r.title=t.title),t.file_path!==void 0&&t.file_path!==s.file_path&&(i.push("file_path = @file_path"),r.file_path=t.file_path),t.content!==void 0&&t.content!==s.content&&(i.push("content = @content"),r.content=t.content),t.priority!==void 0&&t.priority!==s.priority&&(i.push("priority = @priority"),r.priority=t.priority),t.parent_id!==void 0&&t.parent_id!==s.parent_id&&(i.push("parent_id = @parent_id"),r.parent_id=t.parent_id),t.archived!==void 0&&t.archived!==s.archived?(i.push("archived = @archived"),r.archived=t.archived?1:0,t.archived_at!==void 0?(i.push("archived_at = @archived_at"),r.archived_at=t.archived_at):t.archived&&!s.archived?i.push("archived_at = CURRENT_TIMESTAMP"):!t.archived&&s.archived&&i.push("archived_at = NULL")):t.archived_at!==void 0&&t.archived_at!==s.archived_at&&(i.push("archived_at = @archived_at"),r.archived_at=t.archived_at),t.updated_at!==void 0?(i.push("updated_at = @updated_at"),r.updated_at=t.updated_at):i.length>0&&i.push("updated_at = CURRENT_TIMESTAMP"),i.length===0)return s;let c=n.prepare(`
119
+ UPDATE specs SET ${i.join(", ")} WHERE id = @id
120
+ `);try{c.run(r);let o=T(n,e);if(!o)throw new Error(`Failed to update spec ${e}`);return o}catch(o){throw o.code&&o.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${o.message}`):o}}function Te(n,e){return n.prepare("DELETE FROM specs WHERE id = ?").run(e).changes>0}function F(n,e={}){let t=[],s={};e.priority!==void 0&&(t.push("priority = @priority"),s.priority=e.priority),e.parent_id!==void 0&&(t.push("parent_id = @parent_id"),s.parent_id=e.parent_id),e.archived!==void 0&&(t.push("archived = @archived"),s.archived=e.archived?1:0);let i="SELECT * FROM specs";return t.length>0&&(i+=" WHERE "+t.join(" AND ")),i+=" ORDER BY priority DESC, created_at DESC",e.limit!==void 0&&(i+=" LIMIT @limit",s.limit=e.limit),e.offset!==void 0&&(i+=" OFFSET @offset",s.offset=e.offset),n.prepare(i).all(s)}function dn(n,e,t={}){let s=["(title LIKE @query OR content LIKE @query)"],i={query:`%${e}%`};t.priority!==void 0&&(s.push("priority = @priority"),i.priority=t.priority),t.parent_id!==void 0&&(s.push("parent_id = @parent_id"),i.parent_id=t.parent_id),t.archived!==void 0&&(s.push("archived = @archived"),i.archived=t.archived?1:0);let r=`SELECT * FROM specs WHERE ${s.join(" AND ")} ORDER BY priority DESC, created_at DESC`;return t.limit!==void 0?(r+=" LIMIT @limit",i.limit=t.limit):r+=" LIMIT 50",n.prepare(r).all(i)}w();v();function _t(n,e,t,s){let i=t==="spec"?"specs":"issues",r=n.prepare(`SELECT uuid FROM ${i} WHERE id = ?`).get(e);if(!r)throw new Error(`${t==="spec"?"Spec":"Issue"} not found: ${e}`);let c=n.prepare(`
121
+ INSERT INTO tags (entity_id, entity_uuid, entity_type, tag)
122
+ VALUES (@entity_id, @entity_uuid, @entity_type, @tag)
123
+ `);try{return c.run({entity_id:e,entity_uuid:r.uuid,entity_type:t,tag:s}),{entity_id:e,entity_uuid:r.uuid,entity_type:t,tag:s}}catch(o){if(o.code&&o.code.startsWith("SQLITE_CONSTRAINT"))return{entity_id:e,entity_uuid:r.uuid,entity_type:t,tag:s};throw o}}function ht(n,e,t,s){let i=[];for(let r of s)i.push(_t(n,e,t,r));return i}function bn(n,e,t,s){return n.prepare(`
124
+ DELETE FROM tags
125
+ WHERE entity_id = ? AND entity_type = ? AND tag = ?
126
+ `).run(e,t,s).changes>0}function q(n,e,t){return n.prepare(`
127
+ SELECT tag FROM tags
128
+ WHERE entity_id = ? AND entity_type = ?
129
+ ORDER BY tag
130
+ `).all(e,t).map(r=>r.tag)}function Sn(n,e,t){let s="SELECT * FROM tags WHERE tag = @tag",i={tag:e};return t!==void 0&&(s+=" AND entity_type = @entity_type",i.entity_type=t),s+=" ORDER BY entity_id",n.prepare(s).all(i)}function yt(n,e,t){return n.prepare(`
131
+ DELETE FROM tags
132
+ WHERE entity_id = ? AND entity_type = ?
133
+ `).run(e,t).changes}function Dn(n,e,t,s){return n.prepare(`
134
+ SELECT 1 FROM tags
135
+ WHERE entity_id = ? AND entity_type = ? AND tag = ?
136
+ `).get(e,t,s)!==void 0}function xn(n,e){let t="SELECT DISTINCT tag FROM tags",s={};return e!==void 0&&(t+=" WHERE entity_type = @entity_type",s.entity_type=e),t+=" ORDER BY tag",n.prepare(t).all(s).map(c=>c.tag)}function O(n,e,t,s){return yt(n,e,t),s.length>0&&ht(n,e,t,s),s}function In(n,e){let s=n.prepare(`
137
+ INSERT INTO events (
138
+ entity_id, entity_type, event_type, actor,
139
+ old_value, new_value, comment, git_commit_sha, source
140
+ ) VALUES (
141
+ @entity_id, @entity_type, @event_type, @actor,
142
+ @old_value, @new_value, @comment, @git_commit_sha, @source
143
+ )
144
+ `).run({entity_id:e.entity_id,entity_type:e.entity_type,event_type:e.event_type,actor:e.actor,old_value:e.old_value||null,new_value:e.new_value||null,comment:e.comment||null,git_commit_sha:e.git_commit_sha||null,source:e.source||null}),i=Et(n,Number(s.lastInsertRowid));if(!i)throw new Error("Failed to create event");return i}function Et(n,e){return n.prepare("SELECT * FROM events WHERE id = ?").get(e)??null}function ae(n,e={}){let t=[],s={};e.entity_id!==void 0&&(t.push("entity_id = @entity_id"),s.entity_id=e.entity_id),e.entity_type!==void 0&&(t.push("entity_type = @entity_type"),s.entity_type=e.entity_type),e.event_type!==void 0&&(t.push("event_type = @event_type"),s.event_type=e.event_type),e.actor!==void 0&&(t.push("actor = @actor"),s.actor=e.actor);let i="SELECT * FROM events";return t.length>0&&(i+=" WHERE "+t.join(" AND ")),i+=" ORDER BY created_at DESC",e.limit!==void 0&&(i+=" LIMIT @limit",s.limit=e.limit),e.offset!==void 0&&(i+=" OFFSET @offset",s.offset=e.offset),n.prepare(i).all(s)}function Rn(n,e,t,s){return ae(n,{entity_id:e,entity_type:t,limit:s})}function vn(n,e=50){return ae(n,{limit:e})}function On(n,e,t){return ae(n,{actor:e,limit:t})}function wn(n,e,t){return n.prepare(`
145
+ DELETE FROM events
146
+ WHERE entity_id = ? AND entity_type = ?
147
+ `).run(e,t).changes}function bt(n,e,t){let s=`[[${n}`;return e&&(s+=`|${e}`),s+="]]",t&&(s+=`{ ${t} }`),s}function St(n,e){let t=n.split(`
148
+ `);if(e<1||e>t.length)throw new Error(`Line number ${e} is out of bounds (content has ${t.length} lines)`);let s=0;for(let i=0;i<e-1;i++)s+=t[i].length+1;return s}function Dt(n,e){let t=n.indexOf(e);if(t===-1)throw new Error(`Text not found: "${e}"`);return t}function Nn(n,e,t){let{referenceId:s,displayText:i,relationshipType:r,format:c="inline",position:o="after"}=t;if(!e.line&&!e.text)throw new Error("Either line or text must be specified");if(e.line&&e.text)throw new Error("Cannot specify both line and text");let d=bt(s,i,r),a;if(e.line){if(a=St(n,e.line),o==="after"){let f=n.indexOf(`
149
+ `,a);a=f===-1?n.length:f}}else if(e.text)a=Dt(n,e.text),o==="after"&&(a+=e.text.length);else throw new Error("Location must specify line or text");let u;return c==="newline"?o==="before"?u=`${d}
150
+ `:u=`
151
+ ${d}`:o==="before"?u=`${d} `:u=` ${d}`,n.slice(0,a)+u+n.slice(a)}function oe(n,e){return n.inTransaction?e(n):n.transaction(e)(n)}function Wn(n,e){return oe(n,()=>{let t=[];for(let s of e)t.push(s());return t})}function jn(n,e,t=3,s=100){let i=null;for(let r=0;r<=t;r++)try{return e(n)}catch(c){if(i=c,(c.code==="SQLITE_BUSY"||c.code==="SQLITE_LOCKED")&&r<t){let o=s*Math.pow(2,r);new Promise(a=>setTimeout(a,o)).then(()=>{});continue}throw c}throw i||new Error("Transaction failed after retries")}var Re=class n{constructor(e,t){this.db=e;this.savepointId=t||`sp_${Date.now()}_${Math.random().toString().replace(".","")}`,this.db.prepare(`SAVEPOINT ${this.savepointId}`).run()}savepointId;released=!1;commit(){if(this.released)throw new Error("Savepoint already released");this.db.prepare(`RELEASE ${this.savepointId}`).run(),this.released=!0}rollback(){if(this.released)throw new Error("Savepoint already released");this.db.prepare(`ROLLBACK TO ${this.savepointId}`).run(),this.db.prepare(`RELEASE ${this.savepointId}`).run(),this.released=!0}static execute(e,t){let s=new n(e);try{let i=t(s);return s.released||s.commit(),i}catch(i){throw s.released||s.rollback(),i}}};import*as h from"fs";import*as ve from"readline";import*as ce from"path";async function M(n,e={}){let{skipErrors:t=!1,onError:s}=e;if(!h.existsSync(n))return[];let i=[],r=h.createReadStream(n,{encoding:"utf8"}),c=ve.createInterface({input:r,crlfDelay:1/0}),o=0;for await(let d of c)if(o++,d.trim()!=="")try{let a=JSON.parse(d);i.push(a)}catch(a){let u=a;if(s&&s(o,d,u),!t)throw new Error(`Failed to parse JSON at line ${o}: ${u.message}`)}return i}function de(n,e={}){let{skipErrors:t=!1,onError:s}=e;if(!h.existsSync(n))return[];let i=[],c=h.readFileSync(n,"utf8").split(`
152
+ `);for(let o=0;o<c.length;o++){let d=c[o].trim(),a=o+1;if(d!=="")try{let u=JSON.parse(d);i.push(u)}catch(u){let p=u;if(s&&s(a,d,p),!t)throw new Error(`Failed to parse JSON at line ${a}: ${p.message}`)}}return i}async function Y(n,e,t={}){let{atomic:s=!0}=t,i=ce.dirname(n);h.existsSync(i)||h.mkdirSync(i,{recursive:!0});let r=s?`${n}.tmp`:n,c=[...e].sort((a,u)=>{let p=a.created_at,f=u.created_at;if(!p&&!f){let b=a.id||"",y=u.id||"";return b<y?-1:b>y?1:0}if(!p)return 1;if(!f||p<f)return-1;if(p>f)return 1;let g=a.id||"",S=u.id||"";return g<S?-1:g>S?1:0}),d=c.map(a=>JSON.stringify(a)).join(`
153
+ `)+`
154
+ `;if(!(h.existsSync(n)&&h.readFileSync(n,"utf8")===d)&&(h.writeFileSync(r,d,"utf8"),s&&h.renameSync(r,n),c.length>0)){let a=c.map(u=>u.updated_at).filter(u=>u!=null).map(u=>{let p=String(u),g=p.endsWith("Z")||p.includes("+")||/[+-]\d{2}:\d{2}$/.test(p)?p:p.replace(" ","T")+"Z";return new Date(g).getTime()});if(a.length>0){let u=Math.max(...a),p=new Date(u);h.utimesSync(n,p,p)}}}function Oe(n,e,t={}){let{atomic:s=!0}=t,i=ce.dirname(n);h.existsSync(i)||h.mkdirSync(i,{recursive:!0});let r=s?`${n}.tmp`:n,c=[...e].sort((a,u)=>{let p=a.created_at,f=u.created_at;if(!p&&!f){let b=a.id||"",y=u.id||"";return b<y?-1:b>y?1:0}if(!p)return 1;if(!f||p<f)return-1;if(p>f)return 1;let g=a.id||"",S=u.id||"";return g<S?-1:g>S?1:0}),d=c.map(a=>JSON.stringify(a)).join(`
155
+ `)+`
156
+ `;if(!(h.existsSync(n)&&h.readFileSync(n,"utf8")===d)&&(h.writeFileSync(r,d,"utf8"),s&&h.renameSync(r,n),c.length>0)){let a=c.map(u=>u.updated_at).filter(u=>u!=null).map(u=>{let p=String(u),g=p.endsWith("Z")||p.includes("+")||/[+-]\d{2}:\d{2}$/.test(p)?p:p.replace(" ","T")+"Z";return new Date(g).getTime()});if(a.length>0){let u=Math.max(...a),p=new Date(u);h.utimesSync(n,p,p)}}}async function Pn(n,e,t="id"){let s=e[t];if(!s)throw new Error(`Entity missing ${t} field`);let i=await M(n,{skipErrors:!0}),r=i.findIndex(c=>c[t]===s);r>=0?i[r]=e:i.push(e),await Y(n,i)}function Hn(n,e,t="id"){let s=e[t];if(!s)throw new Error(`Entity missing ${t} field`);let i=de(n,{skipErrors:!0}),r=i.findIndex(c=>c[t]===s);r>=0?i[r]=e:i.push(e),Oe(n,i)}async function qn(n,e,t="id"){let s=await M(n,{skipErrors:!0}),i=s.length,r=s.filter(c=>c[t]!==e);return r.length===i?!1:(await Y(n,r),!0)}function Yn(n,e,t="id"){let s=de(n,{skipErrors:!0}),i=s.length,r=s.filter(c=>c[t]!==e);return r.length===i?!1:(Oe(n,r),!0)}async function zn(n,e,t="id"){return(await M(n,{skipErrors:!0})).find(i=>i[t]===e)??null}function Vn(n,e,t="id"){return de(n,{skipErrors:!0}).find(i=>i[t]===e)??null}w();v();function we(n){return{...n,dismissed:n.dismissed===1}}function xt(n){let t=n.prepare(`
157
+ SELECT id FROM issue_feedback ORDER BY id DESC LIMIT 1
158
+ `).get();if(!t)return"FB-001";let s=t.id.match(/^FB-(\d+)$/);if(!s)return"FB-001";let i=parseInt(s[1],10)+1;return`FB-${String(i).padStart(3,"0")}`}function Le(n,e){let t=e.id||xt(n),s=e.anchor?JSON.stringify(e.anchor):null,i=e.agent||"user",r=n.prepare("SELECT uuid FROM issues WHERE id = ?").get(e.issue_id);if(!r)throw new Error(`Issue not found: ${e.issue_id}`);let c=n.prepare("SELECT uuid FROM specs WHERE id = ?").get(e.spec_id);if(!c)throw new Error(`Spec not found: ${e.spec_id}`);let o=n.prepare(`
159
+ INSERT INTO issue_feedback (
160
+ id, issue_id, issue_uuid, spec_id, spec_uuid, feedback_type, content, agent, anchor, dismissed
161
+ ) VALUES (
162
+ @id, @issue_id, @issue_uuid, @spec_id, @spec_uuid, @feedback_type, @content, @agent, @anchor, @dismissed
163
+ )
164
+ `);try{o.run({id:t,issue_id:e.issue_id,issue_uuid:r.uuid,spec_id:e.spec_id,spec_uuid:c.uuid,feedback_type:e.feedback_type,content:e.content,agent:i,anchor:s,dismissed:e.dismissed!==void 0&&e.dismissed?1:0});let d=ue(n,t);if(!d)throw new Error(`Failed to create feedback ${t}`);return d}catch(d){throw d.code&&d.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${d.message}`):d}}function ue(n,e){let s=n.prepare(`
165
+ SELECT * FROM issue_feedback WHERE id = ?
166
+ `).get(e);return s?we(s):null}function Ne(n,e,t){let s=ue(n,e);if(!s)throw new Error(`Feedback not found: ${e}`);let i=[],r={id:e};if(t.content!==void 0&&(i.push("content = @content"),r.content=t.content),t.dismissed!==void 0&&(i.push("dismissed = @dismissed"),r.dismissed=t.dismissed?1:0),t.anchor!==void 0&&(i.push("anchor = @anchor"),r.anchor=JSON.stringify(t.anchor)),i.push("updated_at = CURRENT_TIMESTAMP"),i.length===1)return s;let c=n.prepare(`
167
+ UPDATE issue_feedback SET ${i.join(", ")} WHERE id = @id
168
+ `);try{c.run(r);let o=ue(n,e);if(!o)throw new Error(`Failed to update feedback ${e}`);return o}catch(o){throw o.code&&o.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${o.message}`):o}}function Ce(n,e){return n.prepare("DELETE FROM issue_feedback WHERE id = ?").run(e).changes>0}function J(n,e={}){let t=[],s={};e.issue_id!==void 0&&(t.push("issue_id = @issue_id"),s.issue_id=e.issue_id),e.spec_id!==void 0&&(t.push("spec_id = @spec_id"),s.spec_id=e.spec_id),e.feedback_type!==void 0&&(t.push("feedback_type = @feedback_type"),s.feedback_type=e.feedback_type),e.dismissed!==void 0&&(t.push("dismissed = @dismissed"),s.dismissed=e.dismissed?1:0);let i="SELECT * FROM issue_feedback";return t.length>0&&(i+=" WHERE "+t.join(" AND ")),i+=" ORDER BY created_at DESC",e.limit!==void 0&&(i+=" LIMIT @limit",s.limit=e.limit),e.offset!==void 0&&(i+=" OFFSET @offset",s.offset=e.offset),n.prepare(i).all(s).map(we)}function Tt(n,e){let s=k(n,e.id,"spec").map(r=>({from:r.from_id,from_type:r.from_type,to:r.to_id,to_type:r.to_type,type:r.relationship_type})),i=q(n,e.id,"spec");return{...e,relationships:s,tags:i}}function It(n,e){let s=k(n,e.id,"issue").map(o=>({from:o.from_id,from_type:o.from_type,to:o.to_id,to_type:o.to_type,type:o.relationship_type})),i=q(n,e.id,"issue"),c=J(n,{issue_id:e.id}).map(o=>({id:o.id,issue_id:o.issue_id,spec_id:o.spec_id,feedback_type:o.feedback_type,content:o.content,agent:o.agent,anchor:o.anchor&&typeof o.anchor=="string"?JSON.parse(o.anchor):o.anchor,dismissed:o.dismissed,created_at:o.created_at,updated_at:o.updated_at}));return{...e,relationships:s,tags:i,feedback:c.length>0?c:void 0}}function Rt(n,e={}){let{since:t}=e,s=F(n);return(t?s.filter(r=>new Date(r.updated_at)>t):s).map(r=>Tt(n,r))}function vt(n,e={}){let{since:t}=e,s=$(n);return(t?s.filter(r=>new Date(r.updated_at)>t):s).map(r=>It(n,r))}async function le(n,e={}){let{outputDir:t=".sudocode",specsFile:s="specs.jsonl",issuesFile:i="issues.jsonl"}=e,r=`${t}/${s}`,c=`${t}/${i}`,o=Rt(n,e);await Y(r,o);let d=vt(n,e);return await Y(c,d),{specsCount:o.length,issuesCount:d.length}}var pe=class{constructor(e,t=5e3,s={}){this.db=e;this.delayMs=t;this.options=s}timeoutId=null;pending=!1;trigger(){this.pending=!0,this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=setTimeout(()=>{this.execute()},this.delayMs)}async execute(){if(this.pending){this.pending=!1,this.timeoutId=null;try{await le(this.db,this.options)}catch(e){throw console.error("Export failed:",e),e}}}cancel(){this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null),this.pending=!1}isPending(){return this.pending}async flush(){this.pending&&(this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null),await this.execute())}};function ss(n,e=5e3,t={}){return new pe(n,e,t)}w();v();import*as fe from"path";function Fe(n,e){let t=new Map(n.map(d=>[d.uuid,d])),s=new Set(e.map(d=>d.uuid)),i=e.filter(d=>!t.has(d.uuid)).map(d=>d.id),r=n.filter(d=>!s.has(d.uuid)).map(d=>d.id),c=[],o=[];for(let d of e){let a=t.get(d.uuid);a&&(Ot(a,d)?c.push(d.id):o.push(d.id))}return{added:i,updated:c,deleted:r,unchanged:o}}function Ot(n,e){return n.updated_at!==e.updated_at}function ke(n,e){let t=[],s=new Map(n.map(r=>[r.id,r]));for(let r of e){let c=s.get(r.id);c&&c.uuid!==r.uuid&&t.push({id:r.id,uuid:r.uuid,type:"spec",reason:"Same ID but different UUID (different entities)",localContent:c.title,incomingContent:r.title,localCreatedAt:c.created_at,incomingCreatedAt:r.created_at})}let i=new Map;for(let r of e){let c=i.get(r.id)||[];c.push(r),i.set(r.id,c)}for(let[r,c]of i.entries())if(c.length>1&&new Set(c.map(d=>d.uuid)).size>1)for(let d=1;d<c.length;d++)t.push({id:c[d].id,uuid:c[d].uuid,type:"spec",reason:"Duplicate ID in incoming data with different UUID",localContent:c[0].title,incomingContent:c[d].title,localCreatedAt:c[0].created_at,incomingCreatedAt:c[d].created_at});return t}function ls(n,e,t){let s=0,i=F(n);for(let c of i){let o=new RegExp(`\\b${e}\\b`,"g"),d=c.content.match(o);d&&(s+=d.length)}let r=$(n);for(let c of r){let o=new RegExp(`\\b${e}\\b`,"g"),d=c.content.match(o);d&&(s+=d.length)}return s}function wt(n,e){let t=[],s=new Map;for(let i of e){let r=!0;if(i.localCreatedAt){let o=new Date(i.localCreatedAt).getTime(),d=new Date(i.incomingCreatedAt).getTime();d>o?r=!0:o>d?r=!1:r=i.uuid>i.localContent}let c=s.get(i.uuid);c||(c=Lt(n,i.id,i.type),s.set(i.uuid,c)),t.push({...i,resolution:"renumber",newId:c,...r&&{note:"incoming is newer - correctly renumbered"},...!r&&{note:"local is newer - incoming (older) being renumbered"}})}return t}function Lt(n,e,t){let s=e.match(/^([a-z]+-)?(\d+)$/i);if(!s)return`${t}-${Date.now()}`;let i=s[1]||`${t}-`,r=parseInt(s[2],10),c=`${i}${r+1e3}`,o=0;for(;o<1e3;){if(!(t==="spec"?T(n,c)!==null:E(n,c)!==null))return c;r++,c=`${i}${r+1e3}`,o++}return`${i}${Date.now()}`}function fs(n,e,t){let s=0,i=F(n);for(let c of i){let o=new RegExp(`\\b${e}\\b`,"g");if(o.test(c.content)){let d=c.content.replace(o,t);P(n,c.id,{content:d}),s++}}let r=$(n);for(let c of r){let o=new RegExp(`\\b${e}\\b`,"g"),d=!1,a=c.content;o.test(c.content)&&(a=c.content.replace(o,t),d=!0),d&&(L(n,c.id,{content:a}),s++)}return s}function Ae(n,e,t,s=!1,i=!1){if(s)return{added:t.added.length,updated:t.updated.length,deleted:t.deleted.length};let r=0,c=0,o=0;for(let d of t.added){let a=e.find(u=>u.id===d);a&&(X(n,{id:a.id,uuid:a.uuid,title:a.title,file_path:a.file_path,content:a.content,priority:a.priority,parent_id:a.parent_id,archived:a.archived,archived_at:a.archived_at,created_at:a.created_at,updated_at:a.updated_at}),O(n,a.id,"spec",a.tags||[]),r++)}if(!i)for(let d of t.added){let a=e.find(u=>u.id===d);if(a&&a.relationships&&a.relationships.length>0)for(let u of a.relationships)I(n,{from_id:u.from,from_type:u.from_type,to_id:u.to,to_type:u.to_type,relationship_type:u.type})}for(let d of t.updated){let a=e.find(u=>u.id===d);a&&(P(n,a.id,{title:a.title,file_path:a.file_path,content:a.content,priority:a.priority,parent_id:a.parent_id,archived:a.archived,archived_at:a.archived_at,updated_at:a.updated_at}),O(n,a.id,"spec",a.tags||[]),c++)}if(!i)for(let d of t.updated){let a=e.find(u=>u.id===d);if(a){A(n,a.id,"spec");for(let u of a.relationships||[])I(n,{from_id:u.from,from_type:u.from_type,to_id:u.to,to_type:u.to_type,relationship_type:u.type})}}for(let d of t.deleted)Te(n,d),o++;return{added:r,updated:c,deleted:o}}function $e(n,e,t){let s=J(n,{issue_id:e});for(let i of s)Ce(n,i.id);if(t&&t.length>0)for(let i of t)Le(n,{id:i.id,issue_id:i.issue_id,spec_id:i.spec_id,feedback_type:i.feedback_type,content:i.content,agent:i.agent,anchor:i.anchor,dismissed:i.dismissed})}function Me(n,e,t,s=!1,i=!1){if(s)return{added:t.added.length,updated:t.updated.length,deleted:t.deleted.length};let r=0,c=0,o=0;for(let d of t.added){let a=e.find(u=>u.id===d);a&&(te(n,{id:a.id,uuid:a.uuid,title:a.title,content:a.content,status:a.status,priority:a.priority,assignee:a.assignee,parent_id:a.parent_id,archived:a.archived,archived_at:a.archived_at,created_at:a.created_at,updated_at:a.updated_at,closed_at:a.closed_at}),O(n,a.id,"issue",a.tags||[]),$e(n,a.id,a.feedback),r++)}if(!i)for(let d of t.added){let a=e.find(u=>u.id===d);if(a)for(let u of a.relationships||[])I(n,{from_id:u.from,from_type:u.from_type,to_id:u.to,to_type:u.to_type,relationship_type:u.type})}for(let d of t.updated){let a=e.find(u=>u.id===d);a&&(L(n,a.id,{title:a.title,content:a.content,status:a.status,priority:a.priority,assignee:a.assignee,parent_id:a.parent_id,archived:a.archived,archived_at:a.archived_at,updated_at:a.updated_at,closed_at:a.closed_at}),O(n,a.id,"issue",a.tags||[]),$e(n,a.id,a.feedback),c++)}if(!i)for(let d of t.updated){let a=e.find(u=>u.id===d);if(a){A(n,a.id,"issue");for(let u of a.relationships||[])I(n,{from_id:u.from,from_type:u.from_type,to_id:u.to,to_type:u.to_type,relationship_type:u.type})}}for(let d of t.deleted)Ie(n,d),o++;return{added:r,updated:c,deleted:o}}async function gs(n,e={}){let{inputDir:t=".sudocode",specsFile:s="specs.jsonl",issuesFile:i="issues.jsonl",dryRun:r=!1,resolveCollisions:c=!0}=e,o=fe.join(t,s),d=fe.join(t,i),a=await M(o,{skipErrors:!0}),u=await M(d,{skipErrors:!0}),p=F(n),f=$(n),g=ke(p,a),S=ke(f,u),b=[...g.map(m=>({...m,type:"spec"})),...S.map(m=>({...m,type:"issue"}))],y=[];if(c&&b.length>0){y=wt(n,b);for(let m of y)if(m.resolution==="renumber"&&m.newId){if(m.type==="spec"){let _=a.find(l=>l.id===m.id&&l.uuid===m.uuid);_&&(_.id=m.newId)}else if(m.type==="issue"){let _=u.find(l=>l.id===m.id&&l.uuid===m.uuid);_&&(_.id=m.newId)}}}let D=Fe(p,a),x=Fe(f,u),N={specs:{added:0,updated:0,deleted:0},issues:{added:0,updated:0,deleted:0},collisions:y.length>0?y:b};return r?(N.specs=Ae(n,a,D,r),N.issues=Me(n,u,x,r)):oe(n,()=>{N.specs=Ae(n,a,D,r,!0),N.issues=Me(n,u,x,r,!0);for(let m of D.added){let _=a.find(l=>l.id===m);if(_&&_.relationships&&_.relationships.length>0)for(let l of _.relationships)I(n,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}for(let m of D.updated){let _=a.find(l=>l.id===m);if(_){A(n,_.id,"spec");for(let l of _.relationships||[])I(n,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}}for(let m of x.added){let _=u.find(l=>l.id===m);if(_&&_.relationships&&_.relationships.length>0)for(let l of _.relationships)I(n,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}for(let m of x.updated){let _=u.find(l=>l.id===m);if(_){A(n,_.id,"issue");for(let l of _.relationships||[])I(n,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}}}),N}import U from"gray-matter";import*as W from"fs";w();B();import*as Je from"crypto";function z(n,e,t){let s=n.split(`
169
+ `);if(e<1||e>s.length)throw new Error(`Line number ${e} is out of range (1-${s.length})`);let i=s[e-1],r=Nt(s,e),c=Ue(i,t,50),o=ne(s,e,-50),d=ne(s,e,50),a=r?e-r.startLine:void 0,u=We(c);return{section_heading:r?.heading,section_level:r?.level,line_number:e,line_offset:a,text_snippet:c,context_before:o,context_after:d,content_hash:u,anchor_status:"valid",last_verified_at:new Date().toISOString(),original_location:{line_number:e,section_heading:r?.heading}}}function Nt(n,e){for(let t=e-1;t>=0;t--){let i=n[t].match(/^(#{1,6})\s+(.+?)(\r)?$/);if(i){let r=i[1].length;return{heading:i[2].trim(),level:r,startLine:t+1}}}return null}function Ue(n,e,t=50){if(!n||n.trim()==="")return"";let s=n.trim(),i=0,r=s.length;if(e!==void 0){let o=n.length-n.trimStart().length,d=Math.max(0,e-o),a=Math.floor(t/2);i=Math.max(0,d-a),r=Math.min(s.length,d+a)}else r=Math.min(s.length,t);let c=s.substring(i,r);return i>0&&(c="..."+c),r<s.length&&(c=c+"..."),c}function ne(n,e,t){if(t===0)return"";let s=t>0?1:-1,i=Math.abs(t),r="",c=e-1;for(s>0?c+=1:c-=1;c>=0&&c<n.length&&r.length<i;){let o=n[c],d=i-r.length;if(s>0)r.length>0&&(r+=" "),r+=o.substring(0,d);else{let a=Math.max(0,o.length-d),u=o.substring(a);r.length>0?r=u+" "+r:r=u}c+=s}return r.trim()}function We(n){return Je.createHash("sha256").update(n).digest("hex").substring(0,16)}function Ct(n,e){if(!e.line_number)return!1;let t=n.split(`
170
+ `);if(e.line_number<1||e.line_number>t.length)return!1;let s=t[e.line_number-1];if(e.text_snippet&&e.text_snippet.trim()){let i=e.text_snippet.replace(/\.\.\./g,"").trim();if(i&&!s.includes(i))return!1}if(e.content_hash&&e.text_snippet&&e.text_snippet.trim()){let i=Ue(s,void 0,50);if(i&&We(i)!==e.content_hash)return!1}return!0}function je(n){let e=n.split(`
171
+ `),t=[];for(let s=0;s<e.length;s++){let r=e[s].match(/^(#{1,6})\s+(.+?)(\r)?$/);r&&t.push({heading:r[2].trim(),level:r[1].length,startLine:s+1})}return t}function Ft(n,e,t,s){if(!e)return[];let i=n.split(`
172
+ `),r=[],c=e.replace(/\.\.\./g,"").trim();for(let o=0;o<i.length;o++)if(i[o].includes(c)){let a=.5;t&&ne(i,o+1,-50).includes(t.substring(0,20))&&(a+=.25),s&&ne(i,o+1,50).includes(s.substring(0,20))&&(a+=.25),r.push({lineNumber:o+1,confidence:Math.min(a,1)})}return r.sort((o,d)=>d.confidence-o.confidence)}function kt(n,e){let t=n.length,s=e.length,i=Array(t+1).fill(null).map(()=>Array(s+1).fill(0));for(let r=0;r<=t;r++)i[r][0]=r;for(let r=0;r<=s;r++)i[0][r]=r;for(let r=1;r<=t;r++)for(let c=1;c<=s;c++){let o=n[r-1]===e[c-1]?0:1;i[r][c]=Math.min(i[r-1][c]+1,i[r][c-1]+1,i[r-1][c-1]+o)}return i[t][s]}function At(n,e,t=5){let s=je(n);if(s.length===0)return null;let i=e.toLowerCase().trim(),r=null,c=1/0;for(let o of s){let d=o.heading.toLowerCase().trim(),a=kt(i,d);a<c&&a<=t&&(c=a,r=o)}return r}function Be(n,e,t){if(Ct(e,t))return{...t,anchor_status:"valid",last_verified_at:new Date().toISOString()};if(t.section_heading&&t.line_offset!==void 0){let i=je(e).find(r=>r.heading===t.section_heading);if(i){let r=i.startLine+t.line_offset,c=e.split(`
173
+ `);if(r>0&&r<=c.length){let o=c[r-1];if(t.text_snippet){let d=t.text_snippet.replace(/\.\.\./g,"").trim();if(d&&o.includes(d))return{...z(e,r),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:t.original_location||{line_number:t.line_number||0,section_heading:t.section_heading}}}}}}if(t.text_snippet){let s=Ft(e,t.text_snippet,t.context_before,t.context_after);if(s.length>0&&s[0].confidence>=.7)return{...z(e,s[0].lineNumber),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:t.original_location||{line_number:t.line_number||0,section_heading:t.section_heading}}}if(t.section_heading&&t.line_offset!==void 0){let s=At(e,t.section_heading,5);if(s){let i=s.startLine+t.line_offset,r=e.split(`
174
+ `);if(i>0&&i<=r.length)return{...z(e,i),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:t.original_location||{line_number:t.line_number||0,section_heading:t.section_heading}}}}return{...t,anchor_status:"stale",last_verified_at:new Date().toISOString(),original_location:t.original_location||{line_number:t.line_number||0,section_heading:t.section_heading}}}function $t(n,e,t){let s=U(n),i;if(t&&e)try{i=De(t)}catch{}let r=Ut(s.content,e,i);return{data:s.data,content:s.content,raw:n,references:r}}function Pe(n,e,t){let s=W.readFileSync(n,"utf8");return $t(s,e,t)}function Mt(n,e){return n.substring(0,e).split(`
175
+ `).length}function Jt(n){return{section_heading:n.section_heading,section_level:n.section_level,line_number:n.line_number,line_offset:n.line_offset,text_snippet:n.text_snippet,context_before:n.context_before,context_after:n.context_after,content_hash:n.content_hash}}function Ut(n,e,t){let s=[],i=/\[\[(@)?([a-z]+-\d+)(?:\|([^\]]+))?\]\](?:\{\s*(?:type:\s*)?([a-z-]+)\s*\})?/gi,r;for(;(r=i.exec(n))!==null;){let c=r[1]==="@",o=r[2],d=r[3]?.trim(),a=r[4]?.trim(),u;try{let p=Mt(n,r.index),f=z(n,p,r.index);u=Jt(f)}catch{u=void 0}if(e){let p=null;try{T(e,o)&&(p="spec")}catch{}if(!p)try{E(e,o)&&(p="issue")}catch{}p&&s.push({match:r[0],id:o,type:p,index:r.index,displayText:d,relationshipType:a,anchor:u})}else{let p;if(t){let f=t.id_prefix.spec.toLowerCase(),g=t.id_prefix.issue.toLowerCase();c||o.toLowerCase().startsWith(g+"-")?p="issue":(o.toLowerCase().startsWith(f+"-"),p="spec")}else p=c||o.startsWith("issue-")?"issue":"spec";s.push({match:r[0],id:o,type:p,index:r.index,displayText:d,relationshipType:a,anchor:u})}}return s}function Wt(n,e){return U.stringify(e,n)}function jt(n,e){let t=U(n),s={...t.data,...e},i=Object.fromEntries(Object.entries(s).filter(([r,c])=>c!==void 0));return U.stringify(t.content,i)}function ge(n,e){let t=W.readFileSync(n,"utf8"),s=jt(t,e);W.writeFileSync(n,s,"utf8")}function Ds(n){return n.trimStart().startsWith("---")}function Bt(n,e){return Wt(n,e)}function He(n,e,t){let s=Bt(e,t);W.writeFileSync(n,s,"utf8")}function xs(n){return U(n).content}function Ts(n){return U(n).data}function Is(n){let e=[],t=n.match(/^## Spec Feedback Provided\s*$/m);if(!t)return e;let s=t.index+t[0].length,i=n.slice(s),r=i.match(/^## /m),c=r?i.slice(0,r.index):i,o=/^### (FB-\d+) → ([a-z]+-\d+)(?: \((.*?)\))?\s*\n\*\*Type:\*\* (.+?)\s*\n\*\*Location:\*\* (.*?)\s*\n\*\*Status:\*\* (.+?)\s*\n\n([\s\S]*?)(?=\n###|$)/gm,d;for(;(d=o.exec(c))!==null;){let[,a,u,p,f,g,S,b]=d,y=g.match(/(?:(.+?),\s+)?line (\d+)\s*([✓⚠✗])/),D={id:a,specId:u,specTitle:p||void 0,type:f.trim(),location:{section:y?.[1]?.trim(),line:y?.[2]?parseInt(y[2]):void 0,status:y?.[3]==="\u2713"?"valid":y?.[3]==="\u26A0"?"relocated":"stale"},status:S.trim(),content:b.trim(),createdAt:""},x=b.match(/\*\*Resolution:\*\* (.+)/);x&&(D.resolution=x[1].trim()),e.push(D)}return e}function Pt(n){if(n.length===0)return"";let e=`
176
+ ## Spec Feedback Provided
177
+
178
+ `;for(let t of n){let s=t.location.status==="valid"?"\u2713":t.location.status==="relocated"?"\u26A0":"\u2717",i="";t.location.section&&t.location.line?i=`${t.location.section}, line ${t.location.line} ${s}`:t.location.line?i=`line ${t.location.line} ${s}`:i=`Unknown ${s}`;let r=t.specTitle?` (${t.specTitle})`:"";e+=`### ${t.id} \u2192 ${t.specId}${r}
179
+ `,e+=`**Type:** ${t.type}
180
+ `,e+=`**Location:** ${i}
181
+ `,e+=`**Status:** ${t.status}
182
+
183
+ `,e+=`${t.content}
184
+ `,t.resolution&&(e+=`
185
+ **Resolution:** ${t.resolution}
186
+ `),e+=`
187
+ `}return e}function Rs(n,e){let t=n.match(/^## Spec Feedback Provided\s*$/m);if(t){let i=t.index,c=n.slice(i).match(/^## /m);if(c&&c.index>0){let o=i+c.index;n=n.slice(0,i)+n.slice(o)}else n=n.slice(0,i)}let s=Pt(e);return s&&(n=n.trimEnd()+`
188
+ `+s),n}import*as j from"fs";import*as V from"path";w();v();B();function Ht(n){let{file_path:e,entity_type:t,...s}=n;return s}function qt(n,e,t,s,i,r){let c=new Date().toISOString(),o={...e};if(o.id||(o.id=t==="spec"?be(n,i):Se(n,i)),!o.title){let a=j.readFileSync(s,"utf8").match(/^#\s+(.+)$/m);o.title=a?a[1]:V.basename(s,".md")}return o.created_at||(o.created_at=c),o.updated_at||(o.updated_at=c),t==="spec"||o.status||(o.status="open"),!o.priority&&o.priority!==0&&(o.priority=2),o}async function Ms(n,e,t={}){let{outputDir:s=".sudocode",autoExport:i=!0,user:r="system",autoInitialize:c=!0,writeBackFrontmatter:o=!0}=t;try{let d=Pe(e,n,s),{data:a,content:u,references:p}=d,f=Yt(a,e),g=a.id,S=g,b=V.relative(s,e),y=b.startsWith("..")?V.relative(process.cwd(),e):b,D=null,x=null;if(f==="spec"){if(a.file_path=y,S&&(x=T(n,S)),D=xe(n,y),x)g=x.id,x.file_path!==y&&(console.log(`[sync] File renamed: ${x.file_path} \u2192 ${y}`),D&&D.id!==x.id&&console.warn(`[sync] Warning: File path conflict! Spec ${D.id} already exists at ${y}. Keeping ${x.id} and updating path.`));else if(D)g=D.id,a.id=g;else if(S&&D){let Q=D.id;console.warn(`[sync] Warning: ID in frontmatter (${S}) differs from existing spec ID (${Q}) for ${y}. Using existing ID.`),g=Q,a.id=g}}if(!g)if(c){if(a=qt(n,a,f,e,s,r),g=a.id,o){let Q=Ht(a);ge(e,Q)}}else return{success:!1,action:"no-change",entityId:"",entityType:f,error:"Missing id in frontmatter (auto-initialization disabled)"};let m=!(f==="spec"?T(n,g):E(n,g)),_=j.statSync(e),l=new Date(_.mtimeMs).toISOString();return f==="spec"?await zt(n,g,a,u,p,m,r,l):await Vt(n,g,a,u,p,m,r,l),i&&await le(n,{outputDir:s}),{success:!0,action:m?"created":"updated",entityId:g,entityType:f}}catch(d){return{success:!1,action:"no-change",entityId:"",entityType:"spec",error:d instanceof Error?d.message:String(d)}}}async function Js(n,e,t,s){try{let i=t==="spec"?T(n,e):E(n,e);if(!i)return{success:!1,action:"no-change",entityId:e,entityType:t,error:`${t} not found: ${e}`};let{getOutgoingRelationships:r}=await Promise.resolve().then(()=>(v(),re)),c=r(n,e,t),o=q(n,e,t),d=Qt(i,t,c,o),a=j.existsSync(s);if(a)ge(s,d);else{let u=i.content||"";He(s,d,u)}return{success:!0,action:a?"updated":"created",entityId:e,entityType:t}}catch(i){return{success:!1,action:"no-change",entityId:e,entityType:t,error:i instanceof Error?i.message:String(i)}}}function Yt(n,e){return n.entity_type==="issue"?"issue":n.entity_type==="spec"?"spec":e.includes("/issues/")||e.includes("/issue-")?"issue":(e.includes("/specs/")||e.includes("/spec-"),"spec")}async function zt(n,e,t,s,i,r,c,o){let d=r?null:T(n,e),a=d?.content||"",u={id:e,title:t.title||"Untitled",file_path:t.file_path||"",content:s,priority:t.priority??2,parent_id:t.parent_id||void 0};if(r)X(n,{...u,updated_at:o});else{let p=d?.title!==u.title||d?.content!==u.content||d?.priority!==u.priority||d?.parent_id!==u.parent_id||d?.file_path!==u.file_path;if(P(n,e,{...u,...p&&o?{updated_at:o}:{}}),a!==s){let f=J(n,{spec_id:e});if(f.length>0)for(let g of f){let S=typeof g.anchor=="string"?JSON.parse(g.anchor):g.anchor,b=Be(a,s,S);Ne(n,g.id,{anchor:b})}}}t.tags&&Array.isArray(t.tags)&&O(n,e,"spec",t.tags),await qe(n,e,"spec",i,t.relationships,c)}async function Vt(n,e,t,s,i,r,c,o){let d=r?null:E(n,e),a={id:e,title:t.title||"Untitled",content:s,status:t.status||"open",priority:t.priority??2,assignee:t.assignee||void 0,parent_id:t.parent_id||void 0};if(r)te(n,{...a,updated_at:o});else{let u=d?.title!==a.title||d?.content!==a.content||d?.status!==a.status||d?.priority!==a.priority||d?.assignee!==a.assignee||d?.parent_id!==a.parent_id;L(n,e,{...a,...u&&o?{updated_at:o}:{}})}t.tags&&Array.isArray(t.tags)&&O(n,e,"issue",t.tags),await qe(n,e,"issue",i,t.relationships,c)}async function qe(n,e,t,s,i,r="system"){let{getOutgoingRelationships:c}=await Promise.resolve().then(()=>(v(),re)),o=c(n,e,t),d=new Set(o.map(a=>`${a.relationship_type}:${a.to_type}:${a.to_id}`));for(let a of s){let u=a.relationshipType||"references",p=`${u}:${a.type}:${a.id}`;if(!d.has(p))try{I(n,{from_id:e,from_type:t,to_id:a.id,to_type:a.type,relationship_type:u,metadata:a.anchor?JSON.stringify({anchor:a.anchor}):void 0})}catch{}}if(i&&Array.isArray(i))for(let a of i){let u=`${a.relationship_type}:${a.target_type}:${a.target_id}`;if(!d.has(u))try{I(n,{from_id:e,from_type:t,to_id:a.target_id,to_type:a.target_type,relationship_type:a.relationship_type})}catch{}}}function Qt(n,e,t,s){let i={id:n.id,title:n.title,priority:n.priority,created_at:n.created_at};if(n.parent_id&&(i.parent_id=n.parent_id),s.length>0&&(i.tags=s),t.length>0&&(i.relationships=t),e==="spec")return i;{let r=n,c={...i,status:r.status};return r.assignee&&(c.assignee=r.assignee),r.closed_at&&(c.closed_at=r.closed_at),c}}export{pe as ExportDebouncer,Re as SavepointTransaction,Nn as addReferenceToContent,I as addRelationship,_t as addTag,ht as addTags,Wn as batchTransaction,gn as closeIssue,ls as countReferences,ss as createDebouncedExport,te as createIssue,Bt as createMarkdown,X as createSpec,wn as deleteEntityEvents,Ie as deleteIssue,qn as deleteJSONLLine,Yn as deleteJSONLLineSync,Te as deleteSpec,Fe as detectChanges,ke as detectCollisions,vt as exportIssuesToJSONL,Rt as exportSpecsToJSONL,le as exportToJSONL,Ut as extractCrossReferences,Pt as formatFeedbackForIssue,bt as formatReference,lt as getAllRelationships,xn as getAllTags,hn as getBlockedIssues,en as getDatabase,ut as getDependencies,pt as getDependents,Sn as getEntitiesByTag,Rn as getEntityEvents,Et as getEvent,On as getEventsByActor,Ts as getFrontmatter,H as getIncomingRelationships,E as getIssue,zn as getJSONLEntity,Vn as getJSONLEntitySync,k as getOutgoingRelationships,_n as getReadyIssues,vn as getRecentEvents,ee as getRelationship,T as getSpec,xe as getSpecByFilePath,q as getTags,Ds as hasFrontmatter,Dn as hasTag,gs as importFromJSONL,Me as importIssues,Ae as importSpecs,Ge as initDatabase,In as insertEvent,It as issueToJSONL,$ as listIssues,F as listSpecs,Is as parseFeedbackSection,$t as parseMarkdown,Pe as parseMarkdownFile,ae as queryEvents,M as readJSONL,de as readJSONLSync,ft as relationshipExists,A as removeAllRelationships,yt as removeAllTags,xs as removeFrontmatter,ot as removeRelationship,bn as removeTag,mn as reopenIssue,wt as resolveCollisions,yn as searchIssues,dn as searchSpecs,O as setTags,Tt as specToJSONL,Wt as stringifyMarkdown,Js as syncJSONLToMarkdown,Ms as syncMarkdownToJSONL,oe as transaction,Rs as updateFeedbackInIssue,jt as updateFrontmatter,ge as updateFrontmatterFile,L as updateIssue,Pn as updateJSONLLine,Hn as updateJSONLLineSync,P as updateSpec,fs as updateTextReferences,jn as withRetry,tn as withTransaction,Y as writeJSONL,Oe as writeJSONLSync,He as writeMarkdownFile};
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * JSONL (JSON Lines) reader and writer
3
+ * Supports reading and writing .jsonl files for specs and issues
4
+ */
5
+ import type { SpecJSONL, IssueJSONL } from "./types.js";
6
+ export type JSONLEntity = SpecJSONL | IssueJSONL | Record<string, any>;
7
+ export interface ReadJSONLOptions {
8
+ /**
9
+ * Skip malformed lines instead of throwing
10
+ */
11
+ skipErrors?: boolean;
12
+ /**
13
+ * Custom error handler for malformed lines
14
+ */
15
+ onError?: (lineNumber: number, line: string, error: Error) => void;
16
+ }
17
+ export interface WriteJSONLOptions {
18
+ /**
19
+ * Use atomic write (write to temp file, then rename)
20
+ */
21
+ atomic?: boolean;
22
+ }
23
+ /**
24
+ * Read a JSONL file and parse all lines
25
+ * Uses streaming for memory efficiency with large files
26
+ */
27
+ export declare function readJSONL<T extends JSONLEntity = JSONLEntity>(filePath: string, options?: ReadJSONLOptions): Promise<T[]>;
28
+ /**
29
+ * Read a JSONL file synchronously (for smaller files)
30
+ */
31
+ export declare function readJSONLSync<T extends JSONLEntity = JSONLEntity>(filePath: string, options?: ReadJSONLOptions): T[];
32
+ /**
33
+ * Write entities to a JSONL file
34
+ * Each entity is written as a single line of JSON
35
+ * Entities are sorted by created_at date to minimize merge conflicts
36
+ */
37
+ export declare function writeJSONL<T extends JSONLEntity = JSONLEntity>(filePath: string, entities: T[], options?: WriteJSONLOptions): Promise<void>;
38
+ /**
39
+ * Write entities to a JSONL file synchronously
40
+ * Entities are sorted by created_at date to minimize merge conflicts
41
+ */
42
+ export declare function writeJSONLSync<T extends JSONLEntity = JSONLEntity>(filePath: string, entities: T[], options?: WriteJSONLOptions): void;
43
+ /**
44
+ * Update a single line in a JSONL file by entity ID
45
+ * If the entity doesn't exist, append it
46
+ * If it exists, replace the line
47
+ */
48
+ export declare function updateJSONLLine<T extends JSONLEntity = JSONLEntity>(filePath: string, entity: T, idField?: string): Promise<void>;
49
+ /**
50
+ * Update a single line in a JSONL file synchronously
51
+ */
52
+ export declare function updateJSONLLineSync<T extends JSONLEntity = JSONLEntity>(filePath: string, entity: T, idField?: string): void;
53
+ /**
54
+ * Delete an entity from a JSONL file by ID
55
+ */
56
+ export declare function deleteJSONLLine<T extends JSONLEntity = JSONLEntity>(filePath: string, entityId: string, idField?: string): Promise<boolean>;
57
+ /**
58
+ * Delete an entity from a JSONL file synchronously
59
+ */
60
+ export declare function deleteJSONLLineSync<T extends JSONLEntity = JSONLEntity>(filePath: string, entityId: string, idField?: string): boolean;
61
+ /**
62
+ * Get a single entity from a JSONL file by ID
63
+ */
64
+ export declare function getJSONLEntity<T extends JSONLEntity = JSONLEntity>(filePath: string, entityId: string, idField?: string): Promise<T | null>;
65
+ /**
66
+ * Get a single entity from a JSONL file synchronously
67
+ */
68
+ export declare function getJSONLEntitySync<T extends JSONLEntity = JSONLEntity>(filePath: string, entityId: string, idField?: string): T | null;
69
+ //# sourceMappingURL=jsonl.d.ts.map
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Markdown parser with frontmatter support
3
+ */
4
+ import type Database from "better-sqlite3";
5
+ import type { LocationAnchor, Config } from "@sudocode-ai/types";
6
+ export interface ParsedMarkdown<T extends object = Record<string, any>> {
7
+ /**
8
+ * Parsed frontmatter data
9
+ */
10
+ data: T;
11
+ /**
12
+ * Markdown content (without frontmatter)
13
+ */
14
+ content: string;
15
+ /**
16
+ * Original raw content
17
+ */
18
+ raw: string;
19
+ /**
20
+ * Cross-references found in content
21
+ */
22
+ references: CrossReference[];
23
+ }
24
+ export interface CrossReference {
25
+ /**
26
+ * The full matched text (e.g., "[[spec-001]]" or "[[@issue-042]]")
27
+ */
28
+ match: string;
29
+ /**
30
+ * The entity ID (e.g., "spec-001" or "issue-042")
31
+ */
32
+ id: string;
33
+ /**
34
+ * Entity type (spec or issue)
35
+ */
36
+ type: "spec" | "issue";
37
+ /**
38
+ * Position in content
39
+ */
40
+ index: number;
41
+ /**
42
+ * Optional display text (e.g., "Authentication" from "[[spec-001|Authentication]]")
43
+ */
44
+ displayText?: string;
45
+ /**
46
+ * Optional relationship type (e.g., "blocks" from "[[spec-001]]{ blocks }")
47
+ * Defaults to "references" if not specified
48
+ */
49
+ relationshipType?: string;
50
+ /**
51
+ * Optional location anchor for spatial context of the reference
52
+ */
53
+ anchor?: LocationAnchor;
54
+ }
55
+ /**
56
+ * Parse markdown file with YAML frontmatter
57
+ * @param content - Markdown content to parse
58
+ * @param db - Optional database for validating cross-references
59
+ * @param outputDir - Optional output directory for loading config metadata
60
+ */
61
+ export declare function parseMarkdown<T extends object = Record<string, any>>(content: string, db?: Database.Database, outputDir?: string): ParsedMarkdown<T>;
62
+ /**
63
+ * Parse markdown file from disk
64
+ * @param filePath - Path to markdown file
65
+ * @param db - Optional database for validating cross-references
66
+ * @param outputDir - Optional output directory for loading config metadata
67
+ */
68
+ export declare function parseMarkdownFile<T extends object = Record<string, any>>(filePath: string, db?: Database.Database, outputDir?: string): ParsedMarkdown<T>;
69
+ /**
70
+ * Extract cross-references from markdown content
71
+ * Supports formats:
72
+ * - [[entity-001]] - entity reference (type determined by database lookup)
73
+ * - [[@entity-042]] - entity reference with @ prefix (for clarity)
74
+ * - [[entity-001|Display Text]] - with custom display text
75
+ * - [[entity-001]]{ blocks } - with relationship type (shorthand)
76
+ * - [[entity-001]]{ type: blocks } - with relationship type (explicit)
77
+ * - [[entity-001|Display]]{ blocks } - combination of display text and type
78
+ *
79
+ * If db is provided, validates references against the database and determines entity type.
80
+ * Only returns references to entities that actually exist.
81
+ *
82
+ * If metadata is provided (but no db), uses configured ID prefixes for type detection.
83
+ */
84
+ export declare function extractCrossReferences(content: string, db?: Database.Database, config?: Config): CrossReference[];
85
+ /**
86
+ * Stringify frontmatter and content back to markdown
87
+ */
88
+ export declare function stringifyMarkdown<T extends object = Record<string, any>>(data: T, content: string): string;
89
+ /**
90
+ * Update frontmatter in an existing markdown file
91
+ * Preserves content unchanged
92
+ */
93
+ export declare function updateFrontmatter<T extends object = Record<string, any>>(originalContent: string, updates: Partial<T>): string;
94
+ /**
95
+ * Update frontmatter in a file
96
+ */
97
+ export declare function updateFrontmatterFile<T extends object = Record<string, any>>(filePath: string, updates: Partial<T>): void;
98
+ /**
99
+ * Check if a file has frontmatter
100
+ */
101
+ export declare function hasFrontmatter(content: string): boolean;
102
+ /**
103
+ * Create markdown with frontmatter
104
+ */
105
+ export declare function createMarkdown<T extends object = Record<string, any>>(data: T, content: string): string;
106
+ /**
107
+ * Write markdown file with frontmatter
108
+ */
109
+ export declare function writeMarkdownFile<T extends object = Record<string, any>>(filePath: string, data: T, content: string): void;
110
+ /**
111
+ * Remove frontmatter from markdown content
112
+ */
113
+ export declare function removeFrontmatter(content: string): string;
114
+ /**
115
+ * Get only frontmatter data from markdown
116
+ */
117
+ export declare function getFrontmatter<T extends object = Record<string, any>>(content: string): T;
118
+ export interface FeedbackMarkdownData {
119
+ id: string;
120
+ specId: string;
121
+ specTitle?: string;
122
+ type: string;
123
+ location: {
124
+ section?: string;
125
+ line?: number;
126
+ status: "valid" | "relocated" | "stale";
127
+ };
128
+ status: string;
129
+ content: string;
130
+ createdAt: string;
131
+ resolution?: string;
132
+ }
133
+ /**
134
+ * Parse feedback section from issue markdown content
135
+ * Looks for "## Spec Feedback Provided" section
136
+ */
137
+ export declare function parseFeedbackSection(content: string): FeedbackMarkdownData[];
138
+ /**
139
+ * Format feedback data for inclusion in issue markdown
140
+ */
141
+ export declare function formatFeedbackForIssue(feedback: FeedbackMarkdownData[]): string;
142
+ /**
143
+ * Append or update feedback section in issue markdown
144
+ */
145
+ export declare function updateFeedbackInIssue(issueContent: string, feedback: FeedbackMarkdownData[]): string;
146
+ //# sourceMappingURL=markdown.d.ts.map