@harness-engineering/cli 4.3.3 → 6.0.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 (81) hide show
  1. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +3 -1
  2. package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +5 -0
  3. package/dist/agents/skills/claude-code/harness-rollback/SKILL.md +124 -0
  4. package/dist/agents/skills/claude-code/harness-rollback/skill.yaml +52 -0
  5. package/dist/agents/skills/claude-code/product-requirements/SKILL.md +150 -0
  6. package/dist/agents/skills/claude-code/product-requirements/skill.yaml +70 -0
  7. package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +3 -1
  8. package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +5 -0
  9. package/dist/agents/skills/codex/harness-rollback/SKILL.md +124 -0
  10. package/dist/agents/skills/codex/harness-rollback/skill.yaml +52 -0
  11. package/dist/agents/skills/codex/product-requirements/SKILL.md +150 -0
  12. package/dist/agents/skills/codex/product-requirements/skill.yaml +70 -0
  13. package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +3 -1
  14. package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +5 -0
  15. package/dist/agents/skills/cursor/harness-rollback/SKILL.md +124 -0
  16. package/dist/agents/skills/cursor/harness-rollback/skill.yaml +52 -0
  17. package/dist/agents/skills/cursor/product-requirements/SKILL.md +150 -0
  18. package/dist/agents/skills/cursor/product-requirements/skill.yaml +70 -0
  19. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +3 -1
  20. package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +5 -0
  21. package/dist/agents/skills/gemini-cli/harness-rollback/SKILL.md +124 -0
  22. package/dist/agents/skills/gemini-cli/harness-rollback/skill.yaml +52 -0
  23. package/dist/agents/skills/gemini-cli/product-requirements/SKILL.md +150 -0
  24. package/dist/agents/skills/gemini-cli/product-requirements/skill.yaml +70 -0
  25. package/dist/{agents-md-N4ULMUAK.js → agents-md-OTKZE5HH.js} +4 -4
  26. package/dist/{analyzer-XRCV63KC-WGRHW2ZM.js → analyzer-XRCV63KC-FALMS3MO.js} +2 -2
  27. package/dist/{architecture-OIMIBDJC.js → architecture-3VYDN7MQ.js} +5 -5
  28. package/dist/{assess-project-ITSB6W4L.js → assess-project-27X2FSZZ.js} +1 -1
  29. package/dist/bin/harness-mcp.js +15 -15
  30. package/dist/bin/harness.js +25 -25
  31. package/dist/{check-phase-gate-GN4X7HT6.js → check-phase-gate-IXLFZ6YH.js} +5 -5
  32. package/dist/{chunk-MEDRUIRO.js → chunk-354MCPT3.js} +3 -3
  33. package/dist/{chunk-5BUHPOCP.js → chunk-3H7JA24B.js} +7 -7
  34. package/dist/{chunk-PT65VY4S.js → chunk-3MKQKNY3.js} +6 -6
  35. package/dist/{chunk-LP764MGR.js → chunk-6Y6M3AZA.js} +3 -3
  36. package/dist/{chunk-D7A5JR7M.js → chunk-BMNHLKBA.js} +2 -2
  37. package/dist/{chunk-CRHQYBDA.js → chunk-CTMHHMHQ.js} +101 -4
  38. package/dist/{chunk-MIZQY35D.js → chunk-D7QXGI6E.js} +2 -2
  39. package/dist/{chunk-F3GNBRGL.js → chunk-EFWRZHZ7.js} +101 -97
  40. package/dist/{chunk-LTYVAKWK.js → chunk-IOJGLIEQ.js} +20 -2
  41. package/dist/{chunk-CMU4DNLY.js → chunk-IXGYIQSR.js} +1 -1
  42. package/dist/{chunk-6NEJPS7W.js → chunk-JJLOWMGC.js} +2 -2
  43. package/dist/{chunk-73QZ43DF.js → chunk-KPBGAB35.js} +2 -2
  44. package/dist/{chunk-HJYAXAYQ.js → chunk-L5UKNGC5.js} +2 -2
  45. package/dist/{chunk-VJDSB7CI.js → chunk-LHWBQD7F.js} +24 -1
  46. package/dist/{chunk-JZL2O3RC.js → chunk-LISEPDVT.js} +5 -5
  47. package/dist/{chunk-NEMB36N4.js → chunk-MEIUXTFY.js} +2 -2
  48. package/dist/{chunk-7RH2NTLA.js → chunk-NZ5AXKRA.js} +1 -1
  49. package/dist/{chunk-H5GN7R43.js → chunk-QHFXVVUY.js} +2 -2
  50. package/dist/{chunk-U2NOOATF.js → chunk-S2ETJDQJ.js} +6 -6
  51. package/dist/{chunk-574JCBYH.js → chunk-TM4KFUWP.js} +2 -2
  52. package/dist/{chunk-YVI7ZV73.js → chunk-VGDZAWCJ.js} +803 -214
  53. package/dist/{chunk-TKPAOB2T.js → chunk-VRA64HYI.js} +2 -2
  54. package/dist/{chunk-T46G6YNI.js → chunk-WAFTJFT3.js} +3 -3
  55. package/dist/{chunk-GTHL3TRZ.js → chunk-XF6RE3JQ.js} +2 -2
  56. package/dist/{chunk-XKILFNRK.js → chunk-XNHKXELN.js} +2 -2
  57. package/dist/{ci-workflow-PA3WL6WK.js → ci-workflow-Y5GBKNZP.js} +4 -4
  58. package/dist/{dist-BWFFVKEW.js → dist-4CZLCE33.js} +7 -3
  59. package/dist/{dist-ISDDHDOR.js → dist-S3KCRI7X.js} +3 -1
  60. package/dist/{docs-HOTWQJQF.js → docs-3MWDPK4S.js} +5 -5
  61. package/dist/{engine-MVG2SPGD.js → engine-RJXQ5DHK.js} +4 -4
  62. package/dist/{entropy-3B4U2BTF.js → entropy-OX5LSM4S.js} +5 -5
  63. package/dist/{feedback-WIWWDVUC.js → feedback-OODAP2G2.js} +1 -1
  64. package/dist/{generate-agent-definitions-KPRHY6X3.js → generate-agent-definitions-CCREQZEA.js} +5 -5
  65. package/dist/hooks/adoption-tracker.js +41 -25
  66. package/dist/hooks/pre-compact-state.js +45 -27
  67. package/dist/hooks/sentinel-post.js +125 -102
  68. package/dist/hooks/sentinel-pre.js +70 -53
  69. package/dist/hooks/telemetry-reporter.js +44 -25
  70. package/dist/index.d.ts +66 -0
  71. package/dist/index.js +25 -25
  72. package/dist/{loader-SPJ2ZGYW.js → loader-ZICOJBVX.js} +4 -4
  73. package/dist/{mcp-VSSIWTII.js → mcp-XX6EIBLL.js} +15 -15
  74. package/dist/{performance-JYFS27B3.js → performance-OLZVGMAY.js} +5 -5
  75. package/dist/{review-pipeline-BDT6Y6QV.js → review-pipeline-3QPHMWPC.js} +4 -4
  76. package/dist/{runtime-ZEPHPPQJ.js → runtime-ZFFIH76Z.js} +4 -4
  77. package/dist/{security-FWSDTTEW.js → security-7YW3UK2C.js} +1 -1
  78. package/dist/{state-events-PBDNQPXT.js → state-events-PTWAEGJ2.js} +4 -4
  79. package/dist/{validate-XIMNCIKR.js → validate-H5SB7X3Z.js} +5 -5
  80. package/dist/{validate-cross-check-H2OUHTID.js → validate-cross-check-YYVYMSPA.js} +4 -4
  81. package/package.json +8 -8
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_dist
3
- } from "./chunk-CRHQYBDA.js";
3
+ } from "./chunk-CTMHHMHQ.js";
4
4
  import {
5
5
  Err,
6
6
  Ok
7
- } from "./chunk-VJDSB7CI.js";
7
+ } from "./chunk-LHWBQD7F.js";
8
8
 
