@walwal-harness/cli 6.0.1 → 6.0.2

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 CHANGED
@@ -29,6 +29,27 @@ docmeta:
29
29
 
30
30
  # Changelog
31
31
 
32
+ ## 6.0.2 — `migrate` 가 memory 시스템 entry 까지 자동 처리 (2026-05-07)
33
+
34
+ v6.0.1 patch 적용을 위해 사용자가 memory.md 의 [M-NEXUS-P3] 를 수동 추가해야 했던 불편을 제거. `npx walwal-harness migrate` 한 줄로 모두 처리됩니다.
35
+
36
+ ### Changed
37
+ - `bin/init.js` 의 `detectMigrationNeeded()` 가 memory.md 의 시스템 entry (M-NEXUS-*, M-SYS-*) 누락도 감지.
38
+ - `runMigrate()` 가 누락된 시스템 entry 를 template 에서 발췌해 사용자 memory.md 끝에 append. **사용자 [M-NNN] entry 는 무손상**.
39
+ - postinstall 안내 banner 가 누락된 memory entry 목록도 함께 표시.
40
+
41
+ ### Migration (one-liner)
42
+ ```bash
43
+ npm install @walwal-harness/cli@latest
44
+ npx walwal-harness migrate # progress + config + memory 한 번에
45
+ ```
46
+
47
+ `migrate` 가 처리하는 것:
48
+ - progress.json v3 → v4 (mode → "auto" + mode_decision)
49
+ - config.json mode_selection 자동 주입
50
+ - **(신규)** memory.md 시스템 entry append (M-NEXUS-P3 등)
51
+ - 변경 전 .harness/archive/migration-<ts>/ 에 progress / config / memory 자동 백업.
52
+
32
53
  ## 6.0.1 — Owner ↔ CEO 정체성 + 자율 실행 룰 강화 (2026-05-07)
33
54
 
34
55
  v6.0.0 publish 직후 Owner 의 명시적 교정으로 발견된 두 가지 inviolable 룰 위반 패턴을 패키지에 정식 등재한 patch.
