@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.
- package/README.md +330 -0
- package/dist/cli/feedback-commands.d.ts +53 -0
- package/dist/cli/init-commands.d.ts +22 -0
- package/dist/cli/issue-commands.d.ts +45 -0
- package/dist/cli/query-commands.d.ts +18 -0
- package/dist/cli/reference-commands.d.ts +22 -0
- package/dist/cli/relationship-commands.d.ts +14 -0
- package/dist/cli/server-commands.d.ts +17 -0
- package/dist/cli/spec-commands.d.ts +38 -0
- package/dist/cli/status-commands.d.ts +17 -0
- package/dist/cli/sync-commands.d.ts +24 -0
- package/dist/cli/update-commands.d.ts +12 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +196 -0
- package/dist/db.d.ts +21 -0
- package/dist/export.d.ts +79 -0
- package/dist/filename-generator.d.ts +30 -0
- package/dist/id-generator.d.ts +26 -0
- package/dist/import.d.ts +118 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +189 -0
- package/dist/jsonl.d.ts +69 -0
- package/dist/markdown.d.ts +146 -0
- package/dist/migrations.d.ts +23 -0
- package/dist/operations/events.d.ts +53 -0
- package/dist/operations/feedback-anchors.d.ts +92 -0
- package/dist/operations/feedback.d.ts +76 -0
- package/dist/operations/index.d.ts +10 -0
- package/dist/operations/issues.d.ts +82 -0
- package/dist/operations/references.d.ts +34 -0
- package/dist/operations/relationships.d.ts +57 -0
- package/dist/operations/specs.d.ts +64 -0
- package/dist/operations/tags.d.ts +42 -0
- package/dist/operations/transactions.d.ts +41 -0
- package/dist/sync.d.ts +47 -0
- package/dist/test-schema.d.ts +5 -0
- package/dist/types.d.ts +7 -0
- package/dist/update-checker.d.ts +24 -0
- package/dist/version.d.ts +12 -0
- package/dist/watcher.d.ts +63 -0
- package/package.json +68 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var Tt=Object.defineProperty;var un=Object.getOwnPropertyDescriptor;var fn=Object.getOwnPropertyNames;var gn=Object.prototype.hasOwnProperty;var ce=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{for(var s in e)Tt(t,s,{get:e[s],enumerable:!0})},mn=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of fn(e))!gn.call(t,o)&&o!==s&&Tt(t,o,{get:()=>e[o],enumerable:!(n=un(e,o))||n.enumerable});return t};var hn=t=>mn(Tt({},"__esModule",{value:!0}),t);import*as Xt from"fs";import*as it from"path";import{fileURLToPath as Dn}from"url";function xn(){let t=it.join(En,"..","package.json");return JSON.parse(Xt.readFileSync(t,"utf8")).version}var wn,En,re,Ye=ce(()=>{"use strict";wn=Dn(import.meta.url),En=it.dirname(wn);re=xn()});import*as Ne from"fs";import*as It from"path";import*as es from"crypto";function at(t,e){let s=vt(e),n=On(t);return`${s.id_prefix.spec}-${String(n).padStart(3,"0")}`}function ct(t,e){let s=vt(e),n=Tn(t);return`${s.id_prefix.issue}-${String(n).padStart(3,"0")}`}function On(t){let s=t.prepare(`
|
|
3
|
+
SELECT id FROM specs
|
|
4
|
+
ORDER BY created_at DESC
|
|
5
|
+
LIMIT 1
|
|
6
|
+
`).get();if(s){let r=s.id.match(/(\d+)$/);if(r)return parseInt(r[1],10)+1}return t.prepare("SELECT COUNT(*) as count FROM specs").get().count+1}function Tn(t){let s=t.prepare(`
|
|
7
|
+
SELECT id FROM issues
|
|
8
|
+
ORDER BY created_at DESC
|
|
9
|
+
LIMIT 1
|
|
10
|
+
`).get();if(s){let r=s.id.match(/(\d+)$/);if(r)return parseInt(r[1],10)+1}return t.prepare("SELECT COUNT(*) as count FROM issues").get().count+1}function vt(t){let e=It.join(t,"config.json");if(!Ne.existsSync(e)){let n={version:re,id_prefix:{spec:"SPEC",issue:"ISSUE"}};return In(t,n),n}let s=Ne.readFileSync(e,"utf8");return JSON.parse(s)}function In(t,e){let s=It.join(t,"config.json");Ne.writeFileSync(s,JSON.stringify(e,null,2),"utf8")}function ts(t){return vt(t)}function dt(){return es.randomUUID()}var xe=ce(()=>{"use strict";Ye()});var $t={};rt($t,{createSpec:()=>Oe,deleteSpec:()=>Ge,getSpec:()=>T,getSpecByFilePath:()=>Ve,listSpecs:()=>P,searchSpecs:()=>kt,updateSpec:()=>_e});function Oe(t,e){let s=null;if(e.parent_id){let i=T(t,e.parent_id);if(!i)throw new Error(`Parent spec not found: ${e.parent_id}`);s=i.uuid}let n=e.uuid||dt(),o=["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&&(o.push("created_at"),r.push("@created_at")),e.updated_at&&(o.push("updated_at"),r.push("@updated_at")),e.archived_at!==void 0&&(o.push("archived_at"),r.push("@archived_at"));let a=t.prepare(`
|
|
11
|
+
INSERT INTO specs (
|
|
12
|
+
${o.join(", ")}
|
|
13
|
+
) VALUES (
|
|
14
|
+
${r.join(", ")}
|
|
15
|
+
)
|
|
16
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
17
|
+
uuid = excluded.uuid,
|
|
18
|
+
title = excluded.title,
|
|
19
|
+
file_path = excluded.file_path,
|
|
20
|
+
content = excluded.content,
|
|
21
|
+
priority = excluded.priority,
|
|
22
|
+
parent_id = excluded.parent_id,
|
|
23
|
+
parent_uuid = excluded.parent_uuid,
|
|
24
|
+
archived = excluded.archived,
|
|
25
|
+
archived_at = excluded.archived_at,
|
|
26
|
+
${e.created_at?"created_at = excluded.created_at,":""}
|
|
27
|
+
${e.updated_at?"updated_at = excluded.updated_at":"updated_at = CURRENT_TIMESTAMP"}
|
|
28
|
+
`);try{let i={id:e.id,uuid:n,title:e.title,file_path:e.file_path,content:e.content||"",priority:e.priority??2,parent_id:e.parent_id??null,parent_uuid:s,archived:e.archived?1:0};e.created_at&&(i.created_at=e.created_at),e.updated_at&&(i.updated_at=e.updated_at),e.archived_at!==void 0&&(i.archived_at=e.archived_at),a.run(i);let d=T(t,e.id);if(!d)throw new Error(`Failed to create spec ${e.id}`);return d}catch(i){throw i.code&&i.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${i.message}`):i}}function T(t,e){return t.prepare(`
|
|
29
|
+
SELECT * FROM specs WHERE id = ?
|
|
30
|
+
`).get(e)??null}function Ve(t,e){return t.prepare(`
|
|
31
|
+
SELECT * FROM specs WHERE file_path = ?
|
|
32
|
+
`).get(e)??null}function _e(t,e,s){let n=T(t,e);if(!n)throw new Error(`Spec not found: ${e}`);if(s.parent_id&&!T(t,s.parent_id))throw new Error(`Parent spec not found: ${s.parent_id}`);let o=[],r={id:e};if(s.title!==void 0&&s.title!==n.title&&(o.push("title = @title"),r.title=s.title),s.file_path!==void 0&&s.file_path!==n.file_path&&(o.push("file_path = @file_path"),r.file_path=s.file_path),s.content!==void 0&&s.content!==n.content&&(o.push("content = @content"),r.content=s.content),s.priority!==void 0&&s.priority!==n.priority&&(o.push("priority = @priority"),r.priority=s.priority),s.parent_id!==void 0&&s.parent_id!==n.parent_id&&(o.push("parent_id = @parent_id"),r.parent_id=s.parent_id),s.archived!==void 0&&s.archived!==n.archived?(o.push("archived = @archived"),r.archived=s.archived?1:0,s.archived_at!==void 0?(o.push("archived_at = @archived_at"),r.archived_at=s.archived_at):s.archived&&!n.archived?o.push("archived_at = CURRENT_TIMESTAMP"):!s.archived&&n.archived&&o.push("archived_at = NULL")):s.archived_at!==void 0&&s.archived_at!==n.archived_at&&(o.push("archived_at = @archived_at"),r.archived_at=s.archived_at),s.updated_at!==void 0?(o.push("updated_at = @updated_at"),r.updated_at=s.updated_at):o.length>0&&o.push("updated_at = CURRENT_TIMESTAMP"),o.length===0)return n;let a=t.prepare(`
|
|
33
|
+
UPDATE specs SET ${o.join(", ")} WHERE id = @id
|
|
34
|
+
`);try{a.run(r);let i=T(t,e);if(!i)throw new Error(`Failed to update spec ${e}`);return i}catch(i){throw i.code&&i.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${i.message}`):i}}function Ge(t,e){return t.prepare("DELETE FROM specs WHERE id = ?").run(e).changes>0}function P(t,e={}){let s=[],n={};e.priority!==void 0&&(s.push("priority = @priority"),n.priority=e.priority),e.parent_id!==void 0&&(s.push("parent_id = @parent_id"),n.parent_id=e.parent_id),e.archived!==void 0&&(s.push("archived = @archived"),n.archived=e.archived?1:0);let o="SELECT * FROM specs";return s.length>0&&(o+=" WHERE "+s.join(" AND ")),o+=" ORDER BY priority DESC, created_at DESC",e.limit!==void 0&&(o+=" LIMIT @limit",n.limit=e.limit),e.offset!==void 0&&(o+=" OFFSET @offset",n.offset=e.offset),t.prepare(o).all(n)}function kt(t,e,s={}){let n=["(title LIKE @query OR content LIKE @query)"],o={query:`%${e}%`};s.priority!==void 0&&(n.push("priority = @priority"),o.priority=s.priority),s.parent_id!==void 0&&(n.push("parent_id = @parent_id"),o.parent_id=s.parent_id),s.archived!==void 0&&(n.push("archived = @archived"),o.archived=s.archived?1:0);let r=`SELECT * FROM specs WHERE ${n.join(" AND ")} ORDER BY priority DESC, created_at DESC`;return s.limit!==void 0?(r+=" LIMIT @limit",o.limit=s.limit):r+=" LIMIT 50",t.prepare(r).all(o)}var K=ce(()=>{"use strict";xe()});var ss={};rt(ss,{closeIssue:()=>lt,createIssue:()=>Te,deleteIssue:()=>Ct,getBlockedIssues:()=>Ae,getIssue:()=>O,getReadyIssues:()=>Le,listIssues:()=>U,reopenIssue:()=>$n,searchIssues:()=>Rt,updateIssue:()=>ee});function Te(t,e){let s=null;if(e.parent_id){let i=O(t,e.parent_id);if(!i)throw new Error(`Parent issue not found: ${e.parent_id}`);s=i.uuid}let n=e.uuid||dt(),o=["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&&(o.push("created_at"),r.push("@created_at")),e.updated_at&&(o.push("updated_at"),r.push("@updated_at")),e.closed_at!==void 0&&(o.push("closed_at"),r.push("@closed_at")),e.archived_at!==void 0&&(o.push("archived_at"),r.push("@archived_at"));let a=t.prepare(`
|
|
35
|
+
INSERT INTO issues (
|
|
36
|
+
${o.join(", ")}
|
|
37
|
+
) VALUES (
|
|
38
|
+
${r.join(", ")}
|
|
39
|
+
)
|
|
40
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
41
|
+
uuid = excluded.uuid,
|
|
42
|
+
title = excluded.title,
|
|
43
|
+
content = excluded.content,
|
|
44
|
+
status = excluded.status,
|
|
45
|
+
priority = excluded.priority,
|
|
46
|
+
assignee = excluded.assignee,
|
|
47
|
+
parent_id = excluded.parent_id,
|
|
48
|
+
parent_uuid = excluded.parent_uuid,
|
|
49
|
+
archived = excluded.archived,
|
|
50
|
+
archived_at = excluded.archived_at,
|
|
51
|
+
${e.created_at?"created_at = excluded.created_at,":""}
|
|
52
|
+
${e.updated_at?"updated_at = excluded.updated_at":"updated_at = CURRENT_TIMESTAMP"}
|
|
53
|
+
`);try{let i={id:e.id,uuid:n,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:s,archived:e.archived?1:0};e.created_at&&(i.created_at=e.created_at),e.updated_at&&(i.updated_at=e.updated_at),e.closed_at!==void 0&&(i.closed_at=e.closed_at),e.archived_at!==void 0&&(i.archived_at=e.archived_at),a.run(i);let d=O(t,e.id);if(!d)throw new Error(`Failed to create issue ${e.id}`);return d}catch(i){throw i.code&&i.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${i.message}`):i}}function O(t,e){return t.prepare(`
|
|
54
|
+
SELECT * FROM issues WHERE id = ?
|
|
55
|
+
`).get(e)??null}function ee(t,e,s){let n=O(t,e);if(!n)throw new Error(`Issue not found: ${e}`);if(s.parent_id&&!O(t,s.parent_id))throw new Error(`Parent issue not found: ${s.parent_id}`);let o=[],r={id:e};if(s.title!==void 0&&s.title!==n.title&&(o.push("title = @title"),r.title=s.title),s.content!==void 0&&s.content!==n.content&&(o.push("content = @content"),r.content=s.content),s.status!==void 0&&s.status!==n.status?(o.push("status = @status"),r.status=s.status,s.closed_at!==void 0?(o.push("closed_at = @closed_at"),r.closed_at=s.closed_at):s.status==="closed"&&n.status!=="closed"?o.push("closed_at = CURRENT_TIMESTAMP"):s.status!=="closed"&&n.status==="closed"&&o.push("closed_at = NULL")):s.closed_at!==void 0&&s.closed_at!==n.closed_at&&(o.push("closed_at = @closed_at"),r.closed_at=s.closed_at),s.priority!==void 0&&s.priority!==n.priority&&(o.push("priority = @priority"),r.priority=s.priority),s.assignee!==void 0&&s.assignee!==n.assignee&&(o.push("assignee = @assignee"),r.assignee=s.assignee),s.parent_id!==void 0&&s.parent_id!==n.parent_id&&(o.push("parent_id = @parent_id"),r.parent_id=s.parent_id),s.archived!==void 0&&(s.archived?1:0)!==n.archived?(o.push("archived = @archived"),r.archived=s.archived?1:0,s.archived_at!==void 0?(o.push("archived_at = @archived_at"),r.archived_at=s.archived_at):s.archived&&!n.archived?o.push("archived_at = CURRENT_TIMESTAMP"):!s.archived&&n.archived&&o.push("archived_at = NULL")):s.archived_at!==void 0&&s.archived_at!==n.archived_at&&(o.push("archived_at = @archived_at"),r.archived_at=s.archived_at),s.updated_at!==void 0?(o.push("updated_at = @updated_at"),r.updated_at=s.updated_at):o.length>0&&o.push("updated_at = CURRENT_TIMESTAMP"),o.length===0)return n;let a=t.prepare(`
|
|
56
|
+
UPDATE issues SET ${o.join(", ")} WHERE id = @id
|
|
57
|
+
`);try{a.run(r);let i=O(t,e);if(!i)throw new Error(`Failed to update issue ${e}`);return s.status==="closed"&&n.status!=="closed"&&vn(t,e),i}catch(i){throw i.code&&i.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${i.message}`):i}}function vn(t,e){let s=ue(t,e,"issue","blocks");for(let n of s){let o=n.from_id,r=O(t,o);if(!r||r.status!=="blocked")continue;kn(t,o,e)||t.prepare(`
|
|
58
|
+
UPDATE issues
|
|
59
|
+
SET status = 'open', updated_at = CURRENT_TIMESTAMP
|
|
60
|
+
WHERE id = ?
|
|
61
|
+
`).run(o)}}function kn(t,e,s){let n=t.prepare(`
|
|
62
|
+
SELECT COUNT(*) as count
|
|
63
|
+
FROM relationships r
|
|
64
|
+
JOIN issues blocker ON r.to_id = blocker.id AND r.to_type = 'issue'
|
|
65
|
+
WHERE r.from_id = ?
|
|
66
|
+
AND r.from_type = 'issue'
|
|
67
|
+
AND r.relationship_type = 'blocks'
|
|
68
|
+
AND blocker.status IN ('open', 'in_progress', 'blocked')
|
|
69
|
+
${s?"AND blocker.id != ?":""}
|
|
70
|
+
`),o=s?[e,s]:[e];return n.get(...o).count>0}function Ct(t,e){return t.prepare("DELETE FROM issues WHERE id = ?").run(e).changes>0}function lt(t,e){return ee(t,e,{status:"closed"})}function $n(t,e){return ee(t,e,{status:"open"})}function U(t,e={}){let s=[],n={};e.status!==void 0&&(s.push("status = @status"),n.status=e.status),e.priority!==void 0&&(s.push("priority = @priority"),n.priority=e.priority),e.assignee!==void 0&&(s.push("assignee = @assignee"),n.assignee=e.assignee),e.parent_id!==void 0&&(s.push("parent_id = @parent_id"),n.parent_id=e.parent_id),e.archived!==void 0&&(s.push("archived = @archived"),n.archived=e.archived?1:0);let o="SELECT * FROM issues";return s.length>0&&(o+=" WHERE "+s.join(" AND ")),o+=" ORDER BY priority DESC, created_at DESC",e.limit!==void 0&&(o+=" LIMIT @limit",n.limit=e.limit),e.offset!==void 0&&(o+=" OFFSET @offset",n.offset=e.offset),t.prepare(o).all(n)}function Le(t){return t.prepare("SELECT * FROM ready_issues ORDER BY priority DESC, created_at DESC").all()}function Ae(t){return t.prepare("SELECT * FROM blocked_issues ORDER BY priority DESC, created_at DESC").all()}function Rt(t,e,s={}){let n=["(title LIKE @query OR content LIKE @query)"],o={query:`%${e}%`};s.status!==void 0&&(n.push("status = @status"),o.status=s.status),s.priority!==void 0&&(n.push("priority = @priority"),o.priority=s.priority),s.assignee!==void 0&&(n.push("assignee = @assignee"),o.assignee=s.assignee),s.parent_id!==void 0&&(n.push("parent_id = @parent_id"),o.parent_id=s.parent_id),s.archived!==void 0&&(n.push("archived = @archived"),o.archived=s.archived?1:0);let r=`SELECT * FROM issues WHERE ${n.join(" AND ")} ORDER BY priority DESC, created_at DESC`;return s.limit!==void 0?(r+=" LIMIT @limit",o.limit=s.limit):r+=" LIMIT 50",t.prepare(r).all(o)}var W=ce(()=>{"use strict";xe();ie()});var ut={};rt(ut,{addRelationship:()=>Y,getAllRelationships:()=>jn,getDependencies:()=>Ln,getDependents:()=>An,getIncomingRelationships:()=>ue,getOutgoingRelationships:()=>de,getRelationship:()=>pt,relationshipExists:()=>Mn,removeAllRelationships:()=>je,removeRelationship:()=>Rn});function Y(t,e){let s=e.from_type==="spec"?"specs":"issues",n=t.prepare(`SELECT id, uuid FROM ${s} WHERE id = ?`).get(e.from_id);if(!n)throw new Error(`${e.from_type==="spec"?"Spec":"Issue"} not found: ${e.from_id}`);let o=e.to_type==="spec"?"specs":"issues",r=t.prepare(`SELECT id, uuid FROM ${o} WHERE id = ?`).get(e.to_id);if(!r)throw new Error(`${e.to_type==="spec"?"Spec":"Issue"} not found: ${e.to_id}`);let a=pt(t,e.from_id,e.from_type,e.to_id,e.to_type,e.relationship_type);if(a)return a;let i=t.prepare(`
|
|
71
|
+
INSERT INTO relationships (
|
|
72
|
+
from_id, from_uuid, from_type, to_id, to_uuid, to_type, relationship_type, metadata
|
|
73
|
+
) VALUES (
|
|
74
|
+
@from_id, @from_uuid, @from_type, @to_id, @to_uuid, @to_type, @relationship_type, @metadata
|
|
75
|
+
)
|
|
76
|
+
`);try{i.run({from_id:e.from_id,from_uuid:n.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=pt(t,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"&&Cn(t,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 Cn(t,e,s){let n=O(t,s);if(n&&n.status!=="closed"){let o=O(t,e);o&&(o.status==="open"||o.status==="in_progress")&&t.prepare(`
|
|
77
|
+
UPDATE issues
|
|
78
|
+
SET status = 'blocked', updated_at = CURRENT_TIMESTAMP
|
|
79
|
+
WHERE id = ?
|
|
80
|
+
`).run(e)}}function pt(t,e,s,n,o,r){return t.prepare(`
|
|
81
|
+
SELECT * FROM relationships
|
|
82
|
+
WHERE from_id = ? AND from_type = ?
|
|
83
|
+
AND to_id = ? AND to_type = ?
|
|
84
|
+
AND relationship_type = ?
|
|
85
|
+
`).get(e,s,n,o,r)??null}function Rn(t,e,s,n,o,r){let d=t.prepare(`
|
|
86
|
+
DELETE FROM relationships
|
|
87
|
+
WHERE from_id = ? AND from_type = ?
|
|
88
|
+
AND to_id = ? AND to_type = ?
|
|
89
|
+
AND relationship_type = ?
|
|
90
|
+
`).run(e,s,n,o,r).changes>0;return d&&r==="blocks"&&s==="issue"&&o==="issue"&&Fn(t,e),d}function Fn(t,e){let s=O(t,e);s&&s.status==="blocked"&&(Nn(t,e)||t.prepare(`
|
|
91
|
+
UPDATE issues
|
|
92
|
+
SET status = 'open', updated_at = CURRENT_TIMESTAMP
|
|
93
|
+
WHERE id = ?
|
|
94
|
+
`).run(e))}function Nn(t,e){return t.prepare(`
|
|
95
|
+
SELECT COUNT(*) as count
|
|
96
|
+
FROM relationships r
|
|
97
|
+
JOIN issues blocker ON r.to_id = blocker.id AND r.to_type = 'issue'
|
|
98
|
+
WHERE r.from_id = ?
|
|
99
|
+
AND r.from_type = 'issue'
|
|
100
|
+
AND r.relationship_type = 'blocks'
|
|
101
|
+
AND blocker.status IN ('open', 'in_progress', 'blocked')
|
|
102
|
+
`).get(e).count>0}function de(t,e,s,n){let o=`
|
|
103
|
+
SELECT * FROM relationships
|
|
104
|
+
WHERE from_id = @entity_id AND from_type = @entity_type
|
|
105
|
+
`,r={entity_id:e,entity_type:s};return n!==void 0&&(o+=" AND relationship_type = @relationship_type",r.relationship_type=n),o+=" ORDER BY created_at DESC",t.prepare(o).all(r)}function ue(t,e,s,n){let o=`
|
|
106
|
+
SELECT * FROM relationships
|
|
107
|
+
WHERE to_id = @entity_id AND to_type = @entity_type
|
|
108
|
+
`,r={entity_id:e,entity_type:s};return n!==void 0&&(o+=" AND relationship_type = @relationship_type",r.relationship_type=n),o+=" ORDER BY created_at DESC",t.prepare(o).all(r)}function Ln(t,e,s){return de(t,e,s,"blocks")}function An(t,e,s){return ue(t,e,s,"blocks")}function jn(t,e,s){return{outgoing:de(t,e,s),incoming:ue(t,e,s)}}function Mn(t,e,s,n,o,r){return pt(t,e,s,n,o,r)!==null}function je(t,e,s){return t.prepare(`
|
|
109
|
+
DELETE FROM relationships
|
|
110
|
+
WHERE (from_id = ? AND from_type = ?)
|
|
111
|
+
OR (to_id = ? AND to_type = ?)
|
|
112
|
+
`).run(e,s,e,s).changes}var ie=ce(()=>{"use strict";W()});function Jn(t,e,s,n){let o=s==="spec"?"specs":"issues",r=t.prepare(`SELECT uuid FROM ${o} WHERE id = ?`).get(e);if(!r)throw new Error(`${s==="spec"?"Spec":"Issue"} not found: ${e}`);let a=t.prepare(`
|
|
113
|
+
INSERT INTO tags (entity_id, entity_uuid, entity_type, tag)
|
|
114
|
+
VALUES (@entity_id, @entity_uuid, @entity_type, @tag)
|
|
115
|
+
`);try{return a.run({entity_id:e,entity_uuid:r.uuid,entity_type:s,tag:n}),{entity_id:e,entity_uuid:r.uuid,entity_type:s,tag:n}}catch(i){if(i.code&&i.code.startsWith("SQLITE_CONSTRAINT"))return{entity_id:e,entity_uuid:r.uuid,entity_type:s,tag:n};throw i}}function Pn(t,e,s,n){let o=[];for(let r of n)o.push(Jn(t,e,s,r));return o}function te(t,e,s){return t.prepare(`
|
|
116
|
+
SELECT tag FROM tags
|
|
117
|
+
WHERE entity_id = ? AND entity_type = ?
|
|
118
|
+
ORDER BY tag
|
|
119
|
+
`).all(e,s).map(r=>r.tag)}function Un(t,e,s){return t.prepare(`
|
|
120
|
+
DELETE FROM tags
|
|
121
|
+
WHERE entity_id = ? AND entity_type = ?
|
|
122
|
+
`).run(e,s).changes}function Z(t,e,s,n){return Un(t,e,s),n.length>0&&Pn(t,e,s,n),n}var Ie=ce(()=>{"use strict"});function ns(t){return{...t,dismissed:t.dismissed===1}}function Wn(t){let s=t.prepare(`
|
|
123
|
+
SELECT id FROM issue_feedback ORDER BY id DESC LIMIT 1
|
|
124
|
+
`).get();if(!s)return"FB-001";let n=s.id.match(/^FB-(\d+)$/);if(!n)return"FB-001";let o=parseInt(n[1],10)+1;return`FB-${String(o).padStart(3,"0")}`}function ft(t,e){let s=e.id||Wn(t),n=e.anchor?JSON.stringify(e.anchor):null,o=e.agent||"user",r=t.prepare("SELECT uuid FROM issues WHERE id = ?").get(e.issue_id);if(!r)throw new Error(`Issue not found: ${e.issue_id}`);let a=t.prepare("SELECT uuid FROM specs WHERE id = ?").get(e.spec_id);if(!a)throw new Error(`Spec not found: ${e.spec_id}`);let i=t.prepare(`
|
|
125
|
+
INSERT INTO issue_feedback (
|
|
126
|
+
id, issue_id, issue_uuid, spec_id, spec_uuid, feedback_type, content, agent, anchor, dismissed
|
|
127
|
+
) VALUES (
|
|
128
|
+
@id, @issue_id, @issue_uuid, @spec_id, @spec_uuid, @feedback_type, @content, @agent, @anchor, @dismissed
|
|
129
|
+
)
|
|
130
|
+
`);try{i.run({id:s,issue_id:e.issue_id,issue_uuid:r.uuid,spec_id:e.spec_id,spec_uuid:a.uuid,feedback_type:e.feedback_type,content:e.content,agent:o,anchor:n,dismissed:e.dismissed!==void 0&&e.dismissed?1:0});let d=Me(t,s);if(!d)throw new Error(`Failed to create feedback ${s}`);return d}catch(d){throw d.code&&d.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${d.message}`):d}}function Me(t,e){let n=t.prepare(`
|
|
131
|
+
SELECT * FROM issue_feedback WHERE id = ?
|
|
132
|
+
`).get(e);return n?ns(n):null}function Ke(t,e,s){let n=Me(t,e);if(!n)throw new Error(`Feedback not found: ${e}`);let o=[],r={id:e};if(s.content!==void 0&&(o.push("content = @content"),r.content=s.content),s.dismissed!==void 0&&(o.push("dismissed = @dismissed"),r.dismissed=s.dismissed?1:0),s.anchor!==void 0&&(o.push("anchor = @anchor"),r.anchor=JSON.stringify(s.anchor)),o.push("updated_at = CURRENT_TIMESTAMP"),o.length===1)return n;let a=t.prepare(`
|
|
133
|
+
UPDATE issue_feedback SET ${o.join(", ")} WHERE id = @id
|
|
134
|
+
`);try{a.run(r);let i=Me(t,e);if(!i)throw new Error(`Failed to update feedback ${e}`);return i}catch(i){throw i.code&&i.code.startsWith("SQLITE_CONSTRAINT")?new Error(`Constraint violation: ${i.message}`):i}}function os(t,e){return t.prepare("DELETE FROM issue_feedback WHERE id = ?").run(e).changes>0}function rs(t,e){return Ke(t,e,{dismissed:!0})}function V(t,e={}){let s=[],n={};e.issue_id!==void 0&&(s.push("issue_id = @issue_id"),n.issue_id=e.issue_id),e.spec_id!==void 0&&(s.push("spec_id = @spec_id"),n.spec_id=e.spec_id),e.feedback_type!==void 0&&(s.push("feedback_type = @feedback_type"),n.feedback_type=e.feedback_type),e.dismissed!==void 0&&(s.push("dismissed = @dismissed"),n.dismissed=e.dismissed?1:0);let o="SELECT * FROM issue_feedback";return s.length>0&&(o+=" WHERE "+s.join(" AND ")),o+=" ORDER BY created_at DESC",e.limit!==void 0&&(o+=" LIMIT @limit",n.limit=e.limit),e.offset!==void 0&&(o+=" OFFSET @offset",n.offset=e.offset),t.prepare(o).all(n).map(ns)}var be=ce(()=>{"use strict"});import*as B from"fs";import*as is from"readline";import*as as from"path";async function Ft(t,e={}){let{skipErrors:s=!1,onError:n}=e;if(!B.existsSync(t))return[];let o=[],r=B.createReadStream(t,{encoding:"utf8"}),a=is.createInterface({input:r,crlfDelay:1/0}),i=0;for await(let d of a)if(i++,d.trim()!=="")try{let c=JSON.parse(d);o.push(c)}catch(c){let l=c;if(n&&n(i,d,l),!s)throw new Error(`Failed to parse JSON at line ${i}: ${l.message}`)}return o}async function Nt(t,e,s={}){let{atomic:n=!0}=s,o=as.dirname(t);B.existsSync(o)||B.mkdirSync(o,{recursive:!0});let r=n?`${t}.tmp`:t,a=[...e].sort((c,l)=>{let p=c.created_at,y=l.created_at;if(!p&&!y){let v=c.id||"",x=l.id||"";return v<x?-1:v>x?1:0}if(!p)return 1;if(!y||p<y)return-1;if(p>y)return 1;let g=c.id||"",L=l.id||"";return g<L?-1:g>L?1:0}),d=a.map(c=>JSON.stringify(c)).join(`
|
|
135
|
+
`)+`
|
|
136
|
+
`;if(!(B.existsSync(t)&&B.readFileSync(t,"utf8")===d)&&(B.writeFileSync(r,d,"utf8"),n&&B.renameSync(r,t),a.length>0)){let c=a.map(l=>l.updated_at).filter(l=>l!=null).map(l=>{let p=String(l),g=p.endsWith("Z")||p.includes("+")||/[+-]\d{2}:\d{2}$/.test(p)?p:p.replace(" ","T")+"Z";return new Date(g).getTime()});if(c.length>0){let l=Math.max(...c),p=new Date(l);B.utimesSync(t,p,p)}}}var Lt=ce(()=>{"use strict"});function Cs(t,e){return t.inTransaction?e(t):t.transaction(e)(t)}var Rs=ce(()=>{"use strict"});var Ls={};rt(Ls,{countReferences:()=>go,detectChanges:()=>qt,detectCollisions:()=>Ht,importFromJSONL:()=>st,importIssues:()=>Yt,importSpecs:()=>zt,resolveCollisions:()=>Ns,updateTextReferences:()=>ho});import*as Bt from"path";function qt(t,e){let s=new Map(t.map(d=>[d.uuid,d])),n=new Set(e.map(d=>d.uuid)),o=e.filter(d=>!s.has(d.uuid)).map(d=>d.id),r=t.filter(d=>!n.has(d.uuid)).map(d=>d.id),a=[],i=[];for(let d of e){let c=s.get(d.uuid);c&&(fo(c,d)?a.push(d.id):i.push(d.id))}return{added:o,updated:a,deleted:r,unchanged:i}}function fo(t,e){return t.updated_at!==e.updated_at}function Ht(t,e){let s=[],n=new Map(t.map(r=>[r.id,r]));for(let r of e){let a=n.get(r.id);a&&a.uuid!==r.uuid&&s.push({id:r.id,uuid:r.uuid,type:"spec",reason:"Same ID but different UUID (different entities)",localContent:a.title,incomingContent:r.title,localCreatedAt:a.created_at,incomingCreatedAt:r.created_at})}let o=new Map;for(let r of e){let a=o.get(r.id)||[];a.push(r),o.set(r.id,a)}for(let[r,a]of o.entries())if(a.length>1&&new Set(a.map(d=>d.uuid)).size>1)for(let d=1;d<a.length;d++)s.push({id:a[d].id,uuid:a[d].uuid,type:"spec",reason:"Duplicate ID in incoming data with different UUID",localContent:a[0].title,incomingContent:a[d].title,localCreatedAt:a[0].created_at,incomingCreatedAt:a[d].created_at});return s}function go(t,e,s){let n=0,o=P(t);for(let a of o){let i=new RegExp(`\\b${e}\\b`,"g"),d=a.content.match(i);d&&(n+=d.length)}let r=U(t);for(let a of r){let i=new RegExp(`\\b${e}\\b`,"g"),d=a.content.match(i);d&&(n+=d.length)}return n}function Ns(t,e){let s=[],n=new Map;for(let o of e){let r=!0;if(o.localCreatedAt){let i=new Date(o.localCreatedAt).getTime(),d=new Date(o.incomingCreatedAt).getTime();d>i?r=!0:i>d?r=!1:r=o.uuid>o.localContent}let a=n.get(o.uuid);a||(a=mo(t,o.id,o.type),n.set(o.uuid,a)),s.push({...o,resolution:"renumber",newId:a,...r&&{note:"incoming is newer - correctly renumbered"},...!r&&{note:"local is newer - incoming (older) being renumbered"}})}return s}function mo(t,e,s){let n=e.match(/^([a-z]+-)?(\d+)$/i);if(!n)return`${s}-${Date.now()}`;let o=n[1]||`${s}-`,r=parseInt(n[2],10),a=`${o}${r+1e3}`,i=0;for(;i<1e3;){if(!(s==="spec"?T(t,a)!==null:O(t,a)!==null))return a;r++,a=`${o}${r+1e3}`,i++}return`${o}${Date.now()}`}function ho(t,e,s){let n=0,o=P(t);for(let a of o){let i=new RegExp(`\\b${e}\\b`,"g");if(i.test(a.content)){let d=a.content.replace(i,s);_e(t,a.id,{content:d}),n++}}let r=U(t);for(let a of r){let i=new RegExp(`\\b${e}\\b`,"g"),d=!1,c=a.content;i.test(a.content)&&(c=a.content.replace(i,s),d=!0),d&&(ee(t,a.id,{content:c}),n++)}return n}function zt(t,e,s,n=!1,o=!1){if(n)return{added:s.added.length,updated:s.updated.length,deleted:s.deleted.length};let r=0,a=0,i=0;for(let d of s.added){let c=e.find(l=>l.id===d);c&&(Oe(t,{id:c.id,uuid:c.uuid,title:c.title,file_path:c.file_path,content:c.content,priority:c.priority,parent_id:c.parent_id,archived:c.archived,archived_at:c.archived_at,created_at:c.created_at,updated_at:c.updated_at}),Z(t,c.id,"spec",c.tags||[]),r++)}if(!o)for(let d of s.added){let c=e.find(l=>l.id===d);if(c&&c.relationships&&c.relationships.length>0)for(let l of c.relationships)Y(t,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}for(let d of s.updated){let c=e.find(l=>l.id===d);c&&(_e(t,c.id,{title:c.title,file_path:c.file_path,content:c.content,priority:c.priority,parent_id:c.parent_id,archived:c.archived,archived_at:c.archived_at,updated_at:c.updated_at}),Z(t,c.id,"spec",c.tags||[]),a++)}if(!o)for(let d of s.updated){let c=e.find(l=>l.id===d);if(c){je(t,c.id,"spec");for(let l of c.relationships||[])Y(t,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}}for(let d of s.deleted)Ge(t,d),i++;return{added:r,updated:a,deleted:i}}function Fs(t,e,s){let n=V(t,{issue_id:e});for(let o of n)os(t,o.id);if(s&&s.length>0)for(let o of s)ft(t,{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,dismissed:o.dismissed})}function Yt(t,e,s,n=!1,o=!1){if(n)return{added:s.added.length,updated:s.updated.length,deleted:s.deleted.length};let r=0,a=0,i=0;for(let d of s.added){let c=e.find(l=>l.id===d);c&&(Te(t,{id:c.id,uuid:c.uuid,title:c.title,content:c.content,status:c.status,priority:c.priority,assignee:c.assignee,parent_id:c.parent_id,archived:c.archived,archived_at:c.archived_at,created_at:c.created_at,updated_at:c.updated_at,closed_at:c.closed_at}),Z(t,c.id,"issue",c.tags||[]),Fs(t,c.id,c.feedback),r++)}if(!o)for(let d of s.added){let c=e.find(l=>l.id===d);if(c)for(let l of c.relationships||[])Y(t,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}for(let d of s.updated){let c=e.find(l=>l.id===d);c&&(ee(t,c.id,{title:c.title,content:c.content,status:c.status,priority:c.priority,assignee:c.assignee,parent_id:c.parent_id,archived:c.archived,archived_at:c.archived_at,updated_at:c.updated_at,closed_at:c.closed_at}),Z(t,c.id,"issue",c.tags||[]),Fs(t,c.id,c.feedback),a++)}if(!o)for(let d of s.updated){let c=e.find(l=>l.id===d);if(c){je(t,c.id,"issue");for(let l of c.relationships||[])Y(t,{from_id:l.from,from_type:l.from_type,to_id:l.to,to_type:l.to_type,relationship_type:l.type})}}for(let d of s.deleted)Ct(t,d),i++;return{added:r,updated:a,deleted:i}}async function st(t,e={}){let{inputDir:s=".sudocode",specsFile:n="specs.jsonl",issuesFile:o="issues.jsonl",dryRun:r=!1,resolveCollisions:a=!0}=e,i=Bt.join(s,n),d=Bt.join(s,o),c=await Ft(i,{skipErrors:!0}),l=await Ft(d,{skipErrors:!0}),p=P(t),y=U(t),g=Ht(p,c),L=Ht(y,l),v=[...g.map(D=>({...D,type:"spec"})),...L.map(D=>({...D,type:"issue"}))],x=[];if(a&&v.length>0){x=Ns(t,v);for(let D of x)if(D.resolution==="renumber"&&D.newId){if(D.type==="spec"){let S=c.find(m=>m.id===D.id&&m.uuid===D.uuid);S&&(S.id=D.newId)}else if(D.type==="issue"){let S=l.find(m=>m.id===D.id&&m.uuid===D.uuid);S&&(S.id=D.newId)}}}let b=qt(p,c),C=qt(y,l),_={specs:{added:0,updated:0,deleted:0},issues:{added:0,updated:0,deleted:0},collisions:x.length>0?x:v};return r?(_.specs=zt(t,c,b,r),_.issues=Yt(t,l,C,r)):Cs(t,()=>{_.specs=zt(t,c,b,r,!0),_.issues=Yt(t,l,C,r,!0);for(let D of b.added){let S=c.find(m=>m.id===D);if(S&&S.relationships&&S.relationships.length>0)for(let m of S.relationships)Y(t,{from_id:m.from,from_type:m.from_type,to_id:m.to,to_type:m.to_type,relationship_type:m.type})}for(let D of b.updated){let S=c.find(m=>m.id===D);if(S){je(t,S.id,"spec");for(let m of S.relationships||[])Y(t,{from_id:m.from,from_type:m.from_type,to_id:m.to,to_type:m.to_type,relationship_type:m.type})}}for(let D of C.added){let S=l.find(m=>m.id===D);if(S&&S.relationships&&S.relationships.length>0)for(let m of S.relationships)Y(t,{from_id:m.from,from_type:m.from_type,to_id:m.to,to_type:m.to_type,relationship_type:m.type})}for(let D of C.updated){let S=l.find(m=>m.id===D);if(S){je(t,S.id,"issue");for(let m of S.relationships||[])Y(t,{from_id:m.from,from_type:m.from_type,to_id:m.to,to_type:m.to_type,relationship_type:m.type})}}}),_}var yt=ce(()=>{"use strict";Lt();K();W();ie();Ie();be();Rs()});import{Command as Io}from"commander";import Qt from"chalk";import*as le from"path";import*as Et from"fs";import Sn from"better-sqlite3";import*as ye from"@sudocode-ai/types/schema";var yn=[];function _n(t){return t.exec(`
|
|
137
|
+
CREATE TABLE IF NOT EXISTS migrations (
|
|
138
|
+
version INTEGER PRIMARY KEY,
|
|
139
|
+
name TEXT NOT NULL,
|
|
140
|
+
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
141
|
+
)
|
|
142
|
+
`),t.prepare("SELECT MAX(version) as version FROM migrations").get().version??0}function bn(t,e){t.prepare(`
|
|
143
|
+
INSERT OR REPLACE INTO migrations (version, name)
|
|
144
|
+
VALUES (?, ?)
|
|
145
|
+
`).run(e.version,e.name)}function Zt(t){let e=_n(t),s=yn.filter(n=>n.version>e);if(s.length!==0){console.log(`Running ${s.length} pending migration(s)...`);for(let n of s){console.log(` Applying migration ${n.version}: ${n.name}`);try{n.up(t),bn(t,n),console.log(` \u2713 Migration ${n.version} applied successfully`)}catch(o){throw console.error(` \u2717 Migration ${n.version} failed:`,o),o}}}}function ze(t){let e=new Sn(t.path,{verbose:t.verbose?console.log:void 0});e.exec(ye.DB_CONFIG);for(let s of ye.ALL_TABLES)e.exec(s);for(let s of ye.ALL_INDEXES)e.exec(s);for(let s of ye.ALL_VIEWS)e.exec(s);return Zt(e),e}xe();K();ie();Ie();be();import h from"chalk";import*as ve from"path";import*as ge from"fs";K();W();ie();Ie();be();Lt();function Bn(t,e){let n=de(t,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})),o=te(t,e.id,"spec");return{...e,relationships:n,tags:o}}function qn(t,e){let n=de(t,e.id,"issue").map(i=>({from:i.from_id,from_type:i.from_type,to:i.to_id,to_type:i.to_type,type:i.relationship_type})),o=te(t,e.id,"issue"),a=V(t,{issue_id:e.id}).map(i=>({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&&typeof i.anchor=="string"?JSON.parse(i.anchor):i.anchor,dismissed:i.dismissed,created_at:i.created_at,updated_at:i.updated_at}));return{...e,relationships:n,tags:o,feedback:a.length>0?a:void 0}}function Hn(t,e={}){let{since:s}=e,n=P(t);return(s?n.filter(r=>new Date(r.updated_at)>s):n).map(r=>Bn(t,r))}function zn(t,e={}){let{since:s}=e,n=U(t);return(s?n.filter(r=>new Date(r.updated_at)>s):n).map(r=>qn(t,r))}async function R(t,e={}){let{outputDir:s=".sudocode",specsFile:n="specs.jsonl",issuesFile:o="issues.jsonl"}=e,r=`${s}/${n}`,a=`${s}/${o}`,i=Hn(t,e);await Nt(r,i);let d=zn(t,e);return await Nt(a,d),{specsCount:i.length,issuesCount:d.length}}K();W();xe();import mt from"gray-matter";import*as Je from"fs";import*as cs from"crypto";function fe(t,e,s){let n=t.split(`
|
|
146
|
+
`);if(e<1||e>n.length)throw new Error(`Line number ${e} is out of range (1-${n.length})`);let o=n[e-1],r=Yn(n,e),a=ls(o,s,50),i=gt(n,e,-50),d=gt(n,e,50),c=r?e-r.startLine:void 0,l=ps(a);return{section_heading:r?.heading,section_level:r?.level,line_number:e,line_offset:c,text_snippet:a,context_before:i,context_after:d,content_hash:l,anchor_status:"valid",last_verified_at:new Date().toISOString(),original_location:{line_number:e,section_heading:r?.heading}}}function ds(t,e){let s=t.split(`
|
|
147
|
+
`);for(let n=0;n<s.length;n++){let r=s[n].indexOf(e);if(r!==-1){let a=n+1;return fe(t,a,r)}}return null}function Yn(t,e){for(let s=e-1;s>=0;s--){let o=t[s].match(/^(#{1,6})\s+(.+?)(\r)?$/);if(o){let r=o[1].length;return{heading:o[2].trim(),level:r,startLine:s+1}}}return null}function ls(t,e,s=50){if(!t||t.trim()==="")return"";let n=t.trim(),o=0,r=n.length;if(e!==void 0){let i=t.length-t.trimStart().length,d=Math.max(0,e-i),c=Math.floor(s/2);o=Math.max(0,d-c),r=Math.min(n.length,d+c)}else r=Math.min(n.length,s);let a=n.substring(o,r);return o>0&&(a="..."+a),r<n.length&&(a=a+"..."),a}function gt(t,e,s){if(s===0)return"";let n=s>0?1:-1,o=Math.abs(s),r="",a=e-1;for(n>0?a+=1:a-=1;a>=0&&a<t.length&&r.length<o;){let i=t[a],d=o-r.length;if(n>0)r.length>0&&(r+=" "),r+=i.substring(0,d);else{let c=Math.max(0,i.length-d),l=i.substring(c);r.length>0?r=l+" "+r:r=l}a+=n}return r.trim()}function ps(t){return cs.createHash("sha256").update(t).digest("hex").substring(0,16)}function Vn(t,e){if(!e.line_number)return!1;let s=t.split(`
|
|
148
|
+
`);if(e.line_number<1||e.line_number>s.length)return!1;let n=s[e.line_number-1];if(e.text_snippet&&e.text_snippet.trim()){let o=e.text_snippet.replace(/\.\.\./g,"").trim();if(o&&!n.includes(o))return!1}if(e.content_hash&&e.text_snippet&&e.text_snippet.trim()){let o=ls(n,void 0,50);if(o&&ps(o)!==e.content_hash)return!1}return!0}function us(t){let e=t.split(`
|
|
149
|
+
`),s=[];for(let n=0;n<e.length;n++){let r=e[n].match(/^(#{1,6})\s+(.+?)(\r)?$/);r&&s.push({heading:r[2].trim(),level:r[1].length,startLine:n+1})}return s}function Gn(t,e,s,n){if(!e)return[];let o=t.split(`
|
|
150
|
+
`),r=[],a=e.replace(/\.\.\./g,"").trim();for(let i=0;i<o.length;i++)if(o[i].includes(a)){let c=.5;s&>(o,i+1,-50).includes(s.substring(0,20))&&(c+=.25),n&>(o,i+1,50).includes(n.substring(0,20))&&(c+=.25),r.push({lineNumber:i+1,confidence:Math.min(c,1)})}return r.sort((i,d)=>d.confidence-i.confidence)}function Kn(t,e){let s=t.length,n=e.length,o=Array(s+1).fill(null).map(()=>Array(n+1).fill(0));for(let r=0;r<=s;r++)o[r][0]=r;for(let r=0;r<=n;r++)o[0][r]=r;for(let r=1;r<=s;r++)for(let a=1;a<=n;a++){let i=t[r-1]===e[a-1]?0:1;o[r][a]=Math.min(o[r-1][a]+1,o[r][a-1]+1,o[r-1][a-1]+i)}return o[s][n]}function Qn(t,e,s=5){let n=us(t);if(n.length===0)return null;let o=e.toLowerCase().trim(),r=null,a=1/0;for(let i of n){let d=i.heading.toLowerCase().trim(),c=Kn(o,d);c<a&&c<=s&&(a=c,r=i)}return r}function fs(t,e,s){if(Vn(e,s))return{...s,anchor_status:"valid",last_verified_at:new Date().toISOString()};if(s.section_heading&&s.line_offset!==void 0){let o=us(e).find(r=>r.heading===s.section_heading);if(o){let r=o.startLine+s.line_offset,a=e.split(`
|
|
151
|
+
`);if(r>0&&r<=a.length){let i=a[r-1];if(s.text_snippet){let d=s.text_snippet.replace(/\.\.\./g,"").trim();if(d&&i.includes(d))return{...fe(e,r),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:s.original_location||{line_number:s.line_number||0,section_heading:s.section_heading}}}}}}if(s.text_snippet){let n=Gn(e,s.text_snippet,s.context_before,s.context_after);if(n.length>0&&n[0].confidence>=.7)return{...fe(e,n[0].lineNumber),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:s.original_location||{line_number:s.line_number||0,section_heading:s.section_heading}}}if(s.section_heading&&s.line_offset!==void 0){let n=Qn(e,s.section_heading,5);if(n){let o=n.startLine+s.line_offset,r=e.split(`
|
|
152
|
+
`);if(o>0&&o<=r.length)return{...fe(e,o),anchor_status:"relocated",last_verified_at:new Date().toISOString(),original_location:s.original_location||{line_number:s.line_number||0,section_heading:s.section_heading}}}}return{...s,anchor_status:"stale",last_verified_at:new Date().toISOString(),original_location:s.original_location||{line_number:s.line_number||0,section_heading:s.section_heading}}}function At(t,e,s){let n=mt(t),o;if(s&&e)try{o=ts(s)}catch{}let r=eo(n.content,e,o);return{data:n.data,content:n.content,raw:t,references:r}}function Qe(t,e,s){let n=Je.readFileSync(t,"utf8");return At(n,e,s)}function Zn(t,e){return t.substring(0,e).split(`
|
|
153
|
+
`).length}function Xn(t){return{section_heading:t.section_heading,section_level:t.section_level,line_number:t.line_number,line_offset:t.line_offset,text_snippet:t.text_snippet,context_before:t.context_before,context_after:t.context_after,content_hash:t.content_hash}}function eo(t,e,s){let n=[],o=/\[\[(@)?([a-z]+-\d+)(?:\|([^\]]+))?\]\](?:\{\s*(?:type:\s*)?([a-z-]+)\s*\})?/gi,r;for(;(r=o.exec(t))!==null;){let a=r[1]==="@",i=r[2],d=r[3]?.trim(),c=r[4]?.trim(),l;try{let p=Zn(t,r.index),y=fe(t,p,r.index);l=Xn(y)}catch{l=void 0}if(e){let p=null;try{T(e,i)&&(p="spec")}catch{}if(!p)try{O(e,i)&&(p="issue")}catch{}p&&n.push({match:r[0],id:i,type:p,index:r.index,displayText:d,relationshipType:c,anchor:l})}else{let p;if(s){let y=s.id_prefix.spec.toLowerCase(),g=s.id_prefix.issue.toLowerCase();a||i.toLowerCase().startsWith(g+"-")?p="issue":(i.toLowerCase().startsWith(y+"-"),p="spec")}else p=a||i.startsWith("issue-")?"issue":"spec";n.push({match:r[0],id:i,type:p,index:r.index,displayText:d,relationshipType:c,anchor:l})}}return n}function jt(t,e){return mt.stringify(e,t)}function to(t,e){let s=mt(t),n={...s.data,...e},o=Object.fromEntries(Object.entries(n).filter(([r,a])=>a!==void 0));return mt.stringify(s.content,o)}function Mt(t,e){let s=Je.readFileSync(t,"utf8"),n=to(s,e);Je.writeFileSync(t,n,"utf8")}function so(t,e){return jt(t,e)}function Ze(t,e,s){let n=so(e,s);Je.writeFileSync(t,n,"utf8")}import*as Se from"fs";import*as Xe from"path";function Jt(t,e=50){return t.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,"").slice(0,e)}function ht(t,e,s,n=".md"){let o=Jt(t),r=o+n,a=Xe.join(s,r);if(!Se.existsSync(a))return r;try{let c=Se.readFileSync(a,"utf8").match(/^---\s*\n[\s\S]*?^id:\s*['"]?([^'"\n]+)['"]?\s*$/m);if(c&&c[1]===e)return r}catch{}return`${o}_${e}${n}`}function gs(t,e,s){let n=Xe.join(e,`${t}.md`);if(Se.existsSync(n))return n;if(s){let o=Xe.join(e,`${Jt(s)}.md`);if(Se.existsSync(o))try{let i=Se.readFileSync(o,"utf8").match(/^---\s*\n[\s\S]*?^id:\s*['"]?([^'"\n]+)['"]?\s*$/m);if(i&&i[1]===t)return o}catch{}let r=Xe.join(e,`${Jt(s)}_${t}.md`);if(Se.existsSync(r))return r}return null}async function ms(t,e,s){try{let n=at(t.db,t.outputDir),o=ve.join(t.outputDir,"specs");ge.mkdirSync(o,{recursive:!0});let a=`specs/${s.filePath?ve.basename(s.filePath):ht(e,n,o)}`,i=s.description||"",d=Oe(t.db,{id:n,title:e,file_path:a,content:i,priority:parseInt(s.priority),parent_id:s.parent||void 0});if(s.tags){let l=s.tags.split(",").map(p=>p.trim());Z(t.db,n,"spec",l)}let c={id:n,title:e,priority:parseInt(s.priority),created_at:d.created_at,...s.parent&&{parent_id:s.parent},...s.tags&&{tags:s.tags.split(",").map(l=>l.trim())}};Ze(ve.join(t.outputDir,a),c,i),await R(t.db,{outputDir:t.outputDir}),t.jsonOutput?console.log(JSON.stringify({id:n,title:e,file_path:a},null,2)):(console.log(h.green("\u2713 Created spec"),h.cyan(n)),console.log(h.gray(` Title: ${e}`)),console.log(h.gray(` File: ${a}`)))}catch(n){console.error(h.red("\u2717 Failed to create spec")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function hs(t,e){try{let s=e.grep?kt(t.db,e.grep,{priority:e.priority?parseInt(e.priority):void 0,archived:e.archived!==void 0?e.archived==="true":!1,limit:parseInt(e.limit)}):P(t.db,{priority:e.priority?parseInt(e.priority):void 0,archived:e.archived!==void 0?e.archived==="true":!1,limit:parseInt(e.limit)});if(t.jsonOutput)console.log(JSON.stringify(s,null,2));else{if(s.length===0){console.log(h.gray("No specs found"));return}console.log(h.bold(`
|
|
154
|
+
Found ${s.length} spec(s):
|
|
155
|
+
`));for(let n of s)console.log(h.cyan(n.id),n.title),console.log(h.gray(` Priority: ${n.priority} | ${n.file_path}`));console.log()}}catch(s){console.error(h.red("\u2717 Failed to list specs")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function ys(t,e){try{let s=T(t.db,e);s||(console.error(h.red(`\u2717 Spec not found: ${e}`)),process.exit(1));let n=de(t.db,e,"spec"),o=ue(t.db,e,"spec"),r=te(t.db,e,"spec"),a=V(t.db,{spec_id:e});if(t.jsonOutput)console.log(JSON.stringify({...s,relationships:{outgoing:n,incoming:o},tags:r,feedback:a},null,2));else{if(console.log(),console.log(h.bold.cyan(s.id),h.bold(s.title)),console.log(h.gray("\u2500".repeat(60))),console.log(h.gray("Priority:"),s.priority),console.log(h.gray("File:"),s.file_path),s.parent_id&&console.log(h.gray("Parent:"),s.parent_id),console.log(h.gray("Created:"),s.created_at),console.log(h.gray("Updated:"),s.updated_at),r.length>0&&console.log(h.gray("Tags:"),r.join(", ")),s.content&&(console.log(),console.log(h.bold("Content:")),console.log(s.content)),n.length>0){console.log(),console.log(h.bold("Outgoing Relationships:"));for(let i of n)console.log(` ${h.yellow(i.relationship_type)} \u2192 ${h.cyan(i.to_id)} (${i.to_type})`)}if(o.length>0){console.log(),console.log(h.bold("Incoming Relationships:"));for(let i of o)console.log(` ${h.cyan(i.from_id)} (${i.from_type}) \u2192 ${h.yellow(i.relationship_type)}`)}if(a.length>0){console.log(),console.log(h.bold("Feedback Received:"));for(let i of a){let d=typeof i.anchor=="string"?JSON.parse(i.anchor):i.anchor,c=i.dismissed?h.gray:h.white,l=d.anchor_status==="valid"?h.green:d.anchor_status==="relocated"?h.yellow:h.red;console.log(` ${h.cyan(i.id)} \u2190 ${h.cyan(i.issue_id)}`,c(`[${i.dismissed?"dismissed":"active"}]`),l(`[${d.anchor_status}]`)),console.log(h.gray(` Type: ${i.feedback_type} | ${d.section_heading||"No section"} (line ${d.line_number})`));let p=i.content.substring(0,60)+(i.content.length>60?"...":"");console.log(h.gray(` ${p}`))}}console.log()}}catch(s){console.error(h.red("\u2717 Failed to show spec")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function _s(t,e,s){try{let n=T(t.db,e);n||(console.error(h.red(`\u2717 Spec not found: ${e}`)),process.exit(1));let{updateSpec:o}=await Promise.resolve().then(()=>(K(),$t)),r={};s.title&&(r.title=s.title),s.priority&&(r.priority=parseInt(s.priority)),s.description!==void 0&&(r.content=s.description),s.parent!==void 0&&(r.parent_id=s.parent||void 0),s.archived!==void 0&&(r.archived=s.archived==="true");let a=o(t.db,e,r);if(s.tags!==void 0){let i=s.tags.split(",").map(d=>d.trim());Z(t.db,e,"spec",i)}if(s.description!==void 0||s.title||s.priority||s.parent||s.tags){let i=ve.join(t.outputDir,n.file_path),d="";if(ge.existsSync(i)){d=ge.readFileSync(i,"utf8");let y=d.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);y&&(d=y[1])}let c=te(t.db,e,"spec"),l={id:a.id,title:a.title,priority:a.priority,created_at:a.created_at,...a.parent_id&&{parent_id:a.parent_id},...c.length>0&&{tags:c}},p=s.description!==void 0?s.description:d;Ze(i,l,p)}await R(t.db,{outputDir:t.outputDir}),t.jsonOutput?console.log(JSON.stringify(a,null,2)):(console.log(h.green("\u2713 Updated spec"),h.cyan(e)),s.title&&console.log(h.gray(` Title: ${a.title}`)),s.priority&&console.log(h.gray(` Priority: ${a.priority}`)))}catch(n){console.error(h.red("\u2717 Failed to update spec")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function bs(t,e,s){try{let n=[];for(let o of e)try{let r=T(t.db,o);if(!r){n.push({id:o,success:!1,error:"Spec not found"}),t.jsonOutput||console.error(h.red("\u2717 Spec not found:"),h.cyan(o));continue}let a=ve.join(t.outputDir,r.file_path),{deleteSpec:i}=await Promise.resolve().then(()=>(K(),$t));i(t.db,o)?(ge.existsSync(a)&&ge.unlinkSync(a),n.push({id:o,success:!0}),t.jsonOutput||console.log(h.green("\u2713 Deleted spec"),h.cyan(o))):(n.push({id:o,success:!1,error:"Delete failed"}),t.jsonOutput||console.error(h.red("\u2717 Failed to delete spec"),h.cyan(o)))}catch(r){let a=r instanceof Error?r.message:String(r);n.push({id:o,success:!1,error:a}),t.jsonOutput||console.error(h.red("\u2717 Failed to process"),h.cyan(o),":",a)}await R(t.db,{outputDir:t.outputDir}),t.jsonOutput&&console.log(JSON.stringify(n,null,2))}catch(n){console.error(h.red("\u2717 Failed to delete specs")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}xe();W();ie();Ie();be();import u from"chalk";async function Ss(t,e,s){try{let n=ct(t.db,t.outputDir),o=Te(t.db,{id:n,title:e,content:s.description||"",status:"open",priority:parseInt(s.priority),assignee:s.assignee||void 0,parent_id:s.parent||void 0});if(s.tags){let r=s.tags.split(",").map(a=>a.trim());Z(t.db,n,"issue",r)}await R(t.db,{outputDir:t.outputDir}),t.jsonOutput?console.log(JSON.stringify({id:n,title:e,status:"open"},null,2)):(console.log(u.green("\u2713 Created issue"),u.cyan(n)),console.log(u.gray(` Title: ${e}`)),s.assignee&&console.log(u.gray(` Assignee: ${s.assignee}`)))}catch(n){console.error(u.red("\u2717 Failed to create issue")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function Ds(t,e){try{let s=e.grep?Rt(t.db,e.grep,{status:e.status,assignee:e.assignee,priority:e.priority?parseInt(e.priority):void 0,archived:e.archived!==void 0?e.archived==="true":!1,limit:parseInt(e.limit)}):U(t.db,{status:e.status,assignee:e.assignee,priority:e.priority?parseInt(e.priority):void 0,archived:e.archived!==void 0?e.archived==="true":!1,limit:parseInt(e.limit)});if(t.jsonOutput)console.log(JSON.stringify(s,null,2));else{if(s.length===0){console.log(u.gray("No issues found"));return}console.log(u.bold(`
|
|
156
|
+
Found ${s.length} issue(s):
|
|
157
|
+
`));for(let n of s){let o=n.status==="closed"?u.green:n.status==="in_progress"?u.yellow:n.status==="blocked"?u.red:u.gray,r=n.assignee?u.gray(`@${n.assignee}`):"";console.log(u.cyan(n.id),o(`[${n.status}]`),n.title,r),console.log(u.gray(` Priority: ${n.priority}`))}console.log()}}catch(s){console.error(u.red("\u2717 Failed to list issues")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function ws(t,e){try{let s=O(t.db,e);s||(console.error(u.red(`\u2717 Issue not found: ${e}`)),process.exit(1));let n=de(t.db,e,"issue"),o=ue(t.db,e,"issue"),r=te(t.db,e,"issue"),a=V(t.db,{issue_id:e});if(t.jsonOutput)console.log(JSON.stringify({...s,relationships:{outgoing:n,incoming:o},tags:r,feedback:a},null,2));else{if(console.log(),console.log(u.bold.cyan(s.id),u.bold(s.title)),console.log(u.gray("\u2500".repeat(60))),console.log(u.gray("Status:"),s.status),console.log(u.gray("Priority:"),s.priority),s.assignee&&console.log(u.gray("Assignee:"),s.assignee),s.parent_id&&console.log(u.gray("Parent:"),s.parent_id),console.log(u.gray("Created:"),s.created_at),console.log(u.gray("Updated:"),s.updated_at),s.closed_at&&console.log(u.gray("Closed:"),s.closed_at),r.length>0&&console.log(u.gray("Tags:"),r.join(", ")),s.content&&(console.log(),console.log(u.bold("Content:")),console.log(s.content)),s.content&&(console.log(),console.log(u.bold("Content:")),console.log(s.content)),n.length>0){console.log(),console.log(u.bold("Outgoing Relationships:"));for(let i of n)console.log(` ${u.yellow(i.relationship_type)} \u2192 ${u.cyan(i.to_id)} (${i.to_type})`)}if(o.length>0){console.log(),console.log(u.bold("Incoming Relationships:"));for(let i of o)console.log(` ${u.cyan(i.from_id)} (${i.from_type}) \u2192 ${u.yellow(i.relationship_type)}`)}if(a.length>0){console.log(),console.log(u.bold("Feedback Provided:"));for(let i of a){let d=typeof i.anchor=="string"?JSON.parse(i.anchor):i.anchor,c=i.dismissed?u.gray:u.white,l=d.anchor_status==="valid"?u.green:d.anchor_status==="relocated"?u.yellow:u.red;console.log(` ${u.cyan(i.id)} \u2192 ${u.cyan(i.spec_id)}`,c(`[${i.dismissed?"dismissed":"active"}]`),l(`[${d.anchor_status}]`)),console.log(u.gray(` Type: ${i.feedback_type} | ${d.section_heading||"No section"} (line ${d.line_number})`));let p=i.content.substring(0,60)+(i.content.length>60?"...":"");console.log(u.gray(` ${p}`))}}console.log()}}catch(s){console.error(u.red("\u2717 Failed to show issue")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function Es(t,e,s){try{let n={};s.status&&(n.status=s.status),s.priority&&(n.priority=parseInt(s.priority)),s.assignee&&(n.assignee=s.assignee),s.title&&(n.title=s.title),s.description&&(n.description=s.description),s.archived!==void 0&&(n.archived=s.archived==="true");let o=ee(t.db,e,n);await R(t.db,{outputDir:t.outputDir}),t.jsonOutput?console.log(JSON.stringify(o,null,2)):(console.log(u.green("\u2713 Updated issue"),u.cyan(e)),Object.keys(n).forEach(r=>{console.log(u.gray(` ${r}: ${n[r]}`))}))}catch(n){console.error(u.red("\u2717 Failed to update issue")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function xs(t,e,s){try{let n=[];for(let o of e)try{lt(t.db,o),n.push({id:o,success:!0}),t.jsonOutput||console.log(u.green("\u2713 Closed issue"),u.cyan(o))}catch(r){n.push({id:o,success:!1,error:r instanceof Error?r.message:String(r)}),t.jsonOutput||console.error(u.red("\u2717 Failed to close"),u.cyan(o),":",r instanceof Error?r.message:String(r))}await R(t.db,{outputDir:t.outputDir}),t.jsonOutput&&console.log(JSON.stringify(n,null,2))}catch(n){console.error(u.red("\u2717 Failed to close issues")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function Os(t,e,s){try{let n=[];for(let o of e)try{if(!O(t.db,o)){n.push({id:o,success:!1,error:"Issue not found"}),t.jsonOutput||console.error(u.red("\u2717 Issue not found:"),u.cyan(o));continue}if(s.hard){let{deleteIssue:a}=await Promise.resolve().then(()=>(W(),ss));a(t.db,o)?(n.push({id:o,success:!0,action:"hard_delete"}),t.jsonOutput||console.log(u.green("\u2713 Permanently deleted issue"),u.cyan(o))):(n.push({id:o,success:!1,error:"Delete failed"}),t.jsonOutput||console.error(u.red("\u2717 Failed to delete issue"),u.cyan(o)))}else lt(t.db,o),n.push({id:o,success:!0,action:"soft_delete",status:"closed"}),t.jsonOutput||console.log(u.green("\u2713 Closed issue"),u.cyan(o))}catch(r){let a=r instanceof Error?r.message:String(r);n.push({id:o,success:!1,error:a}),t.jsonOutput||console.error(u.red("\u2717 Failed to process"),u.cyan(o),":",a)}await R(t.db,{outputDir:t.outputDir}),t.jsonOutput&&console.log(JSON.stringify(n,null,2))}catch(n){console.error(u.red("\u2717 Failed to delete issues")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}ie();import ke from"chalk";import*as Pt from"path";import*as Pe from"fs";import*as et from"path";K();W();ie();Ie();be();xe();function no(t){let{file_path:e,entity_type:s,...n}=t;return n}function oo(t,e,s,n,o,r){let a=new Date().toISOString(),i={...e};if(i.id||(i.id=s==="spec"?at(t,o):ct(t,o)),!i.title){let c=Pe.readFileSync(n,"utf8").match(/^#\s+(.+)$/m);i.title=c?c[1]:et.basename(n,".md")}return i.created_at||(i.created_at=a),i.updated_at||(i.updated_at=a),s==="spec"||i.status||(i.status="open"),!i.priority&&i.priority!==0&&(i.priority=2),i}async function tt(t,e,s={}){let{outputDir:n=".sudocode",autoExport:o=!0,user:r="system",autoInitialize:a=!0,writeBackFrontmatter:i=!0}=s;try{let d=Qe(e,t,n),{data:c,content:l,references:p}=d,y=ro(c,e),g=c.id,L=g,v=et.relative(n,e),x=v.startsWith("..")?et.relative(process.cwd(),e):v,b=null,C=null;if(y==="spec"){if(c.file_path=x,L&&(C=T(t,L)),b=Ve(t,x),C)g=C.id,C.file_path!==x&&(console.log(`[sync] File renamed: ${C.file_path} \u2192 ${x}`),b&&b.id!==C.id&&console.warn(`[sync] Warning: File path conflict! Spec ${b.id} already exists at ${x}. Keeping ${C.id} and updating path.`));else if(b)g=b.id,c.id=g;else if(L&&b){let w=b.id;console.warn(`[sync] Warning: ID in frontmatter (${L}) differs from existing spec ID (${w}) for ${x}. Using existing ID.`),g=w,c.id=g}}if(!g)if(a){if(c=oo(t,c,y,e,n,r),g=c.id,i){let w=no(c);Mt(e,w)}}else return{success:!1,action:"no-change",entityId:"",entityType:y,error:"Missing id in frontmatter (auto-initialization disabled)"};let D=!(y==="spec"?T(t,g):O(t,g)),S=Pe.statSync(e),m=new Date(S.mtimeMs).toISOString();return y==="spec"?await io(t,g,c,l,p,D,r,m):await ao(t,g,c,l,p,D,r,m),o&&await R(t,{outputDir:n}),{success:!0,action:D?"created":"updated",entityId:g,entityType:y}}catch(d){return{success:!1,action:"no-change",entityId:"",entityType:"spec",error:d instanceof Error?d.message:String(d)}}}async function me(t,e,s,n){try{let o=s==="spec"?T(t,e):O(t,e);if(!o)return{success:!1,action:"no-change",entityId:e,entityType:s,error:`${s} not found: ${e}`};let{getOutgoingRelationships:r}=await Promise.resolve().then(()=>(ie(),ut)),a=r(t,e,s),i=te(t,e,s),d=co(o,s,a,i),c=Pe.existsSync(n);if(c)Mt(n,d);else{let l=o.content||"";Ze(n,d,l)}return{success:!0,action:c?"updated":"created",entityId:e,entityType:s}}catch(o){return{success:!1,action:"no-change",entityId:e,entityType:s,error:o instanceof Error?o.message:String(o)}}}function ro(t,e){return t.entity_type==="issue"?"issue":t.entity_type==="spec"?"spec":e.includes("/issues/")||e.includes("/issue-")?"issue":(e.includes("/specs/")||e.includes("/spec-"),"spec")}async function io(t,e,s,n,o,r,a,i){let d=r?null:T(t,e),c=d?.content||"",l={id:e,title:s.title||"Untitled",file_path:s.file_path||"",content:n,priority:s.priority??2,parent_id:s.parent_id||void 0};if(r)Oe(t,{...l,updated_at:i});else{let p=d?.title!==l.title||d?.content!==l.content||d?.priority!==l.priority||d?.parent_id!==l.parent_id||d?.file_path!==l.file_path;if(_e(t,e,{...l,...p&&i?{updated_at:i}:{}}),c!==n){let y=V(t,{spec_id:e});if(y.length>0)for(let g of y){let L=typeof g.anchor=="string"?JSON.parse(g.anchor):g.anchor,v=fs(c,n,L);Ke(t,g.id,{anchor:v})}}}s.tags&&Array.isArray(s.tags)&&Z(t,e,"spec",s.tags),await Ts(t,e,"spec",o,s.relationships,a)}async function ao(t,e,s,n,o,r,a,i){let d=r?null:O(t,e),c={id:e,title:s.title||"Untitled",content:n,status:s.status||"open",priority:s.priority??2,assignee:s.assignee||void 0,parent_id:s.parent_id||void 0};if(r)Te(t,{...c,updated_at:i});else{let l=d?.title!==c.title||d?.content!==c.content||d?.status!==c.status||d?.priority!==c.priority||d?.assignee!==c.assignee||d?.parent_id!==c.parent_id;ee(t,e,{...c,...l&&i?{updated_at:i}:{}})}s.tags&&Array.isArray(s.tags)&&Z(t,e,"issue",s.tags),await Ts(t,e,"issue",o,s.relationships,a)}async function Ts(t,e,s,n,o,r="system"){let{getOutgoingRelationships:a}=await Promise.resolve().then(()=>(ie(),ut)),i=a(t,e,s),d=new Set(i.map(c=>`${c.relationship_type}:${c.to_type}:${c.to_id}`));for(let c of n){let l=c.relationshipType||"references",p=`${l}:${c.type}:${c.id}`;if(!d.has(p))try{Y(t,{from_id:e,from_type:s,to_id:c.id,to_type:c.type,relationship_type:l,metadata:c.anchor?JSON.stringify({anchor:c.anchor}):void 0})}catch{}}if(o&&Array.isArray(o))for(let c of o){let l=`${c.relationship_type}:${c.target_type}:${c.target_id}`;if(!d.has(l))try{Y(t,{from_id:e,from_type:s,to_id:c.target_id,to_type:c.target_type,relationship_type:c.relationship_type})}catch{}}}function co(t,e,s,n){let o={id:t.id,title:t.title,priority:t.priority,created_at:t.created_at};if(t.parent_id&&(o.parent_id=t.parent_id),n.length>0&&(o.tags=n),s.length>0&&(o.relationships=s),e==="spec")return o;{let r=t,a={...o,status:r.status};return r.assignee&&(a.assignee=r.assignee),r.closed_at&&(a.closed_at=r.closed_at),a}}K();W();async function Is(t,e,s,n){try{let o,r;if(T(t.db,e)?o="spec":O(t.db,e)?o="issue":(console.error(ke.red(`\u2717 Entity not found: ${e}`)),process.exit(1)),T(t.db,s)?r="spec":O(t.db,s)?r="issue":(console.error(ke.red(`\u2717 Entity not found: ${s}`)),process.exit(1)),Y(t.db,{from_id:e,from_type:o,to_id:s,to_type:r,relationship_type:n.type}),await R(t.db,{outputDir:t.outputDir}),o==="spec"){let a=T(t.db,e);if(a){let i=Pt.join(t.outputDir,a.file_path);await me(t.db,e,"spec",i)}}else if(O(t.db,e)){let i=Pt.join(t.outputDir,"issues",`${e}.md`);await me(t.db,e,"issue",i)}t.jsonOutput?console.log(JSON.stringify({from:e,to:s,type:n.type,success:!0},null,2)):(console.log(ke.green("\u2713 Created relationship")),console.log(ke.cyan(e),ke.yellow(n.type),"\u2192",ke.cyan(s)))}catch(o){console.error(ke.red("\u2717 Failed to create relationship")),console.error(o instanceof Error?o.message:String(o)),process.exit(1)}}import q from"chalk";import*as Ue from"fs";import*as Ut from"path";function lo(t,e,s){let n=`[[${t}`;return e&&(n+=`|${e}`),n+="]]",s&&(n+=`{ ${s} }`),n}function po(t,e){let s=t.split(`
|
|
158
|
+
`);if(e<1||e>s.length)throw new Error(`Line number ${e} is out of bounds (content has ${s.length} lines)`);let n=0;for(let o=0;o<e-1;o++)n+=s[o].length+1;return n}function uo(t,e){let s=t.indexOf(e);if(s===-1)throw new Error(`Text not found: "${e}"`);return s}function vs(t,e,s){let{referenceId:n,displayText:o,relationshipType:r,format:a="inline",position:i="after"}=s;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=lo(n,o,r),c;if(e.line){if(c=po(t,e.line),i==="after"){let y=t.indexOf(`
|
|
159
|
+
`,c);c=y===-1?t.length:y}}else if(e.text)c=uo(t,e.text),i==="after"&&(c+=e.text.length);else throw new Error("Location must specify line or text");let l;return a==="newline"?i==="before"?l=`${d}
|
|
160
|
+
`:l=`
|
|
161
|
+
${d}`:i==="before"?l=`${d} `:l=` ${d}`,t.slice(0,c)+l+t.slice(c)}K();W();async function Wt(t,e,s,n){try{!n.line&&!n.text&&(console.error(q.red("\u2717 Either --line or --text must be specified")),process.exit(1)),n.line&&n.text&&(console.error(q.red("\u2717 Cannot specify both --line and --text")),process.exit(1));let o,r,a;o=T(t.db,e),o?(r="spec",a=Ut.join(t.outputDir,o.file_path)):(o=O(t.db,e),o?(r="issue",a=Ut.join(t.outputDir,"issues",`${e}.md`)):(console.error(q.red(`\u2717 Entity not found: ${e}`)),process.exit(1))),Ue.existsSync(a)||(console.error(q.red(`\u2717 File not found: ${a}`)),process.exit(1));let i=Ue.readFileSync(a,"utf8"),d=At(i),c={};if(n.line){let l=parseInt(n.line);(isNaN(l)||l<1)&&(console.error(q.red("\u2717 Invalid line number")),process.exit(1)),c.line=l}else n.text&&(c.text=n.text);try{let l=vs(d.content,c,{referenceId:s,displayText:n.display,relationshipType:n.type,format:n.format||"inline",position:n.position||"after"}),p=jt(d.data,l);Ue.writeFileSync(a,p,"utf8"),r==="spec"?_e(t.db,e,{content:l}):ee(t.db,e,{content:l}),await R(t.db,{outputDir:t.outputDir}),t.jsonOutput?console.log(JSON.stringify({entity_id:e,reference_id:s,location:c.line?`line ${c.line}`:`text: "${c.text}"`,success:!0},null,2)):(console.log(q.green("\u2713 Added reference to"),q.cyan(e)),console.log(q.gray(` Reference: [[${s}${n.display?`|${n.display}`:""}]]`)),n.type&&console.log(q.gray(` Type: ${n.type}`)),c.line?console.log(q.gray(` Location: line ${c.line} (${n.position||"after"})`)):c.text&&console.log(q.gray(` Location: after "${c.text}"`)),console.log(q.gray(` Format: ${n.format||"inline"}`)))}catch(l){l instanceof Error&&(l.message.includes("not found")?console.error(q.red(`\u2717 ${l.message}`)):l.message.includes("out of bounds")?console.error(q.red(`\u2717 ${l.message}`)):(console.error(q.red("\u2717 Failed to add reference")),console.error(l.message))),process.exit(1)}}catch(o){console.error(q.red("\u2717 Failed to add reference")),console.error(o instanceof Error?o.message:String(o)),process.exit(1)}}W();import ae from"chalk";async function ks(t,e){try{let s={};if(s.issues=Le(t.db),t.jsonOutput)console.log(JSON.stringify(s,null,2));else{if(s.issues.length===0)console.log(ae.gray(`
|
|
162
|
+
No ready issues`));else{console.log(ae.bold(`
|
|
163
|
+
Ready Issues (${s.issues.length}):
|
|
164
|
+
`));for(let n of s.issues){let o=n.assignee?ae.gray(`@${n.assignee}`):"";console.log(ae.cyan(n.id),n.title,o),console.log(ae.gray(` Priority: ${n.priority}`))}}console.log()}}catch(s){console.error(ae.red("\u2717 Failed to get ready items")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function $s(t,e){try{let s={};if(s.issues=Ae(t.db),t.jsonOutput)console.log(JSON.stringify(s,null,2));else{if(s.issues.length===0)console.log(ae.gray(`
|
|
165
|
+
No blocked issues`));else{console.log(ae.bold(`
|
|
166
|
+
Blocked Issues (${s.issues.length}):
|
|
167
|
+
`));for(let n of s.issues)console.log(ae.cyan(n.id),n.title),console.log(ae.gray(` Reason: ${n.status}`))}console.log()}}catch(s){console.error(ae.red("\u2717 Failed to get blocked items")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}import E from"chalk";import*as Q from"fs";import*as j from"path";yt();import yo from"chokidar";import*as A from"path";import*as $e from"fs";yt();K();W();be();Ie();function As(t){let{db:e,baseDir:s,debounceDelay:n=2e3,onLog:o=console.log,onError:r=console.error,ignoreInitial:a=!0,syncJSONLToMarkdown:i=!1}=t,d={filesWatched:0,changesPending:0,changesProcessed:0,errors:0},c=new Map;function l(_,D,S){try{if(!$e.existsSync(_))return!1;let m=Qe(_,e,s),{data:w,content:M}=m,J=S==="spec"?T(e,D):O(e,D);if(!J||w.title!==J.title||M.trim()!==(J.content||"").trim())return!1;if(S==="spec"){if(w.priority!==J.priority)return!1}else{let k=J;if(w.status!==k.status||w.priority!==k.priority)return!1}return!0}catch{return!1}}function p(_){try{if(!$e.existsSync(_))return!1;let S=$e.readFileSync(_,"utf8").trim().split(`
|
|
168
|
+
`).filter(m=>m.trim());for(let m of S){let w=JSON.parse(m),M=w.id,J=_.includes("specs.jsonl")?"spec":"issue",k=J==="spec"?T(e,M):O(e,M);if(!k||w.title!==k.title||(w.content||"").trim()!==(k.content||"").trim()||w.priority!==k.priority||w.parent_id!==k.parent_id||w.archived!==k.archived||w.archived_at!==k.archived_at)return!0;if(J==="spec"){let oe=k;if(w.file_path!==oe.file_path)return!0}else if(J==="issue"){let oe=k;if(w.status!==oe.status||w.assignee!==oe.assignee||w.closed_at!==oe.closed_at)return!0;let Ot=V(e,{issue_id:M}),Re=w.feedback||[];if(Re.length!==Ot.length)return!0;for(let Fe of Re){let pe=Ot.find(pn=>pn.id===Fe.id);if(!pe||Fe.content!==pe.content||Fe.feedback_type!==pe.feedback_type||Fe.spec_id!==pe.spec_id||Fe.dismissed!==pe.dismissed)return!0;let dn=JSON.stringify(Fe.anchor||null),ln=JSON.stringify(pe.anchor&&typeof pe.anchor=="string"?JSON.parse(pe.anchor):pe.anchor||null);if(dn!==ln)return!0}}let F=te(e,M,J),ne=w.tags||[];if(ne.length!==F.length)return!0;let X=new Set(F);if(ne.some(oe=>!X.has(oe)))return!0;let{getOutgoingRelationships:Ee}=(ie(),hn(ut)),ot=Ee(e,M,J),xt=w.relationships||[];if(xt.length!==ot.length)return!0;for(let oe of xt)if(!ot.find(Re=>Re.to_id===oe.to&&Re.to_type===oe.to_type&&Re.relationship_type===oe.type))return!0;if(w.updated_at&&new Date(w.updated_at).getTime()>new Date(k.updated_at).getTime())return!0}return!1}catch{return!0}}let y=A.join(s,"specs"),g=A.join(s,"issues"),L=A.join(s,"specs.jsonl"),v=A.join(s,"issues.jsonl"),x=yo.watch([y,g,L,v],{persistent:!0,ignoreInitial:a,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});o(`[watch] Watching directories: ${y}, ${g} and JSONL files`);async function b(_,D){try{let S=A.extname(_),m=A.basename(_);if(S===".md")if(o(`[watch] ${D} ${A.relative(s,_)}`),D==="unlink"){let w=A.relative(s,_),M=Ve(e,w);M?Ge(e,M.id)&&(o(`[watch] Deleted spec ${M.id} (file removed)`),await R(e,{outputDir:s})):o(`[watch] File deleted but no spec found: ${w}`)}else{try{let M=Qe(_,e,s),{data:J}=M,k=J.id,F=A.relative(s,_),ne=F.startsWith("specs/")||F.startsWith("specs\\")?"spec":"issue";if(k&&l(_,k,ne))return;if(k){let X=ne==="spec"?T(e,k):O(e,k);if(X){let ot=$e.statSync(_).mtimeMs;if(new Date(X.updated_at).getTime()>ot){o(`[watch] Skipping sync for ${ne} ${k} (database is newer)`);return}}}}catch{}let w=await tt(e,_,{outputDir:s,autoExport:!0,autoInitialize:!0,writeBackFrontmatter:!0});w.success?o(`[watch] Synced ${w.entityType} ${w.entityId} (${w.action})`):(r(new Error(`Failed to sync ${_}: ${w.error}`)),d.errors++)}else if((m==="specs.jsonl"||m==="issues.jsonl")&&(o(`[watch] ${D} ${A.relative(s,_)}`),D!=="unlink"&&(p(_)&&(await st(e,{inputDir:s}),o("[watch] Imported JSONL changes to database")),i))){o("[watch] Checking for entities that need markdown updates...");let w=0,M=P(e);for(let F of M)if(F.file_path){let ne=A.join(s,F.file_path);if(l(ne,F.id,"spec"))continue;let X=await me(e,F.id,"spec",ne);X.success?(w++,o(`[watch] Synced spec ${F.id} to ${F.file_path} (${X.action})`)):X.error&&r(new Error(`Failed to sync spec ${F.id}: ${X.error}`))}let J=U(e),k=A.join(s,"issues");for(let F of J){let ne=`${F.id}.md`,X=A.join(k,ne);if(l(X,F.id,"issue"))continue;let Ee=await me(e,F.id,"issue",X);Ee.success?(w++,o(`[watch] Synced issue ${F.id} to markdown (${Ee.action})`)):Ee.error&&r(new Error(`Failed to sync issue ${F.id}: ${Ee.error}`))}w>0?o(`[watch] Synced ${w} entities to markdown`):o("[watch] All markdown files are up to date")}d.changesProcessed++}catch(S){let m=S instanceof Error?S.message:String(S);r(new Error(`Error processing ${_}: ${m}`)),d.errors++}}function C(_,D){let S=c.get(_);S&&(clearTimeout(S),d.changesPending--),d.changesPending++;let m=setTimeout(()=>{c.delete(_),d.changesPending--,b(_,D)},n);c.set(_,m)}return x.on("add",_=>C(_,"add")),x.on("change",_=>C(_,"change")),x.on("unlink",_=>C(_,"unlink")),x.on("ready",()=>{let _=x.getWatched();d.filesWatched=Object.keys(_).reduce((D,S)=>D+_[S].length,0),o(`[watch] Watching ${d.filesWatched} files in ${s}`)}),x.on("error",_=>{r(_),d.errors++}),{stop:async()=>{o("[watch] Stopping watcher...");for(let _ of c.values())clearTimeout(_);c.clear(),d.changesPending=0,await x.close(),o("[watch] Watcher stopped")},getStats:()=>({...d})}}function js(t){let e=!1,s=async n=>{if(!e){e=!0,console.log(`
|
|
169
|
+
[watch] Received ${n}, shutting down gracefully...`);try{await t.stop(),process.exit(0)}catch(o){console.error("[watch] Error during shutdown:",o),process.exit(1)}}};process.on("SIGINT",()=>s("SIGINT")),process.on("SIGTERM",()=>s("SIGTERM")),process.on("unhandledRejection",(n,o)=>{console.error("[watch] Unhandled Rejection at:",o,"reason:",n)})}K();W();import se from"chalk";import*as $ from"fs";import*as G from"path";Ye();function Ms(t){let e=G.join(t,"config.json"),s=G.join(t,"cache.db"),n=G.join(t,"specs"),o=G.join(t,"issues");return $.existsSync(e)&&$.existsSync(s)&&$.existsSync(n)&&$.existsSync(o)}async function Vt(t={}){let e=t.specPrefix||"SPEC",s=t.issuePrefix||"ISSUE",n=t.dir||G.join(process.cwd(),".sudocode"),o=t.jsonOutput||!1;$.mkdirSync(n,{recursive:!0}),$.mkdirSync(G.join(n,"specs"),{recursive:!0}),$.mkdirSync(G.join(n,"issues"),{recursive:!0});let r=[],a=G.join(n,"cache.db"),i=$.existsSync(a),d;i?(r.push("cache.db"),d=ze({path:a})):($.mkdirSync(G.dirname(a),{recursive:!0}),d=ze({path:a}));let c={version:re,id_prefix:{spec:e,issue:s},worktree:{worktreeStoragePath:".sudocode/worktrees",autoCreateBranches:!0,autoDeleteBranches:!1,enableSparseCheckout:!1,branchPrefix:"sudocode",cleanupOrphanedWorktreesOnStartup:!0}};$.writeFileSync(G.join(n,"config.json"),JSON.stringify(c,null,2),"utf8");let l=!1,p=!1,y=G.join(n,"specs.jsonl");$.existsSync(y)?(r.push("specs.jsonl"),l=$.readFileSync(y,"utf8").trim().length>0):$.writeFileSync(y,"","utf8");let g=G.join(n,"issues.jsonl");if($.existsSync(g)?(r.push("issues.jsonl"),p=$.readFileSync(g,"utf8").trim().length>0):$.writeFileSync(g,"","utf8"),l||p)try{o||console.log(se.blue("Importing from existing JSONL files..."));let{importFromJSONL:v}=await Promise.resolve().then(()=>(yt(),Ls)),x=await v(d,{inputDir:n,resolveCollisions:!0});o||((x.specs.added>0||x.specs.updated>0)&&console.log(se.gray(` Specs: ${x.specs.added} added, ${x.specs.updated} updated`)),(x.issues.added>0||x.issues.updated>0)&&console.log(se.gray(` Issues: ${x.issues.added} added, ${x.issues.updated} updated`)),x.collisions.length>0&&console.log(se.yellow(` Resolved ${x.collisions.length} ID collisions`)))}catch(v){o||console.log(se.yellow(` Warning: Failed to import JSONL data - ${v instanceof Error?v.message:String(v)}`))}$.writeFileSync(G.join(n,".gitignore"),`cache.db*
|
|
170
|
+
issues/
|
|
171
|
+
specs/
|
|
172
|
+
worktrees/`,"utf8"),d.close(),o||(console.log(se.green("\u2713 Initialized sudocode in"),se.cyan(n)),console.log(se.gray(` Spec prefix: ${e}`)),console.log(se.gray(` Issue prefix: ${s}`)),console.log(se.gray(` Database: ${a}`)),r.length>0&&console.log(se.yellow(` Preserved existing: ${r.join(", ")}`)))}async function Js(t){try{await Vt(t)}catch(e){console.error(se.red("\u2717 Initialization failed")),console.error(e instanceof Error?e.message:String(e)),process.exit(1)}}async function qs(t,e){if(!Ms(t.outputDir)){console.log(E.blue("Initializing sudocode...")),console.log();try{await Vt({specPrefix:"SPEC",issuePrefix:"ISSUE",dir:t.outputDir,jsonOutput:t.jsonOutput})}catch(s){console.error(E.red("\u2717 Auto-initialization failed")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}console.log()}if(e.watch){console.log(E.blue("Starting file watcher...")),console.log(E.gray(` Watching: ${t.outputDir}`)),console.log(E.gray(" Press Ctrl+C to stop"));let s=As({db:t.db,baseDir:t.outputDir,debounceDelay:2e3,syncJSONLToMarkdown:!0,onLog:n=>{t.jsonOutput||console.log(E.gray(n))},onError:n=>{console.error(E.red(`[watch] Error: ${n.message}`))}});js(s),await new Promise(()=>{})}else if(e.fromMarkdown)await Ps(t);else if(e.toMarkdown)await Us(t);else{let{direction:s,reason:n}=_o(t);console.log(E.blue("Detecting sync direction...")),console.log(E.gray(` ${n}`)),console.log(),s==="no-sync"?(console.log(E.green("\u2713 Everything is in sync")),console.log(E.gray(" Use --from-markdown or --to-markdown to force a specific direction"))):s==="from-markdown"?(console.log(E.blue("\u2192 Syncing FROM markdown TO database (markdown is newer)")),console.log(),await Ps(t)):s==="to-markdown"&&(console.log(E.blue("\u2192 Syncing FROM database TO markdown (database is newer)")),console.log(),await Us(t))}}async function Hs(t,e){try{await R(t.db,{outputDir:e.output}),t.jsonOutput?console.log(JSON.stringify({success:!0,outputDir:e.output},null,2)):(console.log(E.green("\u2713 Exported to JSONL")),console.log(E.gray(` Output: ${e.output}`)))}catch(s){console.error(E.red("\u2717 Failed to export")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function zs(t,e){try{await st(t.db,{inputDir:e.input}),t.jsonOutput?console.log(JSON.stringify({success:!0,inputDir:e.input},null,2)):(console.log(E.green("\u2713 Imported from JSONL")),console.log(E.gray(` Input: ${e.input}`)))}catch(s){console.error(E.red("\u2717 Failed to import")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function Ps(t){console.log(E.blue("Syncing from markdown to database..."));let e=j.join(t.outputDir,"specs"),s=j.join(t.outputDir,"issues"),n=0,o=0,r={outputDir:t.outputDir,autoExport:!1,autoInitialize:!0,writeBackFrontmatter:!0};if(Q.existsSync(e)){let a=_t(e);console.log(E.gray(` Found ${a.length} spec files`));for(let i of a){let d=await tt(t.db,i,r);d.success?(n++,console.log(E.gray(` \u2713 ${d.action} ${d.entityType} ${d.entityId}`))):(o++,console.log(E.red(` \u2717 Failed to sync ${j.basename(i)}: ${d.error}`)))}}if(Q.existsSync(s)){let a=_t(s);console.log(E.gray(` Found ${a.length} issue files`));for(let i of a){let d=await tt(t.db,i,r);d.success?(n++,console.log(E.gray(` \u2713 ${d.action} ${d.entityType} ${d.entityId}`))):(o++,console.log(E.red(` \u2717 Failed to sync ${j.basename(i)}: ${d.error}`)))}}n>0&&await R(t.db,{outputDir:t.outputDir}),console.log(),console.log(E.green(`\u2713 Synced ${n} files to database`)),o>0&&console.log(E.yellow(` ${o} errors`))}async function Us(t){console.log(E.blue("Syncing from database to markdown..."));let e=j.join(t.outputDir,"specs"),s=j.join(t.outputDir,"issues");Q.mkdirSync(e,{recursive:!0}),Q.mkdirSync(s,{recursive:!0});let n=0,o=0,r=P(t.db,{});console.log(E.gray(` Found ${r.length} specs in database`));for(let i of r){let d=j.join(t.outputDir,i.file_path);if(!Q.existsSync(d)){let l=gs(i.id,e,i.title);if(l)d=l;else{let p=ht(i.title,i.id,e);d=j.join(e,p)}}let c=await me(t.db,i.id,"spec",d);c.success?(n++,console.log(E.gray(` \u2713 ${c.action} spec ${i.id} \u2192 ${j.basename(d)}`))):(o++,console.log(E.red(` \u2717 Failed to sync spec ${i.id}: ${c.error}`)))}let a=U(t.db,{});console.log(E.gray(` Found ${a.length} issues in database`));for(let i of a){let d=`${i.id}.md`,c=j.join(s,d),l=await me(t.db,i.id,"issue",c);l.success?(n++,console.log(E.gray(` \u2713 ${l.action} issue ${i.id}`))):(o++,console.log(E.red(` \u2717 Failed to sync issue ${i.id}: ${l.error}`)))}console.log(),console.log(E.green(`\u2713 Synced ${n} entities to markdown`)),o>0&&console.log(E.yellow(` ${o} errors`))}function _t(t){let e=[];function s(n){let o=Q.readdirSync(n,{withFileTypes:!0});for(let r of o){let a=j.join(n,r.name);r.isDirectory()?s(a):r.isFile()&&r.name.endsWith(".md")&&e.push(a)}}return s(t),e}function Ws(t){if(t.length===0)return null;let e=null;for(let s of t)try{let o=Q.statSync(s).mtime;(!e||o>e)&&(e=o)}catch{continue}return e}function Bs(t){try{return Q.statSync(t).mtime}catch{return null}}function _o(t){let e=j.join(t.outputDir,"specs"),s=j.join(t.outputDir,"issues"),n=j.join(t.outputDir,"specs.jsonl"),o=j.join(t.outputDir,"issues.jsonl"),r=Bs(n),a=Bs(o),i=[],d=[];Q.existsSync(e)&&(i=_t(e)),Q.existsSync(s)&&(d=_t(s));let c=Ws(i),l=Ws(d),p=!1,y=!1,g=[];return!r&&!c?g.push("No spec files or JSONL found"):!r&&c?(y=!0,g.push("Specs JSONL missing, markdown exists")):r&&!c?(p=!0,g.push("Spec markdown files missing, JSONL exists")):r&&c&&(c>r?(y=!0,g.push(`Spec markdown files are newer (${De(c)} > ${De(r)})`)):r>c?(p=!0,g.push(`Specs JSONL is newer (${De(r)} > ${De(c)})`)):g.push("Specs are in sync")),!a&&!l?g.push("No issue files or JSONL found"):!a&&l?(y=!0,g.push("Issues JSONL missing, markdown exists")):a&&!l?(p=!0,g.push("Issue markdown files missing, JSONL exists")):a&&l&&(l>a?(y=!0,g.push(`Issue markdown files are newer (${De(l)} > ${De(a)})`)):a>l?(p=!0,g.push(`Issues JSONL is newer (${De(a)} > ${De(l)})`)):g.push("Issues are in sync")),y&&p?{direction:"from-markdown",reason:g.join("; ")+" (choosing markdown as source)"}:y?{direction:"from-markdown",reason:g.join("; ")}:p?{direction:"to-markdown",reason:g.join("; ")}:{direction:"no-sync",reason:g.join("; ")}}function De(t){return t.toISOString().replace("T"," ").substring(0,19)}K();W();W();import N from"chalk";async function Ys(t,e){let s=P(t.db,{}),n=U(t.db,{}),o=Le(t.db),r=Ae(t.db),a={open:n.filter(i=>i.status==="open").length,in_progress:n.filter(i=>i.status==="in_progress").length,blocked:n.filter(i=>i.status==="blocked").length,needs_review:n.filter(i=>i.status==="needs_review").length,closed:n.filter(i=>i.status==="closed").length};if(t.jsonOutput){console.log(JSON.stringify({specs:{total:s.length},issues:{total:n.length,by_status:a,ready:o.length,blocked:r.length}},null,2));return}console.log(N.bold(`
|
|
173
|
+
Sudocode Status
|
|
174
|
+
`)),console.log(N.blue("Specs:")),console.log(` ${N.cyan(s.length)} total`),console.log(),console.log(N.blue("Issues:")),console.log(` ${N.cyan(n.length)} total (${a.open} open, ${a.in_progress} in_progress, ${a.blocked} blocked, ${a.needs_review} needs_review, ${a.closed} closed)`),console.log(` ${N.green(o.length)} ready to work on`),console.log(` ${N.yellow(r.length)} blocked`),console.log(),console.log(N.gray("Sync status: All files in sync")),console.log()}async function Vs(t,e){let s=P(t.db,{}),n=U(t.db,{}),o=Le(t.db),r=Ae(t.db),a={open:n.filter(b=>b.status==="open").length,in_progress:n.filter(b=>b.status==="in_progress").length,blocked:n.filter(b=>b.status==="blocked").length,needs_review:n.filter(b=>b.status==="needs_review").length,closed:n.filter(b=>b.status==="closed").length},i=t.db.prepare(`
|
|
175
|
+
SELECT relationship_type, COUNT(*) as count
|
|
176
|
+
FROM relationships
|
|
177
|
+
GROUP BY relationship_type
|
|
178
|
+
`),d={},c=i.all();for(let b of c)d[b.relationship_type]=b.count;let l=c.reduce((b,C)=>b+C.count,0),p=new Date;p.setDate(p.getDate()-7);let y=s.filter(b=>new Date(b.updated_at)>p).length,g=n.filter(b=>new Date(b.updated_at)>p).length,L=n.filter(b=>new Date(b.created_at)>p).length,v=n.filter(b=>b.closed_at&&new Date(b.closed_at)>p).length;if(t.jsonOutput){console.log(JSON.stringify({specs:{total:s.length},issues:{total:n.length,by_status:a,ready:o.length,blocked:r.length},relationships:{total:l,by_type:d},recent_activity:{specs_updated:y,issues_updated:g,issues_created:L,issues_closed:v}},null,2));return}console.log(N.bold(`
|
|
179
|
+
Project Statistics
|
|
180
|
+
`)),console.log(N.blue("Specs:")),console.log(` Total: ${N.cyan(s.length)}`),console.log(),console.log(N.blue("Issues:")),console.log(` Total: ${N.cyan(n.length)}`),console.log(` By Status: ${a.open} open, ${a.in_progress} in_progress, ${a.blocked} blocked, ${a.needs_review} needs_review, ${a.closed} closed`),console.log(` Ready: ${N.green(o.length)}`),console.log(` Blocked: ${N.yellow(r.length)}`),console.log(),console.log(N.blue("Relationships:")),console.log(` Total: ${N.cyan(l)}`);let x=Object.entries(d).map(([b,C])=>`${C} ${b}`).join(", ");x&&console.log(` ${x}`),console.log(),console.log(N.blue("Recent Activity (last 7 days):")),console.log(` ${y} specs updated`),console.log(` ${g} issues updated`),console.log(` ${L} issues created`),console.log(` ${v} issues closed`),console.log()}be();K();W();import f from"chalk";async function Gs(t,e,s,n){try{O(t.db,e)||(console.error(f.red(`\u2717 Issue not found: ${e}`)),process.exit(1));let r=T(t.db,s);r||(console.error(f.red(`\u2717 Spec not found: ${s}`)),process.exit(1));let a=r.content,i;if(n.line){let c=parseInt(n.line);(isNaN(c)||c<1)&&(console.error(f.red("\u2717 Invalid line number")),process.exit(1)),i=fe(a,c)}else n.text?(i=ds(a,n.text),i||(console.error(f.red(`\u2717 Text not found in spec: "${n.text}"`)),process.exit(1))):(console.error(f.red("\u2717 Either --line or --text must be specified")),process.exit(1));let d=ft(t.db,{issue_id:e,spec_id:s,feedback_type:n.type,content:n.content,agent:n.agent||process.env.USER||"cli",anchor:i,dismissed:!1});t.jsonOutput?console.log(JSON.stringify(d,null,2)):(console.log(f.green("\u2713 Created feedback"),f.cyan(d.id)),console.log(f.gray(` Issue: ${e}`)),console.log(f.gray(` Spec: ${s}`)),console.log(f.gray(` Type: ${n.type}`)),console.log(f.gray(` Location: ${i.section_heading||"Unknown"} (line ${i.line_number})`)))}catch(o){console.error(f.red("\u2717 Failed to create feedback")),console.error(o instanceof Error?o.message:String(o)),process.exit(1)}}async function Ks(t,e){try{let s={issue_id:e.issue,spec_id:e.spec,feedback_type:e.type,dismissed:e.dismissed!==void 0?e.dismissed==="true":void 0,limit:parseInt(e.limit)},n=V(t.db,s);if(t.jsonOutput)console.log(JSON.stringify(n,null,2));else{if(n.length===0){console.log(f.gray("No feedback found"));return}console.log(f.bold(`
|
|
181
|
+
Found ${n.length} feedback item(s):
|
|
182
|
+
`));for(let o of n){let r=typeof o.anchor=="string"?JSON.parse(o.anchor):o.anchor,a=o.dismissed?f.gray:f.white,i=r.anchor_status==="valid"?f.green:r.anchor_status==="relocated"?f.yellow:f.red;console.log(f.cyan(o.id),a(`[${o.dismissed?"dismissed":"active"}]`),i(`[${r.anchor_status}]`),f.gray(`${o.issue_id} \u2192 ${o.spec_id}`)),console.log(f.gray(` Type: ${o.feedback_type} | ${r.section_heading||"No section"} (line ${r.line_number})`)),console.log(f.gray(` ${o.content.substring(0,80)}${o.content.length>80?"...":""}`))}console.log()}}catch(s){console.error(f.red("\u2717 Failed to list feedback")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function Qs(t,e){try{let s=Me(t.db,e);s||(console.error(f.red(`\u2717 Feedback not found: ${e}`)),process.exit(1));let n=typeof s.anchor=="string"?JSON.parse(s.anchor):s.anchor;if(t.jsonOutput)console.log(JSON.stringify({...s,anchor:n},null,2));else{console.log(),console.log(f.bold.cyan(s.id),f.bold(s.feedback_type)),console.log(f.gray("\u2500".repeat(60))),console.log(f.gray("Issue:"),s.issue_id),console.log(f.gray("Spec:"),s.spec_id),console.log(f.gray("Status:"),s.dismissed?"Dismissed":"Active"),console.log(f.gray("Agent:"),s.agent),console.log(f.gray("Created:"),s.created_at),console.log(f.gray("Updated:"),s.updated_at),console.log(),console.log(f.bold("Content:")),console.log(s.content),console.log(),console.log(f.bold("Anchor Location:"));let o=n.anchor_status==="valid"?f.green:n.anchor_status==="relocated"?f.yellow:f.red;console.log(f.gray(" Status:"),o(n.anchor_status)),console.log(f.gray(" Section:"),n.section_heading||"None"),console.log(f.gray(" Line:"),n.line_number||"Unknown"),n.text_snippet&&console.log(f.gray(" Snippet:"),`"${n.text_snippet}"`),n.original_location&&n.anchor_status!=="valid"&&(console.log(),console.log(f.bold("Original Location:")),console.log(f.gray(" Line:"),n.original_location.line_number),console.log(f.gray(" Section:"),n.original_location.section_heading||"None")),console.log()}}catch(s){console.error(f.red("\u2717 Failed to show feedback")),console.error(s instanceof Error?s.message:String(s)),process.exit(1)}}async function Zs(t,e,s){try{let n=rs(t.db,e);t.jsonOutput?console.log(JSON.stringify(n,null,2)):console.log(f.green("\u2713 Dismissed feedback"),f.cyan(e))}catch(n){console.error(f.red("\u2717 Failed to dismiss feedback")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}async function Xs(t){try{let s=V(t.db,{}).filter(n=>(typeof n.anchor=="string"?JSON.parse(n.anchor):n.anchor).anchor_status==="stale");if(t.jsonOutput)console.log(JSON.stringify(s,null,2));else{if(s.length===0){console.log(f.green("\u2713 No stale anchors found"));return}console.log(f.bold.red(`
|
|
183
|
+
Found ${s.length} stale anchor(s):
|
|
184
|
+
`));for(let n of s){let o=typeof n.anchor=="string"?JSON.parse(n.anchor):n.anchor;console.log(f.cyan(n.id),f.red("[stale]"),f.gray(`${n.issue_id} \u2192 ${n.spec_id}`)),console.log(f.gray(` Original: ${o.original_location?.section_heading||"Unknown"} (line ${o.original_location?.line_number})`)),o.text_snippet&&console.log(f.gray(` Snippet: "${o.text_snippet}"`))}console.log(),console.log(f.yellow("Tip: Use `sg feedback relocate <id> --line <number>` to manually relocate anchors"))}}catch(e){console.error(f.red("\u2717 Failed to list stale feedback")),console.error(e instanceof Error?e.message:String(e)),process.exit(1)}}async function en(t,e,s){try{let n=Me(t.db,e);n||(console.error(f.red(`\u2717 Feedback not found: ${e}`)),process.exit(1));let o=T(t.db,n.spec_id);o||(console.error(f.red(`\u2717 Spec not found: ${n.spec_id}`)),process.exit(1));let r=parseInt(s.line);(isNaN(r)||r<1)&&(console.error(f.red("\u2717 Invalid line number")),process.exit(1));let a=fe(o.content,r),i=typeof n.anchor=="string"?JSON.parse(n.anchor):n.anchor;a.original_location=i.original_location||{line_number:i.line_number||0,section_heading:i.section_heading},a.anchor_status="relocated";let d=Ke(t.db,e,{anchor:a});t.jsonOutput?console.log(JSON.stringify(d,null,2)):(console.log(f.green("\u2713 Relocated feedback anchor"),f.cyan(e)),console.log(f.gray(` New location: ${a.section_heading||"Unknown"} (line ${r})`)))}catch(n){console.error(f.red("\u2717 Failed to relocate feedback")),console.error(n instanceof Error?n.message:String(n)),process.exit(1)}}import{spawn as xo}from"child_process";import*as Dt from"path";import{fileURLToPath as Oo}from"url";import we from"chalk";Ye();import*as he from"fs";import*as Kt from"path";import*as tn from"os";var sn="@sudocode-ai/cli",nn=Kt.join(tn.tmpdir(),"sudocode-cli"),Gt=Kt.join(nn,"update-cache.json"),bo=1e3*60*60*24;async function So(){try{let t=await fetch(`https://registry.npmjs.org/${sn}/latest`,{headers:{Accept:"application/json"}});return t.ok&&(await t.json()).version||null}catch{return null}}function Do(){try{if(!he.existsSync(Gt))return null;let t=he.readFileSync(Gt,"utf-8"),e=JSON.parse(t);return Date.now()-e.timestamp>bo?null:e}catch{return null}}function wo(t){try{he.mkdirSync(nn,{recursive:!0});let e={timestamp:Date.now(),latest:t};he.writeFileSync(Gt,JSON.stringify(e,null,2),"utf-8")}catch{}}async function bt(){let t=Do();if(t)return{current:re,latest:t.latest,updateAvailable:re!==t.latest};let e=await So();return e?(wo(e),{current:re,latest:e,updateAvailable:re!==e}):null}function Eo(t,e){let s=t.split(".").map(Number),n=e.split(".").map(Number);for(let o=0;o<3;o++){let r=s[o]||0,a=n[o]||0;if(r<a)return!0;if(r>a)return!1}return!1}async function St(){let t=await bt();return!t||!t.updateAvailable||!Eo(t.current,t.latest)?null:`
|
|
185
|
+
\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
|
|
186
|
+
\u2502 \u2502
|
|
187
|
+
\u2502 Update available: ${t.current} \u2192 ${t.latest} \u2502
|
|
188
|
+
\u2502 \u2502
|
|
189
|
+
\u2502 Run: npm install -g ${sn} \u2502
|
|
190
|
+
\u2502 Or: sudocode update \u2502
|
|
191
|
+
\u2502 \u2502
|
|
192
|
+
\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F
|
|
193
|
+
`.trim()}async function on(t,e){try{let i=await St();i&&(console.log(),console.log(we.yellow(i)),console.log())}catch{}let s=Oo(import.meta.url),n=Dt.dirname(s),o=Dt.resolve(n,"../../../server/dist/src/index.js"),r={...process.env,SUDOCODE_DIR:t.outputDir,PORT:e.port||process.env.PORT||"3000"};console.log(we.blue("Starting sudocode local server...")),e.port&&console.log(we.gray(`Port: ${e.port}`));let a=xo("node",[o],{detached:e.detach||!1,stdio:e.detach?"ignore":"inherit",env:r});e.detach?(a.unref(),console.log(we.green(`\u2713 Server started in background on http://localhost:${r.PORT}`)),console.log(we.gray(` Process ID: ${a.pid}`)),console.log(we.gray(` Health check: http://localhost:${r.PORT}/health`))):(process.on("SIGINT",()=>{console.log(we.yellow(`
|
|
194
|
+
|
|
195
|
+
Shutting down server...`)),a.kill(),process.exit(0)}),a.on("exit",i=>{i!==0&&i!==null&&(console.error(we.red(`Server exited with code ${i}`)),process.exit(i))}))}import H from"chalk";import{execSync as To}from"child_process";var nt="@sudocode-ai/cli";async function rn(){console.log(H.cyan("Checking for updates..."));let t=await bt();if(!t){console.log(H.yellow("Unable to check for updates")),console.log("Please try again later or check manually:"),console.log(` npm view ${nt} version`);return}console.log(`Current version: ${H.cyan(t.current)}`),console.log(`Latest version: ${H.cyan(t.latest)}`),t.updateAvailable?(console.log(),console.log(H.green("\u2713 Update available!")),console.log(),console.log("To update, run:"),console.log(H.yellow(` npm install -g ${nt}`)),console.log(H.yellow(" sudocode update"))):(console.log(),console.log(H.green("\u2713 You are using the latest version")))}async function an(){console.log(H.cyan("Checking for updates..."));let t=await bt();if(!t)console.log(H.yellow("Unable to check for updates")),console.log("Attempting to update anyway...");else if(t.updateAvailable)console.log(`Updating from ${t.current} to ${t.latest}...`);else{console.log(H.green("\u2713 Already on latest version:"),t.current);return}try{console.log(),console.log(H.cyan("Running: npm install -g "+nt)),console.log(),To(`npm install -g ${nt}`,{stdio:"inherit"}),console.log(),console.log(H.green("\u2713 Update completed successfully!")),console.log(),console.log("Run 'sudocode --version' to verify the new version")}catch(e){console.log(),console.error(H.red("\u2717 Update failed")),console.log(),console.log("Please try updating manually:"),console.log(H.yellow(` npm install -g ${nt}`)),console.log(),e instanceof Error&&(console.log("Error details:"),console.log(H.dim(e.message))),process.exit(1)}}Ye();var Be=null,We="",wt=".sudocode",cn=!1;function vo(){let t=process.cwd(),e=le.parse(t).root;for(;t!==e;){let s=le.join(t,".sudocode","cache.db");if(Et.existsSync(s))return s;t=le.dirname(t)}return null}function ko(){if(!We){let t=vo();t?(We=t,wt=le.dirname(t)):(wt=le.join(process.cwd(),".sudocode"),We=le.join(wt,"cache.db"))}try{Et.mkdirSync(le.dirname(We),{recursive:!0}),Be=ze({path:We})}catch(t){console.error(Qt.red("Error: Failed to open database")),console.error(t instanceof Error?t.message:String(t)),process.exit(1)}}function I(){return Be||(console.error(Qt.red("Error: Database not initialized")),process.exit(1)),{db:Be,outputDir:wt,jsonOutput:cn}}var z=new Io;z.name("sudocode").description("sudocode - git-native agentic context management").version(re).option("--db <path>","Database path (default: auto-discover)").option("--json","Output in JSON format").hook("preAction",t=>{let e=t.optsWithGlobals();e.db&&(We=e.db),e.json&&(cn=!0),t.name()!=="init"&&ko()}).hook("postAction",()=>{Be&&(Be.close(),Be=null)});z.command("init").description("Initialize .sudocode directory structure").option("--spec-prefix <prefix>","ID prefix for specs","SPEC").option("--issue-prefix <prefix>","ID prefix for issues","ISSUE").action(async t=>{await Js({specPrefix:t.specPrefix,issuePrefix:t.issuePrefix})});var qe=z.command("spec").alias("specs").description("Manage specifications");qe.command("create <title>").description("Create a new spec").option("-p, --priority <priority>","Priority (0-4)","2").option("-d, --description <desc>","Description").option("--file-path <path>","File path for markdown").option("--parent <id>","Parent spec ID").option("--tags <tags>","Comma-separated tags").action(async(t,e)=>{await ms(I(),t,e)});qe.command("list").description("List all specs").option("-p, --priority <priority>","Filter by priority").option("-g, --grep <query>","Search by title or content").option("--archived <bool>","Filter by archive status (true/false)").option("--limit <num>","Limit results","50").action(async t=>{await hs(I(),t)});qe.command("show <id>").description("Show spec details").action(async t=>{await ys(I(),t)});qe.command("update <id>").description("Update a spec").option("-p, --priority <priority>","New priority").option("--title <title>","New title").option("-d, --description <desc>","New description").option("--parent <id>","New parent spec ID").option("--tags <tags>","New comma-separated tags").option("--archived <bool>","Archive status (true/false)").action(async(t,e)=>{await _s(I(),t,e)});qe.command("delete <id...>").description("Delete one or more specs").action(async(t,e)=>{await bs(I(),t,e)});qe.command("add-ref <entity-id> <reference-id>").description("Add a reference to a spec").option("-l, --line <number>","Line number to insert reference").option("-t, --text <text>","Text to search for insertion point").option("--display <text>","Display text for reference").option("--type <type>","Relationship type (blocks, implements, etc.)").option("--format <format>","Format: inline or newline","inline").action(async(t,e,s)=>{await Wt(I(),t,e,s)});var Ce=z.command("issue").alias("issues").description("Manage issues");Ce.command("create <title>").description("Create a new issue").option("-p, --priority <priority>","Priority (0-4)","2").option("-d, --description <desc>","Description").option("-a, --assignee <assignee>","Assignee").option("--parent <id>","Parent issue ID").option("--tags <tags>","Comma-separated tags").action(async(t,e)=>{await Ss(I(),t,e)});Ce.command("list").description("List all issues").option("-s, --status <status>","Filter by status").option("-a, --assignee <assignee>","Filter by assignee").option("-p, --priority <priority>","Filter by priority").option("-g, --grep <query>","Search by title or content").option("--archived <bool>","Filter by archive status (true/false)").option("--limit <num>","Limit results","50").action(async t=>{await Ds(I(),t)});Ce.command("show <id>").description("Show issue details").action(async t=>{await ws(I(),t)});Ce.command("update <id>").description("Update an issue").option("-s, --status <status>","New status").option("-p, --priority <priority>","New priority").option("-a, --assignee <assignee>","New assignee").option("--title <title>","New title").option("--description <desc>","New description").option("--archived <bool>","Archive status (true/false)").action(async(t,e)=>{await Es(I(),t,e)});Ce.command("close <id...>").description("Close one or more issues").option("-r, --reason <reason>","Reason for closing").action(async(t,e)=>{await xs(I(),t,e)});Ce.command("delete <id...>").description("Delete one or more issues").option("--hard","Permanently delete from database (default: close the issue)").action(async(t,e)=>{await Os(I(),t,e)});Ce.command("add-ref <entity-id> <reference-id>").description("Add a reference to an issue").option("-l, --line <number>","Line number to insert reference").option("-t, --text <text>","Text to search for insertion point").option("--display <text>","Display text for reference").option("--type <type>","Relationship type (blocks, implements, etc.)").option("--format <format>","Format: inline or newline","inline").option("--position <position>","Position: before or after","after").action(async(t,e,s)=>{await Wt(I(),t,e,s)});z.command("link <from> <to>").description("Create a relationship between entities").option("-t, --type <type>","Relationship type","references").action(async(t,e,s)=>{await Is(I(),t,e,s)});z.command("ready").description("Show ready issues (no blockers)").action(async t=>{await ks(I(),t)});z.command("blocked").description("Show blocked issues").action(async t=>{await $s(I(),t)});z.command("status").description("Show project status summary").option("-v, --verbose","Show detailed status").action(async t=>{await Ys(I(),t)});z.command("stats").description("Show detailed project statistics").action(async t=>{await Vs(I(),t)});var He=z.command("feedback").description("Manage spec feedback from issues");He.command("add <issue-id> <spec-id>").description("Add feedback to a spec from an issue").option("-l, --line <number>","Line number in spec").option("-t, --text <text>","Text to search for anchor").option("--type <type>","Feedback type (comment, suggestion, request)","comment").option("-c, --content <text>","Feedback content (required)").option("-a, --agent <name>","Agent name").action(async(t,e,s)=>{await Gs(I(),t,e,s)});He.command("list").description("List all feedback").option("-i, --issue <id>","Filter by issue ID").option("-s, --spec <id>","Filter by spec ID").option("-t, --type <type>","Filter by feedback type").option("--status <status>","Filter by status (open, acknowledged, resolved, wont_fix)").option("--limit <num>","Limit results","50").action(async t=>{await Ks(I(),t)});He.command("show <id>").description("Show detailed feedback information").action(async t=>{await Qs(I(),t)});He.command("dismiss <id>").description("Dismiss feedback").option("-c, --comment <text>","Optional comment").action(async(t,e)=>{await Zs(I(),t,e)});He.command("stale").description("List all stale feedback anchors").action(async()=>{await Xs(I())});He.command("relocate <id>").description("Manually relocate a stale anchor").option("-l, --line <number>","New line number (required)").action(async(t,e)=>{await en(I(),t,e)});z.command("sync").description("Sync between markdown, JSONL, and database").option("--watch","Watch for changes and auto-sync").option("--from-markdown","Sync from markdown to database").option("--to-markdown","Sync from database to markdown").action(async t=>{await qs(I(),t)});z.command("export").description("Export database to JSONL").option("-o, --output <dir>","Output directory",".sudocode").action(async t=>{await Hs(I(),t)});z.command("import").description("Import from JSONL to database").option("-i, --input <dir>","Input directory",".sudocode").action(async t=>{await zs(I(),t)});z.command("server").description("Start the sudocode local server").option("-p, --port <port>","Port to run server on","3000").option("-d, --detach","Run server in background").action(async t=>{await on(I(),t)});z.command("update").description("Update sudocode to the latest version").option("--check","Check for updates without installing").action(async t=>{t.check?await rn():await an()});z.parse();var $o=process.argv.includes("update"),Co=process.argv.includes("server");!$o&&!Co&&St().then(t=>{t&&(console.log(),console.log(Qt.yellow(t)),console.log())}).catch(()=>{});
|
|
196
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database initialization and connection management
|
|
3
|
+
*/
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
export interface DatabaseOptions {
|
|
6
|
+
path: string;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Initialize and configure the SQLite database
|
|
11
|
+
*/
|
|
12
|
+
export declare function initDatabase(options: DatabaseOptions): Database.Database;
|
|
13
|
+
/**
|
|
14
|
+
* Get or create a database connection
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDatabase(path: string): Database.Database;
|
|
17
|
+
/**
|
|
18
|
+
* Create a new transaction
|
|
19
|
+
*/
|
|
20
|
+
export declare function withTransaction<T>(db: Database.Database, callback: (db: Database.Database) => T): T;
|
|
21
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export SQLite data to JSONL files
|
|
3
|
+
*/
|
|
4
|
+
import type Database from "better-sqlite3";
|
|
5
|
+
import type { Spec, Issue, SpecJSONL, IssueJSONL } from "./types.js";
|
|
6
|
+
export interface ExportOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Output directory for JSONL files
|
|
9
|
+
*/
|
|
10
|
+
outputDir?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Only export entities that have been updated since this timestamp
|
|
13
|
+
*/
|
|
14
|
+
since?: Date;
|
|
15
|
+
/**
|
|
16
|
+
* Custom file names
|
|
17
|
+
*/
|
|
18
|
+
specsFile?: string;
|
|
19
|
+
issuesFile?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Convert a Spec to SpecJSONL format with embedded relationships and tags
|
|
23
|
+
*/
|
|
24
|
+
export declare function specToJSONL(db: Database.Database, spec: Spec): SpecJSONL;
|
|
25
|
+
/**
|
|
26
|
+
* Convert an Issue to IssueJSONL format with embedded relationships and tags
|
|
27
|
+
*/
|
|
28
|
+
export declare function issueToJSONL(db: Database.Database, issue: Issue): IssueJSONL;
|
|
29
|
+
/**
|
|
30
|
+
* Export all specs to JSONL format
|
|
31
|
+
*/
|
|
32
|
+
export declare function exportSpecsToJSONL(db: Database.Database, options?: ExportOptions): SpecJSONL[];
|
|
33
|
+
/**
|
|
34
|
+
* Export all issues to JSONL format
|
|
35
|
+
*/
|
|
36
|
+
export declare function exportIssuesToJSONL(db: Database.Database, options?: ExportOptions): IssueJSONL[];
|
|
37
|
+
/**
|
|
38
|
+
* Export both specs and issues to JSONL files
|
|
39
|
+
*/
|
|
40
|
+
export declare function exportToJSONL(db: Database.Database, options?: ExportOptions): Promise<{
|
|
41
|
+
specsCount: number;
|
|
42
|
+
issuesCount: number;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Debouncer for export operations
|
|
46
|
+
*/
|
|
47
|
+
export declare class ExportDebouncer {
|
|
48
|
+
private db;
|
|
49
|
+
private delayMs;
|
|
50
|
+
private options;
|
|
51
|
+
private timeoutId;
|
|
52
|
+
private pending;
|
|
53
|
+
constructor(db: Database.Database, delayMs?: number, options?: ExportOptions);
|
|
54
|
+
/**
|
|
55
|
+
* Trigger an export (will be debounced)
|
|
56
|
+
*/
|
|
57
|
+
trigger(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Execute the export immediately
|
|
60
|
+
*/
|
|
61
|
+
execute(): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Cancel any pending export
|
|
64
|
+
*/
|
|
65
|
+
cancel(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Check if an export is pending
|
|
68
|
+
*/
|
|
69
|
+
isPending(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Wait for any pending export to complete
|
|
72
|
+
*/
|
|
73
|
+
flush(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a debounced export function
|
|
77
|
+
*/
|
|
78
|
+
export declare function createDebouncedExport(db: Database.Database, delayMs?: number, options?: ExportOptions): ExportDebouncer;
|
|
79
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate human-readable filenames from spec titles
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert a title to snake_case filename
|
|
6
|
+
* - Lowercase
|
|
7
|
+
* - Replace spaces and special chars with underscores
|
|
8
|
+
* - Remove consecutive underscores
|
|
9
|
+
* - Trim underscores from start/end
|
|
10
|
+
* - Truncate to reasonable length
|
|
11
|
+
*/
|
|
12
|
+
export declare function titleToFilename(title: string, maxLength?: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* Generate a unique filename based on title, with ID suffix if collision
|
|
15
|
+
* @param title - The spec title
|
|
16
|
+
* @param id - The spec ID (used for collision resolution)
|
|
17
|
+
* @param directory - Directory to check for collisions
|
|
18
|
+
* @param extension - File extension (default: .md)
|
|
19
|
+
* @returns Unique filename
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateUniqueFilename(title: string, id: string, directory: string, extension?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Find existing markdown file for a spec (supports both naming conventions)
|
|
24
|
+
* @param specId - The spec ID
|
|
25
|
+
* @param directory - Directory to search
|
|
26
|
+
* @param title - Optional title for title-based search
|
|
27
|
+
* @returns Path to existing file if found, null otherwise
|
|
28
|
+
*/
|
|
29
|
+
export declare function findExistingSpecFile(specId: string, directory: string, title?: string): string | null;
|
|
30
|
+
//# sourceMappingURL=filename-generator.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID generation utilities
|
|
3
|
+
*/
|
|
4
|
+
import type Database from "better-sqlite3";
|
|
5
|
+
import type { Config } from "@sudocode-ai/types";
|
|
6
|
+
/**
|
|
7
|
+
* Generate next spec ID based on database contents
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateSpecId(db: Database.Database, outputDir: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Generate next issue ID based on database contents
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateIssueId(db: Database.Database, outputDir: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get current config
|
|
16
|
+
*/
|
|
17
|
+
export declare function getConfig(outputDir: string): Config;
|
|
18
|
+
/**
|
|
19
|
+
* Update config (version-controlled)
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateConfig(outputDir: string, updates: Partial<Config>): void;
|
|
22
|
+
/**
|
|
23
|
+
* Generate a UUID v4
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateUUID(): string;
|
|
26
|
+
//# sourceMappingURL=id-generator.d.ts.map
|