9
9
  // src/persona/generators/agents-md.ts
10
10
  init_dist();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveProjectConfig
3
- } from "./chunk-XKILFNRK.js";
3
+ } from "./chunk-XNHKXELN.js";
4
4
  import {
5
5
  sanitizePath
6
6
  } from "./chunk-W6Y7ZW3Y.js";
@@ -49,7 +49,7 @@ async function handleValidateProject(input) {
49
49
  checks.config = "pass";
50
50
  const config = configResult.value;
51
51
  try {
52
- const core = await import("./dist-BWFFVKEW.js");
52
+ const core = await import("./dist-4CZLCE33.js");
53
53
  if (typeof core.validateFileStructure === "function" && Array.isArray(config.conventions)) {
54
54
  const conventions = config.conventions;
55
55
  const structureResult = await core.validateFileStructure(projectPath, conventions);
@@ -68,7 +68,7 @@ async function handleValidateProject(input) {
68
68
  } catch {
69
69
  }
70
70
  try {
71
- const core = await import("./dist-BWFFVKEW.js");
71
+ const core = await import("./dist-4CZLCE33.js");
72
72
  if (typeof core.validateAgentsMap === "function") {
73
73
  const agentsMapPath = path.join(projectPath, "AGENTS.md");
74
74
  const agentsResult = await core.validateAgentsMap(agentsMapPath);
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_dist
3
- } from "./chunk-CRHQYBDA.js";
3
+ } from "./chunk-CTMHHMHQ.js";
4
4
  import {
5
5
  Err,
6
6
  Ok
7
- } from "./chunk-VJDSB7CI.js";
7
+ } from "./chunk-LHWBQD7F.js";
8
8
 
9
9
  // src/persona/generators/ci-workflow.ts
10
10
  init_dist();
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_dist
3
- } from "./chunk-CRHQYBDA.js";
3
+ } from "./chunk-CTMHHMHQ.js";
4
4
  import {
5
5
  Err,
6
6
  Ok
7
- } from "./chunk-VJDSB7CI.js";
7
+ } from "./chunk-LHWBQD7F.js";
8
8
 
