@selvakumaresra/specship 0.7.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/commands/ss-domain.md +98 -0
  2. package/commands/ss-triage.md +177 -0
  3. package/dist/bin/specship.js +308 -0
  4. package/dist/bin/specship.js.map +1 -1
  5. package/dist/db/migrations.d.ts +1 -1
  6. package/dist/db/migrations.d.ts.map +1 -1
  7. package/dist/db/migrations.js +28 -1
  8. package/dist/db/migrations.js.map +1 -1
  9. package/dist/db/schema.sql +26 -2
  10. package/dist/db/spec-queries.d.ts +29 -0
  11. package/dist/db/spec-queries.d.ts.map +1 -1
  12. package/dist/db/spec-queries.js +63 -0
  13. package/dist/db/spec-queries.js.map +1 -1
  14. package/dist/enforce/enforce.d.ts +70 -0
  15. package/dist/enforce/enforce.d.ts.map +1 -0
  16. package/dist/enforce/enforce.js +125 -0
  17. package/dist/enforce/enforce.js.map +1 -0
  18. package/dist/extraction/specs/markdown-spec-extractor.d.ts +21 -0
  19. package/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
  20. package/dist/extraction/specs/markdown-spec-extractor.js +144 -0
  21. package/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
  22. package/dist/fitness/fitness.d.ts +75 -0
  23. package/dist/fitness/fitness.d.ts.map +1 -0
  24. package/dist/fitness/fitness.js +204 -0
  25. package/dist/fitness/fitness.js.map +1 -0
  26. package/dist/graph/maintainability.d.ts +101 -0
  27. package/dist/graph/maintainability.d.ts.map +1 -0
  28. package/dist/graph/maintainability.js +278 -0
  29. package/dist/graph/maintainability.js.map +1 -0
  30. package/dist/index.d.ts +65 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +149 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/installer/instructions-template.d.ts +5 -4
  35. package/dist/installer/instructions-template.d.ts.map +1 -1
  36. package/dist/installer/instructions-template.js +10 -4
  37. package/dist/installer/instructions-template.js.map +1 -1
  38. package/dist/installer/targets/claude.d.ts.map +1 -1
  39. package/dist/installer/targets/claude.js +4 -0
  40. package/dist/installer/targets/claude.js.map +1 -1
  41. package/dist/installer/targets/shared.d.ts.map +1 -1
  42. package/dist/installer/targets/shared.js +4 -0
  43. package/dist/installer/targets/shared.js.map +1 -1
  44. package/dist/mcp/fitness-tool.d.ts +12 -0
  45. package/dist/mcp/fitness-tool.d.ts.map +1 -0
  46. package/dist/mcp/fitness-tool.js +46 -0
  47. package/dist/mcp/fitness-tool.js.map +1 -0
  48. package/dist/mcp/maintainability-tool.d.ts +13 -0
  49. package/dist/mcp/maintainability-tool.d.ts.map +1 -0
  50. package/dist/mcp/maintainability-tool.js +64 -0
  51. package/dist/mcp/maintainability-tool.js.map +1 -0
  52. package/dist/mcp/server-instructions.d.ts +1 -1
  53. package/dist/mcp/server-instructions.d.ts.map +1 -1
  54. package/dist/mcp/server-instructions.js +3 -2
  55. package/dist/mcp/server-instructions.js.map +1 -1
  56. package/dist/mcp/spec-tools.d.ts.map +1 -1
  57. package/dist/mcp/spec-tools.js +115 -1
  58. package/dist/mcp/spec-tools.js.map +1 -1
  59. package/dist/mcp/tools.d.ts +13 -0
  60. package/dist/mcp/tools.d.ts.map +1 -1
  61. package/dist/mcp/tools.js +75 -0
  62. package/dist/mcp/tools.js.map +1 -1
  63. package/dist/reflect/apply.d.ts +31 -0
  64. package/dist/reflect/apply.d.ts.map +1 -0
  65. package/dist/reflect/apply.js +286 -0
  66. package/dist/reflect/apply.js.map +1 -0
  67. package/dist/reflect/hash.d.ts +20 -0
  68. package/dist/reflect/hash.d.ts.map +1 -0
  69. package/dist/reflect/hash.js +36 -0
  70. package/dist/reflect/hash.js.map +1 -0
  71. package/dist/reflect/index.d.ts +16 -0
  72. package/dist/reflect/index.d.ts.map +1 -0
  73. package/dist/reflect/index.js +43 -0
  74. package/dist/reflect/index.js.map +1 -0
  75. package/dist/reflect/miner.d.ts +21 -0
  76. package/dist/reflect/miner.d.ts.map +1 -0
  77. package/dist/reflect/miner.js +463 -0
  78. package/dist/reflect/miner.js.map +1 -0
  79. package/dist/reflect/store.d.ts +31 -0
  80. package/dist/reflect/store.d.ts.map +1 -0
  81. package/dist/reflect/store.js +101 -0
  82. package/dist/reflect/store.js.map +1 -0
  83. package/dist/reflect/sweep.d.ts +26 -0
  84. package/dist/reflect/sweep.d.ts.map +1 -0
  85. package/dist/reflect/sweep.js +42 -0
  86. package/dist/reflect/sweep.js.map +1 -0
  87. package/dist/reflect/targets.d.ts +52 -0
  88. package/dist/reflect/targets.d.ts.map +1 -0
  89. package/dist/reflect/targets.js +192 -0
  90. package/dist/reflect/targets.js.map +1 -0
  91. package/dist/reflect/types.d.ts +96 -0
  92. package/dist/reflect/types.d.ts.map +1 -0
  93. package/dist/reflect/types.js +13 -0
  94. package/dist/reflect/types.js.map +1 -0
  95. package/dist/resolution/domain-gap-seed.d.ts +60 -0
  96. package/dist/resolution/domain-gap-seed.d.ts.map +1 -0
  97. package/dist/resolution/domain-gap-seed.js +87 -0
  98. package/dist/resolution/domain-gap-seed.js.map +1 -0
  99. package/dist/resolution/spec-link-resolver.d.ts +46 -1
  100. package/dist/resolution/spec-link-resolver.d.ts.map +1 -1
  101. package/dist/resolution/spec-link-resolver.js +78 -0
  102. package/dist/resolution/spec-link-resolver.js.map +1 -1
  103. package/dist/server/routes/domain.js +0 -0
  104. package/dist/server/routes/events.js +20 -0
  105. package/dist/server/routes/maintainability.js +18 -0
  106. package/dist/server/routes/reflect.js +93 -0
  107. package/dist/server/server.js +6 -0
  108. package/dist/types.d.ts +4 -2
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/types.js +6 -0
  111. package/dist/types.js.map +1 -1
  112. package/dist/web/chunk-EZZBWC7Z.js +1 -0
  113. package/dist/web/chunk-ITHLF4GI.js +1 -0
  114. package/dist/web/{chunk-UBOZGQNK.js → chunk-IZQXYQNQ.js} +1 -1
  115. package/dist/web/chunk-JBO7ZIPO.js +1 -0
  116. package/dist/web/chunk-JQXCRIK2.js +1 -0
  117. package/dist/web/{chunk-ASZ77FMZ.js → chunk-JT2YIHPL.js} +1 -1
  118. package/dist/web/{chunk-WLIMNDS3.js → chunk-ONKHTXHJ.js} +1 -1
  119. package/dist/web/{chunk-FHZHD2ZG.js → chunk-P5JX67LT.js} +1 -1
  120. package/dist/web/chunk-PDTQX2UL.js +6 -0
  121. package/dist/web/chunk-TPDB5GJN.js +1 -0
  122. package/dist/web/{chunk-RASJHUXS.js → chunk-XWDR6MPC.js} +1 -1
  123. package/dist/web/chunk-Y6WWDS4R.js +1 -0
  124. package/dist/web/chunk-Z5L3T5EO.js +1 -0
  125. package/dist/web/{chunk-D5OCNEJA.js → chunk-ZG7H3XPL.js} +1 -1
  126. package/dist/web/index.html +1 -1
  127. package/dist/web/main-GYPY5V5H.js +1 -0
  128. package/dist/workflows/executor.d.ts.map +1 -1
  129. package/dist/workflows/executor.js +3 -0
  130. package/dist/workflows/executor.js.map +1 -1
  131. package/dist/workflows/runners/prompt.d.ts +31 -8
  132. package/dist/workflows/runners/prompt.d.ts.map +1 -1
  133. package/dist/workflows/runners/prompt.js +117 -23
  134. package/dist/workflows/runners/prompt.js.map +1 -1
  135. package/dist/workflows/runners/types.d.ts +7 -1
  136. package/dist/workflows/runners/types.d.ts.map +1 -1
  137. package/package.json +1 -1
  138. package/dist/web/chunk-HGBF7AY5.js +0 -1
  139. package/dist/web/chunk-JQ534IB6.js +0 -6
  140. package/dist/web/chunk-MVOMVPYB.js +0 -1
  141. package/dist/web/chunk-NZEZCT65.js +0 -1
  142. package/dist/web/chunk-WQWYTRFN.js +0 -1
  143. package/dist/web/main-LHCYPOXF.js +0 -1
