@walwal-harness/cli 6.0.4 → 6.0.5
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 +21 -0
- package/bin/init.js +121 -4
- package/package.json +1 -1
- package/scripts/harness-archive.sh +0 -109
- package/scripts/harness-dashboard-up.sh +0 -72
- 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-gotcha-register.sh +0 -393
- package/scripts/harness-monitor.sh +0 -398
- package/scripts/harness-next.sh +0 -546
- package/scripts/harness-progress-set.sh +0 -41
- package/scripts/harness-prompt-history.sh +0 -164
- package/scripts/harness-queue-manager.sh +0 -694
- package/scripts/harness-session-start.sh +0 -129
- package/scripts/harness-statusline.sh +0 -139
- package/scripts/harness-tmux.sh +0 -372
- package/scripts/harness-user-prompt-submit.sh +0 -105
- package/scripts/init-agents-md.sh +0 -337
- package/scripts/init-ref-docs.sh +0 -262
- package/scripts/lib/harness-audit.sh +0 -113
- package/scripts/lib/harness-guardrail.sh +0 -148
- package/scripts/lib/harness-keywait.sh +0 -57
- package/scripts/lib/harness-render-progress.sh +0 -346
- package/scripts/scan-project.sh +0 -367
package/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,27 @@ docmeta:
|
|
|
29
29
|
|
|
30
30
|
# Changelog
|
|
31
31
|
|
|
32
|
+
## 6.0.5 — migrate 가 gotcha entry / bundle version 까지 sync (2026-05-07)
|
|
33
|
+
|
|
34
|
+
### Why
|
|
35
|
+
Owner 보고 — `npm install @walwal-harness/cli@latest && npx walwal-harness migrate` 가 "이미 최신 버전입니다" 로 종료. 그러나 v6.0.4 에서 새로 추가된 `gotchas/conductor.md` 의 [G-005], [G-006], `gotchas/service-ops.md`, `gotchas/generator-frontend.md [G-001]` 가 사용자 프로젝트에 merge 되지 않음. **존재 여부 (3 항목 — progress v4 / config.mode_selection / M-NEXUS-P3) 만 확인하고 콘텐츠는 비교 안 함** → 본질적 버그.
|
|
36
|
+
|
|
37
|
+
### Changes
|
|
38
|
+
- **bin/init.js `detectMigrationNeeded`** — 두 신규 시그널 추가:
|
|
39
|
+
- `gotchaMissingEntries`: `gotchas/*.md` 별로 패키지 → 사용자 [G-NNN] entry 차이 산출 (memory.md 패턴과 동일)
|
|
40
|
+
- `bundleVersionStale`: `.harness/.bundle-version` 스탬프와 패키지 버전 비교
|
|
41
|
+
- **bin/init.js `runMigrate`** — gotcha entry append + bundle stamp 갱신 단계 추가. 사용자가 직접 추가한 [G-NNN] entry 는 절대 건드리지 않으며, 패키지의 신규 시스템 entry 만 끝에 추가.
|
|
42
|
+
- **bin/init.js `extractGotchaEntryBlock` / `extractEntryBlock`** — JS 정규식 `\Z` 미지원 fix. 마지막 entry 가 추출 누락되던 버그 동시 해결 (v6.0.2 부터 잠재).
|
|
43
|
+
- **bin/init.js main flow** — 콘텐츠 드리프트 없이 stamp 만 누락된 경우 init 종료 시 자동 갱신. stamp 만으로 매번 migrate 권유 알림이 뜨는 것 방지.
|
|
44
|
+
|
|
45
|
+
### Migration
|
|
46
|
+
```bash
|
|
47
|
+
npm install @walwal-harness/cli@latest
|
|
48
|
+
npx walwal-harness migrate # gotchas/conductor.md G-005/G-006, gotchas/service-ops.md, gotchas/generator-frontend.md G-001 자동 append + stamp 갱신
|
|
49
|
+
npx walwal-harness verify
|
|
50
|
+
```
|
|
51
|
+
사용자 [G-NNN] entry 는 보존되고 시스템 entry 만 끝에 append. 변경 전 `.harness/archive/migration-<ts>/gotchas-<file>` 백업.
|
|
52
|
+
|
|
32
53
|
## 6.0.4 — Sub-skill 협업 + Service-Ops 상시 + Team 병렬 spawn (2026-05-07)
|
|
33
54
|
|
|
34
55
|
### Why
|
package/bin/init.js
CHANGED
|
@@ -988,7 +988,41 @@ function detectMigrationNeeded() {
|
|
|
988
988
|
progressV3toV4: false,
|
|
989
989
|
configMissingModeSelection: false,
|
|
990
990
|
memoryMissingSystemEntries: [],
|
|
991
|
+
gotchaMissingEntries: {}, // { "<filename>": [G-IDs...] }
|
|
992
|
+
bundleVersionStale: null, // { current, installed }
|
|
991
993
|
};
|
|
994
|
+
|
|
995
|
+
// Gotcha entry-level diff: for each bundled gotcha file, compare entry IDs.
|
|
996
|
+
// 사용자가 직접 추가한 [G-NNN] 은 절대 건드리지 않으며, 패키지에서 새로
|
|
997
|
+
// 도입된 시스템 entry 만 append 대상.
|
|
998
|
+
const gotchasSrc = path.join(PKG_ROOT, 'gotchas');
|
|
999
|
+
const gotchasDest = path.join(HARNESS_DIR, 'gotchas');
|
|
1000
|
+
if (fs.existsSync(gotchasSrc) && fs.existsSync(gotchasDest)) {
|
|
1001
|
+
const files = fs.readdirSync(gotchasSrc).filter((f) => f.endsWith('.md') && f !== 'README.md');
|
|
1002
|
+
for (const file of files) {
|
|
1003
|
+
const srcPath = path.join(gotchasSrc, file);
|
|
1004
|
+
const destPath = path.join(gotchasDest, file);
|
|
1005
|
+
if (!fs.existsSync(destPath)) continue; // installSkills/init 이 처리
|
|
1006
|
+
try {
|
|
1007
|
+
const srcIds = extractGotchaEntryIds(fs.readFileSync(srcPath, 'utf8'));
|
|
1008
|
+
const dstIds = new Set(extractGotchaEntryIds(fs.readFileSync(destPath, 'utf8')));
|
|
1009
|
+
const missing = srcIds.filter((id) => !dstIds.has(id));
|
|
1010
|
+
if (missing.length) flags.gotchaMissingEntries[file] = missing;
|
|
1011
|
+
} catch {}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Bundle version stamp: detects fresh package vs. last-applied bundle.
|
|
1016
|
+
// Even if the 3 schema flags pass, a newer bundle may have introduced new
|
|
1017
|
+
// gotcha/SKILL/template content the user hasn't seen yet.
|
|
1018
|
+
try {
|
|
1019
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8'));
|
|
1020
|
+
const stampPath = path.join(HARNESS_DIR, '.bundle-version');
|
|
1021
|
+
const installed = fs.existsSync(stampPath) ? fs.readFileSync(stampPath, 'utf8').trim() : null;
|
|
1022
|
+
if (installed !== pkg.version) {
|
|
1023
|
+
flags.bundleVersionStale = { current: pkg.version, installed };
|
|
1024
|
+
}
|
|
1025
|
+
} catch {}
|
|
992
1026
|
if (fs.existsSync(progressPath)) {
|
|
993
1027
|
try {
|
|
994
1028
|
const p = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
|
|
@@ -1025,7 +1059,29 @@ function extractEntryIds(md) {
|
|
|
1025
1059
|
// Extracts a single entry block (heading + body until next ### or EOF) from the template.
|
|
1026
1060
|
function extractEntryBlock(md, id) {
|
|
1027
1061
|
const escId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1028
|
-
const re = new RegExp(`(^### \\[${escId}\\][\\s\\S]*?)(?=^### \\[
|
|
1062
|
+
const re = new RegExp(`(^### \\[${escId}\\][\\s\\S]*?)(?=^### \\[|$(?![\\s\\S]))`, 'm');
|
|
1063
|
+
const m = md.match(re);
|
|
1064
|
+
return m ? m[1].trimEnd() : null;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// Returns gotcha entry IDs ("[G-001]", "[G-NEXUS-P3]" etc.) found in a markdown body.
|
|
1068
|
+
// Supports both `### [G-NNN]` and `## [G-NNN] ...` heading levels.
|
|
1069
|
+
function extractGotchaEntryIds(md) {
|
|
1070
|
+
const re = /^#{2,3}\s+\[(G-[A-Z0-9_-]+)\]/gm;
|
|
1071
|
+
const ids = [];
|
|
1072
|
+
let m;
|
|
1073
|
+
while ((m = re.exec(md)) !== null) ids.push(m[1]);
|
|
1074
|
+
return ids;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// Extracts a single gotcha entry block from a markdown body.
|
|
1078
|
+
function extractGotchaEntryBlock(md, id) {
|
|
1079
|
+
const escId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1080
|
+
// JS lacks \Z; emulate end-of-string via (?![\s\S]) negative lookahead.
|
|
1081
|
+
const re = new RegExp(
|
|
1082
|
+
`(^#{2,3}\\s+\\[${escId}\\][\\s\\S]*?)(?=^#{2,3}\\s+\\[G-|$(?![\\s\\S]))`,
|
|
1083
|
+
'm',
|
|
1084
|
+
);
|
|
1029
1085
|
const m = md.match(re);
|
|
1030
1086
|
return m ? m[1].trimEnd() : null;
|
|
1031
1087
|
}
|
|
@@ -1048,6 +1104,17 @@ function showMigrationProposal(flags) {
|
|
|
1048
1104
|
console.log(' [' + flags.memoryMissingSystemEntries.join(', ') + ']');
|
|
1049
1105
|
console.log(' 사용자 [M-NNN] entry 는 보존, 시스템 entry 만 끝에 추가.');
|
|
1050
1106
|
}
|
|
1107
|
+
const gotchaSummary = Object.entries(flags.gotchaMissingEntries || {});
|
|
1108
|
+
if (gotchaSummary.length) {
|
|
1109
|
+
console.log(' • gotchas/: 시스템 entry 누락 — entry-level append 가능 (사용자 [G-NNN] 보존)');
|
|
1110
|
+
for (const [file, ids] of gotchaSummary) {
|
|
1111
|
+
console.log(` ${file}: [${ids.join(', ')}]`);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (flags.bundleVersionStale) {
|
|
1115
|
+
const { current, installed } = flags.bundleVersionStale;
|
|
1116
|
+
console.log(` • bundle: ${installed ?? '(없음)'} → ${current} 스탬프 갱신 필요`);
|
|
1117
|
+
}
|
|
1051
1118
|
console.log('');
|
|
1052
1119
|
console.log(' 적용: npx walwal-harness migrate');
|
|
1053
1120
|
console.log(' 미리보기: npx walwal-harness migrate --dry-run');
|
|
@@ -1060,13 +1127,18 @@ function showMigrationProposal(flags) {
|
|
|
1060
1127
|
function runMigrate(opts = {}) {
|
|
1061
1128
|
const dryRun = opts.dryRun || false;
|
|
1062
1129
|
const flags = detectMigrationNeeded();
|
|
1130
|
+
const gotchaMissingTotal = Object.values(flags.gotchaMissingEntries || {}).reduce((n, a) => n + a.length, 0);
|
|
1063
1131
|
if (
|
|
1064
1132
|
!flags.progressV3toV4 &&
|
|
1065
1133
|
!flags.configMissingModeSelection &&
|
|
1066
|
-
(!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0)
|
|
1134
|
+
(!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0) &&
|
|
1135
|
+
gotchaMissingTotal === 0 &&
|
|
1136
|
+
!flags.bundleVersionStale
|
|
1067
1137
|
) {
|
|
1068
1138
|
console.log('');
|
|
1069
|
-
|
|
1139
|
+
let pkgVer = 'unknown';
|
|
1140
|
+
try { pkgVer = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8')).version; } catch {}
|
|
1141
|
+
log(`이미 최신 — bundle v${pkgVer} 일치, progress v${TARGET_PROGRESS_VERSION}, config.mode_selection, memory 시스템 entry, gotcha entry 모두 sync.`);
|
|
1070
1142
|
return;
|
|
1071
1143
|
}
|
|
1072
1144
|
|
|
@@ -1141,6 +1213,39 @@ function runMigrate(opts = {}) {
|
|
|
1141
1213
|
}
|
|
1142
1214
|
}
|
|
1143
1215
|
|
|
1216
|
+
// 4. gotcha entry merge — for each bundled gotcha file, append missing
|
|
1217
|
+
// [G-NNN] entries while preserving everything the user already has.
|
|
1218
|
+
const gotchaMissing = flags.gotchaMissingEntries || {};
|
|
1219
|
+
for (const [file, missingIds] of Object.entries(gotchaMissing)) {
|
|
1220
|
+
if (!missingIds.length) continue;
|
|
1221
|
+
const srcPath = path.join(PKG_ROOT, 'gotchas', file);
|
|
1222
|
+
const destPath = path.join(HARNESS_DIR, 'gotchas', file);
|
|
1223
|
+
if (!fs.existsSync(srcPath) || !fs.existsSync(destPath)) continue;
|
|
1224
|
+
const original = fs.readFileSync(destPath, 'utf8');
|
|
1225
|
+
const tpl = fs.readFileSync(srcPath, 'utf8');
|
|
1226
|
+
const blocks = [];
|
|
1227
|
+
for (const id of missingIds) {
|
|
1228
|
+
const block = extractGotchaEntryBlock(tpl, id);
|
|
1229
|
+
if (block) blocks.push(block);
|
|
1230
|
+
}
|
|
1231
|
+
if (!blocks.length) continue;
|
|
1232
|
+
log(` gotchas/${file}: 시스템 entry ${blocks.length}개 append (${missingIds.join(', ')})`);
|
|
1233
|
+
if (!dryRun) {
|
|
1234
|
+
fs.writeFileSync(path.join(backupDir, `gotchas-${file}`), original);
|
|
1235
|
+
const sep = original.endsWith('\n') ? '\n' : '\n\n';
|
|
1236
|
+
fs.writeFileSync(destPath, original + sep + blocks.join('\n\n') + '\n');
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// 5. Bundle version stamp — record which package version was last applied.
|
|
1241
|
+
if (flags.bundleVersionStale) {
|
|
1242
|
+
const { current, installed } = flags.bundleVersionStale;
|
|
1243
|
+
log(` .bundle-version: ${installed ?? '(none)'} → ${current}`);
|
|
1244
|
+
if (!dryRun) {
|
|
1245
|
+
fs.writeFileSync(path.join(HARNESS_DIR, '.bundle-version'), current + '\n');
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1144
1249
|
console.log('');
|
|
1145
1250
|
if (dryRun) {
|
|
1146
1251
|
log('Dry-run 완료 — 실제 변경 적용하려면 `npx walwal-harness migrate` 실행');
|
|
@@ -1320,8 +1425,20 @@ function main() {
|
|
|
1320
1425
|
|
|
1321
1426
|
// v6.0 — propose migration if existing project is on v3
|
|
1322
1427
|
const migFlags = detectMigrationNeeded();
|
|
1323
|
-
|
|
1428
|
+
const gotchaMissing = Object.keys(migFlags.gotchaMissingEntries || {}).length > 0;
|
|
1429
|
+
const hasContentDrift =
|
|
1430
|
+
migFlags.progressV3toV4 ||
|
|
1431
|
+
migFlags.configMissingModeSelection ||
|
|
1432
|
+
(migFlags.memoryMissingSystemEntries && migFlags.memoryMissingSystemEntries.length) ||
|
|
1433
|
+
gotchaMissing;
|
|
1434
|
+
if (hasContentDrift) {
|
|
1324
1435
|
showMigrationProposal(migFlags);
|
|
1436
|
+
} else if (migFlags.bundleVersionStale) {
|
|
1437
|
+
// 콘텐츠 드리프트 없이 stamp 만 누락/오래됨 → 정합성 차원에서 직접 갱신.
|
|
1438
|
+
try {
|
|
1439
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8'));
|
|
1440
|
+
fs.writeFileSync(path.join(HARNESS_DIR, '.bundle-version'), pkg.version + '\n');
|
|
1441
|
+
} catch {}
|
|
1325
1442
|
}
|
|
1326
1443
|
|
|
1327
1444
|
// v6.0 — Brick Office dashboard one-liner
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.5",
|
|
4
4
|
"description": "Production harness for AI agent engineering — NEXUS-adapted company metaphor (Dispatcher/CEO + Conductor + Meeting-Manager + COO/Planner + CTO + CQO + Service-Ops). Solo/Team mode, Brainstormer, Planner, Generator(BE/FE/Designer/DevOps), Evaluator chain (Code-Quality → Functional → Visual + Architecture/Security). Supports React, Next.js, and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# harness-archive.sh — 스프린트 종료 시 자동 아카이빙
|
|
3
|
-
#
|
|
4
|
-
# 동작:
|
|
5
|
-
# 1. .harness/actions/ 의 스프린트 산출물을 .harness/archive/D-NNN/S-NNN/ 로 이동
|
|
6
|
-
# 2. progress.json 의 sprint 상태를 초기화 (신규 dispatch 준비)
|
|
7
|
-
# 3. dispatch.id 가 없으면 counter++ 로 새 dispatch 시작
|
|
8
|
-
#
|
|
9
|
-
# 유지되는 파일 (이동하지 않음):
|
|
10
|
-
# - .harness/gotchas/**, .harness/conventions/**, .harness/ref/**
|
|
11
|
-
# - .harness/config.json, .harness/memory.md
|
|
12
|
-
# - .harness/progress.json (초기화만)
|
|
13
|
-
#
|
|
14
|
-
# 호출 주체: harness-next.sh (next_agent="archive" 도달 시 자동)
|
|
15
|
-
|
|
16
|
-
set -e
|
|
17
|
-
|
|
18
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
19
|
-
source "$SCRIPT_DIR/lib/harness-render-progress.sh" 2>/dev/null || true
|
|
20
|
-
|
|
21
|
-
PROJECT_ROOT="${1:-.}"
|
|
22
|
-
PROJECT_ROOT="$(cd "$PROJECT_ROOT" && pwd)"
|
|
23
|
-
|
|
24
|
-
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
25
|
-
ACTIONS_DIR="$PROJECT_ROOT/.harness/actions"
|
|
26
|
-
ARCHIVE_ROOT="$PROJECT_ROOT/.harness/archive"
|
|
27
|
-
|
|
28
|
-
if [ ! -f "$PROGRESS" ]; then
|
|
29
|
-
echo "[archive] ERROR: progress.json not found" >&2
|
|
30
|
-
exit 1
|
|
31
|
-
fi
|
|
32
|
-
|
|
33
|
-
command -v jq >/dev/null 2>&1 || { echo "[archive] ERROR: jq required" >&2; exit 1; }
|
|
34
|
-
|
|
35
|
-
# ── Read current dispatch/sprint numbers ──
|
|
36
|
-
dispatch_counter=$(jq -r '.dispatch.counter // 0' "$PROGRESS")
|
|
37
|
-
dispatch_id=$(jq -r '.dispatch.id // empty' "$PROGRESS")
|
|
38
|
-
sprint_num=$(jq -r '.sprint.number // 0' "$PROGRESS")
|
|
39
|
-
|
|
40
|
-
# Ensure dispatch id exists (fallback for legacy progress.json without dispatch)
|
|
41
|
-
if [ -z "$dispatch_id" ] || [ "$dispatch_id" = "null" ]; then
|
|
42
|
-
if [ "$dispatch_counter" -lt 1 ]; then
|
|
43
|
-
dispatch_counter=1
|
|
44
|
-
fi
|
|
45
|
-
dispatch_id=$(printf 'D-%03d' "$dispatch_counter")
|
|
46
|
-
fi
|
|
47
|
-
|
|
48
|
-
sprint_id=$(printf 'S-%03d' "$sprint_num")
|
|
49
|
-
target_dir="$ARCHIVE_ROOT/$dispatch_id/$sprint_id"
|
|
50
|
-
|
|
51
|
-
echo ""
|
|
52
|
-
echo " ── Archive ────────────────────────────"
|
|
53
|
-
echo " Dispatch : $dispatch_id"
|
|
54
|
-
echo " Sprint : $sprint_id"
|
|
55
|
-
echo " Target : ${target_dir#$PROJECT_ROOT/}"
|
|
56
|
-
|
|
57
|
-
# ── Move actions/ contents into archive ──
|
|
58
|
-
if [ -d "$ACTIONS_DIR" ] && [ "$(ls -A "$ACTIONS_DIR" 2>/dev/null)" ]; then
|
|
59
|
-
mkdir -p "$target_dir"
|
|
60
|
-
moved=0
|
|
61
|
-
for f in "$ACTIONS_DIR"/*; do
|
|
62
|
-
[ -e "$f" ] || continue
|
|
63
|
-
name="$(basename "$f")"
|
|
64
|
-
if [ -e "$target_dir/$name" ]; then
|
|
65
|
-
# Collision — suffix with timestamp to avoid overwrite
|
|
66
|
-
ts=$(date +%Y%m%d-%H%M%S)
|
|
67
|
-
mv "$f" "$target_dir/${name%.}.${ts}"
|
|
68
|
-
else
|
|
69
|
-
mv "$f" "$target_dir/"
|
|
70
|
-
fi
|
|
71
|
-
moved=$((moved + 1))
|
|
72
|
-
done
|
|
73
|
-
echo " Moved : $moved file(s)"
|
|
74
|
-
else
|
|
75
|
-
echo " Moved : 0 file(s) (actions/ empty)"
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
# ── Reset progress.json for next dispatch ──
|
|
79
|
-
# - sprint → init
|
|
80
|
-
# - agents → cleared
|
|
81
|
-
# - artifacts → pending
|
|
82
|
-
# - dispatch.id cleared (next dispatcher run will allocate new D-NNN)
|
|
83
|
-
# - failure → cleared
|
|
84
|
-
jq --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '
|
|
85
|
-
.pipeline = null
|
|
86
|
-
| .dispatch.id = null
|
|
87
|
-
| .sprint = { number: 0, status: "init", retry_count: 0 }
|
|
88
|
-
| .current_agent = null
|
|
89
|
-
| .agent_status = "pending"
|
|
90
|
-
| .completed_agents = []
|
|
91
|
-
| .next_agent = "dispatcher"
|
|
92
|
-
| .failure = { agent: null, location: null, message: null, retry_target: null }
|
|
93
|
-
| (.artifacts // {}) as $a
|
|
94
|
-
| .artifacts = ($a | with_entries(
|
|
95
|
-
if (.value | type) == "object"
|
|
96
|
-
then .value = { status: "pending", updated_by: null, updated_at: null }
|
|
97
|
-
else .
|
|
98
|
-
end))
|
|
99
|
-
| .updated_at = $now
|
|
100
|
-
' "$PROGRESS" > "${PROGRESS}.tmp" && mv "${PROGRESS}.tmp" "$PROGRESS"
|
|
101
|
-
|
|
102
|
-
# ── Clear handoff so next session starts fresh ──
|
|
103
|
-
HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
|
|
104
|
-
echo '{}' > "$HANDOFF"
|
|
105
|
-
|
|
106
|
-
echo " Status : archived, progress reset"
|
|
107
|
-
echo ""
|
|
108
|
-
echo " ✓ 다음 요청은 새로운 dispatch 로 시작합니다."
|
|
109
|
-
echo ""
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# walwal-harness — Brick Office dashboard launcher
|
|
3
|
-
#
|
|
4
|
-
# 처음 쓰는 사용자도 한 줄로 대시보드를 띄워볼 수 있게 만든 helper.
|
|
5
|
-
# walwal-harness CLI 패키지에는 R3F + Next.js 무게 때문에 dashboard 가 미포함이고,
|
|
6
|
-
# 본 스크립트가 git sparse-checkout 으로 apps/harness-dashboard/ 만 가져와서
|
|
7
|
-
# 사용자 프로젝트 외부 (~/.walwal-harness/dashboard) 에 격리 설치 후 dev 실행한다.
|
|
8
|
-
#
|
|
9
|
-
# Usage:
|
|
10
|
-
# bash scripts/harness-dashboard-up.sh # install + dev (port 3001)
|
|
11
|
-
# bash scripts/harness-dashboard-up.sh --port 3050 # override port
|
|
12
|
-
# HARNESS_ROOT=/path/to/project bash ... # explicit harness root
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
REPO_URL="${WALWAL_HARNESS_REPO:-https://github.com/30eggis/walwal-harness.git}"
|
|
16
|
-
DASHBOARD_PATH="apps/harness-dashboard"
|
|
17
|
-
LOCAL_DIR="${HOME}/.walwal-harness/dashboard"
|
|
18
|
-
PORT="${PORT:-3001}"
|
|
19
|
-
|
|
20
|
-
while [[ $# -gt 0 ]]; do
|
|
21
|
-
case "$1" in
|
|
22
|
-
--port) PORT="$2"; shift 2 ;;
|
|
23
|
-
--reinstall) rm -rf "$LOCAL_DIR"; shift ;;
|
|
24
|
-
--help|-h)
|
|
25
|
-
sed -n '2,16p' "$0"
|
|
26
|
-
exit 0 ;;
|
|
27
|
-
*) echo "[brick-office] unknown arg: $1" >&2; exit 2 ;;
|
|
28
|
-
esac
|
|
29
|
-
done
|
|
30
|
-
|
|
31
|
-
if [[ -z "${HARNESS_ROOT:-}" ]]; then
|
|
32
|
-
HARNESS_ROOT="$(pwd)"
|
|
33
|
-
fi
|
|
34
|
-
if [[ ! -d "${HARNESS_ROOT}/.harness" ]]; then
|
|
35
|
-
echo "[brick-office] FAIL: ${HARNESS_ROOT} 에 .harness/ 가 없습니다."
|
|
36
|
-
echo " 먼저 'npx walwal-harness' 로 초기화하세요."
|
|
37
|
-
exit 3
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
echo "[brick-office] HARNESS_ROOT = ${HARNESS_ROOT}"
|
|
41
|
-
echo "[brick-office] dashboard 격리 경로 = ${LOCAL_DIR}"
|
|
42
|
-
|
|
43
|
-
if [[ ! -d "${LOCAL_DIR}/${DASHBOARD_PATH}" ]]; then
|
|
44
|
-
echo "[brick-office] 첫 실행 — git sparse-checkout 으로 dashboard 만 가져옵니다 (~5MB)."
|
|
45
|
-
mkdir -p "${LOCAL_DIR}"
|
|
46
|
-
cd "${LOCAL_DIR}"
|
|
47
|
-
git init -q
|
|
48
|
-
git remote add origin "${REPO_URL}" 2>/dev/null || true
|
|
49
|
-
git config core.sparseCheckout true
|
|
50
|
-
echo "${DASHBOARD_PATH}/" > .git/info/sparse-checkout
|
|
51
|
-
git fetch --depth=1 origin main -q
|
|
52
|
-
git checkout main -q
|
|
53
|
-
echo "[brick-office] 다운로드 완료."
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
cd "${LOCAL_DIR}/${DASHBOARD_PATH}"
|
|
57
|
-
|
|
58
|
-
if [[ ! -d node_modules ]]; then
|
|
59
|
-
echo "[brick-office] npm install (한 번만 실행, ~30s)..."
|
|
60
|
-
npm install --no-audit --no-fund --loglevel=error
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
echo ""
|
|
64
|
-
echo "╔══════════════════════════════════════════════════════════╗"
|
|
65
|
-
echo "║ Brick Office — http://localhost:${PORT}"
|
|
66
|
-
echo "║ ║"
|
|
67
|
-
echo "║ HARNESS_ROOT 이 가리키는 프로젝트의 .harness/ 상태를 ║"
|
|
68
|
-
echo "║ 실시간 (SSE) 시각화합니다. Ctrl+C 로 종료. ║"
|
|
69
|
-
echo "╚══════════════════════════════════════════════════════════╝"
|
|
70
|
-
echo ""
|
|
71
|
-
|
|
72
|
-
HARNESS_ROOT="${HARNESS_ROOT}" npm run dev:dashboard -- -p "${PORT}"
|