9
9
  // src/mcp/utils/config-resolver.ts
10
10
  init_dist();
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  generateCIWorkflow
3
- } from "./chunk-GTHL3TRZ.js";
4
- import "./chunk-CRHQYBDA.js";
5
- import "./chunk-7RH2NTLA.js";
6
- import "./chunk-VJDSB7CI.js";
3
+ } from "./chunk-XF6RE3JQ.js";
4
+ import "./chunk-CTMHHMHQ.js";
5
+ import "./chunk-NZ5AXKRA.js";
6
+ import "./chunk-LHWBQD7F.js";
7
7
  import "./chunk-WZJR6SOI.js";
8
8
  import "./chunk-QCLOIUMX.js";
9
9
  import "./chunk-XARGEOJV.js";
@@ -219,6 +219,7 @@ import {
219
219
  claim,
220
220
  classifyConfidence,
221
221
  classifyFinding,
222
+ classifyRevert,
222
223
  clearFailuresCache,
223
224
  clearLearningsCache,
224
225
  clearPulseAdapters,
@@ -524,7 +525,7 @@ import {
524
525
  writeStrategyDoc,
525
526
  writeTaint,
526
527
  xssRules
527
- } from "./chunk-CRHQYBDA.js";
528
+ } from "./chunk-CTMHHMHQ.js";
528
529
  import {
529
530
  EXTENSION_MAP,
530
531
  EntropyAnalyzer,
@@ -550,7 +551,7 @@ import {
550
551
  resetParserCache,
551
552
  resolveFileToLayer,
552
553
  validateDependencies
553
- } from "./chunk-7RH2NTLA.js";
554
+ } from "./chunk-NZ5AXKRA.js";
554
555
  import {
555
556
  AuthAuditEntrySchema,
556
557
  AuthTokenPublicSchema,
@@ -589,6 +590,7 @@ import {
589
590
  ProposalStatusSchema,
590
591
  ProposalTypeSchema,
591
592
  REQUIRED_STRATEGY_SECTIONS,
593
+ RoutingError,
592
594
  SESSIONS_DEFAULTS,
593
595
  SESSION_SECTION_NAMES,
594
596
  STANDARD_COGNITIVE_MODES,
@@ -605,7 +607,7 @@ import {
605
607
  isErr,
606
608
  isOk,
607
609
  migrateProposalRecord
608
- } from "./chunk-VJDSB7CI.js";
610
+ } from "./chunk-LHWBQD7F.js";
609
611
  import "./chunk-WZJR6SOI.js";
610
612
  import {
611
613
  ArchBaselineSchema,
@@ -806,6 +808,7 @@ export {
806
808
  ROADMAP_READ_ALLOWLIST,
807
809
  RUNNER_PRESETS,
808
810
  RegressionDetector,
811
+ RoutingError,
809
812
  RuleRegistry,
810
813
  SECURITY_DESCRIPTOR,
811
814
  SESSIONS_DEFAULTS,
@@ -932,6 +935,7 @@ export {
932
935
  claim,
933
936
  classifyConfidence,
934
937
  classifyFinding,
938
+ classifyRevert,
935
939
  clearFailuresCache,
936
940
  clearLearningsCache,
937
941
  clearPulseAdapters,
@@ -36,6 +36,7 @@ import {
36
36
  ProposalStatusSchema,
37
37
  ProposalTypeSchema,
38
38
  REQUIRED_STRATEGY_SECTIONS,
39
+ RoutingError,
39
40
  SESSIONS_DEFAULTS,
40
41
  SESSION_SECTION_NAMES,
41
42
  STANDARD_COGNITIVE_MODES,
@@ -53,7 +54,7 @@ import {
53
54
  isErr,
54
55
  isOk,
55
56
  migrateProposalRecord
56
- } from "./chunk-VJDSB7CI.js";
57
+ } from "./chunk-LHWBQD7F.js";
57
58
  import "./chunk-KFQGP6VL.js";
58
59
  init_dist();
59
60
  export {
@@ -94,6 +95,7 @@ export {
94
95
  ProposalStatusSchema,
95
96
  ProposalTypeSchema,
96
97
  REQUIRED_STRATEGY_SECTIONS,
98
+ RoutingError,
97
99
  SESSIONS_DEFAULTS,
98
100
  SESSION_SECTION_NAMES,
99
101
  STANDARD_COGNITIVE_MODES,
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  checkDocsDefinition,
3
3
  handleCheckDocs
4
- } from "./chunk-PT65VY4S.js";
4
+ } from "./chunk-3MKQKNY3.js";
5
5
  import "./chunk-RC3OI5NK.js";
6
6
  import "./chunk-W6Y7ZW3Y.js";
7
- import "./chunk-LTYVAKWK.js";
7
+ import "./chunk-IOJGLIEQ.js";
8
8
  import "./chunk-ZCZD7FHU.js";
9
9
  import "./chunk-3WGJMBKH.js";
10
- import "./chunk-CRHQYBDA.js";
11
- import "./chunk-7RH2NTLA.js";
12
- import "./chunk-VJDSB7CI.js";
10
+ import "./chunk-CTMHHMHQ.js";
11
+ import "./chunk-NZ5AXKRA.js";
12
+ import "./chunk-LHWBQD7F.js";
13
13
  import "./chunk-WZJR6SOI.js";
14
14
  import "./chunk-QCLOIUMX.js";
15
15
  import "./chunk-XARGEOJV.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  TemplateEngine
3
- } from "./chunk-6NEJPS7W.js";
4
- import "./chunk-CRHQYBDA.js";
5
- import "./chunk-7RH2NTLA.js";
6
- import "./chunk-VJDSB7CI.js";
3
+ } from "./chunk-JJLOWMGC.js";
4
+ import "./chunk-CTMHHMHQ.js";
5
+ import "./chunk-NZ5AXKRA.js";
6
+ import "./chunk-LHWBQD7F.js";
7
7
  import "./chunk-WZJR6SOI.js";
8
8
  import "./chunk-QCLOIUMX.js";
9
9
  import "./chunk-XARGEOJV.js";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  detectEntropyDefinition,
3
3
  handleDetectEntropy
4
- } from "./chunk-JZL2O3RC.js";
4
+ } from "./chunk-LISEPDVT.js";
5
5
  import "./chunk-RC3OI5NK.js";
