spexcode 0.6.1 → 0.6.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.
Files changed (72) hide show
  1. package/README.md +97 -149
  2. package/package.json +1 -1
  3. package/spec-cli/hooks/harness.sh +26 -6
  4. package/spec-cli/src/anchors.ts +27 -5
  5. package/spec-cli/src/cli.ts +171 -28
  6. package/spec-cli/src/client.ts +112 -13
  7. package/spec-cli/src/delivery-queue.ts +62 -4
  8. package/spec-cli/src/execution-trace.ts +444 -0
  9. package/spec-cli/src/gateway-hub.ts +10 -8
  10. package/spec-cli/src/gateway.ts +99 -6
  11. package/spec-cli/src/git.ts +477 -101
  12. package/spec-cli/src/graph.ts +56 -6
  13. package/spec-cli/src/graphCache.ts +86 -17
  14. package/spec-cli/src/graphStream.ts +1 -1
  15. package/spec-cli/src/guide.ts +93 -4
  16. package/spec-cli/src/harness-select.ts +2 -2
  17. package/spec-cli/src/harness.ts +344 -66
  18. package/spec-cli/src/help.ts +22 -10
  19. package/spec-cli/src/host-resources.ts +62 -7
  20. package/spec-cli/src/identity-presets.js +16 -6
  21. package/spec-cli/src/index.ts +101 -13
  22. package/spec-cli/src/layout.ts +116 -33
  23. package/spec-cli/src/lint.ts +37 -7
  24. package/spec-cli/src/materialize.ts +10 -5
  25. package/spec-cli/src/plugin-harness.ts +10 -10
  26. package/spec-cli/src/reviews.ts +57 -28
  27. package/spec-cli/src/session-execution.ts +68 -0
  28. package/spec-cli/src/session-files.ts +121 -0
  29. package/spec-cli/src/session-follow.ts +4 -4
  30. package/spec-cli/src/session-reparent.ts +33 -0
  31. package/spec-cli/src/session-timeline.ts +163 -14
  32. package/spec-cli/src/session-web.ts +135 -0
  33. package/spec-cli/src/sessions.ts +584 -104
  34. package/spec-cli/src/uninstall.ts +1 -1
  35. package/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +2 -21
  36. package/spec-cli/templates/spec/project/.plugins/core/spec.md +12 -13
  37. package/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +5 -22
  38. package/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +2 -1
  39. package/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +4 -6
  40. package/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +3 -9
  41. package/spec-dashboard/dist/assets/{App-F9uaAVcH.js → App-B6IbFbGu.js} +2 -2
  42. package/spec-dashboard/dist/assets/Dashboard-_sDk7Rcg.js +27 -0
  43. package/spec-dashboard/dist/assets/EvalsPage-BT357Lyt.js +2 -0
  44. package/spec-dashboard/dist/assets/{IssuesPage-CuKLFhH3.js → IssuesPage-BG9rNOgV.js} +1 -1
  45. package/spec-dashboard/dist/assets/MobileApp-D9yPMR3A.js +2 -0
  46. package/spec-dashboard/dist/assets/{Modal-CQgYymmr.js → Modal-B3EcgeA3.js} +1 -1
  47. package/spec-dashboard/dist/assets/{PageScroll-hT7UTLvD.js → PageScroll-CNZOugWV.js} +1 -1
  48. package/spec-dashboard/dist/assets/{ProjectsPage-CtXxakF9.js → ProjectsPage-C2CRHmvs.js} +1 -1
  49. package/spec-dashboard/dist/assets/SessionInterface-DOEjuT3l.js +40 -0
  50. package/spec-dashboard/dist/assets/{SessionWindow-CixDi4PI.js → SessionWindow-1nYgZ4CL.js} +1 -1
  51. package/spec-dashboard/dist/assets/Settings-7WeTJn0V.js +1 -0
  52. package/spec-dashboard/dist/assets/Thread-CEbzAFQn.js +13 -0
  53. package/spec-dashboard/dist/assets/data-SlvxNA2r.js +1 -0
  54. package/spec-dashboard/dist/assets/{index-DrVao0Ep.js → index-DLVeOHL-.js} +10 -10
  55. package/spec-dashboard/dist/assets/index-DYLGfPjx.css +1 -0
  56. package/spec-dashboard/dist/assets/{launch-BBH02b1v.js → launch-yxCYr64x.js} +29 -29
  57. package/spec-dashboard/dist/assets/sessionSurface--7l69h4F.js +1 -0
  58. package/spec-dashboard/dist/index.html +2 -2
  59. package/spec-eval/src/cli.ts +6 -1
  60. package/spec-eval/src/evaltab.ts +7 -5
  61. package/spec-eval/src/freshness.ts +383 -104
  62. package/spec-eval/src/scenariofresh.ts +2 -2
  63. package/spec-eval/src/sessioneval.ts +126 -132
  64. package/spec-dashboard/dist/assets/Dashboard-Ba_jhxp1.js +0 -27
  65. package/spec-dashboard/dist/assets/EvalsPage-FixoOg_n.js +0 -2
  66. package/spec-dashboard/dist/assets/MobileApp-CHgEHORJ.js +0 -2
  67. package/spec-dashboard/dist/assets/SessionInterface-Bpie-9fs.js +0 -39
  68. package/spec-dashboard/dist/assets/Settings-C2MsucfE.js +0 -1
  69. package/spec-dashboard/dist/assets/Thread-C6Go8HRh.js +0 -13
  70. package/spec-dashboard/dist/assets/data-B-RQmit6.js +0 -1
  71. package/spec-dashboard/dist/assets/index-CsI8DElI.css +0 -1
  72. package/spec-dashboard/dist/assets/terminalFont-C6oGNKrf.js +0 -1
