@sudocode-ai/cli 0.1.0 → 0.1.2
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/dist/cli/feedback-commands.d.ts.map +1 -0
- package/dist/cli/feedback-commands.js +274 -0
- package/dist/cli/feedback-commands.js.map +1 -0
- package/dist/cli/init-commands.d.ts.map +1 -0
- package/dist/cli/init-commands.js +148 -0
- package/dist/cli/init-commands.js.map +1 -0
- package/dist/cli/issue-commands.d.ts.map +1 -0
- package/dist/cli/issue-commands.js +310 -0
- package/dist/cli/issue-commands.js.map +1 -0
- package/dist/cli/query-commands.d.ts.map +1 -0
- package/dist/cli/query-commands.js +61 -0
- package/dist/cli/query-commands.js.map +1 -0
- package/dist/cli/reference-commands.d.ts.map +1 -0
- package/dist/cli/reference-commands.js +136 -0
- package/dist/cli/reference-commands.js.map +1 -0
- package/dist/cli/relationship-commands.d.ts.map +1 -0
- package/dist/cli/relationship-commands.js +76 -0
- package/dist/cli/relationship-commands.js.map +1 -0
- package/dist/cli/server-commands.d.ts.map +1 -0
- package/dist/cli/server-commands.js +99 -0
- package/dist/cli/server-commands.js.map +1 -0
- package/dist/cli/spec-commands.d.ts.map +1 -0
- package/dist/cli/spec-commands.js +321 -0
- package/dist/cli/spec-commands.js.map +1 -0
- package/dist/cli/status-commands.d.ts.map +1 -0
- package/dist/cli/status-commands.js +131 -0
- package/dist/cli/status-commands.js.map +1 -0
- package/dist/cli/sync-commands.d.ts.map +1 -0
- package/dist/cli/sync-commands.js +416 -0
- package/dist/cli/sync-commands.js.map +1 -0
- package/dist/cli/update-commands.d.ts.map +1 -0
- package/dist/cli/update-commands.js +78 -0
- package/dist/cli/update-commands.js.map +1 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +425 -195
- package/dist/cli.js.map +1 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +54 -0
- package/dist/db.js.map +1 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +195 -0
- package/dist/export.js.map +1 -0
- package/dist/filename-generator.d.ts.map +1 -0
- package/dist/filename-generator.js +93 -0
- package/dist/filename-generator.js.map +1 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +123 -0
- package/dist/id-generator.js.map +1 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +608 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -189
- package/dist/index.js.map +1 -0
- package/dist/jsonl.d.ts.map +1 -0
- package/dist/jsonl.js +333 -0
- package/dist/jsonl.js.map +1 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +357 -0
- package/dist/markdown.js.map +1 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +57 -0
- package/dist/migrations.js.map +1 -0
- package/dist/operations/events.d.ts.map +1 -0
- package/dist/operations/events.js +108 -0
- package/dist/operations/events.js.map +1 -0
- package/dist/operations/feedback-anchors.d.ts.map +1 -0
- package/dist/operations/feedback-anchors.js +444 -0
- package/dist/operations/feedback-anchors.js.map +1 -0
- package/dist/operations/feedback.d.ts.map +1 -0
- package/dist/operations/feedback.js +234 -0
- package/dist/operations/feedback.js.map +1 -0
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +10 -0
- package/dist/operations/index.js.map +1 -0
- package/dist/operations/issues.d.ts.map +1 -0
- package/dist/operations/issues.js +411 -0
- package/dist/operations/issues.js.map +1 -0
- package/dist/operations/references.d.ts.map +1 -0
- package/dist/operations/references.js +117 -0
- package/dist/operations/references.js.map +1 -0
- package/dist/operations/relationships.d.ts.map +1 -0
- package/dist/operations/relationships.js +236 -0
- package/dist/operations/relationships.js.map +1 -0
- package/dist/operations/specs.d.ts.map +1 -0
- package/dist/operations/specs.js +290 -0
- package/dist/operations/specs.js.map +1 -0
- package/dist/operations/tags.d.ts.map +1 -0
- package/dist/operations/tags.js +127 -0
- package/dist/operations/tags.js.map +1 -0
- package/dist/operations/transactions.d.ts.map +1 -0
- package/dist/operations/transactions.js +111 -0
- package/dist/operations/transactions.js.map +1 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +442 -0
- package/dist/sync.js.map +1 -0
- package/dist/test-schema.d.ts.map +1 -0
- package/dist/test-schema.js +46 -0
- package/dist/test-schema.js.map +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/update-checker.d.ts.map +1 -0
- package/dist/update-checker.js +151 -0
- package/dist/update-checker.js.map +1 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +438 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +4 -7
package/dist/cli.js
CHANGED
|
@@ -1,196 +1,426 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
specs
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
2
|
+
/**
|
|
3
|
+
* sudocode CLI - Git-native spec and issue management
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import { initDatabase } from "./db.js";
|
|
10
|
+
// Import command handlers
|
|
11
|
+
import { handleSpecCreate, handleSpecList, handleSpecShow, handleSpecUpdate, handleSpecDelete, } from "./cli/spec-commands.js";
|
|
12
|
+
import { handleIssueCreate, handleIssueList, handleIssueShow, handleIssueUpdate, handleIssueClose, handleIssueDelete, } from "./cli/issue-commands.js";
|
|
13
|
+
import { handleLink } from "./cli/relationship-commands.js";
|
|
14
|
+
import { handleAddReference } from "./cli/reference-commands.js";
|
|
15
|
+
import { handleReady, handleBlocked } from "./cli/query-commands.js";
|
|
16
|
+
import { handleSync, handleExport, handleImport } from "./cli/sync-commands.js";
|
|
17
|
+
import { handleStatus, handleStats } from "./cli/status-commands.js";
|
|
18
|
+
import { handleFeedbackAdd, handleFeedbackList, handleFeedbackShow, handleFeedbackDismiss, handleFeedbackStale, handleFeedbackRelocate, } from "./cli/feedback-commands.js";
|
|
19
|
+
import { handleServerStart } from "./cli/server-commands.js";
|
|
20
|
+
import { handleInit } from "./cli/init-commands.js";
|
|
21
|
+
import { handleUpdate, handleUpdateCheck } from "./cli/update-commands.js";
|
|
22
|
+
import { getUpdateNotification } from "./update-checker.js";
|
|
23
|
+
import { VERSION } from "./version.js";
|
|
24
|
+
// Global state
|
|
25
|
+
let db = null;
|
|
26
|
+
let dbPath = "";
|
|
27
|
+
let outputDir = ".sudocode";
|
|
28
|
+
let jsonOutput = false;
|
|
29
|
+
/**
|
|
30
|
+
* Find database path
|
|
31
|
+
* Searches for .sudocode/cache.db in current directory and parent directories
|
|
32
|
+
*/
|
|
33
|
+
function findDatabasePath() {
|
|
34
|
+
let currentDir = process.cwd();
|
|
35
|
+
const root = path.parse(currentDir).root;
|
|
36
|
+
while (currentDir !== root) {
|
|
37
|
+
const potentialPath = path.join(currentDir, ".sudocode", "cache.db");
|
|
38
|
+
if (fs.existsSync(potentialPath)) {
|
|
39
|
+
return potentialPath;
|
|
40
|
+
}
|
|
41
|
+
currentDir = path.dirname(currentDir);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize database connection
|
|
47
|
+
*/
|
|
48
|
+
function initDB() {
|
|
49
|
+
if (!dbPath) {
|
|
50
|
+
const found = findDatabasePath();
|
|
51
|
+
if (found) {
|
|
52
|
+
dbPath = found;
|
|
53
|
+
outputDir = path.dirname(found);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Default location
|
|
57
|
+
outputDir = path.join(process.cwd(), ".sudocode");
|
|
58
|
+
dbPath = path.join(outputDir, "cache.db");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
// Ensure the database directory exists before opening/creating the database
|
|
63
|
+
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
64
|
+
db = initDatabase({ path: dbPath });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error(chalk.red("Error: Failed to open database"));
|
|
68
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get command context
|
|
74
|
+
*/
|
|
75
|
+
function getContext() {
|
|
76
|
+
if (!db) {
|
|
77
|
+
console.error(chalk.red("Error: Database not initialized"));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
return { db, outputDir, jsonOutput };
|
|
81
|
+
}
|
|
82
|
+
// Create main program
|
|
83
|
+
const program = new Command();
|
|
84
|
+
program
|
|
85
|
+
.name("sudocode")
|
|
86
|
+
.description("sudocode - git-native agentic context management")
|
|
87
|
+
.version(VERSION)
|
|
88
|
+
.option("--db <path>", "Database path (default: auto-discover)")
|
|
89
|
+
.option("--json", "Output in JSON format")
|
|
90
|
+
.hook("preAction", (thisCommand) => {
|
|
91
|
+
// Get global options
|
|
92
|
+
const opts = thisCommand.optsWithGlobals();
|
|
93
|
+
if (opts.db)
|
|
94
|
+
dbPath = opts.db;
|
|
95
|
+
if (opts.json)
|
|
96
|
+
jsonOutput = true;
|
|
97
|
+
// Skip DB init for init command
|
|
98
|
+
if (thisCommand.name() !== "init") {
|
|
99
|
+
initDB();
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
.hook("postAction", () => {
|
|
103
|
+
// Close database after command completes
|
|
104
|
+
if (db) {
|
|
105
|
+
db.close();
|
|
106
|
+
db = null;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// INIT COMMAND
|
|
111
|
+
// ============================================================================
|
|
112
|
+
program
|
|
113
|
+
.command("init")
|
|
114
|
+
.description("Initialize .sudocode directory structure")
|
|
115
|
+
.option("--spec-prefix <prefix>", "ID prefix for specs", "SPEC")
|
|
116
|
+
.option("--issue-prefix <prefix>", "ID prefix for issues", "ISSUE")
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
await handleInit({
|
|
119
|
+
specPrefix: options.specPrefix,
|
|
120
|
+
issuePrefix: options.issuePrefix,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// SPEC COMMANDS
|
|
125
|
+
// ============================================================================
|
|
126
|
+
const spec = program
|
|
127
|
+
.command("spec")
|
|
128
|
+
.alias("specs")
|
|
129
|
+
.description("Manage specifications");
|
|
130
|
+
spec
|
|
131
|
+
.command("create <title>")
|
|
132
|
+
.description("Create a new spec")
|
|
133
|
+
.option("-p, --priority <priority>", "Priority (0-4)", "2")
|
|
134
|
+
.option("-d, --description <desc>", "Description")
|
|
135
|
+
.option("--file-path <path>", "File path for markdown")
|
|
136
|
+
.option("--parent <id>", "Parent spec ID")
|
|
137
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
138
|
+
.action(async (title, options) => {
|
|
139
|
+
await handleSpecCreate(getContext(), title, options);
|
|
140
|
+
});
|
|
141
|
+
spec
|
|
142
|
+
.command("list")
|
|
143
|
+
.description("List all specs")
|
|
144
|
+
.option("-p, --priority <priority>", "Filter by priority")
|
|
145
|
+
.option("-g, --grep <query>", "Search by title or content")
|
|
146
|
+
.option("--archived <bool>", "Filter by archive status (true/false)")
|
|
147
|
+
.option("--limit <num>", "Limit results", "50")
|
|
148
|
+
.action(async (options) => {
|
|
149
|
+
await handleSpecList(getContext(), options);
|
|
150
|
+
});
|
|
151
|
+
spec
|
|
152
|
+
.command("show <id>")
|
|
153
|
+
.description("Show spec details")
|
|
154
|
+
.action(async (id) => {
|
|
155
|
+
await handleSpecShow(getContext(), id);
|
|
156
|
+
});
|
|
157
|
+
spec
|
|
158
|
+
.command("update <id>")
|
|
159
|
+
.description("Update a spec")
|
|
160
|
+
.option("-p, --priority <priority>", "New priority")
|
|
161
|
+
.option("--title <title>", "New title")
|
|
162
|
+
.option("-d, --description <desc>", "New description")
|
|
163
|
+
.option("--parent <id>", "New parent spec ID")
|
|
164
|
+
.option("--tags <tags>", "New comma-separated tags")
|
|
165
|
+
.option("--archived <bool>", "Archive status (true/false)")
|
|
166
|
+
.action(async (id, options) => {
|
|
167
|
+
await handleSpecUpdate(getContext(), id, options);
|
|
168
|
+
});
|
|
169
|
+
spec
|
|
170
|
+
.command("delete <id...>")
|
|
171
|
+
.description("Delete one or more specs")
|
|
172
|
+
.action(async (ids, options) => {
|
|
173
|
+
await handleSpecDelete(getContext(), ids, options);
|
|
174
|
+
});
|
|
175
|
+
spec
|
|
176
|
+
.command("add-ref <entity-id> <reference-id>")
|
|
177
|
+
.description("Add a reference to a spec")
|
|
178
|
+
.option("-l, --line <number>", "Line number to insert reference")
|
|
179
|
+
.option("-t, --text <text>", "Text to search for insertion point")
|
|
180
|
+
.option("--display <text>", "Display text for reference")
|
|
181
|
+
.option("--type <type>", "Relationship type (blocks, implements, etc.)")
|
|
182
|
+
.option("--format <format>", "Format: inline or newline", "inline")
|
|
183
|
+
.action(async (entityId, referenceId, options) => {
|
|
184
|
+
await handleAddReference(getContext(), entityId, referenceId, options);
|
|
185
|
+
});
|
|
186
|
+
// ============================================================================
|
|
187
|
+
// ISSUE COMMANDS
|
|
188
|
+
// ============================================================================
|
|
189
|
+
const issue = program
|
|
190
|
+
.command("issue")
|
|
191
|
+
.alias("issues")
|
|
192
|
+
.description("Manage issues");
|
|
193
|
+
issue
|
|
194
|
+
.command("create <title>")
|
|
195
|
+
.description("Create a new issue")
|
|
196
|
+
.option("-p, --priority <priority>", "Priority (0-4)", "2")
|
|
197
|
+
.option("-d, --description <desc>", "Description")
|
|
198
|
+
.option("-a, --assignee <assignee>", "Assignee")
|
|
199
|
+
.option("--parent <id>", "Parent issue ID")
|
|
200
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
201
|
+
.action(async (title, options) => {
|
|
202
|
+
await handleIssueCreate(getContext(), title, options);
|
|
203
|
+
});
|
|
204
|
+
issue
|
|
205
|
+
.command("list")
|
|
206
|
+
.description("List all issues")
|
|
207
|
+
.option("-s, --status <status>", "Filter by status")
|
|
208
|
+
.option("-a, --assignee <assignee>", "Filter by assignee")
|
|
209
|
+
.option("-p, --priority <priority>", "Filter by priority")
|
|
210
|
+
.option("-g, --grep <query>", "Search by title or content")
|
|
211
|
+
.option("--archived <bool>", "Filter by archive status (true/false)")
|
|
212
|
+
.option("--limit <num>", "Limit results", "50")
|
|
213
|
+
.action(async (options) => {
|
|
214
|
+
await handleIssueList(getContext(), options);
|
|
215
|
+
});
|
|
216
|
+
issue
|
|
217
|
+
.command("show <id>")
|
|
218
|
+
.description("Show issue details")
|
|
219
|
+
.action(async (id) => {
|
|
220
|
+
await handleIssueShow(getContext(), id);
|
|
221
|
+
});
|
|
222
|
+
issue
|
|
223
|
+
.command("update <id>")
|
|
224
|
+
.description("Update an issue")
|
|
225
|
+
.option("-s, --status <status>", "New status")
|
|
226
|
+
.option("-p, --priority <priority>", "New priority")
|
|
227
|
+
.option("-a, --assignee <assignee>", "New assignee")
|
|
228
|
+
.option("--title <title>", "New title")
|
|
229
|
+
.option("--description <desc>", "New description")
|
|
230
|
+
.option("--archived <bool>", "Archive status (true/false)")
|
|
231
|
+
.action(async (id, options) => {
|
|
232
|
+
await handleIssueUpdate(getContext(), id, options);
|
|
233
|
+
});
|
|
234
|
+
issue
|
|
235
|
+
.command("close <id...>")
|
|
236
|
+
.description("Close one or more issues")
|
|
237
|
+
.option("-r, --reason <reason>", "Reason for closing")
|
|
238
|
+
.action(async (ids, options) => {
|
|
239
|
+
await handleIssueClose(getContext(), ids, options);
|
|
240
|
+
});
|
|
241
|
+
issue
|
|
242
|
+
.command("delete <id...>")
|
|
243
|
+
.description("Delete one or more issues")
|
|
244
|
+
.option("--hard", "Permanently delete from database (default: close the issue)")
|
|
245
|
+
.action(async (ids, options) => {
|
|
246
|
+
await handleIssueDelete(getContext(), ids, options);
|
|
247
|
+
});
|
|
248
|
+
issue
|
|
249
|
+
.command("add-ref <entity-id> <reference-id>")
|
|
250
|
+
.description("Add a reference to an issue")
|
|
251
|
+
.option("-l, --line <number>", "Line number to insert reference")
|
|
252
|
+
.option("-t, --text <text>", "Text to search for insertion point")
|
|
253
|
+
.option("--display <text>", "Display text for reference")
|
|
254
|
+
.option("--type <type>", "Relationship type (blocks, implements, etc.)")
|
|
255
|
+
.option("--format <format>", "Format: inline or newline", "inline")
|
|
256
|
+
.option("--position <position>", "Position: before or after", "after")
|
|
257
|
+
.action(async (entityId, referenceId, options) => {
|
|
258
|
+
await handleAddReference(getContext(), entityId, referenceId, options);
|
|
259
|
+
});
|
|
260
|
+
// ============================================================================
|
|
261
|
+
// RELATIONSHIP COMMANDS
|
|
262
|
+
// ============================================================================
|
|
263
|
+
program
|
|
264
|
+
.command("link <from> <to>")
|
|
265
|
+
.description("Create a relationship between entities")
|
|
266
|
+
.option("-t, --type <type>", "Relationship type", "references")
|
|
267
|
+
.action(async (from, to, options) => {
|
|
268
|
+
await handleLink(getContext(), from, to, options);
|
|
269
|
+
});
|
|
270
|
+
// ============================================================================
|
|
271
|
+
// READY & BLOCKED COMMANDS
|
|
272
|
+
// ============================================================================
|
|
273
|
+
program
|
|
274
|
+
.command("ready")
|
|
275
|
+
.description("Show ready issues (no blockers)")
|
|
276
|
+
.action(async (options) => {
|
|
277
|
+
await handleReady(getContext(), options);
|
|
278
|
+
});
|
|
279
|
+
program
|
|
280
|
+
.command("blocked")
|
|
281
|
+
.description("Show blocked issues")
|
|
282
|
+
.action(async (options) => {
|
|
283
|
+
await handleBlocked(getContext(), options);
|
|
284
|
+
});
|
|
285
|
+
// ============================================================================
|
|
286
|
+
// STATUS & STATS COMMANDS
|
|
287
|
+
// ============================================================================
|
|
288
|
+
program
|
|
289
|
+
.command("status")
|
|
290
|
+
.description("Show project status summary")
|
|
291
|
+
.option("-v, --verbose", "Show detailed status")
|
|
292
|
+
.action(async (options) => {
|
|
293
|
+
await handleStatus(getContext(), options);
|
|
294
|
+
});
|
|
295
|
+
program
|
|
296
|
+
.command("stats")
|
|
297
|
+
.description("Show detailed project statistics")
|
|
298
|
+
.action(async (options) => {
|
|
299
|
+
await handleStats(getContext(), options);
|
|
300
|
+
});
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// FEEDBACK COMMANDS
|
|
303
|
+
// ============================================================================
|
|
304
|
+
const feedback = program
|
|
305
|
+
.command("feedback")
|
|
306
|
+
.description("Manage spec feedback from issues");
|
|
307
|
+
feedback
|
|
308
|
+
.command("add <issue-id> <spec-id>")
|
|
309
|
+
.description("Add feedback to a spec from an issue")
|
|
310
|
+
.option("-l, --line <number>", "Line number in spec")
|
|
311
|
+
.option("-t, --text <text>", "Text to search for anchor")
|
|
312
|
+
.option("--type <type>", "Feedback type (comment, suggestion, request)", "comment")
|
|
313
|
+
.option("-c, --content <text>", "Feedback content (required)")
|
|
314
|
+
.option("-a, --agent <name>", "Agent name")
|
|
315
|
+
.action(async (issueId, specId, options) => {
|
|
316
|
+
await handleFeedbackAdd(getContext(), issueId, specId, options);
|
|
317
|
+
});
|
|
318
|
+
feedback
|
|
319
|
+
.command("list")
|
|
320
|
+
.description("List all feedback")
|
|
321
|
+
.option("-i, --issue <id>", "Filter by issue ID")
|
|
322
|
+
.option("-s, --spec <id>", "Filter by spec ID")
|
|
323
|
+
.option("-t, --type <type>", "Filter by feedback type")
|
|
324
|
+
.option("--status <status>", "Filter by status (open, acknowledged, resolved, wont_fix)")
|
|
325
|
+
.option("--limit <num>", "Limit results", "50")
|
|
326
|
+
.action(async (options) => {
|
|
327
|
+
await handleFeedbackList(getContext(), options);
|
|
328
|
+
});
|
|
329
|
+
feedback
|
|
330
|
+
.command("show <id>")
|
|
331
|
+
.description("Show detailed feedback information")
|
|
332
|
+
.action(async (id) => {
|
|
333
|
+
await handleFeedbackShow(getContext(), id);
|
|
334
|
+
});
|
|
335
|
+
feedback
|
|
336
|
+
.command("dismiss <id>")
|
|
337
|
+
.description("Dismiss feedback")
|
|
338
|
+
.option("-c, --comment <text>", "Optional comment")
|
|
339
|
+
.action(async (id, options) => {
|
|
340
|
+
await handleFeedbackDismiss(getContext(), id, options);
|
|
341
|
+
});
|
|
342
|
+
feedback
|
|
343
|
+
.command("stale")
|
|
344
|
+
.description("List all stale feedback anchors")
|
|
345
|
+
.action(async () => {
|
|
346
|
+
await handleFeedbackStale(getContext());
|
|
347
|
+
});
|
|
348
|
+
feedback
|
|
349
|
+
.command("relocate <id>")
|
|
350
|
+
.description("Manually relocate a stale anchor")
|
|
351
|
+
.option("-l, --line <number>", "New line number (required)")
|
|
352
|
+
.action(async (id, options) => {
|
|
353
|
+
await handleFeedbackRelocate(getContext(), id, options);
|
|
354
|
+
});
|
|
355
|
+
// ============================================================================
|
|
356
|
+
// SYNC COMMANDS
|
|
357
|
+
// ============================================================================
|
|
358
|
+
program
|
|
359
|
+
.command("sync")
|
|
360
|
+
.description("Sync between markdown, JSONL, and database")
|
|
361
|
+
.option("--watch", "Watch for changes and auto-sync")
|
|
362
|
+
.option("--from-markdown", "Sync from markdown to database")
|
|
363
|
+
.option("--to-markdown", "Sync from database to markdown")
|
|
364
|
+
.action(async (options) => {
|
|
365
|
+
await handleSync(getContext(), options);
|
|
366
|
+
});
|
|
367
|
+
program
|
|
368
|
+
.command("export")
|
|
369
|
+
.description("Export database to JSONL")
|
|
370
|
+
.option("-o, --output <dir>", "Output directory", ".sudocode")
|
|
371
|
+
.action(async (options) => {
|
|
372
|
+
await handleExport(getContext(), options);
|
|
373
|
+
});
|
|
374
|
+
program
|
|
375
|
+
.command("import")
|
|
376
|
+
.description("Import from JSONL to database")
|
|
377
|
+
.option("-i, --input <dir>", "Input directory", ".sudocode")
|
|
378
|
+
.action(async (options) => {
|
|
379
|
+
await handleImport(getContext(), options);
|
|
380
|
+
});
|
|
381
|
+
// ============================================================================
|
|
382
|
+
// SERVER COMMANDS
|
|
383
|
+
// ============================================================================
|
|
384
|
+
program
|
|
385
|
+
.command("server")
|
|
386
|
+
.description("Start the sudocode local server")
|
|
387
|
+
.option("-p, --port <port>", "Port to run server on", "3000")
|
|
388
|
+
.option("-d, --detach", "Run server in background")
|
|
389
|
+
.action(async (options) => {
|
|
390
|
+
await handleServerStart(getContext(), options);
|
|
391
|
+
});
|
|
392
|
+
// ============================================================================
|
|
393
|
+
// UPDATE COMMANDS
|
|
394
|
+
// ============================================================================
|
|
395
|
+
program
|
|
396
|
+
.command("update")
|
|
397
|
+
.description("Update sudocode to the latest version")
|
|
398
|
+
.option("--check", "Check for updates without installing")
|
|
399
|
+
.action(async (options) => {
|
|
400
|
+
if (options.check) {
|
|
401
|
+
await handleUpdateCheck();
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
await handleUpdate();
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
// Parse arguments
|
|
408
|
+
program.parse();
|
|
409
|
+
// Check for updates (non-blocking)
|
|
410
|
+
// Skip for update and server commands (server handles it explicitly)
|
|
411
|
+
const isUpdateCommand = process.argv.includes("update");
|
|
412
|
+
const isServerCommand = process.argv.includes("server");
|
|
413
|
+
if (!isUpdateCommand && !isServerCommand) {
|
|
414
|
+
getUpdateNotification()
|
|
415
|
+
.then((notification) => {
|
|
416
|
+
if (notification) {
|
|
417
|
+
console.log();
|
|
418
|
+
console.log(chalk.yellow(notification));
|
|
419
|
+
console.log();
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
.catch(() => {
|
|
423
|
+
// Silently ignore update check failures
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=cli.js.map
|