@walwal-harness/cli 6.0.4 → 6.1.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.
- package/CHANGELOG.md +63 -0
- package/bin/init.js +121 -4
- package/commands/harness-solo.md +20 -20
- package/commands/harness-team.md +1 -1
- package/package.json +1 -1
- package/scripts/conductor-tick.sh +382 -0
- package/scripts/harness-archive.sh +14 -0
- package/scripts/harness-meeting-doc.sh +153 -0
- package/scripts/harness-next.sh +31 -0
- package/scripts/harness-session-start.sh +16 -5
- package/scripts/harness-task-session.sh +48 -0
- package/scripts/harness-user-prompt-submit.sh +27 -9
- package/skills/brainstorming/SKILL.md +4 -4
- package/skills/conductor/SKILL.md +12 -16
- package/skills/cqo/SKILL.md +7 -0
- package/skills/cto/SKILL.md +7 -0
- package/skills/dispatcher/SKILL.md +17 -28
- package/skills/evaluator-code-quality/SKILL.md +1 -1
- package/skills/evaluator-functional/SKILL.md +1 -1
- package/skills/evaluator-visual/SKILL.md +1 -1
- package/skills/generator-backend/SKILL.md +1 -1
- package/skills/generator-frontend/SKILL.md +1 -1
- package/skills/meeting-manager/SKILL.md +33 -1
- package/skills/planner/SKILL.md +23 -9
- package/skills/service-ops/SKILL.md +19 -4
package/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,69 @@ docmeta:
|
|
|
29
29
|
|
|
30
30
|
# Changelog
|
|
31
31
|
|
|
32
|
+
## 6.1.0 — document-driven company loop + task-session isolation (2026-05-08)
|
|
33
|
+
|
|
34
|
+
### Why
|
|
35
|
+
v6.0.x 는 회사형 조직 비유와 Cxx 라우팅을 문서로는 설명했지만, 실제 런타임은 여전히 얕았다. 특히 다음 두 결함이 컸다.
|
|
36
|
+
|
|
37
|
+
- 회의 결과가 `누가 다음 owner 인가` 를 구조적으로 기록하지 않음
|
|
38
|
+
- `goal_adherence` 하락 시 원인 분류 없이 Planner로 보내는 경향이 있음
|
|
39
|
+
|
|
40
|
+
또한 agent 간 자기강화 편향을 줄이기 위한 문서 중심 task session 분리도 충분히 강제되지 않았다.
|
|
41
|
+
|
|
42
|
+
### Changes
|
|
43
|
+
- **document-driven meeting decision**
|
|
44
|
+
- `meeting-manager` 가 `notice.md`, `prep-*.md`, `meeting-<id>.md` skeleton 을 자동 생성
|
|
45
|
+
- 회의 기록에 `decision.owner`, `action_type`, `rationale`, `evidence`, `drift_classification` JSON 블록 추가
|
|
46
|
+
- `conductor-tick` 은 더 이상 `meeting_reason` 문자열만 보지 않고 회의 decision 문서를 우선 읽어 다음 owner 를 결정
|
|
47
|
+
- **goal drift classification**
|
|
48
|
+
- `implementation_drift | planning_drift | ops_drift | goal_drift` 분류 추가
|
|
49
|
+
- 분류별 기본 라우팅:
|
|
50
|
+
- `implementation_drift -> cto`
|
|
51
|
+
- `planning_drift -> planner`
|
|
52
|
+
- `ops_drift -> service-ops`
|
|
53
|
+
- `goal_drift -> dispatcher`
|
|
54
|
+
- **task-session isolation**
|
|
55
|
+
- `harness-next` 가 다음 agent 마다 `.harness/actions/task-sessions/<agent>/<id>.md` 생성
|
|
56
|
+
- `handoff.json` 에 `task_session_path` 추가
|
|
57
|
+
- `UserPromptSubmit` 가 running agent 와 다른 `/harness-*` 호출을 경고가 아니라 **hard block**
|
|
58
|
+
- **direct invocation policy**
|
|
59
|
+
- 모든 harness skill 의 `disable-model-invocation` 을 `false` 로 통일
|
|
60
|
+
- orchestration/control-plane 과 worker/evaluator 모두 직접 호출 가능 상태로 정리
|
|
61
|
+
- **archive reset hardening**
|
|
62
|
+
- archive 시 `workflow`, `meetings.decision`, `service_ops.drift_classification`, `task_sessions.current` 초기화
|
|
63
|
+
|
|
64
|
+
### Validation
|
|
65
|
+
- `bash -n` 으로 주요 스크립트 문법 검증
|
|
66
|
+
- `jq empty` 로 `config.json`, `progress.json` 검증
|
|
67
|
+
- `/private/tmp` 샌드박스에서:
|
|
68
|
+
- `dispatcher -> meeting-manager` 시 회의 문서 자동 생성 확인
|
|
69
|
+
- 회의 decision 편집 후 `dispatcher / planner / cto` 로 문서 기반 재라우팅 확인
|
|
70
|
+
- `goal_adherence` 하락 시 drift classification 반영 확인
|
|
71
|
+
- context isolation hard block 확인
|
|
72
|
+
- `task_session_path` 생성 확인
|
|
73
|
+
|
|
74
|
+
## 6.0.5 — migrate 가 gotcha entry / bundle version 까지 sync (2026-05-07)
|
|
75
|
+
|
|
76
|
+
### Why
|
|
77
|
+
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) 만 확인하고 콘텐츠는 비교 안 함** → 본질적 버그.
|
|
78
|
+
|
|
79
|
+
### Changes
|
|
80
|
+
- **bin/init.js `detectMigrationNeeded`** — 두 신규 시그널 추가:
|
|
81
|
+
- `gotchaMissingEntries`: `gotchas/*.md` 별로 패키지 → 사용자 [G-NNN] entry 차이 산출 (memory.md 패턴과 동일)
|
|
82
|
+
- `bundleVersionStale`: `.harness/.bundle-version` 스탬프와 패키지 버전 비교
|
|
83
|
+
- **bin/init.js `runMigrate`** — gotcha entry append + bundle stamp 갱신 단계 추가. 사용자가 직접 추가한 [G-NNN] entry 는 절대 건드리지 않으며, 패키지의 신규 시스템 entry 만 끝에 추가.
|
|
84
|
+
- **bin/init.js `extractGotchaEntryBlock` / `extractEntryBlock`** — JS 정규식 `\Z` 미지원 fix. 마지막 entry 가 추출 누락되던 버그 동시 해결 (v6.0.2 부터 잠재).
|
|
85
|
+
- **bin/init.js main flow** — 콘텐츠 드리프트 없이 stamp 만 누락된 경우 init 종료 시 자동 갱신. stamp 만으로 매번 migrate 권유 알림이 뜨는 것 방지.
|
|
86
|
+
|
|
87
|
+
### Migration
|
|
88
|
+
```bash
|
|
89
|
+
npm install @walwal-harness/cli@latest
|
|
90
|
+
npx walwal-harness migrate # gotchas/conductor.md G-005/G-006, gotchas/service-ops.md, gotchas/generator-frontend.md G-001 자동 append + stamp 갱신
|
|
91
|
+
npx walwal-harness verify
|
|
92
|
+
```
|
|
93
|
+
사용자 [G-NNN] entry 는 보존되고 시스템 entry 만 끝에 append. 변경 전 `.harness/archive/migration-<ts>/gotchas-<file>` 백업.
|
|
94
|
+
|
|
32
95
|
## 6.0.4 — Sub-skill 협업 + Service-Ops 상시 + Team 병렬 spawn (2026-05-07)
|
|
33
96
|
|
|
34
97
|
### 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/commands/harness-solo.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
docmeta:
|
|
3
3
|
id: harness-solo
|
|
4
|
-
title: /harness-solo —
|
|
4
|
+
title: /harness-solo — 비상용 Single-Agent Fallback
|
|
5
5
|
type: input
|
|
6
6
|
createdAt: 2026-04-20T00:00:00Z
|
|
7
7
|
updatedAt: 2026-05-07T00:00:00Z
|
|
@@ -24,14 +24,14 @@ docmeta:
|
|
|
24
24
|
tags: [harness, solo-mode, command, override, v6]
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
# /harness-solo —
|
|
27
|
+
# /harness-solo — 비상용 Single-Agent Fallback (v6.0+)
|
|
28
28
|
|
|
29
|
-
> v6.0
|
|
29
|
+
> v6.0 의 정상 경로는 회사형 자동 루프입니다. 본 명령은 그 루프를 일시적으로 벗어나는 **비상용 override** 입니다.
|
|
30
30
|
>
|
|
31
31
|
> **효과**: `progress.json.mode = "solo"` 강제 + `mode_decision.user_override = "solo"` 기록. 현재 sprint 끝까지 유지. 다음 sprint 진입 시 Conductor 가 재자동결정. **Auto 복귀**: 사용자 발화 "auto 로 돌려" 또는 "Conductor 결정으로".
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
디버깅, 스크립트 장애, 수동 hotfix 같은 예외 상황에서만 사용합니다.
|
|
34
|
+
회사 루프에서 전환 시, 진행 중이던 피처의 상태를 보존하고 단일 에이전트 fallback 으로 이어갑니다.
|
|
35
35
|
|
|
36
36
|
## 실행 절차
|
|
37
37
|
|
|
@@ -49,12 +49,12 @@ echo "현재 모드: $MODE"
|
|
|
49
49
|
bash scripts/harness-queue-manager.sh recover .
|
|
50
50
|
|
|
51
51
|
# mode를 solo로 설정
|
|
52
|
-
jq '.mode = "solo" | .team_state.active_teams = 0 | .team_state.paused_at = (now | todate)' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
52
|
+
jq '.mode = "solo" | .mode_decision.user_override = "solo" | .team_state.active_teams = 0 | .team_state.paused_at = (now | todate)' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
**paused → solo 전환 시:**
|
|
56
56
|
```bash
|
|
57
|
-
jq '.mode = "solo"' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
57
|
+
jq '.mode = "solo" | .mode_decision.user_override = "solo"' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
### Step 2: 현재 진행 상태 표시
|
|
@@ -75,29 +75,29 @@ fi
|
|
|
75
75
|
progress.json의 `next_agent` 필드를 확인하여 다음 단계를 안내합니다:
|
|
76
76
|
|
|
77
77
|
- **next_agent = "dispatcher"** → "프롬프트로 요구사항을 입력하면 자동으로 dispatcher가 분석합니다."
|
|
78
|
-
- **next_agent = "planner"** →
|
|
79
|
-
- **next_agent = "generator-backend"** →
|
|
80
|
-
- **next_agent = "generator-frontend"** →
|
|
81
|
-
- **next_agent = "evaluator-functional"** →
|
|
82
|
-
- **next_agent = "evaluator-visual"** →
|
|
78
|
+
- **next_agent = "planner"** → Planner 단계가 다음입니다. SessionStart / 내부 handoff가 연결돼 있으면 자동 진입, 아니면 해당 스킬을 수동 호출합니다.
|
|
79
|
+
- **next_agent = "generator-backend"** → Backend generator 단계가 다음입니다.
|
|
80
|
+
- **next_agent = "generator-frontend"** → Frontend generator 단계가 다음입니다.
|
|
81
|
+
- **next_agent = "evaluator-functional"** → Functional evaluator 단계가 다음입니다.
|
|
82
|
+
- **next_agent = "evaluator-visual"** → Visual evaluator 단계가 다음입니다.
|
|
83
83
|
|
|
84
84
|
### Step 4: Solo 모드 진행
|
|
85
85
|
|
|
86
|
-
각 에이전트는 완료 즉시
|
|
86
|
+
각 에이전트는 완료 즉시 **내부 handoff(`harness-next.sh` 또는 SessionStart hook)** 로 다음 에이전트에 넘겨집니다. Owner가 `/harness-next` 를 직접 다룬다는 전제는 6.0 회사 모델과 맞지 않습니다.
|
|
87
87
|
|
|
88
88
|
**예외 — 사용자 승인 게이트가 있는 단계:**
|
|
89
|
-
- **Brainstorming**: brainstorm-spec.md 완성 후 사용자 승인 대기 → 승인 시
|
|
90
|
-
- **Planner**: plan.md / api-contract.json 완성 후 사용자 승인 대기 → 승인 시
|
|
89
|
+
- **Brainstorming**: brainstorm-spec.md 완성 후 사용자 승인 대기 → 승인 시 내부 handoff
|
|
90
|
+
- **Planner**: plan.md / api-contract.json 완성 후 사용자 승인 대기 → 승인 시 내부 handoff
|
|
91
91
|
|
|
92
|
-
흐름이
|
|
92
|
+
흐름이 멈췄다면 원인은 보통 내부 handoff 스크립트/훅 미설치 또는 `next_agent` 불일치입니다. 이 경우 상태 파일과 hook 설치 상태를 먼저 점검합니다.
|
|
93
93
|
|
|
94
94
|
feature-queue.json이 존재하는 경우:
|
|
95
95
|
- 피처 완료(evaluator PASS) 시 `bash scripts/harness-queue-manager.sh pass {FEATURE_ID} .`를 호출하여 공유 상태 업데이트
|
|
96
96
|
- Team 모드로 전환해도 이미 완료된 피처는 skip됨
|
|
97
97
|
|
|
98
|
-
##
|
|
98
|
+
## 사용 권장 상황
|
|
99
99
|
|
|
100
100
|
- 프롬프트로 각 에이전트 순차 실행
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
101
|
+
- 내부 handoff 스크립트 장애 시 응급 복구
|
|
102
|
+
- 아주 짧은 수동 hotfix / 상태 수선
|
|
103
|
+
- 정상 회사 루프로 복귀: `/harness-team`
|
package/commands/harness-team.md
CHANGED
|
@@ -54,7 +54,7 @@ Planner가 완료한 feature-list.json의 피처들을 최대 3개 팀이 병렬
|
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
# progress.json에 mode=team 설정
|
|
57
|
-
jq '.mode = "team" | .team_state.active_teams = 3 | .team_state.paused_at = null' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
57
|
+
jq '.mode = "team" | .mode_decision.user_override = "team" | .team_state.active_teams = 3 | .team_state.paused_at = null' .harness/progress.json > /tmp/progress_tmp.json && mv /tmp/progress_tmp.json .harness/progress.json
|
|
58
58
|
|
|
59
59
|
# Queue 초기화 또는 복구
|
|
60
60
|
if [ ! -f .harness/actions/feature-queue.json ]; then
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "6.0
|
|
3
|
+
"version": "6.1.0",
|
|
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"
|