@walwal-harness/cli 6.1.4 → 6.1.6

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 (58) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +43 -74
  3. package/assets/launchd/com.walwal.harness-wake.plist.template +32 -0
  4. package/assets/templates/CONVENTIONS.md +12 -0
  5. package/assets/templates/HARNESS.md +8 -8
  6. package/assets/templates/company-pipeline-manifest.json +71 -0
  7. package/assets/templates/config.json +29 -27
  8. package/assets/templates/memory.md +16 -2
  9. package/assets/templates/progress.json.template +6 -5
  10. package/bin/init.js +180 -90
  11. package/conventions/shared.md +34 -0
  12. package/gotchas/conductor.md +16 -0
  13. package/gotchas/dispatcher.md +16 -0
  14. package/gotchas/meeting-manager.md +8 -0
  15. package/gotchas/service-ops.md +8 -0
  16. package/package.json +4 -4
  17. package/scripts/conductor-tick.sh +157 -56
  18. package/scripts/harness-archive.sh +7 -5
  19. package/scripts/harness-dashboard-up.sh +11 -3
  20. package/scripts/harness-hourly-review.sh +582 -0
  21. package/scripts/harness-meeting-doc.sh +55 -16
  22. package/scripts/harness-next.sh +1 -1
  23. package/scripts/harness-parity-audit.sh +101 -0
  24. package/scripts/harness-queue-manager.sh +13 -6
  25. package/scripts/harness-service-ops-monitor.sh +273 -0
  26. package/scripts/harness-session-start.sh +60 -31
  27. package/scripts/harness-statusline.sh +8 -12
  28. package/scripts/harness-stop.sh +85 -0
  29. package/scripts/harness-user-prompt-submit.sh +11 -29
  30. package/scripts/harness-wake-install.sh +180 -0
  31. package/scripts/harness-wake.sh +350 -0
  32. package/scripts/harness-worker-dispatch.sh +188 -0
  33. package/scripts/lib/harness-agent-resolver.sh +127 -0
  34. package/scripts/lib/harness-progress-migrate.sh +6 -1
  35. package/scripts/lib/harness-render-progress.sh +3 -3
  36. package/skills/brainstorming/SKILL.md +2 -2
  37. package/skills/conductor/SKILL.md +67 -55
  38. package/skills/cqo/SKILL.md +1 -0
  39. package/skills/cto/SKILL.md +1 -0
  40. package/skills/dispatcher/SKILL.md +33 -14
  41. package/skills/evaluator-code-quality/SKILL.md +4 -4
  42. package/skills/evaluator-functional/SKILL.md +6 -6
  43. package/skills/evaluator-visual/SKILL.md +4 -4
  44. package/skills/generator-backend/SKILL.md +4 -4
  45. package/skills/generator-frontend/SKILL.md +5 -5
  46. package/skills/meeting-manager/SKILL.md +82 -12
  47. package/skills/planner/SKILL.md +3 -3
  48. package/skills/service-ops/SKILL.md +25 -0
  49. package/commands/harness-solo.md +0 -103
  50. package/commands/harness-stop.md +0 -53
  51. package/commands/harness-team.md +0 -530
  52. package/scripts/harness-dashboard.sh +0 -509
  53. package/scripts/harness-goal-init.sh +0 -72
  54. package/scripts/harness-goal-show.sh +0 -37
  55. package/scripts/harness-gotcha-memory.sh +0 -348
  56. package/scripts/harness-monitor.sh +0 -398
  57. package/scripts/harness-prompt-history.sh +0 -164
  58. package/scripts/harness-tmux.sh +0 -372
@@ -9,6 +9,7 @@ PROJECT_ROOT="$(resolve_harness_root "${1:-.}")" || exit 0
9
9
  PROGRESS="$PROJECT_ROOT/.harness/progress.json"
10
10
  CONFIG="$PROJECT_ROOT/.harness/config.json"
11
11
  FEATURES="$PROJECT_ROOT/.harness/actions/feature-list.json"
12
+ QUEUE="$PROJECT_ROOT/.harness/actions/feature-queue.json"
12
13
 
13
14
  [ -f "$PROGRESS" ] || exit 0