@@ -0,0 +1 @@
1
+ import{P as N}from"./index-DLVeOHL-.js";const u="spexcode.terminal-font-size",T=9,g=18,c=1,r=new Set;function b(){const e=Number.parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--type-terminal"));if(!Number.isFinite(e))throw new Error("Terminal font-size token is missing or invalid");return e}function f(e){const t=Number(e);return Number.isFinite(t)&&t>=T&&t<=g?Math.round(t/c)*c:null}function _(){let e=null;try{e=f(localStorage.getItem(u))}catch{}return e??b()}function p(e){const t=f(e);if(t===null)throw new Error(`Invalid terminal font size: ${e}`);try{localStorage.setItem(u,String(t))}catch{}for(const s of r)s(t);return t}function w(e){return r.add(e),()=>r.delete(e)}const S="terminal",y="conversation",F="spexcode.session-surface.v1",A=new Set([S,y]),o=new Set;let l=null;const d=(e=N)=>`${F}.${e||"root"}`,i=()=>({defaultSurface:S,sessions:{}}),a=e=>A.has(e);function I(e){const t=i();return!e||typeof e!="object"||(a(e.defaultSurface)&&(t.defaultSurface=e.defaultSurface),e.sessions&&typeof e.sessions=="object"&&!Array.isArray(e.sessions)&&(t.sessions=Object.fromEntries(Object.entries(e.sessions).filter(([,s])=>a(s))))),t}function n(){try{const e=localStorage.getItem(d());return e?I(JSON.parse(e)):i()}catch{return l||i()}}function m(e){l=e;try{localStorage.setItem(d(),JSON.stringify(e))}catch{}for(const t of o)t(e);return e}function E(e){if(!a(e))throw new Error(`Invalid session surface: ${e}`);return e}function R(){return n().defaultSurface}function h(e){const t=n();return t.sessions[e]||t.defaultSurface}function z(e){const t=n();return m({...t,defaultSurface:E(e)}).defaultSurface}function M(e,t){if(!e)throw new Error("A session id is required to set its base surface");const s=n();return m({...s,sessions:{...s.sessions,[e]:E(t)}}).sessions[e]}function C(e){return o.add(e),()=>o.delete(e)}export{S,c as T,R as a,y as b,g as c,T as d,z as e,w as f,_ as g,C as h,h as i,M as j,p as s};
@@ -20,8 +20,8 @@
20
20
  } catch (e) { /* localStorage unavailable — the bare :root default (Minimal) stands */ }
21
21
  })()
22
22
  </script>
23
- <script type="module" crossorigin src="/assets/index-DrVao0Ep.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-CsI8DElI.css">
23
+ <script type="module" crossorigin src="/assets/index-DLVeOHL-.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-DYLGfPjx.css">
25
25
  </head>
26
26
  <body>
27
27
  <div id="root"></div>