6
6
  import "./chunk-W6Y7ZW3Y.js";
7
- import "./chunk-LTYVAKWK.js";
7
+ import "./chunk-IOJGLIEQ.js";
8
8
  import "./chunk-ZCZD7FHU.js";
9
9
  import "./chunk-3WGJMBKH.js";
10
- import "./chunk-CRHQYBDA.js";
11
- import "./chunk-7RH2NTLA.js";
12
- import "./chunk-VJDSB7CI.js";
10
+ import "./chunk-CTMHHMHQ.js";
11
+ import "./chunk-NZ5AXKRA.js";
12
+ import "./chunk-LHWBQD7F.js";
13
13
  import "./chunk-WZJR6SOI.js";
14
14
  import "./chunk-QCLOIUMX.js";
15
15
  import "./chunk-XARGEOJV.js";
@@ -5,7 +5,7 @@ import {
5
5
  handleCreateSelfReview,
6
6
  handleRequestPeerReview,
7
7
  requestPeerReviewDefinition
8
- } from "./chunk-MEDRUIRO.js";
8
+ } from "./chunk-354MCPT3.js";
9
9
  import "./chunk-RC3OI5NK.js";
10
10
  import "./chunk-W6Y7ZW3Y.js";
11
11
  import "./chunk-KFQGP6VL.js";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createGenerateAgentDefinitionsCommand,