14
15
  [ -f "$CONFIG" ] || exit 0
@@ -22,17 +23,17 @@ fi
22
23
  current_agent=$(jq -r '.current_agent // "null"' "$PROGRESS")
23
24
  agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS")
24
25
  pipeline=$(jq -r '.pipeline // "null"' "$PROGRESS")
25
- mode=$(jq -r '.mode // "auto"' "$PROGRESS")
26
+ mode=$(jq -r '.mode // "company"' "$PROGRESS")
26
27
  # v6.2 — parallel tracks (fork-join) state
27
28
  parallel_tracks=$(jq -c '.conductor.tracks // []' "$PROGRESS")
28
29
  parallel_rendezvous=$(jq -c '.conductor.rendezvous // null' "$PROGRESS")
29
30
  parallel_pending_count=$(jq -r '[ .conductor.tracks // [] | .[] | select(.status == "pending" or .status == "running") ] | length' "$PROGRESS")
30
- user_override=$(jq -r '.mode_decision.user_override // "null"' "$PROGRESS")
31
31
  requested_mode=$(jq -r '.service_ops.requested_mode // "null"' "$PROGRESS")
32
32
  planner_requested_mode=$(jq -r '.planner.requested_mode // "null"' "$PROGRESS")
33
33
  planner_last_brief=$(jq -r '.planner.last_brief // "null"' "$PROGRESS")
34
34
  goal_adherence=$(jq -r '.goals.current_adherence // "null"' "$PROGRESS")
35
35
  meetings_active_count=$(jq -r '(.meetings.active | length) // 0' "$PROGRESS")
36
+ pending_required_execution=$(jq -r 'if (.meetings.decision.required_execution // null) != null then "true" else "false" end' "$PROGRESS")
36
37
  cqo_verdict=$(jq -r '.cqo.sprint_verdict // "pending"' "$PROGRESS")
37
38
  ops_report=$(jq -r '.service_ops.auto_retro.last_report // "null"' "$PROGRESS")
38
39
  cto_hotfixes=$(jq -r '.cto.open_hotfixes // 0' "$PROGRESS")
@@ -57,50 +58,16 @@ escape_json_string() {
57
58
  jq -Rn --arg v "$1" '$v'
58
59
  }
59
60
 