@@ -7,7 +7,7 @@ import { trackedSourceFiles } from '../../spec-cli/src/source-files.js'
7
7
  import { mainBranch, envSessionId, readRawRecord } from '../../spec-cli/src/layout.js'
8
8
  import { evalNodes, evalNodesAt, validateScenarios, resolveEvalNode, scenarioCodeAxis, scenarioHash, scenarioProjection, writeScenarioMeasurementMetadata, EVAL_FILE, type EvalNode, type ScenarioTestReference } from './scenarios.js'
9
9
  import { readReadings, readSidecar, appendReading, appendRetraction, latestPerScenario, evidenceOf, isJsonBlob, type Reading, type Verdict, type Evidence, type EvidenceKind, type Retraction } from './sidecar.js'
10
- import { staleAxes, contentProbeFor, anchorProbeFor, anchorProblems, type AnchorDemand } from './freshness.js'
10
+ import { staleAxes, contentProbeFor, anchorProbeFor, anchorProblems, type AnchorDemand, type ContentProbeDemand } from './freshness.js'
11
11
  import { parseRelation, relationClaimsPath } from '../../spec-cli/src/anchors.js'
12
12
  import { scenarioIndex } from './scenariofresh.js'
13
13
  import { loadEvalRemarkTracks, trackKey } from '../../spec-cli/src/issues.js'
@@ -144,6 +144,7 @@ async function scan(args: string[] = []): Promise<number> {
144
144
  // the in-loop primes stay as the correctness backstop and become cache hits.
145
145
  const latestByDir = new Map<string, ReturnType<typeof latestPerScenario>>()
146
146
  const anchorDemands: AnchorDemand[] = []
147
+ const contentDemands: ContentProbeDemand[] = []
147
148
  for (const s of specs) {
148
149
  const dirRel = dirname(s.path)
149
150
  const y = yByDir.get(dirRel)
@@ -156,8 +157,12 @@ async function scan(args: string[] = []): Promise<number> {
156
157
  const axis = scenarioCodeAxis(sc.code, s.codeEntries)
157
158
  if (changed && !nodeChanged(dirRel, axis.paths, changed, nodeDirs)) continue
158
159
  anchorDemands.push({ sinceSha: r.codeSha, entries: axis.entries })
160
+ if (!commitReachable(idx, r.codeSha))
161
+ contentDemands.push({ anchorSha: r.codeSha, paths: axis.paths, evalPath: y.evalPath })
159
162
  }
160
163
  }
164
+ await probe.primeMany?.(contentDemands)
165
+ await probe.primeBlocks?.()
161
166
  await anchors.prime?.(anchorDemands)
162
167
  for (const s of specs) {
163
168
  const dirRel = dirname(s.path)
@@ -138,12 +138,14 @@ export async function evalTimelines(ids: readonly string[], ctx?: EvalContext, o
138
138
  idx, scidx, tracks, probe, anchors, order: true,
139
139
  }))
140
140
 
141
- // An off-history anchor is the only reading that needs a content verdict; those primes serialize inside the
142
- // probe per anchor, so issuing them together lets one anchor's paths union into one child instead of N.
143
- await Promise.all(plans.flatMap((plan) => plan.ynode
141
+ // An off-history anchor is the only reading that needs a content verdict. Plan the population first so the
142
+ // probe can answer many anchor/HEAD pairs through bounded plural children instead of one child per anchor.
143
+ const contentDemands = plans.flatMap((plan) => plan.ynode
144
144
  ? plan.rows.filter((row) => !commitReachable(idx, row.reading.codeSha))
145
- .map((row) => probe.prime?.(row.reading.codeSha, row.axis.paths, plan.ynode!.evalPath))
146
- : []))
145
+ .map((row) => ({ anchorSha: row.reading.codeSha, paths: row.axis.paths, evalPath: plan.ynode!.evalPath }))
146
+ : [])
147
+ if (probe.primeMany) await probe.primeMany(contentDemands)
148
+ else await Promise.all(contentDemands.map((row) => probe.prime?.(row.anchorSha, [...row.paths], row.evalPath)))
147
149
  await anchors.prime?.(plans.flatMap((plan) => plan.rows.map((row) => ({ sinceSha: row.reading.codeSha, entries: row.axis.entries }))))
148
150
  // the primes above only RECORDED which eval.md blocks the assemble step will compare; one batched pair of
149
151
  // children answers the whole read's worth, the same shape the anchor prime above already has.