@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.
- package/CHANGELOG.md +40 -0
- package/README.md +43 -74
- package/assets/launchd/com.walwal.harness-wake.plist.template +32 -0
- package/assets/templates/CONVENTIONS.md +12 -0
- package/assets/templates/HARNESS.md +8 -8
- package/assets/templates/company-pipeline-manifest.json +71 -0
- package/assets/templates/config.json +29 -27
- package/assets/templates/memory.md +16 -2
- package/assets/templates/progress.json.template +6 -5
- package/bin/init.js +180 -90
- package/conventions/shared.md +34 -0
- package/gotchas/conductor.md +16 -0
- package/gotchas/dispatcher.md +16 -0
- package/gotchas/meeting-manager.md +8 -0
- package/gotchas/service-ops.md +8 -0
- package/package.json +4 -4
- package/scripts/conductor-tick.sh +157 -56
- package/scripts/harness-archive.sh +7 -5
- package/scripts/harness-dashboard-up.sh +11 -3
- package/scripts/harness-hourly-review.sh +582 -0
- package/scripts/harness-meeting-doc.sh +55 -16
- package/scripts/harness-next.sh +1 -1
- package/scripts/harness-parity-audit.sh +101 -0
- package/scripts/harness-queue-manager.sh +13 -6
- package/scripts/harness-service-ops-monitor.sh +273 -0
- package/scripts/harness-session-start.sh +60 -31
- package/scripts/harness-statusline.sh +8 -12
- package/scripts/harness-stop.sh +85 -0
- package/scripts/harness-user-prompt-submit.sh +11 -29
- package/scripts/harness-wake-install.sh +180 -0
- package/scripts/harness-wake.sh +350 -0
- package/scripts/harness-worker-dispatch.sh +188 -0
- package/scripts/lib/harness-agent-resolver.sh +127 -0
- package/scripts/lib/harness-progress-migrate.sh +6 -1
- package/scripts/lib/harness-render-progress.sh +3 -3
- package/skills/brainstorming/SKILL.md +2 -2
- package/skills/conductor/SKILL.md +67 -55
- package/skills/cqo/SKILL.md +1 -0
- package/skills/cto/SKILL.md +1 -0
- package/skills/dispatcher/SKILL.md +33 -14
- package/skills/evaluator-code-quality/SKILL.md +4 -4
- package/skills/evaluator-functional/SKILL.md +6 -6
- package/skills/evaluator-visual/SKILL.md +4 -4
- package/skills/generator-backend/SKILL.md +4 -4
- package/skills/generator-frontend/SKILL.md +5 -5
- package/skills/meeting-manager/SKILL.md +82 -12
- package/skills/planner/SKILL.md +3 -3
- package/skills/service-ops/SKILL.md +25 -0
- package/commands/harness-solo.md +0 -103
- package/commands/harness-stop.md +0 -53
- package/commands/harness-team.md +0 -530
- package/scripts/harness-dashboard.sh +0 -509
- package/scripts/harness-goal-init.sh +0 -72
- package/scripts/harness-goal-show.sh +0 -37
- package/scripts/harness-gotcha-memory.sh +0 -348
- package/scripts/harness-monitor.sh +0 -398
- package/scripts/harness-prompt-history.sh +0 -164
- 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 // "
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
.mode_decision.
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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="
|
|
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
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
328
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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 = \"
|
|
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 = "
|
|
92
|
-
| .
|
|
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)
|
|
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
|
|