60
- maybe_select_mode() {
61
- local effective="$mode"
62
- if [ "$user_override" != "null" ] && [ -n "$user_override" ]; then
63
- effective="$user_override"
64
- set_progress ".mode = \"$effective\" |
65
- .mode_decision.owner = \"conductor\" |
66
- .mode_decision.user_override = \"$effective\" |
61
+ normalize_company_mode() {
62
+ if [ "$mode" != "company" ]; then
63
+ set_progress '.mode = "company" |
64
+ .mode_decision.owner = "conductor" |
65
+ .mode_decision.policy = "always_company_parallel" |
66
+ .mode_decision.user_override = null |
67
67
  .mode_decision.decided_at = (now | todate) |
68
- .mode_decision.rationale = \"user override: $effective\""
69
- echo "$effective"
70
- return
71
- fi
72
- if [ "$mode" != "auto" ] || [ ! -f "$FEATURES" ]; then
73
- echo "$mode"
74
- return
75
- fi
76
-
77
- local feature_count ready_at_start critical_depth
78
- feature_count=$(jq '.features | length // 0' "$FEATURES" 2>/dev/null || echo 0)
79
- ready_at_start=$(jq '[.features[]? | select(((.depends_on // []) | length) == 0)] | length' "$FEATURES" 2>/dev/null || echo 0)
80
- critical_depth=$(jq '
81
- def feature($id): .features[]? | select(.id == $id);
82
- def depth($id):
83
- (feature($id) | .depends_on // []) as $deps
84
- | if ($deps | length) == 0 then 1 else ([ $deps[] | depth(.) ] | max + 1) end;
85
- ([.features[]?.id | depth(.)] | max) // 0
86
- ' "$FEATURES" 2>/dev/null || echo 0)
87
-
88
- local team_ready team_features team_depth selected rationale
89
- team_ready=$(jq -r '.mode_selection.rules.force_team_when.ready_at_start_gte // 3' "$CONFIG")
90
- team_features=$(jq -r '.mode_selection.rules.force_team_when.feature_count_gte // 6' "$CONFIG")
91
- team_depth=$(jq -r '.mode_selection.rules.force_team_when.critical_path_depth_lte // 2' "$CONFIG")
92
-
93
- if [ "$ready_at_start" -ge "$team_ready" ] && [ "$feature_count" -ge "$team_features" ] && [ "$critical_depth" -le "$team_depth" ]; then
94
- selected="team"
95
- else
96
- selected=$(jq -r '.mode_selection.rules.tie_breaker // "team"' "$CONFIG")
68
+ .mode_decision.rationale = "legacy mode normalized to always-on company mode"'
97
69
  fi
98
- rationale="company-default: ready=${ready_at_start}, features=${feature_count}, depth=${critical_depth} -> ${selected}"
99
- set_progress ".mode = \"$selected\" |
100
- .mode_decision.owner = \"conductor\" |
101
- .mode_decision.decided_at = (now | todate) |
102
- .mode_decision.rationale = \"$rationale\""
103
- echo "$selected"
70
+ echo "company"
104
71
  }
105
72
 
106
73
  infer_drift_classification() {
@@ -140,8 +107,24 @@ meeting_stage_for_owner() {
140
107
  esac
141
108
  }
142
109
 
110
+ ensure_team_queue() {
111
+ [ "$effective_mode" = "company" ] || return 0
112
+ [ -f "$FEATURES" ] || return 0
113
+ [ -x "$SCRIPT_DIR/harness-queue-manager.sh" ] || return 0
114
+
115
+ if [ ! -f "$QUEUE" ]; then
116
+ bash "$SCRIPT_DIR/harness-queue-manager.sh" init all "$PROJECT_ROOT" >/dev/null 2>&1 || true
117
+ else
118
+ bash "$SCRIPT_DIR/harness-queue-manager.sh" recover "$PROJECT_ROOT" >/dev/null 2>&1 || true
119
+ fi
120
+ }
121
+
143
122
  load_meeting_decision() {
144
123
  local decision
124
+ if jq -e '(.meetings.decision.required_execution // null) != null' "$PROGRESS" >/dev/null 2>&1; then
125
+ jq -c '.meetings.decision' "$PROGRESS"
126
+ return 0
127
+ fi
145
128
  decision=$(bash "$SCRIPT_DIR/harness-meeting-doc.sh" "$PROJECT_ROOT" read-decision 2>/dev/null || true)
146
129
  if [ -n "$decision" ]; then
147
130
  echo "$decision"
@@ -150,7 +133,56 @@ load_meeting_decision() {
150
133
  fi
151
134
  }
152
135
 
153
- effective_mode="$(maybe_select_mode)"
136
+ dispatch_company_workers() {
137
+ [ "$effective_mode" = "company" ] || { echo "[]"; return 0; }
138
+ [ -f "$FEATURES" ] || { echo "[]"; return 0; }
139
+ [ -x "$SCRIPT_DIR/harness-worker-dispatch.sh" ] || { echo "[]"; return 0; }
140
+ bash "$SCRIPT_DIR/harness-worker-dispatch.sh" "$PROJECT_ROOT" 2>/dev/null || echo "[]"
141
+ }
142
+
143
+ ensure_strategy_work_package() {
144
+ local required_json="$1"
145
+ local deliverable_path="$2"
146
+ local target_path="$PROJECT_ROOT/$deliverable_path"
147
+ local stamp
148
+ stamp="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
149
+
150
+ [ -n "$deliverable_path" ] && [ "$deliverable_path" != "null" ] || return 0
151
+ mkdir -p "$(dirname "$target_path")"
152
+ if [ ! -f "$target_path" ]; then
153
+ {
154
+ echo "# Strategy Cadence Recovery Work Package"
155
+ echo ""
156
+ echo "- created_at: $stamp"
157
+ echo "- owner: Planner/COO"
158
+ echo "- source_decision: $(jq -r '.source_path // "unknown"' <<<"$required_json")"
159
+ echo "- required_execution_id: $(jq -r '.id // "unknown"' <<<"$required_json")"
160
+ echo "- status: opened"
161
+ echo ""
162
+ echo "## Candidate Idea"
163
+ echo ""
164
+ echo "Planner/COO must define one concrete strategy candidate for this hour. A restatement of the goal is not sufficient."
165
+ echo ""
166
+ echo "## Data Source"
167
+ echo ""
168
+ echo "Name the market data source, lookback window, and any filters used by the candidate."
169
+ echo ""
170
+ echo "## Backtest Command"
171
+ echo ""
172
+ echo '```bash'
173
+ echo "# Fill with the exact command that produces a backtest result artifact."
174
+ echo '```'
175
+ echo ""
176
+ echo "## CQO Acceptance"
177
+ echo ""
178
+ echo "- PASS requires a generated candidate artifact and a backtest/evaluation artifact."
179
+ echo "- If no candidate is generated before the next hourly review, classify the cycle as paperwork_only_failure."
180
+ } > "$target_path"
181
+ fi
182
+ }
183
+
184
+ effective_mode="$(normalize_company_mode)"
185
+ ensure_team_queue
154
186
  drift_classification="$(infer_drift_classification)"
155
187
 
156
188
  next="$candidate"
@@ -241,6 +273,10 @@ elif [ "$parallel_pending_count" -gt 0 ] && [ "$agent_status" = "completed" ] &&
241
273
  planner_filter=".planner.requested_mode = \"$next_action\""
242
274
  fi
243
275
  meeting_filter=".conductor.tracks = $updated_tracks | .meetings.decision.tracks = $updated_tracks"
276
+ else
277
+ next="$candidate"
278
+ action="parallel:await-rendezvous"
279
+ meeting_filter=".conductor.tracks = $updated_tracks | .meetings.decision.tracks = $updated_tracks"
244
280
  fi
245
281
  else
246
282
  # All tracks completed → rendezvous (followup-review)
@@ -270,7 +306,7 @@ elif [ "$parallel_pending_count" -gt 0 ] && [ "$agent_status" = "completed" ] &&
270
306
  .conductor.rendezvous = null"
271
307
  fi
272
308
 
273
- elif [ "$requested_mode" != "null" ] && [ -n "$requested_mode" ] && [ "$current_agent" != "service-ops" ]; then
309
+ elif [ "$pending_required_execution" != "true" ] && [ "$requested_mode" != "null" ] && [ -n "$requested_mode" ] && [ "$current_agent" != "service-ops" ]; then
274
310
  next="service-ops"
275
311
  action="spawn:service-ops:${requested_mode}"
276
312
 
@@ -302,6 +338,8 @@ elif [ "$current_agent" = "meeting-manager" ] && [ "$agent_status" = "completed"
302
338
  evidence=$(jq -c '.evidence // []' <<<"$meeting_decision")
303
339
  decision_drift=$(jq -r '.drift_classification // "unknown"' <<<"$meeting_decision")
304
340
  source_path=$(jq -r '.source_path // "null"' <<<"$meeting_decision")
341
+ required_execution=$(jq -c '.required_execution // null' <<<"$meeting_decision")
342
+ required_deliverable=$(jq -r '.required_execution.deliverable_path // "null"' <<<"$meeting_decision")
305
343
  # v6.2 — tracks length >= 2 → fork-join, else single. mode 필드 없음.
306
344
  decision_tracks=$(jq -c '.tracks // []' <<<"$meeting_decision")
307
345
  decision_rendezvous=$(jq -c '.rendezvous // null' <<<"$meeting_decision")
@@ -311,23 +349,50 @@ elif [ "$current_agent" = "meeting-manager" ] && [ "$agent_status" = "completed"
311
349
  implementation_drift) owner="cto" ;;
312
350
  planning_drift) owner="planner" ;;
313
351
  ops_drift) owner="service-ops" ;;
314
- goal_drift) owner="dispatcher" ;;
352
+ goal_drift) owner="planner" ;;
315
353
  *)
316
354
  if [ "$plan_artifacts_ready" = false ]; then owner="planner"; else owner="cto"; fi
317
355
  ;;
318
356
  esac
319
357
  fi
320
358
 
321
- # v6.2 — Parallel fork: if 2+ tracks, materialize conductor.tracks[] and dispatch
322
- # the first pending track owner. Subsequent ticks advance remaining tracks.
323
- if [ "$(jq 'length' <<<"$decision_tracks")" -gt 1 ]; then
359
+ if [ "$required_execution" = "null" ]; then
360
+ case "$owner:$action_type" in
361
+ planner:continue-current-handoff|planner:execution-plan|cto:continue-current-handoff|cqo:continue-current-handoff|generator-*:continue-current-handoff|evaluator-*:continue-current-handoff)
362
+ next="meeting-manager"
363
+ action="convene:followup-review:execution-contract-missing"
364
+ new_conductor_state="waiting_meeting"
365
+ new_workflow_stage="followup-review"
366
+ meeting_prepare=true
367
+ meeting_filter="
368
+ .meetings.active = [\"meeting-manager\"] |
369
+ .meetings.requested_type = \"followup-review\" |
370
+ .meetings.requested_reason = \"execution-contract-missing\" |
371
+ .meetings.contract_missing = {
372
+ \"owner\": \"$owner\",
373
+ \"action_type\": \"$action_type\",
374
+ \"source_path\": $(escape_json_string "$source_path"),
375
+ \"detected_at\": (now | todate)
376
+ }"
377
+ ;;
378
+ esac
379
+ fi
380
+
381
+ # v6.2 — Parallel fork: if 2+ tracks, materialize all tracks as running.
382
+ # `next_agent` keeps the first owner only for backward-compatible handoff display;
383
+ # the fork state itself must expose every track as active in the same tick.
384
+ if [ "$action" = "convene:followup-review:execution-contract-missing" ]; then
385
+ :
386
+ elif [ "$(jq 'length' <<<"$decision_tracks")" -gt 1 ]; then
324
387
  first_track_owner=$(jq -r '.[0].owner' <<<"$decision_tracks")
325
388
  first_track_action=$(jq -r '.[0].action_type // "triage"' <<<"$decision_tracks")
326
389
  first_track_id=$(jq -r '.[0].id // "track-1"' <<<"$decision_tracks")
327
- # mark first track as running, rest as pending
328
- materialized_tracks=$(jq -c --arg first "$first_track_id" '
390
+ active_track_owners=$(jq -c '[.[] | .owner] | unique' <<<"$decision_tracks")
391
+ # mark every independent track as running; rendezvous waits for completion.
392
+ materialized_tracks=$(jq -c '
329
393
  [ .[] | . + {
330
- status: (if .id == $first then "running" else (.status // "pending") end),
394
+ status: "running",
395
+ started_at: (now | todate),
331
396
  deliverable_path: (.deliverable_path // null)
332
397
  }
333
398
  ]
@@ -347,6 +412,7 @@ elif [ "$current_agent" = "meeting-manager" ] && [ "$agent_status" = "completed"
347
412
  .meetings.requested_reason = null |
348
413
  .meetings.requested_tracks = [] |
349
414
  .meetings.requested_rendezvous = null |
415
+ .meetings.active = $active_track_owners |
350
416
  .meetings.decision = {
351
417
  \"owner\": \"$owner\",
352
418
  \"action_type\": \"$action_type\",
@@ -361,6 +427,10 @@ elif [ "$current_agent" = "meeting-manager" ] && [ "$agent_status" = "completed"
361
427
  .conductor.rendezvous = $decision_rendezvous |
362
428
  .conductor.fork_meeting_id = (.meetings.current_id // null)"
363
429
  else
430
+ if [ "$action_type" = "strategy-cadence-recovery" ]; then
431
+ ensure_strategy_work_package "$required_execution" "$required_deliverable"
432
+ owner="planner"
433
+ fi
364
434
  next="$owner"
365
435
  action="dispatch:${owner}:${action_type}"
366
436
  new_workflow_stage="$(meeting_stage_for_owner "$owner")"
@@ -383,6 +453,7 @@ elif [ "$current_agent" = "meeting-manager" ] && [ "$agent_status" = "completed"
383
453
  \"evidence\": $evidence,
384
454
  \"drift_classification\": $(escape_json_string "$decision_drift"),
385
455
  \"source_path\": $(escape_json_string "$source_path"),
456
+ \"required_execution\": $required_execution,
386
457
  \"tracks\": [],
387
458
  \"rendezvous\": null
388
459
  } |
@@ -446,7 +517,17 @@ elif [ "$current_agent" = "coo-developer" ] && [ "$agent_status" = "completed" ]
446
517
  fi
447
518
 
448
519
  elif [ "$current_agent" = "cto" ]; then
449
- if [ "${cto_hotfixes:-0}" -gt 0 ] || [ "${ops_recommendations:-0}" -gt 0 ]; then
520
+ cto_step_b_status=$(jq -r '.cto.step_b_status // ""' "$PROGRESS")
521
+ if [ "$agent_status" = "step-B-code-edited" ] || [[ "$cto_step_b_status" == *deferred* ]]; then
522
+ next="cqo"
523
+ action="spawn:cqo:gateway-typecheck-verify"
524
+ new_workflow_stage="quality-review"
525
+ meeting_filter='
526
+ .cqo.requested_mode = "gateway-typecheck-verify" |
527
+ .meetings.active = ["cqo"] |
528
+ .meetings.requested_type = null |
529
+ .meetings.requested_reason = null'
530
+ elif [ "${cto_hotfixes:-0}" -gt 0 ] || [ "${ops_recommendations:-0}" -gt 0 ]; then
450
531
  next="planner"
451
532
  action="dispatch:planner:execution-plan"
452
533
  new_workflow_stage="coo-replan"
@@ -502,13 +583,13 @@ elif [ "$candidate" = "archive" ]; then
502
583
  local_drift="$drift_classification"
503
584
  if [ "$requested_mode" = "auto-retro" ] || [ "${open_incidents:-0}" -gt 0 ] || [ "${ops_alerts:-0}" -gt 0 ] || { [ "$goal_adherence" != "null" ] && awk "BEGIN {exit !($goal_adherence < 0.7)}"; }; then
504
585
  next="meeting-manager"
505
- action="convene:sprint-review:${local_drift}"
586
+ action="convene:operating-review:${local_drift}"
506
587
  new_conductor_state="waiting_meeting"
507
588
  new_workflow_stage="ops-review"
508
589
  meeting_prepare=true
509
590
  meeting_filter="
510
591
  .meetings.active = [\"meeting-manager\"] |
511
- .meetings.requested_type = \"sprint-review\" |
592
+ .meetings.requested_type = \"followup-review\" |
512
593
  .meetings.requested_reason = \"ops-batch\" |
513
594
  .service_ops.drift_classification = \"$local_drift\" |
514
595
  .meetings.decision = {
@@ -553,6 +634,26 @@ if [ "$next" = "meeting-manager" ] && [ "$workflow_stage" = "ops-review" ]; then
553
634
  filter="$filter | .workflow.loop_count = ((.workflow.loop_count // 0) + 1)"
554
635
  fi
555
636
 
637
+ worker_dispatches="[]"
638
+ if [ "$new_conductor_state" = "running" ] &&
639
+ [ "$next" != "meeting-manager" ] &&
640
+ [ "$next" != "service-ops" ] &&
641
+ [ "$next" != "planner" ] &&
642
+ [ "$next" != "cto" ] &&
643
+ [ "$next" != "cqo" ] &&
644
+ [ "$next" != "archive" ]; then
645
+ worker_dispatches="$(dispatch_company_workers)"
646
+ if jq -e 'type == "array" and length > 0' >/dev/null 2>&1 <<<"$worker_dispatches"; then
647
+ dispatch_count="$(jq 'length' <<<"$worker_dispatches")"
648
+ filter="$filter |
649
+ .conductor.current_action = \"dispatch:workers:${dispatch_count}\" |
650
+ .next_agent = \"conductor\" |
651
+ .workflow.stage = \"implementation\" |
652
+ .workflow.last_reason = \"dispatch:workers:${dispatch_count}\""
653
+ next="conductor"
654
+ fi
655
+ fi
656
+
556
657
  set_progress "$filter"
557
658
 
558
659
  if [ "$meeting_prepare" = true ] && [ "$next" = "meeting-manager" ]; then
@@ -88,15 +88,17 @@ jq --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '
88
88
  | .current_agent = null
89
89
  | .agent_status = "pending"
90
90
  | .completed_agents = []
91
- | .next_agent = "dispatcher"
92
- | .workflow = { stage: "goal-intake", last_transition: null, loop_count: 0, last_reason: null }
91
+ | .next_agent = "meeting-manager"
92
+ | .conductor.state = "waiting_meeting"
93
+ | .conductor.current_action = "autonomous-post-archive-review"
94
+ | .workflow = { stage: "ops-monitoring", last_transition: $now, loop_count: 0, last_reason: "autonomous-post-archive-review" }
93
95
  | .task_sessions.current = { agent: null, id: null, path: null, source: null }
94
96
  | .failure = { agent: null, location: null, message: null, retry_target: null }
95
- | .meetings.active = []
97
+ | .meetings.active = ["meeting-manager"]
98
+ | .meetings.requested_type = "followup-review"
99
+ | .meetings.requested_reason = "autonomous-post-archive"
96
100
  | .meetings.current_id = null
97
101
  | .meetings.current_record_path = null
98
- | .meetings.requested_type = null
99
- | .meetings.requested_reason = null
100
102
  | .meetings.last_type = null
101
103
  | .meetings.last_reason = null
102
104
  | .meetings.last_decision = null
@@ -4,7 +4,7 @@
4
4
  # 처음 쓰는 사용자도 한 줄로 대시보드를 띄워볼 수 있게 만든 helper.
5
5
  # walwal-harness CLI 패키지에는 R3F + Next.js 무게 때문에 dashboard 가 미포함이고,
6
6
  # 본 스크립트가 git sparse-checkout 으로 apps/harness-dashboard/ 만 가져와서
7
- # 사용자 프로젝트 외부 (~/.walwal-harness/dashboard) 에 격리 설치 후 dev 실행한다.
7
+ # 사용자 프로젝트 외부 (~/.walwal-harness/dashboard/<project-key>) 에 격리 설치 후 dev 실행한다.
8
8
  #
9
9
  # Usage:
10
10
  # bash scripts/harness-dashboard-up.sh # install + dev (port 3001)
@@ -14,13 +14,13 @@ set -euo pipefail
14
14
 
15
15
  REPO_URL="${WALWAL_HARNESS_REPO:-https://github.com/30eggis/walwal-harness.git}"
16
16
  DASHBOARD_PATH="apps/harness-dashboard"
17
- LOCAL_DIR="${HOME}/.walwal-harness/dashboard"
18
17
  PORT="${PORT:-3001}"
18
+ REINSTALL=false
19
19
 
20
20
  while [[ $# -gt 0 ]]; do
21
21
  case "$1" in
22
22
  --port) PORT="$2"; shift 2 ;;
23
- --reinstall) rm -rf "$LOCAL_DIR"; shift ;;
23
+ --reinstall) REINSTALL=true; shift ;;
24
24
  --help|-h)
25
25
  sed -n '2,16p' "$0"
26
26
  exit 0 ;;
@@ -37,6 +37,14 @@ if [[ ! -d "${HARNESS_ROOT}/.harness" ]]; then
37
37
  exit 3
38
38
  fi
39
39
 
40
+ PROJECT_KEY="$(printf '%s' "${HARNESS_ROOT}" | shasum -a 1 | awk '{print substr($1,1,12)}')"
41
+ PROJECT_NAME="$(basename "${HARNESS_ROOT}")"
42
+ LOCAL_DIR="${HOME}/.walwal-harness/dashboard/${PROJECT_NAME}-${PROJECT_KEY}"
43
+
44
+ if [[ "$REINSTALL" == "true" ]]; then
45
+ rm -rf "$LOCAL_DIR"
46
+ fi
47
+
40
48
  echo "[brick-office] HARNESS_ROOT = ${HARNESS_ROOT}"
41
49
  echo "[brick-office] dashboard 격리 경로 = ${LOCAL_DIR}"
42
50