3
3
  generateAgentDefinitions
4
- } from "./chunk-CMU4DNLY.js";
4
+ } from "./chunk-IXGYIQSR.js";
5
5
  import "./chunk-KET4QQZB.js";
6
- import "./chunk-73QZ43DF.js";
6
+ import "./chunk-KPBGAB35.js";
7
7
  import "./chunk-3ISINLYT.js";
8
8
  import "./chunk-UTJJJDNN.js";
9
9
  import "./chunk-3WGJMBKH.js";
10
- import "./chunk-CRHQYBDA.js";
11
- import "./chunk-7RH2NTLA.js";
12
- import "./chunk-VJDSB7CI.js";
10
+ import "./chunk-CTMHHMHQ.js";
11
+ import "./chunk-NZ5AXKRA.js";
12
+ import "./chunk-LHWBQD7F.js";
13
13
  import "./chunk-WZJR6SOI.js";
14
14
  import "./chunk-QCLOIUMX.js";
15
15
  import "./chunk-XARGEOJV.js";
@@ -112,23 +112,56 @@ function deriveDuration(events) {
112
112
  return max - min;
113
113
  }
114
114
 
115
- function main() {
116
- let raw = '';
115
+ /** Read stdin (fd 0) and parse it as JSON. Returns null when it should exit-0. */
116
+ function readStdinJson() {
117
+ let raw;
117
118
  try {
118
119
  raw = readFileSync(0, 'utf-8');
119
120
  } catch {
120
- process.exit(0);
121
+ return null;
121
122
  }
122
123
 
123
124
  if (!raw.trim()) {
124
- process.exit(0);
125
+ return null;
125
126
  }
126
127
 
127
- let input;
128
128
  try {
129
- input = JSON.parse(raw);
129
+ return JSON.parse(raw);
130
130
  } catch {
131
131
  process.stderr.write('[adoption-tracker] Could not parse stdin — skipping\n');
132
+ return null;
133
+ }
134
+ }
135
+
136
+ /** Group events by their skill name, preserving order. */
137
+ function groupBySkill(events) {
138
+ const skillGroups = new Map();
139
+ for (const event of events) {
140
+ if (!skillGroups.has(event.skill)) {
141
+ skillGroups.set(event.skill, []);
142
+ }
143
+ skillGroups.get(event.skill).push(event);
144
+ }
145
+ return skillGroups;
146
+ }
147
+
148
+ /** Build a single adoption record for one skill's events. */
149
+ function buildRecord(skill, events, allEvents, sessionId) {
150
+ // Use all events for this skill (including non-relevant) for timing
151
+ const allSkillEvents = allEvents.filter((e) => e.skill === skill);
152
+ return {
153
+ skill,
154
+ session: sessionId,
155
+ startedAt: allSkillEvents[0]?.timestamp ?? events[0].timestamp,
156
+ duration: deriveDuration(allSkillEvents.length > 0 ? allSkillEvents : events),
157
+ outcome: deriveOutcome(events),
158
+ phasesReached: derivePhasesReached(events),
159
+ };
160
+ }
161
+
162
+ function main() {
163
+ const input = readStdinJson();
164
+ if (input === null) {
132
165
  process.exit(0);
133
166
  }
134
167
 
@@ -170,13 +203,7 @@ function main() {
170
203
  }
171
204
 
172
205
  // Group events by skill
173
- const skillGroups = new Map();
174
- for (const event of relevantEvents) {
175
- if (!skillGroups.has(event.skill)) {
176
- skillGroups.set(event.skill, []);
177
- }
178
- skillGroups.get(event.skill).push(event);
179
- }
206
+ const skillGroups = groupBySkill(relevantEvents);
180
207
 
181
208
  // Reconstruct invocation records
182
209
  const sessionId = input.session_id ?? 'unknown';
@@ -186,18 +213,7 @@ function main() {
186
213
 
187
214
  let written = 0;
188
215
  for (const [skill, events] of skillGroups) {
189
- // Use all events for this skill (including non-relevant) for timing
190
- const allSkillEvents = allEvents.filter((e) => e.skill === skill);
191
-
192
- const record = {
193
- skill,
194
- session: sessionId,
195
- startedAt: allSkillEvents[0]?.timestamp ?? events[0].timestamp,
196
- duration: deriveDuration(allSkillEvents.length > 0 ? allSkillEvents : events),
197
- outcome: deriveOutcome(events),
198
- phasesReached: derivePhasesReached(events),
199
- };
200
-
216
+ const record = buildRecord(skill, events, allEvents, sessionId);
201
217
  appendFileSync(adoptionFile, JSON.stringify(record) + '\n');
202
218
  written++;
203
219
  }
@@ -43,7 +43,11 @@ function findActiveSession(sessionsDir) {
43
43
  }
44
44
  }
45
45
 
46
- function main() {
46
+ /**
47
+ * Read and validate stdin as JSON. On any failure, writes the matching
48
+ * fail-open stderr message and exits 0. Returns the raw string on success.
49
+ */
50
+ function readValidStdin() {
47
51
  let raw = '';
48
52
  try {
49
53
  raw = readFileSync(0, 'utf-8');
@@ -64,39 +68,53 @@ function main() {
64
68
  process.exit(0);
65
69
  }
66
70
 
71
+ return raw;
72
+ }
73
+
74
+ /** Map a decision entry to its display string. */
75
+ function decisionToString(d) {
76
+ return typeof d === 'string' ? d : (d?.decision ?? d?.summary ?? JSON.stringify(d));
77
+ }
78
+
79
+ /** The active session's current state string, or null when absent. */
80
+ function sessionCurrentState(session) {
81
+ return session?.state?.currentState ?? null;
82
+ }
83
+
84
+ /** Last five decisions from harness state, each mapped to a display string. */
85
+ function recentDecisionsFrom(state) {
86
+ const decisions = state?.decisions ?? [];
87
+ return decisions.slice(-5).map(decisionToString);
88
+ }
89
+
90
+ /** Current phase: prefer the live session state, fall back to the persisted position. */
91
+ function currentPhaseFrom(state, session) {
92
+ return sessionCurrentState(session) ?? state?.position?.phase ?? null;
93
+ }
94
+
95
+ /** Build the pre-compact summary object from harness state and active session. */
96
+ function buildSummary(state, session) {
97
+ return {
98
+ timestamp: new Date().toISOString(),
99
+ sessionId: session?.dir ?? null,
100
+ activeStream: sessionCurrentState(session),
101
+ recentDecisions: recentDecisionsFrom(state),
102
+ openQuestions: state?.blockers ?? [],
103
+ currentPhase: currentPhaseFrom(state, session),
104
+ };
105
+ }
106
+
107
+ function main() {
108
+ readValidStdin();
109
+
67
110
  try {
68
111
  const cwd = process.cwd();
69
112
  const harnessDir = join(cwd, '.harness');
70
113
  const stateDir = join(harnessDir, 'state');
71
114
 
72
- // Read harness state
73
115
  const state = readJsonSafe(join(harnessDir, 'state.json'));
74
-
75
- // Find active session
76
116
  const session = findActiveSession(join(harnessDir, 'sessions'));
77
-
78
- // Extract recent decisions (last 5)
79
- const decisions = state?.decisions ?? [];
80
- const recentDecisions = decisions.slice(-5).map((d) =>
81
- typeof d === 'string' ? d : (d?.decision ?? d?.summary ?? JSON.stringify(d))
82
- );
83
-
84
- // Extract open questions / blockers
85
- const openQuestions = state?.blockers ?? [];
86
-
87
- // Determine current phase from session state
88
- const currentPhase = session?.state?.currentState
89
- ?? (state?.position?.phase ?? null);
90
-
91
- // Build summary
92
- const summary = {
93
- timestamp: new Date().toISOString(),
94
- sessionId: session?.dir ?? null,
95
- activeStream: session?.state?.currentState ?? null,
96
- recentDecisions,
97
- openQuestions,
98
- currentPhase,
99
- };
117
+ const summary = buildSummary(state, session);
100
118
 
101
119
  mkdirSync(stateDir, { recursive: true });
102
120
  writeFileSync(