@@ -1 +0,0 @@
1
- import{b as B}from"./chunk-HZA6NEAB.js";import{a as A,c as j}from"./chunk-SHPTC4RL.js";import{a as W}from"./chunk-7RNS77UP.js";import{a as V}from"./chunk-E44X4RH2.js";import{Aa as p,Ga as P,I as w,Ia as b,Ka as c,M as y,N as C,O,P as I,R as z,Ta as R,Ua as E,Va as s,W as _,Wa as x,Xa as T,ea as o,ka as $,lb as h,qa as D,ra as u,sa as m,va as M,wa as S,xa as g,ya as d,za as a,zb as F}from"./chunk-PDN6QYGJ.js";import"./chunk-Q7L6LLAK.js";var H=(i,t)=>t.from+t.to,N=(i,t)=>t.id;function q(i,t){if(i&1){let e=P();d(0,"button",24),b("click",function(){y(e);let r=c(2);return C(r.cancel())}),p(1,"app-icon",25),s(2," Cancel "),a()}if(i&2){let e=c(2);g("disabled",e.actionPending()!==null),o(),g("size",12)}}function Q(i,t){if(i&1&&(d(0,"span",17),s(1),a(),d(2,"span",18),s(3),a(),p(4,"app-state-pill",19)(5,"span",20),d(6,"span",21),p(7,"app-icon",22),s(8),a(),u(9,q,3,2,"button",23)),i&2){let e=t,n=c();o(),x(e.workflowName),o(2),x(e.id.slice(0,8)),o(),g("state",e.status)("pulse",e.status==="running"),o(3),g("size",11),o(),T(" ",n.fmtDuration(e.startedAt,e.completedAt)," "),o(),m(e.status==="running"||e.status==="paused"?9:-1)}}function U(i,t){i&1&&(d(0,"span",26),s(1,"Loading\u2026"),a(),p(2,"span",20))}function J(i,t){if(i&1&&(d(0,"span",27),s(1),a(),p(2,"span",20)),i&2){let e=c();o(),x(e.error())}}function K(i,t){if(i&1&&(d(0,"div",4),s(1),a()),i&2){let e=c();o(),T("Action failed: ",e.actionError())}}function X(i,t){i&1&&(d(0,"div",4),s(1),a()),i&2&&(o(),x(t))}function Y(i,t){if(i&1){let e=P();d(0,"div",5)(1,"span",28),p(2,"app-icon",29),a(),d(3,"div",20)(4,"div",30),s(5,"Approval required \u2014 review diff before merge"),a(),d(6,"div",31),s(7," Review the artifacts carefully before approving. "),a()(),d(8,"button",32),b("click",function(){y(e);let r=c();return C(r.activeTab.set("artifacts"))}),s(9," Inspect artifacts "),a(),d(10,"button",24),b("click",function(){y(e);let r=c();return C(r.reject())}),s(11," Reject "),a(),d(12,"button",33),b("click",function(){y(e);let r=c();return C(r.approve())}),p(13,"app-icon",34),s(14," Approve "),a()()}if(i&2){let e=c();o(2),g("size",18),o(8),g("disabled",e.actionPending()!==null),o(2),g("disabled",e.actionPending()!==null),o(),g("size",13)}}function Z(i,t){if(i&1&&(O(),p(0,"path",35)),i&2){let e=c(),n=c(2);D("d",n.edgePath(e,t))("stroke",e.status==="completed"?"var(--success)":"rgba(150,160,180,0.4)")("opacity",e.status==="completed"?"0.7":"0.5")}}function ee(i,t){if(i&1&&u(0,Z,1,3,":svg:path",35),i&2){let e,n=c().$implicit,r=c();m((e=r.nodeMap()[n.to])?0:-1,e)}}function te(i,t){if(i&1&&u(0,ee,1,1),i&2){let e,n=t.$implicit,r=c();m((e=r.nodeMap()[n.from])?0:-1,e)}}function ne(i,t){i&1&&p(0,"app-icon",38),i&2&&g("size",11)}function ie(i,t){i&1&&p(0,"app-icon",39),i&2&&g("size",11)}function re(i,t){i&1&&p(0,"app-icon",40),i&2&&g("size",10)}function oe(i,t){if(i&1){let e=P();d(0,"div",36),b("click",function(){let r=y(e).$implicit,l=c();return C(l.selectedNode.set(r.id))}),d(1,"span",37),u(2,ne,1,1,"app-icon",38)(3,ie,1,1,"app-icon",39)(4,re,1,1,"app-icon",40),a(),d(5,"div",41)(6,"div",42),s(7),a(),d(8,"div",43),s(9),a()()()}if(i&2){let e=t.$implicit,n=c();R("left",e.x/n.DAG_W*100,"%")("top",e.y,"px")("border-color",n.nodeBorderColor(e))("box-shadow",n.nodeBoxShadow(e)),E("rd-node-running",e.status==="running")("rd-node-selected",n.selectedNode()===e.id)("rd-node-pending",e.status==="pending")("rd-node-skipped",e.status==="skipped"),D("aria-label",e.id),o(),R("background",n.nodeDotBg(e))("border",n.nodeDotBorder(e)),E("rd-dot-spin",e.status==="running"),o(),m(e.status==="completed"?2:e.status==="failed"?3:e.status==="paused"?4:-1),o(5),x(e.label),o(2),x(e.kind)}}function ae(i,t){i&1&&(d(0,"span",45),s(1,"live"),a())}function de(i,t){if(i&1){let e=P();d(0,"button",44),b("click",function(){let r=y(e).$implicit,l=c();return C(l.activeTab.set(r.id))}),s(1),u(2,ae,2,0,"span",45),a()}if(i&2){let e=t.$implicit,n=c();E("rd-tab-active",n.activeTab()===e.id),o(),T(" ",e.label," "),o(),m(e.id==="events"&&n.streamStatus()==="live"?2:-1)}}function se(i,t){if(i&1&&(d(0,"div",46)(1,"span",48),s(2),a(),d(3,"span",49),s(4),a(),d(5,"span",50),s(6),a(),d(7,"span",51),s(8),a()()),i&2){let e=t.$implicit,n=c(2);D("data-event-type",e.eventType),o(2),x(n.fmtTime(e.createdAt)),o(),R("color",n.evColor(e.eventType)),o(),x(e.eventType),o(2),x(n.stepIdOf(e)),o(2),x(n.eventDetail(e))}}function le(i,t){i&1&&(d(0,"div",47),p(1,"span",52),s(2," streaming\u2026 "),a())}function ce(i,t){if(i&1&&(d(0,"div",14),M(1,se,9,7,"div",46,N),u(3,le,3,0,"div",47),a()),i&2){let e=c();o(),S(e.events()),o(2),m(e.streamStatus()==="live"||e.streamStatus()==="connecting"?3:-1)}}function pe(i,t){i&1&&(d(0,"div",15)(1,"div",53),s(2," No artifacts available from the API. "),a()())}function ue(i,t){i&1&&(d(0,"div",16)(1,"div",54),s(2,"Cost data is not available from the API."),a()())}var me={step_started:"var(--info)",step_completed:"var(--success)",tool_called:"var(--node-code)",artifact_created:"var(--node-route)",approval_requested:"var(--warn)",run_started:"var(--info)",run_completed:"var(--success)",run_failed:"var(--error)",run_cancelled:"var(--text-muted)",run_paused:"var(--warn)"},G=class i{api=w(V);projects=w(W);route=w(A);router=w(j);destroyRef=w(z);runId=_("");run=_(null);events=_([]);loading=_(!0);error=_(null);streamStatus=_("connecting");actionPending=_(null);actionError=_(null);closeStream=null;status=h(()=>this.run()?.status??null);isTerminal=h(()=>{let t=this.status();return t==="completed"||t==="failed"||t==="cancelled"});approvalPending=h(()=>[...this.events()].reverse().find(e=>e.eventType==="approval_requested"||e.eventType==="approval_granted"||e.eventType==="approval_rejected")?.eventType==="approval_requested");TABS=[{id:"events",label:"Events"},{id:"artifacts",label:"Artifacts"},{id:"cost",label:"Cost"}];activeTab=_("events");DAG_W=920;DAG_H=180;dagNodes=h(()=>{let t=this.run(),e=this.stepStatusMap(),n=t?.metadata?.nodes;if(n?.length){let v=this.layoutCols(n.map(f=>f.id));return n.map((f,k)=>{let L=v[k]??k;return{id:f.id,label:f.id,kind:f.kind??"agent",status:e[f.id]??"pending",x:L*160+20,y:72}})}let r=[...new Set(this.events().map(v=>v.data?.stepId??v.stepId??"").filter(Boolean))];if(!r.length)return[];let l=Math.min(160,(this.DAG_W-40)/Math.max(r.length,1));return r.map((v,f)=>({id:v,label:v,kind:this.events().find(k=>(k.data?.stepId??k.stepId)===v)?.stepKind??"step",status:e[v]??"pending",x:f*l+20,y:72}))});dagEdges=h(()=>{let e=this.run()?.metadata?.edges;if(e?.length)return e;let n=this.dagNodes();return n.slice(0,-1).map((r,l)=>({from:r.id,to:n[l+1].id}))});nodeMap=h(()=>{let t={};for(let e of this.dagNodes())t[e.id]=e;return t});selectedNode=_("");stepStatusMap=h(()=>{let t={};for(let e of this.events()){let n=e.data?.stepId??e.stepId??"";if(n)switch(e.eventType){case"step_started":t[n]="running";break;case"step_completed":t[n]="completed";break;case"step_failed":t[n]="failed";break;case"step_skipped":t[n]="skipped";break}}if(this.status()==="paused")for(let e of Object.keys(t))t[e]==="running"&&(t[e]="paused");return t});ngOnInit(){let t=this.route.snapshot.paramMap.get("id")??"";if(!t){this.error.set("No run id"),this.loading.set(!1);return}this.runId.set(t),this.bootstrap(t)}ngOnDestroy(){this.closeStream?.(),this.closeStream=null}async bootstrap(t){try{let e=await this.api.get(`/api/workflows/runs/${encodeURIComponent(t)}${this.projects.projectQuery()}`);this.run.set(e.run),this.events.set(e.events??[]),this.loading.set(!1),this.isTerminal()?this.streamStatus.set("closed"):this.openStream(t)}catch(e){this.error.set(e instanceof Error?e.message:String(e)),this.loading.set(!1)}}openStream(t){this.streamStatus.set("connecting");let e=this.api.openEventStream(`/api/workflows/runs/${encodeURIComponent(t)}/events${this.projects.projectQuery()}`,(n,r)=>{if(n==="done"){this.streamStatus.set("closed"),this.refreshRun();return}let l=r;!l||typeof l!="object"||l.id==null||(this.streamStatus.set("live"),this.appendEvent(l),n.startsWith("run_")&&this.refreshRun())},()=>{this.streamStatus.set("error")});this.closeStream=e,this.destroyRef.onDestroy(()=>e())}appendEvent(t){this.events.update(e=>{if(e.some(r=>r.id===t.id))return e;let n=[...e,t];return n.sort((r,l)=>r.id-l.id),n})}async refreshRun(){try{let t=this.runId();if(!t)return;let e=await this.api.get(`/api/workflows/runs/${encodeURIComponent(t)}${this.projects.projectQuery()}`);this.run.set(e.run)}catch{}}async approve(){await this.action("approve")}async reject(){let t=prompt("Reason for rejecting?")??void 0;await this.action("reject",t?{reason:t}:void 0)}async cancel(){confirm("Cancel this run?")&&await this.action("cancel")}async resume(){await this.action("resume")}async action(t,e){this.actionPending.set(t),this.actionError.set(null);try{await this.api.post(`/api/workflows/runs/${encodeURIComponent(this.runId())}/${t}${this.projects.projectQuery()}`,e??{}),await this.refreshRun(),(t==="resume"||t==="approve")&&!this.isTerminal()&&!this.closeStream&&this.openStream(this.runId())}catch(n){this.actionError.set(n instanceof Error?n.message:String(n))}finally{this.actionPending.set(null)}}fmtTime(t){return t?new Date(t).toLocaleTimeString():"\u2014"}fmtDuration(t,e){if(!t)return"\u2014";let r=(e??Date.now())-t;return r>=6e4?Math.round(r/6e4)+"m "+Math.round(r%6e4/1e3)+"s":r>=1e3?(r/1e3).toFixed(1)+"s":r+"ms"}eventDetail(t){if(!t.data)return"";let e=t.data.output,n=t.data.error;if(typeof n=="string")return n;if(typeof e=="string")return e.length>200?e.slice(0,200)+"\u2026":e;if(e!=null)try{let r=JSON.stringify(e);return r.length>200?r.slice(0,200)+"\u2026":r}catch{return""}return""}stepIdOf(t){return t.data?.stepId??t.stepId??""}evColor(t){return me[t]??"var(--text-secondary)"}back(){this.router.navigate(["/runs"])}edgePath(t,e){let n=t.x+150,r=t.y+18,l=e.x,v=e.y+18,f=(n+l)/2;return`M ${n} ${r} C ${f} ${r}, ${f} ${v}, ${l} ${v}`}nodeBorderColor(t){return this.selectedNode()===t.id?"var(--accent)":t.status==="pending"||t.status==="skipped"?"var(--border-subtle)":{running:"var(--info)",completed:"var(--success)",failed:"var(--error)",paused:"var(--warn)"}[t.status]??"var(--border-subtle)"}nodeBoxShadow(t){return t.status==="running"?"0 0 0 3px var(--info-soft)":this.selectedNode()===t.id?"0 4px 14px rgba(0,0,0,0.4)":"none"}nodeDotBg(t){return t.status==="completed"?"var(--success)":t.status==="failed"?"var(--error)":t.status==="paused"?"var(--warn)":"transparent"}nodeDotBorder(t){return t.status==="pending"||t.status==="running"||t.status==="skipped"?`1.5px solid ${{pending:"var(--text-muted)",running:"var(--info)",skipped:"var(--text-muted)"}[t.status]}`:"none"}layoutCols(t){return t.map((e,n)=>n)}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=$({type:i,selectors:[["app-run-detail"]],decls:27,vars:10,consts:[[1,"col","rd-root"],[1,"row","gap-10","rd-head"],["type","button",1,"btn","btn-ghost","btn-sm",3,"click"],["name","chevronLeft",3,"size"],[1,"rd-banner","rd-banner-error"],[1,"row","gap-12","rd-approval"],[1,"rd-dag"],["width","100%",1,"rd-dag-svg"],["id","rarrow","viewBox","0 0 10 10","refX","8","refY","5","markerWidth","6","markerHeight","6","orient","auto-start-reverse"],["d","M0 0 L10 5 L0 10 z","fill","rgba(160,170,190,0.6)"],["role","button",1,"rd-node",3,"rd-node-running","rd-node-selected","rd-node-pending","rd-node-skipped","left","top","border-color","box-shadow"],[1,"col","rd-panel"],[1,"row","gap-2","rd-tabs"],["type","button",1,"rd-tab",3,"rd-tab-active"],["aria-live","polite",1,"scroll-y","rd-events"],[1,"rd-artifacts","row"],[1,"rd-cost-wrap",2,"padding","16px"],[1,"mono","rd-wf-name"],[1,"mono","muted",2,"font-size","11.5px"],[3,"state","pulse"],[1,"grow"],[1,"mono","muted","row","gap-4",2,"font-size","11.5px"],["name","clock",3,"size"],["type","button",1,"btn","btn-destructive","btn-sm",3,"disabled"],["type","button",1,"btn","btn-destructive","btn-sm",3,"click","disabled"],["name","cancel",3,"size"],[1,"muted",2,"font-size","12px"],[1,"rd-error"],[2,"color","var(--warn)","flex-shrink","0"],["name","pause",3,"size"],[2,"font-weight","600","font-size","13px"],[1,"secondary",2,"font-size","12px","margin-top","1px"],["type","button",1,"btn","btn-secondary","btn-sm",3,"click"],["type","button",1,"btn","btn-primary","btn-sm",3,"click","disabled"],["name","check",3,"size"],["fill","none","stroke-width","1.6","marker-end","url(#rarrow)"],["role","button",1,"rd-node",3,"click"],[1,"rd-node-dot"],["name","check",2,"color","#fff",3,"size"],["name","x",2,"color","#fff",3,"size"],["name","pause",2,"color","#fff",3,"size"],[1,"grow",2,"min-width","0"],[1,"rd-node-label"],[1,"mono","muted","rd-node-type"],["type","button",1,"rd-tab",3,"click"],[1,"pill","rd-live-pill"],[1,"row","gap-10","rd-event-row"],[1,"row","gap-6","muted",2,"padding","6px 0"],[1,"muted","tabular","rd-event-time"],[1,"rd-event-kind"],[1,"muted","rd-event-node"],[1,"secondary","rd-event-text"],[1,"rd-stream-dot"],[1,"muted","rd-no-artifacts",2,"margin","auto","font-size","12.5px"],[1,"muted",2,"font-size","12.5px"]],template:function(e,n){if(e&1&&(d(0,"div",0)(1,"div",1)(2,"button",2),b("click",function(){return n.back()}),p(3,"app-icon",3),s(4," Runs "),a(),u(5,Q,10,7)(6,U,3,0)(7,J,3,1),a(),u(8,K,2,1,"div",4),u(9,X,2,1,"div",4),u(10,Y,15,4,"div",5),d(11,"div",6),O(),d(12,"svg",7)(13,"defs")(14,"marker",8),p(15,"path",9),a()(),M(16,te,1,1,null,null,H),a(),M(18,oe,10,26,"div",10,N),a(),I(),d(20,"div",11)(21,"div",12),M(22,de,3,4,"button",13,N),a(),u(24,ce,4,1,"div",14),u(25,pe,3,0,"div",15),u(26,ue,3,0,"div",16),a()()),e&2){let r,l;o(3),g("size",14),o(2),m((r=n.run())?5:n.loading()?6:n.error()?7:-1,r),o(3),m(n.actionError()?8:-1),o(),m((l=(l=n.run())==null?null:l.errorMessage)?9:-1,l),o(),m(n.approvalPending()?10:-1),o(2),D("height",n.DAG_H)("viewBox","0 0 "+n.DAG_W+" "+n.DAG_H),o(4),S(n.dagEdges()),o(2),S(n.dagNodes()),o(4),S(n.TABS),o(2),m(n.activeTab()==="events"?24:-1),o(),m(n.activeTab()==="artifacts"?25:-1),o(),m(n.activeTab()==="cost"?26:-1)}},dependencies:[B,F],styles:["[_nghost-%COMP%]{display:contents}.rd-root[_ngcontent-%COMP%]{flex:1;min-height:0}.rd-head[_ngcontent-%COMP%]{padding:12px 16px;border-bottom:1px solid var(--border-subtle);flex-shrink:0}.rd-wf-name[_ngcontent-%COMP%]{font-weight:600;font-size:14px}.rd-error[_ngcontent-%COMP%]{color:var(--error);font-size:12px}.rd-banner[_ngcontent-%COMP%]{padding:10px 16px;font-size:12.5px;flex-shrink:0}.rd-banner-error[_ngcontent-%COMP%]{background:var(--error-soft);color:var(--error);border-bottom:1px solid color-mix(in srgb,var(--error) 30%,transparent)}.rd-approval[_ngcontent-%COMP%]{padding:12px 16px;background:var(--warn-soft);border-bottom:1px solid rgba(229,165,10,.3);flex-shrink:0}.rd-dag[_ngcontent-%COMP%]{position:relative;height:180px;background:var(--bg-canvas-2, var(--bg-canvas));background-image:radial-gradient(circle,var(--dot-grid, rgba(255, 255, 255, .07)) 1px,transparent 1px);background-size:20px 20px;border-bottom:1px solid var(--border-subtle);overflow:hidden;flex-shrink:0}.rd-dag-svg[_ngcontent-%COMP%]{position:absolute;inset:0;pointer-events:none}.rd-node[_ngcontent-%COMP%]{position:absolute;width:150px;height:36px;display:flex;align-items:center;gap:8px;padding:0 11px;border-radius:8px;background:var(--bg-panel);border:1.5px solid var(--border-subtle);cursor:pointer;transition:border-color .12s,box-shadow .12s}.rd-node[_ngcontent-%COMP%]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.rd-node-running[_ngcontent-%COMP%]{background:var(--info-soft)}.rd-node-pending[_ngcontent-%COMP%]{opacity:.6}.rd-node-skipped[_ngcontent-%COMP%]{border-style:dotted}.rd-node-dot[_ngcontent-%COMP%]{width:18px;height:18px;border-radius:50%;display:grid;place-items:center;flex-shrink:0}.rd-dot-spin[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_rd-spin 1.4s linear infinite;border-top-color:transparent!important}@keyframes _ngcontent-%COMP%_rd-spin{to{transform:rotate(360deg)}}.rd-node-label[_ngcontent-%COMP%]{font-size:12px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rd-node-type[_ngcontent-%COMP%]{font-size:9px}.rd-panel[_ngcontent-%COMP%]{flex:1;min-height:0}.rd-tabs[_ngcontent-%COMP%]{padding:8px 14px 0;border-bottom:1px solid var(--border-subtle);flex-shrink:0}.rd-tab[_ngcontent-%COMP%]{padding:7px 13px;border:none;background:transparent;cursor:pointer;font-size:12.5px;font-weight:500;font-family:var(--font-ui);text-transform:capitalize;color:var(--text-muted);border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px;transition:color .1s}.rd-tab[_ngcontent-%COMP%]:hover{color:var(--text-secondary)}.rd-tab-active[_ngcontent-%COMP%]{color:var(--text-primary);border-bottom-color:var(--accent)}.rd-live-pill[_ngcontent-%COMP%]{font-size:9px;background:var(--info-soft);color:var(--info)}.rd-events[_ngcontent-%COMP%]{flex:1;padding:8px 14px;font-family:var(--font-mono);font-size:11.5px;min-height:0}.rd-event-row[_ngcontent-%COMP%]{padding:4px 0;border-bottom:1px solid rgba(255,255,255,.03)}.rd-event-time[_ngcontent-%COMP%]{flex-shrink:0;width:80px;font-size:11px}.rd-event-kind[_ngcontent-%COMP%]{width:132px;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rd-event-node[_ngcontent-%COMP%]{flex-shrink:0;width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.rd-event-text[_ngcontent-%COMP%]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.rd-stream-dot[_ngcontent-%COMP%]{width:6px;height:6px;border-radius:50%;background:var(--info);animation:_ngcontent-%COMP%_rd-pulse 1s infinite}@keyframes _ngcontent-%COMP%_rd-pulse{0%,to{opacity:1}50%{opacity:.3}}.rd-artifacts[_ngcontent-%COMP%]{flex:1;min-height:0}.rd-no-artifacts[_ngcontent-%COMP%]{padding:40px;text-align:center}"],changeDetection:0})};export{G as RunDetail};
@@ -1 +0,0 @@
1
- import{a as D}from"./chunk-X2HTISHL.js";import{a as $}from"./chunk-UYC52MBC.js";import{a as R}from"./chunk-WDU3WICG.js";import{c as I}from"./chunk-GR72OOCN.js";import{c as F}from"./chunk-SHPTC4RL.js";import{a as O}from"./chunk-7RNS77UP.js";import{a as z}from"./chunk-E44X4RH2.js";import{Aa as c,Ga as h,I as k,Ia as m,Ka as p,M as f,N as u,Va as l,W,Wa as y,Xa as b,bb as _,ea as o,ka as P,lb as V,ra as w,sa as x,ua as M,va as v,wa as C,xa as s,ya as i,za as r,zb as j}from"./chunk-PDN6QYGJ.js";import{a as S,b as T}from"./chunk-Q7L6LLAK.js";var g=()=>[],A=(t,n)=>n.workflow.name,N=(t,n)=>n.name;function L(t,n){t&1&&c(0,"app-pick-project-empty",0)}function G(t,n){if(t&1&&(i(0,"code",15),l(1),r()),t&2){let e=n.$implicit;o(),y(e)}}function H(t,n){if(t&1&&(i(0,"code",17),l(1),r()),t&2){let e=n.$implicit;o(),b("$",e.name)}}function Q(t,n){if(t&1&&(i(0,"span",16),l(1,"inputs"),r(),v(2,H,2,1,"code",17,N)),t&2){let e=p().$implicit;o(2),C(e.workflow.inputs??_(0,g))}}function Y(t,n){if(t&1){let e=h();i(0,"div",4)(1,"div",6)(2,"span",7),l(3),r(),i(4,"app-pill",8),l(5),r(),c(6,"span",9),i(7,"button",10),m("click",function(){let d=f(e).$implicit,E=p(2);return u(E.openModal(d))}),c(8,"app-icon",11),l(9," Run "),r()(),i(10,"div",12),l(11),r(),i(12,"div",13)(13,"span",14),l(14,"requires"),r(),v(15,G,2,1,"code",15,M),w(17,Q,4,1),r()()}if(t&2){let e=n.$implicit,a=p(2);o(3),y(e.workflow.name),o(),s("color",a.scopeColor[e.scope])("bg",a.scopeBg[e.scope]),o(),y(e.scope),o(3),s("size",12),o(3),y(e.workflow.description||"\u2014"),o(4),C(e.workflow.requires??_(7,g)),o(2),x((e.workflow.inputs??_(8,g)).length>0?17:-1)}}function J(t,n){t&1&&(i(0,"span",33),l(1," *"),r())}function K(t,n){if(t&1){let e=h();i(0,"div",31)(1,"label",32),l(2),w(3,J,2,0,"span",33),r(),i(4,"input",34),m("input",function(d){let E=f(e).$implicit,B=p(4);return u(B.setVal(E.name,d.target.value))}),r()()}if(t&2){let e=n.$implicit,a=p(4);o(2),b(" ",e.name," "),o(),x(e.required?3:-1),o(),s("placeholder",e.description||e.name)("value",a.modalVals()[e.name]||"")}}function U(t,n){if(t&1&&v(0,K,5,4,"div",31,N),t&2){let e=p();C(e.workflow.inputs??_(0,g))}}function X(t,n){t&1&&(i(0,"div",27),l(1,"No inputs required."),r())}function Z(t,n){if(t&1&&(i(0,"app-pill"),c(1,"app-icon",35),l(2),r()),t&2){let e=n.$implicit;o(),s("size",10),o(),b(" ",e," ")}}function ee(t,n){if(t&1&&(i(0,"div",28),v(1,Z,3,2,"app-pill",null,M),r()),t&2){let e=p();o(),C(e.workflow.requires??_(0,g))}}function te(t,n){if(t&1){let e=h();i(0,"div",18),m("mousedown",function(){f(e);let d=p(2);return u(d.closeModal())}),i(1,"div",19),m("mousedown",function(d){return d.stopPropagation()}),i(2,"div",20),c(3,"app-icon",21),i(4,"span",22),l(5),r(),i(6,"button",23),m("click",function(){f(e);let d=p(2);return u(d.closeModal())}),c(7,"app-icon",24),r()(),i(8,"div",25)(9,"div",26),l(10),r(),w(11,U,2,1)(12,X,2,0,"div",27),w(13,ee,3,1,"div",28),r(),i(14,"div",29)(15,"button",30),m("click",function(){f(e);let d=p(2);return u(d.closeModal())}),l(16,"Cancel"),r(),i(17,"button",10),m("click",function(){f(e);let d=p(2);return u(d.launchRun())}),c(18,"app-icon",11),l(19," Launch run "),r()()()()}if(t&2){let e=n;o(3),s("size",16),o(2),y(e.workflow.name),o(2),s("size",14),o(3),b(" ",e.workflow.description," "),o(),x((e.workflow.inputs??_(7,g)).length>0?11:12),o(2),x((e.workflow.requires??_(8,g)).length>0?13:-1),o(5),s("size",13)}}function ne(t,n){if(t&1&&(i(0,"div",1),c(1,"app-page-head",2),i(2,"div",3),v(3,Y,18,9,"div",4,A),r()(),w(5,te,20,9,"div",5)),t&2){let e,a=p();o(3),C(a.entries()),o(2),x((e=a.modalEntry())?5:-1,e)}}var q=class t{api=k(z);projects=k(O);router=k(F);resource=I(this.api,()=>`/api/workflows${this.projects.projectQuery()}`);entries=V(()=>this.resource.state().data?.workflows??[]);modalEntry=W(null);modalVals=W({});scopeColor={bundled:"var(--node-spec)",global:"var(--node-code)",project:"var(--node-route)"};scopeBg={bundled:"color-mix(in srgb, var(--node-spec) 14%, transparent)",global:"color-mix(in srgb, var(--node-code) 14%, transparent)",project:"color-mix(in srgb, var(--node-route) 14%, transparent)"};openModal(n){this.modalVals.set({}),this.modalEntry.set(n)}closeModal(){this.modalEntry.set(null)}setVal(n,e){this.modalVals.update(a=>T(S({},a),{[n]:e}))}async launchRun(){this.modalEntry()&&(this.closeModal(),this.router.navigate(["/runs"]))}static \u0275fac=function(e){return new(e||t)};static \u0275cmp=P({type:t,selectors:[["app-workflows"]],decls:2,vars:1,consts:[["surface","Workflows"],[1,"scroll-y","wf-page"],["icon","workflow","title","Workflows","sub","Run a YAML-defined DAG of agent, shell and approval steps"],[1,"wf-grid"],[1,"card","card-pad","wf-card"],[1,"wf-overlay"],[1,"row","gap-8"],[1,"mono","wf-name"],[3,"color","bg"],[1,"grow"],["type","button",1,"btn","btn-primary","btn-sm",3,"click"],["name","play",3,"size"],[1,"secondary","wf-desc"],[1,"row","gap-6","wf-footer"],[1,"muted",2,"font-size","10.5px"],[1,"mono","wf-req-chip"],[1,"muted",2,"font-size","10.5px","margin-left","6px"],[1,"mono","wf-inp-chip"],[1,"wf-overlay",3,"mousedown"],[1,"wf-modal",3,"mousedown"],[1,"row","gap-10","wf-modal-head"],["name","workflow",2,"color","var(--accent)",3,"size"],[1,"mono","grow",2,"font-weight","600"],["type","button",1,"btn","btn-ghost","btn-xs",3,"click"],["name","x",3,"size"],[1,"wf-modal-body"],[1,"secondary",2,"font-size","12.5px","margin-bottom","16px","line-height","1.55"],[1,"muted",2,"font-size","12px","padding","8px 0"],[1,"row","gap-6",2,"margin-top","6px","margin-bottom","4px"],[1,"row","gap-8","wf-modal-foot"],["type","button",1,"btn","btn-ghost","btn-sm",3,"click"],[2,"margin-bottom","12px"],[1,"eyebrow",2,"display","block","margin-bottom","5px"],[2,"color","var(--error)"],[1,"input","mono",2,"width","100%",3,"input","placeholder","value"],["name","check",3,"size"]],template:function(e,a){e&1&&w(0,L,1,0,"app-pick-project-empty",0)(1,ne,6,1),e&2&&x(a.resource.state().noProject?0:1)},dependencies:[R,$,D,j],styles:["[_nghost-%COMP%]{display:contents}.wf-page[_ngcontent-%COMP%]{flex:1;padding:18px}.wf-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:1fr 1fr;gap:12px}.wf-card[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:10px}.wf-name[_ngcontent-%COMP%]{font-size:13.5px;font-weight:600}.wf-desc[_ngcontent-%COMP%]{font-size:12.5px;line-height:1.5;min-height:36px}.wf-footer[_ngcontent-%COMP%]{flex-wrap:wrap;border-top:1px solid var(--border-subtle);padding-top:10px}.wf-req-chip[_ngcontent-%COMP%]{font-size:10.5px;color:var(--text-secondary);background:var(--bg-canvas);padding:1px 6px;border-radius:4px;font-family:var(--font-mono)}.wf-inp-chip[_ngcontent-%COMP%]{font-size:10.5px;color:var(--node-spec);background:var(--node-spec-soft);padding:1px 6px;border-radius:4px;font-family:var(--font-mono)}.wf-overlay[_ngcontent-%COMP%]{position:fixed;inset:0;background:#00000080;z-index:90;display:grid;place-items:center}.wf-modal[_ngcontent-%COMP%]{width:460px;background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:12px;box-shadow:var(--shadow-pop)}.wf-modal-head[_ngcontent-%COMP%]{padding:14px 16px;border-bottom:1px solid var(--border-subtle)}.wf-modal-body[_ngcontent-%COMP%]{padding:16px}.wf-modal-foot[_ngcontent-%COMP%]{padding:12px 16px;border-top:1px solid var(--border-subtle);justify-content:flex-end}"],changeDetection:0})};export{q as Workflows};
@@ -1 +0,0 @@
1
- import{E as n,I as p,R as l,W as s,X as y,lb as f}from"./chunk-PDN6QYGJ.js";import{a as o,b as d}from"./chunk-Q7L6LLAK.js";var m="specship.theme",h=class i{destroyRef=p(l);pref=s(this.loadPref());effective=s("dark");constructor(){this.applyEffective();let e=window.matchMedia("(prefers-color-scheme: light)"),t=()=>{this.pref()==="system"&&this.applyEffective()};e.addEventListener("change",t),this.destroyRef.onDestroy(()=>e.removeEventListener("change",t)),y(()=>{let r=this.pref();try{localStorage.setItem(m,r)}catch{}this.applyEffective()})}setPref(e){this.pref.set(e)}toggle(){this.setPref(this.effective()==="dark"?"light":"dark")}loadPref(){try{let e=localStorage.getItem(m);if(e==="dark"||e==="light"||e==="system")return e}catch{}return"dark"}applyEffective(){let e=window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark",t=this.pref(),r=t==="system"?e:t;document.documentElement.setAttribute("data-theme",r),this.effective.set(r)}static \u0275fac=function(t){return new(t||i)};static \u0275prov=n({token:i,factory:i.\u0275fac,providedIn:"root"})};var u="specship.notify.prefs",a={approval:!0,runDone:!0,drift:!0},g=class i{permission=s("default");prefs=s(this.loadPrefs());supported=f(()=>this.permission()!=="unsupported");granted=f(()=>this.permission()==="granted");constructor(){if(typeof window>"u"||typeof Notification>"u"){this.permission.set("unsupported");return}this.permission.set(Notification.permission)}enabled(e){return this.prefs()[e]!==!1}toggle(e){let t=d(o({},this.prefs()),{[e]:!this.enabled(e)});this.prefs.set(t),this.savePrefs(t)}async requestPermission(){if(typeof Notification>"u"){this.permission.set("unsupported");return}try{let e=await Notification.requestPermission();this.permission.set(e)}catch{}}notify(e,t,r={}){if(!(this.permission()!=="granted"||!this.enabled(e))&&!(typeof Notification>"u"))try{let c=new Notification(t,{body:r.body,tag:r.tag});r.onClick&&(c.onclick=()=>{try{window.focus()}catch{}r.onClick(),c.close()})}catch{}}loadPrefs(){if(typeof localStorage>"u")return o({},a);try{let e=localStorage.getItem(u);return e?o(o({},a),JSON.parse(e)):o({},a)}catch{return o({},a)}}savePrefs(e){if(!(typeof localStorage>"u"))try{localStorage.setItem(u,JSON.stringify(e))}catch{}}static \u0275fac=function(t){return new(t||i)};static \u0275prov=n({token:i,factory:i.\u0275fac,providedIn:"root"})};export{h as a,g as b};
@@ -1 +0,0 @@
1
- import{a as G,b as he}from"./chunk-WQWYTRFN.js";import{a as fe,b as ve,c as B}from"./chunk-GR72OOCN.js";import{b as ce,c as z,d as me,e as ue,f as ge}from"./chunk-SHPTC4RL.js";import{a as I}from"./chunk-7RNS77UP.js";import{a as H}from"./chunk-E44X4RH2.js";import{$ as ae,Aa as c,Ba as d,Ca as p,Da as C,E as $,Ga as k,Ha as V,I as f,Ia as b,Ja as R,Ka as g,M as y,N as P,O as ee,R as ie,Ta as se,Ua as w,V as oe,Va as s,W as S,Wa as h,Xa as A,Ya as le,ca as re,cb as de,da as te,ea as o,ka as x,lb as D,ob as F,pb as E,qa as M,ra as m,sa as u,va as T,wa as j,wb as pe,xa as v,ya as a,za as r,zb as L}from"./chunk-PDN6QYGJ.js";import"./chunk-Q7L6LLAK.js";var _e=[{path:"",pathMatch:"full",redirectTo:"dashboard"},{path:"dashboard",loadComponent:()=>import("./chunk-D5OCNEJA.js").then(e=>e.Dashboard),data:{nav:"dashboard",title:"Dashboard"}},{path:"graph",loadComponent:()=>import("./chunk-WLIMNDS3.js").then(e=>e.Graph),data:{nav:"graph",title:"Graph"}},{path:"specs",loadComponent:()=>import("./chunk-JQ534IB6.js").then(e=>e.Specs),data:{nav:"specs",title:"Specs"}},{path:"drift",loadComponent:()=>import("./chunk-FHZHD2ZG.js").then(e=>e.Drift),data:{nav:"drift",title:"Drift queue"}},{path:"workflows",loadComponent:()=>import("./chunk-NZEZCT65.js").then(e=>e.Workflows),data:{nav:"workflows",title:"Workflows"}},{path:"runs",loadComponent:()=>import("./chunk-UBOZGQNK.js").then(e=>e.Runs),data:{nav:"runs",title:"Runs"}},{path:"runs/:id",loadComponent:()=>import("./chunk-MVOMVPYB.js").then(e=>e.RunDetail),data:{nav:"runs",title:"Run detail"}},{path:"chat",loadComponent:()=>import("./chunk-L37MTFSG.js").then(e=>e.Chat),data:{nav:"chat",title:"Chat"}},{path:"sessions",loadComponent:()=>import("./chunk-ASZ77FMZ.js").then(e=>e.Sessions),data:{nav:"sessions",title:"Sessions"}},{path:"sessions/:id",loadComponent:()=>import("./chunk-RASJHUXS.js").then(e=>e.SessionDetail),data:{nav:"sessions",title:"Session detail"}},{path:"heatmap",loadComponent:()=>import("./chunk-YAMRN47K.js").then(e=>e.Heatmap),data:{nav:"heatmap",title:"Heatmap"}},{path:"costs",loadComponent:()=>import("./chunk-WCHGDXWC.js").then(e=>e.Costs),data:{nav:"costs",title:"Costs"}},{path:"specship-impact",loadComponent:()=>import("./chunk-TQ3P2QZO.js").then(e=>e.SpecshipImpact),data:{nav:"specship-impact",title:"SpecShip Impact"}},{path:"compare",loadComponent:()=>import("./chunk-WCKHQIYN.js").then(e=>e.Compare),data:{nav:"compare",title:"Compare projects"}},{path:"tips",loadComponent:()=>import("./chunk-A5R3MJMO.js").then(e=>e.Tips),data:{nav:"tips",title:"Tips"}},{path:"memory",loadComponent:()=>import("./chunk-45QHGCB4.js").then(e=>e.Memory),data:{nav:"memory",title:"Memory"}},{path:"design",loadComponent:()=>import("./chunk-WAI2JMZP.js").then(e=>e.Design),data:{nav:"design",title:"Design system"}},{path:"settings",loadComponent:()=>import("./chunk-HGBF7AY5.js").then(e=>e.Settings),data:{nav:"settings",title:"Settings"}},{path:"**",redirectTo:"dashboard"}];var be={providers:[oe(),ge(_e)]};function xe(e,n){e&1&&(ee(),C(0,"rect",14)(1,"rect",15))}var q=class e{size=E(24);tile=E(!0);glow=E(!0);static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-logo-mark"]],inputs:{size:[1,"size"],tile:[1,"tile"],glow:[1,"glow"]},decls:16,vars:5,consts:[["viewBox","0 0 32 32","fill","none",2,"flex-shrink","0"],["id","ssTile","x1","0","y1","0","x2","32","y2","32","gradientUnits","userSpaceOnUse"],["stop-color","#12161E"],["offset","1","stop-color","#0B0D11"],["id","ssLead","x1","18","y1","11","x2","26","y2","21","gradientUnits","userSpaceOnUse"],["stop-color","#6FA0F6"],["offset","1","stop-color","#5B93F2"],["transform","translate(4.6 4.6) scale(0.715)"],["d","M5 16 H11 M11 9 L23 16 L11 23","stroke","rgba(150,165,200,0.5)","stroke-width","1.9","stroke-linecap","round","stroke-linejoin","round","fill","none"],["x1","11","y1","9","x2","11","y2","23","stroke","rgba(150,165,200,0.4)","stroke-width","1.9","stroke-linecap","round"],["cx","23","cy","16","r","3.6","fill","url(#ssLead)"],["cx","11","cy","9","r","2.9","fill","#A586F5"],["cx","11","cy","23","r","2.9","fill","#46C26B"],["cx","5","cy","16","r","2.1","fill","#29D2BE"],["width","32","height","32","rx","7.2","fill","url(#ssTile)"],["x","0.5","y","0.5","width","31","height","31","rx","6.7","fill","none","stroke","rgba(255,255,255,0.08)"]],template:function(t,i){t&1&&(ee(),d(0,"svg",0)(1,"defs")(2,"linearGradient",1),C(3,"stop",2)(4,"stop",3),p(),d(5,"linearGradient",4),C(6,"stop",5)(7,"stop",6),p()(),m(8,xe,2,0),d(9,"g",7),C(10,"path",8)(11,"line",9)(12,"circle",10)(13,"circle",11)(14,"circle",12)(15,"circle",13),p()()),t&2&&(se("filter",i.glow()?"drop-shadow(0 0 9px rgba(91,147,242,0.35))":"none"),M("width",i.size())("height",i.size()),o(8),u(i.tile()?8:-1))},styles:["[_nghost-%COMP%]{display:inline-flex;align-items:center;justify-content:center;line-height:0}"],changeDetection:0})};var Ce=e=>["/",e],ye=(e,n)=>n.group,Pe=(e,n)=>n.id;function ke(e,n){e&1&&(a(0,"div",3),s(1,"SpecShip "),a(2,"span",14),s(3,"Desktop"),r()())}function we(e,n){if(e&1&&(a(0,"div",15),s(1),r()),e&2){let t=g().$implicit;o(),h(t.group)}}function Se(e,n){if(e&1&&(a(0,"span",18),s(1),r()),e&2){let t=g(2).$implicit,i=g(2);M("data-kind",t.badgeKind),o(),h(i.badgeOf(t))}}function Me(e,n){if(e&1&&(a(0,"span",11),s(1),r(),m(2,Se,2,2,"span",18)),e&2){let t=g().$implicit,i=g(2);o(),h(t.label),o(),u(i.badgeOf(t)>0?2:-1)}}function Ee(e,n){if(e&1&&(a(0,"a",16),c(1,"span",8),a(2,"span",9),c(3,"app-icon",17),r(),m(4,Me,3,2),r()),e&2){let t=n.$implicit,i=g(2);v("routerLink",de(5,Ce,t.id))("title",i.collapsed()?t.label:null),o(3),v("name",t.icon)("size",16),o(),u(i.collapsed()?-1:4)}}function Oe(e,n){if(e&1&&(a(0,"div",5),m(1,we,2,1,"div",15),T(2,Ee,5,7,"a",16,Pe),r()),e&2){let t=n.$implicit,i=g();o(),u(i.collapsed()?-1:1),o(),j(t.items)}}function Te(e,n){e&1&&(a(0,"span",11),s(1,"Design system"),r())}function je(e,n){e&1&&(a(0,"span",11),s(1,"Settings"),r())}var K=class e{collapsed=E(!1);api=f(H);projects=f(I);status=B(this.api,()=>`/api/status${this.projects.projectQuery()}`);tips=B(this.api,()=>"/api/claude/tips");nav=[{group:"Project",items:[{id:"dashboard",label:"Dashboard",icon:"dashboard"},{id:"graph",label:"Graph",icon:"graph"},{id:"specs",label:"Specs",icon:"book"},{id:"drift",label:"Drift queue",icon:"drift",badge:()=>this.status.state().data?.drift??0,badgeKind:"warn"},{id:"workflows",label:"Workflows",icon:"workflow"},{id:"runs",label:"Runs",icon:"play"},{id:"chat",label:"Chat",icon:"chat"}]},{group:"Claude Code",items:[{id:"sessions",label:"Sessions",icon:"sessions"},{id:"heatmap",label:"Heatmap",icon:"heatmap"},{id:"costs",label:"Costs",icon:"dollar"},{id:"specship-impact",label:"SpecShip Impact",icon:"graph"},{id:"compare",label:"Compare projects",icon:"compare"},{id:"memory",label:"Memory",icon:"memory"},{id:"tips",label:"Tips",icon:"tips",badge:()=>(this.tips.state().data?.tips??[]).filter(n=>n.severity!=="info").length,badgeKind:"error"}]}];badgeOf(n){return n.badge?n.badge():0}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-sidebar"]],inputs:{collapsed:[1,"collapsed"]},decls:18,vars:10,consts:[[1,"sidebar"],[1,"brand"],[3,"size"],[1,"brand-text"],[1,"scroll-y","nav-scroll"],[1,"nav-group"],[1,"pinned"],["routerLink","/design","routerLinkActive","active",1,"nav-item",3,"title"],[1,"indicator"],[1,"nav-icon"],["name","palette",3,"size"],[1,"nav-label"],["routerLink","/settings","routerLinkActive","active",1,"nav-item",3,"title"],["name","settings",3,"size"],[1,"muted"],[1,"eyebrow","group-label"],["routerLinkActive","active",1,"nav-item",3,"routerLink","title"],[3,"name","size"],[1,"badge"]],template:function(t,i){t&1&&(a(0,"nav",0)(1,"div",1),c(2,"app-logo-mark",2),m(3,ke,4,0,"div",3),r(),a(4,"div",4),T(5,Oe,4,1,"div",5,ye),r(),a(7,"div",6)(8,"a",7),c(9,"span",8),a(10,"span",9),c(11,"app-icon",10),r(),m(12,Te,2,0,"span",11),r(),a(13,"a",12),c(14,"span",8),a(15,"span",9),c(16,"app-icon",13),r(),m(17,je,2,0,"span",11),r()()()),t&2&&(w("collapsed",i.collapsed()),o(2),v("size",26),o(),u(i.collapsed()?-1:3),o(2),j(i.nav),o(3),v("title",i.collapsed()?"Design system":null),o(3),v("size",16),o(),u(i.collapsed()?-1:12),o(),v("title",i.collapsed()?"Settings":null),o(3),v("size",16),o(),u(i.collapsed()?-1:17))},dependencies:[me,ue,L,q],styles:['@charset "UTF-8";[_nghost-%COMP%]{display:contents}.sidebar[_ngcontent-%COMP%]{width:var(--sidebar-w);flex-shrink:0;background:var(--bg-panel);border-right:1px solid var(--border-subtle);display:flex;flex-direction:column;transition:width .12s;overflow:hidden;font-family:var(--font-ui)}.sidebar.collapsed[_ngcontent-%COMP%]{width:var(--sidebar-w-collapsed)}.brand[_ngcontent-%COMP%]{display:flex;align-items:center;gap:8px;padding:15px 16px}.collapsed[_ngcontent-%COMP%] .brand[_ngcontent-%COMP%]{justify-content:center;padding:14px 0}.brand-text[_ngcontent-%COMP%]{font-weight:600;font-size:13.5px;letter-spacing:-.01em}.brand-text[_ngcontent-%COMP%] .muted[_ngcontent-%COMP%]{color:var(--text-muted);font-weight:400}.nav-scroll[_ngcontent-%COMP%]{flex:1;padding:4px 8px}.nav-group[_ngcontent-%COMP%]{margin-bottom:10px}.group-label[_ngcontent-%COMP%]{padding:8px 8px 4px}.nav-item[_ngcontent-%COMP%]{position:relative;display:flex;align-items:center;gap:10px;height:32px;padding:0 10px;border-radius:7px;text-decoration:none;margin-bottom:1px;color:var(--text-secondary);font-weight:450;font-size:13px;transition:background .1s}.collapsed[_ngcontent-%COMP%] .nav-item[_ngcontent-%COMP%]{padding:0;justify-content:center}.nav-item[_ngcontent-%COMP%]:hover{background:var(--bg-hover);color:var(--text-primary)}.nav-item.active[_ngcontent-%COMP%]{background:var(--bg-active);color:var(--text-primary);font-weight:600}.nav-item.active[_ngcontent-%COMP%] .indicator[_ngcontent-%COMP%]{position:absolute;left:0;top:7px;bottom:7px;width:2.5px;border-radius:2px;background:var(--accent)}.nav-icon[_ngcontent-%COMP%]{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;color:var(--text-secondary)}.nav-item[_ngcontent-%COMP%]:hover .nav-icon[_ngcontent-%COMP%]{color:var(--text-primary)}.nav-item.active[_ngcontent-%COMP%] .nav-icon[_ngcontent-%COMP%]{color:var(--accent)}.nav-label[_ngcontent-%COMP%]{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.badge[_ngcontent-%COMP%]{font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:10px;font-weight:700;padding:1px 6px;min-width:18px;border-radius:999px;display:inline-flex;justify-content:center;color:var(--text-secondary);background:#ffffff0f}.badge[data-kind=error][_ngcontent-%COMP%]{color:var(--error);background:var(--error-soft)}.badge[data-kind=warn][_ngcontent-%COMP%]{color:var(--warn);background:var(--warn-soft)}.pinned[_ngcontent-%COMP%]{padding:8px;border-top:1px solid var(--border-subtle)}'],changeDetection:0})};function De(e,n){if(e&1&&(d(0,"span",8),s(1),p(),C(2,"span",1),d(3,"span",9)(4,"span",10),s(5,"backend"),p(),d(6,"span",4),s(7),p()(),C(8,"span",1),d(9,"span",9)(10,"span",10),s(11,"nodes"),p(),d(12,"span",4),s(13),p()(),d(14,"span",9)(15,"span",10),s(16,"edges"),p(),d(17,"span",4),s(18),p()(),C(19,"span",1),d(20,"span",9)(21,"span",10),s(22,"drift"),p(),d(23,"span",4),s(24),p()(),C(25,"span",11),d(26,"span",9)(27,"span",10),s(28,"indexed"),p(),d(29,"span",4),s(30),p()()),e&2){let t=g(),i=t.status.state().data;o(),h(i.projectPath),o(6),h(i.backend),o(6),h(i.nodeCount.toLocaleString()),o(5),h(i.edgeCount.toLocaleString()),o(5),w("warn",i.drift>0)("success",i.drift===0),o(),h(i.drift),o(6),h(t.indexedLabel())}}function ze(e,n){e&1&&(d(0,"span",12),s(1,"loading status\u2026"),p(),C(2,"span",11))}function Ie(e,n){if(e&1&&(d(0,"span",12),s(1),p(),C(2,"span",11)),e&2){let t=g();o(),h(t.conn.online()?"no backend":"offline \u2014 no cached data")}}function Le(e,n){e&1&&(d(0,"span",5),s(1),p()),e&2&&(o(),A("\xB7 ",n))}function Ne(e,n){e&1&&(d(0,"span",6),s(1,"\u26A0"),p()),e&2&&V("title",n)}var W=class e{api=f(H);projects=f(I);refreshSvc=f(ve);conn=f(fe);status=B(this.api,()=>`/api/status${this.projects.projectQuery()}`);offlineAge=D(()=>{let n=this.status.state().cachedAt??this.conn.lastOnlineAt();if(n===null)return null;let t=Date.now()-n;return t<1e4?"just now":t<6e4?`${Math.round(t/1e3)}s ago`:t<36e5?`${Math.round(t/6e4)}m ago`:t<864e5?`${Math.round(t/36e5)}h ago`:`${Math.round(t/864e5)}d ago`});indexedLabel=D(()=>{let n=this.status.state().data?.lastIndexed;if(!n)return"never";try{let t=new Date(n),i=Date.now()-t.getTime();return i<6e4?"just now":i<36e5?`${Math.round(i/6e4)}m ago`:i<864e5?`${Math.round(i/36e5)}h ago`:t.toLocaleDateString()}catch{return String(n)}});async refresh(){await this.refreshSvc.triggerGlobalRefresh()}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-status-strip"]],decls:13,vars:14,consts:[[1,"status-strip"],[1,"divider"],[1,"seg","conn",3,"title"],[1,"conn-dot"],[1,"mono","val"],[1,"muted","conn-age"],[1,"refresh-error","mono",3,"title"],[1,"refresh",3,"click","disabled","title"],[1,"seg","mono"],[1,"seg"],[1,"lbl"],[1,"grow"],[1,"mono","muted"]],template:function(t,i){if(t&1&&(d(0,"div",0),m(1,De,31,10)(2,ze,3,0)(3,Ie,3,1),C(4,"span",1),d(5,"span",2),C(6,"span",3),d(7,"span",4),s(8),p(),m(9,Le,2,1,"span",5),p(),m(10,Ne,2,1,"span",6),d(11,"button",7),R("click",function(){return i.refresh()}),s(12,"\u21BB"),p()()),t&2){let l,_;o(),u(i.status.state().data?1:i.status.state().loading?2:3),o(4),V("title",i.conn.online()?"Connected to the SpecShip server":"Server unreachable \u2014 showing the last cached data"),o(),w("live",i.conn.online())("off",!i.conn.online()),o(2),h(i.conn.online()?"Live":"Offline"),o(),u((l=!i.conn.online()&&i.offlineAge())?9:-1,l),o(),u((_=i.refreshSvc.error())?10:-1,_),o(),w("spinning",i.refreshSvc.loading()),V("disabled",i.refreshSvc.loading()||!i.conn.online())("title",i.conn.online()?i.refreshSvc.loading()?"Refreshing\u2026":"Refresh: sync index + re-ingest Claude Code transcripts. Updates Sessions, Heatmap, Costs, Memory, Drift, Graph.":"Offline \u2014 reconnect to refresh"),M("aria-label",i.conn.online()?i.refreshSvc.loading()?"Refreshing\u2026":"Refresh everything \u2014 sync index + ingest Claude Code transcripts":"Offline \u2014 reconnect to refresh")}},styles:["[_nghost-%COMP%]{display:contents}.status-strip[_ngcontent-%COMP%]{height:var(--status-h);flex-shrink:0;display:flex;align-items:center;gap:14px;padding:0 14px;border-bottom:1px solid var(--border-subtle);background:var(--bg-panel-2);font-size:11.5px;overflow:hidden;white-space:nowrap}.seg[_ngcontent-%COMP%]{display:flex;align-items:center;gap:6px;flex-shrink:0}.lbl[_ngcontent-%COMP%]{color:var(--text-muted);font-size:11px}.val[_ngcontent-%COMP%]{color:var(--text-secondary);font-variant-numeric:tabular-nums}.val.warn[_ngcontent-%COMP%]{color:var(--warn)}.val.success[_ngcontent-%COMP%]{color:var(--success)}.divider[_ngcontent-%COMP%]{width:1px;height:12px;background:var(--border-subtle);flex-shrink:0}.grow[_ngcontent-%COMP%]{flex:1}.muted[_ngcontent-%COMP%]{color:var(--text-muted)}.refresh[_ngcontent-%COMP%]{background:transparent;border:none;color:var(--text-muted);cursor:pointer;font-size:14px;padding:2px 6px;border-radius:4px;transition:background .12s,color .12s}.refresh[_ngcontent-%COMP%]:hover:not(:disabled){background:var(--bg-hover);color:var(--text-primary)}.refresh[_ngcontent-%COMP%]:disabled{cursor:progress;opacity:.8}.refresh[_ngcontent-%COMP%]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.refresh.spinning[_ngcontent-%COMP%]{display:inline-block;animation:_ngcontent-%COMP%_spin .9s linear infinite;color:var(--accent)}@keyframes _ngcontent-%COMP%_spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.refresh-error[_ngcontent-%COMP%]{color:var(--warn);font-size:12px;padding:0 2px;cursor:help}.conn[_ngcontent-%COMP%]{gap:5px}.conn-dot[_ngcontent-%COMP%]{width:6px;height:6px;border-radius:50%;flex-shrink:0}.conn-dot.live[_ngcontent-%COMP%]{background:var(--success);box-shadow:0 0 6px var(--success)}.conn-dot.off[_ngcontent-%COMP%]{background:var(--warn);box-shadow:0 0 6px var(--warn)}.conn-age[_ngcontent-%COMP%]{font-size:11px}"],changeDetection:0})};var Re=(e,n)=>n.slug;function Ae(e,n){e&1&&c(0,"span",8)}function Fe(e,n){e&1&&c(0,"span",9)}function Be(e,n){e&1&&c(0,"span",10)}function $e(e,n){if(e&1&&(a(0,"span",7),s(1),r(),m(2,Ae,1,0,"span",8)(3,Fe,1,0,"span",9)(4,Be,1,0,"span",10)),e&2){let t=n,i=g();o(),h(i.shortPath(t.path)),o(),u(t.exists?t.initialized?4:3:2)}}function Ve(e,n){e&1&&(a(0,"span",3),s(1,"Select project"),r())}function He(e,n){if(e&1){let t=k();a(0,"button",20),b("click",function(){y(t);let l=g(2);return P(l.clear())}),c(1,"app-icon",21),s(2," Clear "),r()}e&2&&(o(),v("size",11))}function Ge(e,n){e&1&&(a(0,"span",16),s(1,"\xB7 loading\u2026"),r())}function qe(e,n){if(e&1&&(a(0,"span",16),s(1),r()),e&2){let t=g(2);o(),A("\xB7 ",t.filtered().length," shown \xB7 live")}}function Ke(e,n){e&1&&(a(0,"div",18),s(1,"No projects match."),r())}function We(e,n){e&1&&(a(0,"span",25),s(1,"missing"),r())}function Ue(e,n){e&1&&(a(0,"span",26),s(1,"not init"),r())}function Qe(e,n){e&1&&(a(0,"span",27),s(1,"initialized"),r())}function Je(e,n){if(e&1&&(a(0,"span"),s(1),r()),e&2){let t=g().$implicit,i=g(2);o(),A("\xB7 ",i.formatRelative(t.lastModifiedMs))}}function Ye(e,n){e&1&&c(0,"app-icon",29),e&2&&v("size",13)}function Xe(e,n){if(e&1){let t=k();a(0,"button",22),b("click",function(){let l=y(t).$implicit,_=g(2);return P(_.pick(l.slug))}),a(1,"div",23)(2,"div",24)(3,"span",7),s(4),r(),m(5,We,2,0,"span",25)(6,Ue,2,0,"span",26)(7,Qe,2,0,"span",27),r(),a(8,"div",28)(9,"span"),s(10),r(),m(11,Je,2,1,"span"),r()(),m(12,Ye,1,1,"app-icon",29),r()}if(e&2){let t=n.$implicit,i=g(2);w("active",i.projects.activeSlug()===t.slug),o(4),h(i.shortPath(t.path)),o(),u(t.exists?t.initialized?7:6:5),o(5),le("",t.sessionCount," session",t.sessionCount===1?"":"s"),o(),u(t.lastModifiedMs>0?11:-1),o(),u(i.projects.activeSlug()===t.slug?12:-1)}}function Ze(e,n){if(e&1){let t=k();a(0,"div",6)(1,"div",11),c(2,"app-icon",12),a(3,"input",13),b("input",function(l){y(t);let _=g();return P(_.onQuery(l.target.value))}),r(),m(4,He,3,1,"button",14),r(),a(5,"div",15)(6,"span"),s(7),r(),m(8,Ge,2,0,"span",16)(9,qe,2,1,"span",16),r(),a(10,"div",17),m(11,Ke,2,0,"div",18),T(12,Xe,13,8,"button",19,Re),r()()}if(e&2){let t=g();o(2),v("size",13),o(),v("value",t.query()),o(),u(t.projects.activeSlug()?4:-1),o(3),h(t.projects.claudeRoot()??"~/.claude/projects"),o(),u(t.projects.loading()?8:9),o(3),u(t.filtered().length===0&&!t.projects.loading()?11:-1),o(),j(t.filtered())}}var U=class e{host=f(ae);projects=f(I);open=S(!1);query=S("");filtered=D(()=>{let n=this.query().trim().toLowerCase(),t=this.projects.projects();return n?t.filter(i=>i.path.toLowerCase().includes(n)||i.slug.toLowerCase().includes(n)):t});badge=D(()=>this.projects.projects().length);toggle(){this.open.update(n=>!n)}pick(n){this.projects.setActive(n),this.open.set(!1),this.query.set("")}clear(){this.projects.setActive(null),this.open.set(!1)}onQuery(n){this.query.set(n)}onDocumentClick(n){if(!this.open())return;let t=n.target;t&&!this.host.nativeElement.contains(t)&&this.open.set(!1)}onEscape(){this.open()&&this.open.set(!1)}formatRelative(n){if(!n)return"";let t=Date.now()-n,i=Math.round(t/1e3);if(i<60)return`${i}s ago`;let l=Math.round(i/60);if(l<60)return`${l}m ago`;let _=Math.round(l/60);if(_<24)return`${_}h ago`;let ne=Math.round(_/24);return ne<30?`${ne}d ago`:new Date(n).toLocaleDateString()}shortPath(n){if(!n)return"";let t=this.detectHome();return t&&n===t?"~":t&&n.startsWith(t+"/")?"~/"+n.slice(t.length+1):n}detectHome(){let n=this.projects.claudeRoot();if(!n)return null;let t="/.claude/projects";return n.endsWith(t)?n.slice(0,-t.length):null}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-project-picker"]],hostBindings:function(t,i){t&1&&b("click",function(_){return i.onDocumentClick(_)},te)("keydown.escape",function(){return i.onEscape()},te)},decls:9,vars:9,consts:[[1,"wrap"],["type","button","aria-label","Switch project",1,"trigger",3,"click"],["name","folder",3,"size"],[1,"placeholder"],[1,"badge","mono"],[3,"name","size"],["role","dialog","aria-label","Pick a project",1,"popover"],[1,"path","mono"],["title","path no longer exists on disk",1,"status-dot","missing"],["title","not yet specship init'd",1,"status-dot","warn"],["title","initialized",1,"status-dot","ok"],[1,"popover-head","row","gap-8"],["name","search",3,"size"],["type","text","placeholder","Filter projects\u2026","autofocus","",1,"popover-input",3,"input","value"],["title","Clear selection",1,"btn","btn-ghost","btn-xs"],[1,"popover-meta","mono"],[1,"muted"],[1,"popover-list","scroll-y"],[1,"empty"],["type","button",1,"row-item",3,"active"],["title","Clear selection",1,"btn","btn-ghost","btn-xs",3,"click"],["name","x",3,"size"],["type","button",1,"row-item",3,"click"],[1,"col","gap-2","grow"],[1,"row","gap-6","path-line"],[1,"pill","missing"],[1,"pill","warn"],[1,"pill","ok"],[1,"meta","row","gap-8","mono","muted"],["name","check",3,"size"]],template:function(t,i){if(t&1&&(a(0,"div",0)(1,"button",1),b("click",function(){return i.toggle()}),c(2,"app-icon",2),m(3,$e,5,2)(4,Ve,2,0,"span",3),a(5,"span",4),s(6),r(),c(7,"app-icon",5),r(),m(8,Ze,14,6,"div",6),r()),t&2){let l;w("open",i.open()),o(),M("aria-expanded",i.open()),o(),v("size",13),o(),u((l=i.projects.active())?3:4,l),o(3),h(i.badge()),o(),v("name",i.open()?"chevronDown":"chevronRight")("size",11),o(),u(i.open()?8:-1)}},dependencies:[L],styles:["[_nghost-%COMP%]{display:inline-flex;min-width:0}.wrap[_ngcontent-%COMP%]{position:relative;min-width:0}.trigger[_ngcontent-%COMP%]{height:30px;padding:0 11px 0 10px;background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:8px;color:var(--text-secondary);display:inline-flex;align-items:center;gap:8px;font-family:var(--font-ui);font-size:12.5px;cursor:pointer;max-width:360px;min-width:0;transition:background .1s,border-color .1s}.trigger[_ngcontent-%COMP%]:hover, .wrap.open[_ngcontent-%COMP%] .trigger[_ngcontent-%COMP%]{background:var(--bg-panel-2);border-color:var(--border-strong);color:var(--text-primary)}.trigger[_ngcontent-%COMP%] app-icon[_ngcontent-%COMP%]{color:var(--text-muted);flex-shrink:0}.trigger[_ngcontent-%COMP%]:hover app-icon[_ngcontent-%COMP%]{color:var(--text-secondary)}.path[_ngcontent-%COMP%]{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.placeholder[_ngcontent-%COMP%]{color:var(--text-muted);font-style:italic}.status-dot[_ngcontent-%COMP%]{width:6px;height:6px;border-radius:50%;flex-shrink:0}.status-dot.ok[_ngcontent-%COMP%]{background:var(--success)}.status-dot.warn[_ngcontent-%COMP%]{background:var(--warn)}.status-dot.missing[_ngcontent-%COMP%]{background:var(--error)}.badge[_ngcontent-%COMP%]{font-size:10px;padding:1px 6px;border-radius:999px;background:var(--bg-active);color:var(--text-muted);font-variant-numeric:tabular-nums;flex-shrink:0}.popover[_ngcontent-%COMP%]{position:absolute;top:calc(100% + 6px);left:0;z-index:30;width:420px;max-width:calc(100vw - 40px);background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:10px;box-shadow:var(--shadow-pop);display:flex;flex-direction:column;max-height:480px;animation:_ngcontent-%COMP%_pp-in .12s ease-out}@keyframes _ngcontent-%COMP%_pp-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.popover-head[_ngcontent-%COMP%]{padding:10px 12px 8px;border-bottom:1px solid var(--border-subtle)}.popover-head[_ngcontent-%COMP%] app-icon[_ngcontent-%COMP%]{color:var(--text-muted);flex-shrink:0}.popover-input[_ngcontent-%COMP%]{flex:1;min-width:0;background:transparent;border:none;outline:none;font-family:var(--font-ui);font-size:13px;color:var(--text-primary)}.popover-input[_ngcontent-%COMP%]::placeholder{color:var(--text-muted)}.popover-meta[_ngcontent-%COMP%]{padding:6px 12px 8px;font-size:10.5px;color:var(--text-secondary);border-bottom:1px solid var(--border-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.popover-meta[_ngcontent-%COMP%] .muted[_ngcontent-%COMP%]{color:var(--text-muted)}.popover-list[_ngcontent-%COMP%]{flex:1;min-height:0;padding:4px}.row-item[_ngcontent-%COMP%]{width:100%;display:flex;align-items:center;gap:10px;padding:9px 10px;border:none;border-radius:7px;background:transparent;color:inherit;cursor:pointer;font-family:inherit;text-align:left;transition:background 80ms}.row-item[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.row-item.active[_ngcontent-%COMP%]{background:var(--accent-soft);color:var(--text-primary)}.row-item.active[_ngcontent-%COMP%] app-icon[_ngcontent-%COMP%]{color:var(--accent)}.path-line[_ngcontent-%COMP%]{min-width:0}.path-line[_ngcontent-%COMP%] .path[_ngcontent-%COMP%]{font-size:12.5px;font-weight:500;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta[_ngcontent-%COMP%]{font-size:10.5px}.pill[_ngcontent-%COMP%]{font-size:10px;font-weight:600;padding:1px 7px;border-radius:999px;white-space:nowrap;flex-shrink:0}.pill.ok[_ngcontent-%COMP%]{color:var(--success);background:var(--success-soft)}.pill.warn[_ngcontent-%COMP%]{color:var(--warn);background:var(--warn-soft)}.pill.missing[_ngcontent-%COMP%]{color:var(--error);background:var(--error-soft)}.empty[_ngcontent-%COMP%]{text-align:center;color:var(--text-muted);font-size:12px;padding:18px 12px}.muted[_ngcontent-%COMP%]{color:var(--text-muted)}.mono[_ngcontent-%COMP%]{font-family:var(--font-mono)}.grow[_ngcontent-%COMP%]{flex:1;min-width:0}.row[_ngcontent-%COMP%]{display:flex;align-items:center}.col[_ngcontent-%COMP%]{display:flex;flex-direction:column}.gap-2[_ngcontent-%COMP%]{gap:2px}.gap-6[_ngcontent-%COMP%]{gap:6px}.gap-8[_ngcontent-%COMP%]{gap:8px}.scroll-y[_ngcontent-%COMP%]{overflow-y:auto;overflow-x:hidden}"],changeDetection:0})};var Q=class e{deferred=null;canInstall=S(!1);constructor(){typeof window>"u"||window.matchMedia?.("(display-mode: standalone)").matches===!0||window.navigator.standalone===!0||(window.addEventListener("beforeinstallprompt",t=>{t.preventDefault(),this.deferred=t,this.canInstall.set(!0)}),window.addEventListener("appinstalled",()=>{this.deferred=null,this.canInstall.set(!1)}))}async install(){let n=this.deferred;if(n){this.deferred=null,this.canInstall.set(!1);try{await n.prompt(),await n.userChoice}catch{}}}static \u0275fac=function(t){return new(t||e)};static \u0275prov=$({token:e,factory:e.\u0275fac,providedIn:"root"})};function et(e,n){if(e&1){let t=k();a(0,"button",9),b("click",function(){y(t);let l=g();return P(l.onInstall())}),c(1,"app-icon",10),a(2,"span"),s(3,"Install"),r()()}e&2&&(o(),v("size",14))}var J=class e{toggleSidebar=F();openPalette=F();theme=f(G);effective=this.theme.effective;pwa=f(Q);onToggleTheme(){this.theme.toggle()}onMenuClick(){this.toggleSidebar.emit()}onPalette(){this.openPalette.emit()}onInstall(){this.pwa.install()}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-top-bar"]],outputs:{toggleSidebar:"toggleSidebar",openPalette:"openPalette"},decls:14,vars:6,consts:[[1,"topbar"],["title","Toggle sidebar","aria-label","Toggle sidebar",1,"ghost","icon-btn",3,"click"],["name","menu",3,"size"],["aria-label","Open command palette",1,"palette-trigger",3,"click"],["name","search",3,"size"],[1,"grow"],["title","Install SpecShip as an app","aria-label","Install SpecShip as an app",1,"ghost",2,"display","inline-flex","align-items","center","gap","6px","padding","0 10px","height","30px","font-size","12px"],["aria-label","Toggle theme",1,"ghost","icon-btn",3,"click","title"],[3,"name","size"],["title","Install SpecShip as an app","aria-label","Install SpecShip as an app",1,"ghost",2,"display","inline-flex","align-items","center","gap","6px","padding","0 10px","height","30px","font-size","12px",3,"click"],["name","plus",3,"size"]],template:function(t,i){t&1&&(a(0,"div",0)(1,"button",1),b("click",function(){return i.onMenuClick()}),c(2,"app-icon",2),r(),c(3,"app-project-picker"),a(4,"button",3),b("click",function(){return i.onPalette()}),c(5,"app-icon",4),a(6,"span"),s(7,"Search or jump to\u2026"),r(),a(8,"kbd"),s(9,"\u2318K"),r()(),c(10,"span",5),m(11,et,4,1,"button",6),a(12,"button",7),b("click",function(){return i.onToggleTheme()}),c(13,"app-icon",8),r()()),t&2&&(o(2),v("size",16),o(3),v("size",13),o(6),u(i.pwa.canInstall()?11:-1),o(),v("title","Theme: "+i.effective()),o(),v("name",i.effective()==="dark"?"sun":"moon")("size",16))},dependencies:[L,U],styles:["[_nghost-%COMP%]{display:contents}.topbar[_ngcontent-%COMP%]{height:44px;flex-shrink:0;display:flex;align-items:center;gap:10px;padding:0 14px;border-bottom:1px solid var(--border-subtle);background:var(--bg-canvas)}.ghost[_ngcontent-%COMP%]{background:transparent;border:1px solid transparent;color:var(--text-secondary);cursor:pointer}.ghost[_ngcontent-%COMP%]:hover{background:var(--bg-hover);color:var(--text-primary)}.icon-btn[_ngcontent-%COMP%]{padding:6px 9px;border-radius:5px;font-size:16px}.palette-trigger[_ngcontent-%COMP%]{flex:1;max-width:380px;height:30px;padding:0 11px;background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:8px;cursor:text;color:var(--text-muted);font-size:12.5px;text-align:left;display:flex;align-items:center;gap:8px}.palette-trigger[_ngcontent-%COMP%]:hover{border-color:var(--border-strong);color:var(--text-secondary)}.palette-trigger[_ngcontent-%COMP%] app-icon[_ngcontent-%COMP%]{color:var(--text-muted)}.palette-trigger[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{flex:1}kbd[_ngcontent-%COMP%]{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);background:var(--bg-canvas);border:1px solid var(--border-subtle);border-radius:4px;padding:2px 6px}.grow[_ngcontent-%COMP%]{flex:1}"],changeDetection:0})};var tt=(e,n)=>n.id;function nt(e,n){if(e&1){let t=k();d(0,"button",6),R("click",function(){let l=y(t).$implicit,_=g(2);return P(_.go(l.id))}),d(1,"span",7),s(2),p(),d(3,"span",8),s(4),p()()}if(e&2){let t=n.$implicit;o(2),h(t.label),o(2),h(t.sub)}}function it(e,n){if(e&1){let t=k();d(0,"div",1),R("click",function(l){y(t);let _=g();return P(_.onBackdrop(l))}),d(1,"div",2)(2,"div",3)(3,"span"),s(4,"Jump to\u2026"),p(),d(5,"kbd"),s(6,"esc"),p()(),d(7,"div",4),T(8,nt,5,2,"button",5,tt),p()()()}if(e&2){let t=g();o(8),j(t.items)}}var ot=[{id:"dashboard",label:"Dashboard",sub:"/dashboard"},{id:"graph",label:"Graph",sub:"/graph"},{id:"specs",label:"Specs",sub:"/specs"},{id:"drift",label:"Drift queue",sub:"/drift"},{id:"workflows",label:"Workflows",sub:"/workflows"},{id:"runs",label:"Runs",sub:"/runs"},{id:"chat",label:"Chat",sub:"/chat"},{id:"sessions",label:"Sessions",sub:"/sessions"},{id:"heatmap",label:"Heatmap",sub:"/heatmap"},{id:"costs",label:"Costs",sub:"/costs"},{id:"compare",label:"Compare projects",sub:"/compare"},{id:"tips",label:"Tips",sub:"/tips"},{id:"settings",label:"Settings",sub:"/settings"}],Y=class e{open=E(!1);close=F();router=f(z);items=ot;go(n){this.router.navigate(["/"+n]),this.close.emit()}onBackdrop(n){n.target===n.currentTarget&&this.close.emit()}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-command-palette"]],inputs:{open:[1,"open"]},outputs:{close:"close"},decls:1,vars:1,consts:[[1,"backdrop"],[1,"backdrop",3,"click"],[1,"palette"],[1,"palette-header"],[1,"palette-list","scroll-y"],[1,"item"],[1,"item",3,"click"],[1,"label"],[1,"sub","mono"]],template:function(t,i){t&1&&m(0,it,10,0,"div",0),t&2&&u(i.open()?0:-1)},styles:["[_nghost-%COMP%]{display:contents}.backdrop[_ngcontent-%COMP%]{position:fixed;inset:0;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:grid;place-items:start center;padding-top:12vh;z-index:100;animation:fadeIn .1s}.palette[_ngcontent-%COMP%]{width:560px;max-width:90vw;background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:12px;box-shadow:var(--shadow-pop);overflow:hidden}.palette-header[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:center;padding:12px 14px;border-bottom:1px solid var(--border-subtle);font-size:13px}.palette-list[_ngcontent-%COMP%]{max-height:380px;padding:6px}.item[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:center;width:100%;padding:8px 10px;background:transparent;border:none;border-radius:7px;cursor:pointer;color:var(--text-primary);font-family:inherit;font-size:13px;text-align:left}.item[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.label[_ngcontent-%COMP%]{flex:1}.sub[_ngcontent-%COMP%]{font-size:10.5px;color:var(--text-muted)}kbd[_ngcontent-%COMP%]{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);background:var(--bg-canvas);border:1px solid var(--border-subtle);border-radius:4px;padding:2px 6px}"],changeDetection:0})};var X=class e{es=null;notify=f(he);router=f(z);start(){if(!(this.es||typeof EventSource>"u")){try{this.es=new EventSource("/api/events")}catch{return}this.es.onmessage=n=>{let t;try{t=JSON.parse(n.data)}catch{return}!t||t.kind!=="approval"&&t.kind!=="runDone"&&t.kind!=="drift"||this.notify.notify(t.kind,t.title,{body:t.detail,tag:`${t.project}:${t.kind}:${t.id}`,onClick:()=>this.routeFor(t)})}}}stop(){this.es?.close(),this.es=null}routeFor(n){let t={project:n.project};n.kind==="drift"?this.router.navigate(["/drift"],{queryParams:t}):this.router.navigate(["/runs",n.id],{queryParams:t})}static \u0275fac=function(t){return new(t||e)};static \u0275prov=$({token:e,factory:e.\u0275fac,providedIn:"root"})};var Z=class e{_theme=f(G);_destroyRef=f(ie);_router=f(z);_events=f(X);constructor(){this._events.start()}sidebarCollapsed=S(typeof window<"u"&&window.innerWidth<1100);paletteOpen=S(!1);gChord={armed:!1,t:0};onGlobalKey(n){let t=n.metaKey||n.ctrlKey;if(t&&n.key.toLowerCase()==="k"){n.preventDefault(),this.paletteOpen.update(i=>!i);return}if(n.key==="Escape"){this.paletteOpen.set(!1);return}if(!t&&n.key.toLowerCase()==="g"&&!this.gChord.armed){let i=n.target;if(i&&/input|textarea/i.test(i.tagName))return;this.gChord.armed=!0,this.gChord.t=Date.now(),setTimeout(()=>{this.gChord.armed=!1},600);return}if(this.gChord.armed&&!t){let i=n.key.toLowerCase();i==="d"?this._router.navigate(["/dashboard"]):i==="g"?this._router.navigate(["/graph"]):i==="s"&&this._router.navigate(["/specs"]),this.gChord.armed=!1}}toggleSidebar(){this.sidebarCollapsed.update(n=>!n)}onOpenPalette(){this.paletteOpen.set(!0)}onClosePalette(){this.paletteOpen.set(!1)}static \u0275fac=function(t){return new(t||e)};static \u0275cmp=x({type:e,selectors:[["app-root"]],hostBindings:function(t,i){t&1&&b("keydown",function(_){return i.onGlobalKey(_)},re)},decls:8,vars:2,consts:[[1,"shell"],[3,"collapsed"],[1,"main"],[3,"toggleSidebar","openPalette"],[1,"page-frame"],[3,"close","open"]],template:function(t,i){t&1&&(a(0,"div",0),c(1,"app-sidebar",1),a(2,"div",2),c(3,"app-status-strip"),a(4,"app-top-bar",3),b("toggleSidebar",function(){return i.toggleSidebar()})("openPalette",function(){return i.onOpenPalette()}),r(),a(5,"div",4),c(6,"router-outlet"),r()(),a(7,"app-command-palette",5),b("close",function(){return i.onClosePalette()}),r()()),t&2&&(o(),v("collapsed",i.sidebarCollapsed()),o(6),v("open",i.paletteOpen()))},dependencies:[ce,K,W,J,Y],styles:["[_nghost-%COMP%]{display:block;height:100%}.shell[_ngcontent-%COMP%]{display:flex;height:100vh;background:var(--bg-canvas);color:var(--text-primary);font-family:var(--font-ui);font-size:var(--fs-base)}.main[_ngcontent-%COMP%]{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}.page-frame[_ngcontent-%COMP%]{flex:1;min-height:0;display:flex;flex-direction:column;background:var(--bg-canvas)}"],changeDetection:0})};pe(Z,be).catch(e=>console.error(e));typeof navigator<"u"&&"serviceWorker"in navigator&&window.addEventListener("load",()=>{navigator.serviceWorker.register("sw.js").catch(e=>{console.warn("[specship] offline service worker registration failed",e)})});