package/bin/init.js CHANGED
@@ -973,10 +973,22 @@ function runTeamStudio() {
973
973
  // ─────────────────────────────────────────
974
974
  const TARGET_PROGRESS_VERSION = 4;
975
975
 
976
+ // System memory entries that must exist in every install. ID prefix convention:
977
+ // M-NEXUS-* : Foundational NEXUS doctrine rules
978
+ // M-SYS-* : Cross-agent system-level rules
979
+ // User-added [M-NNN] entries are NEVER touched.
980
+ const SYSTEM_MEMORY_ENTRY_PATTERN = /^### \[M-(NEXUS|SYS)-[A-Z0-9_-]+\]/m;
981
+
976
982
  function detectMigrationNeeded() {
977
983
  const progressPath = path.join(HARNESS_DIR, 'progress.json');
978
984
  const configPath = path.join(HARNESS_DIR, 'config.json');
979
- const flags = { progressV3toV4: false, configMissingModeSelection: false };
985
+ const memoryPath = path.join(HARNESS_DIR, 'memory.md');
986
+ const memoryTplPath = path.join(PKG_ROOT, 'assets', 'templates', 'memory.md');
987
+ const flags = {
988
+ progressV3toV4: false,
989
+ configMissingModeSelection: false,
990
+ memoryMissingSystemEntries: [],
991
+ };
980
992
  if (fs.existsSync(progressPath)) {
981
993
  try {
982
994
  const p = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
@@ -989,9 +1001,35 @@ function detectMigrationNeeded() {
989
1001
  if (!c.mode_selection) flags.configMissingModeSelection = true;
990
1002
  } catch {}
991
1003
  }
1004
+ if (fs.existsSync(memoryPath) && fs.existsSync(memoryTplPath)) {
1005
+ try {
1006
+ const userMem = fs.readFileSync(memoryPath, 'utf8');
1007
+ const tplMem = fs.readFileSync(memoryTplPath, 'utf8');
1008
+ const tplEntryIds = extractEntryIds(tplMem).filter((id) => /^M-(NEXUS|SYS)-/.test(id));
1009
+ const userEntryIds = new Set(extractEntryIds(userMem));
1010
+ flags.memoryMissingSystemEntries = tplEntryIds.filter((id) => !userEntryIds.has(id));
1011
+ } catch {}
1012
+ }
992
1013
  return flags;
993
1014
  }
994
1015
 
1016
+ // Returns the list of memory entry IDs found in the markdown body, e.g. ["M-001", "M-NEXUS-P3"].
1017
+ function extractEntryIds(md) {
1018
+ const re = /^### \[(M-[A-Z0-9_-]+)\]/gm;
1019
+ const ids = [];
1020
+ let m;
1021
+ while ((m = re.exec(md)) !== null) ids.push(m[1]);
1022
+ return ids;
1023
+ }
1024
+
1025
+ // Extracts a single entry block (heading + body until next ### or EOF) from the template.
1026
+ function extractEntryBlock(md, id) {
1027
+ const escId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1028
+ const re = new RegExp(`(^### \\[${escId}\\][\\s\\S]*?)(?=^### \\[|\\Z)`, 'm');
1029
+ const m = md.match(re);
1030
+ return m ? m[1].trimEnd() : null;
1031
+ }
1032
+
995
1033
  function showMigrationProposal(flags) {
996
1034
  console.log('');
997
1035
  console.log('╔══════════════════════════════════════════════════════════╗');
@@ -1005,6 +1043,11 @@ function showMigrationProposal(flags) {
1005
1043
  console.log(' • config.json: mode_selection 섹션 누락 — 자동 주입 가능');
1006
1044
  console.log(' Conductor 가 ready≥3 + features≥6 + depth≤2 로 자동 모드 결정.');
1007
1045
  }
1046
+ if (flags.memoryMissingSystemEntries && flags.memoryMissingSystemEntries.length) {
1047
+ console.log(' • memory.md: 시스템 entry 누락 — append 가능');
1048
+ console.log(' [' + flags.memoryMissingSystemEntries.join(', ') + ']');
1049
+ console.log(' 사용자 [M-NNN] entry 는 보존, 시스템 entry 만 끝에 추가.');
1050
+ }
1008
1051
  console.log('');
1009
1052
  console.log(' 적용: npx walwal-harness migrate');
1010
1053
  console.log(' 미리보기: npx walwal-harness migrate --dry-run');
@@ -1017,9 +1060,13 @@ function showMigrationProposal(flags) {
1017
1060
  function runMigrate(opts = {}) {
1018
1061
  const dryRun = opts.dryRun || false;
1019
1062
  const flags = detectMigrationNeeded();
1020
- if (!flags.progressV3toV4 && !flags.configMissingModeSelection) {
1063
+ if (
1064
+ !flags.progressV3toV4 &&
1065
+ !flags.configMissingModeSelection &&
1066
+ (!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0)
1067
+ ) {
1021
1068
  console.log('');
1022
- log('이미 최신 버전입니다 (progress.json v' + TARGET_PROGRESS_VERSION + ' + config.json mode_selection 존재).');
1069
+ log('이미 최신 버전입니다 (progress v' + TARGET_PROGRESS_VERSION + ' + config.mode_selection + memory 시스템 entry 모두 존재).');
1023
1070
  return;
1024
1071
  }
1025
1072
 
@@ -1071,6 +1118,29 @@ function runMigrate(opts = {}) {
1071
1118
  }
1072
1119
  }
1073
1120
 
1121
+ // 3. memory.md — append missing system entries (M-NEXUS-*, M-SYS-*) only.
1122
+ // User-added [M-NNN] entries are NEVER touched.
1123
+ const memoryPath = path.join(HARNESS_DIR, 'memory.md');
1124
+ const memoryTplPath = path.join(PKG_ROOT, 'assets', 'templates', 'memory.md');
1125
+ const missingMemEntries = flags.memoryMissingSystemEntries || [];
1126
+ if (missingMemEntries.length && fs.existsSync(memoryPath) && fs.existsSync(memoryTplPath)) {
1127
+ const original = fs.readFileSync(memoryPath, 'utf8');
1128
+ const tpl = fs.readFileSync(memoryTplPath, 'utf8');
1129
+ const blocks = [];
1130
+ for (const id of missingMemEntries) {
1131
+ const block = extractEntryBlock(tpl, id);
1132
+ if (block) blocks.push(block);
1133
+ }
1134
+ if (blocks.length) {
1135
+ log(` memory.md: 시스템 entry ${blocks.length}개 append (${missingMemEntries.join(', ')})`);
1136
+ if (!dryRun) {
1137
+ fs.writeFileSync(path.join(backupDir, 'memory.md'), original);
1138
+ const sep = original.endsWith('\n') ? '\n' : '\n\n';
1139
+ fs.writeFileSync(memoryPath, original + sep + blocks.join('\n\n') + '\n');
1140
+ }
1141
+ }
1142
+ }
1143
+
1074
1144
  console.log('');
1075
1145
  if (dryRun) {
1076
1146
  log('Dry-run 완료 — 실제 변경 적용하려면 `npx walwal-harness migrate` 실행');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "6.0.1",
3
+ "version": "6.0.2",
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"