@walwal-harness/cli 7.1.7 → 7.1.9

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 (89) hide show
  1. package/HR-Resource/index.json +19 -43
  2. package/HR-Resource/marketing-marketing-cross-border-ecommerce/SKILL.md +108 -223
  3. package/HR-Resource/marketing-marketing-global-marketplace-operator/SKILL.md +175 -0
  4. package/HR-Resource/marketing-marketing-google-seo-specialist/SKILL.md +91 -0
  5. package/HR-Resource/marketing-marketing-instagram-commerce-strategist/SKILL.md +81 -0
  6. package/HR-Resource/marketing-marketing-korea-global-market-localization-strategist/SKILL.md +186 -0
  7. package/HR-Resource/marketing-marketing-livestream-commerce-coach/SKILL.md +88 -272
  8. package/HR-Resource/marketing-marketing-naver-seo-specialist/SKILL.md +88 -0
  9. package/HR-Resource/marketing-marketing-short-video-editing-coach/SKILL.md +99 -395
  10. package/HR-Resource/marketing-marketing-youtube-shopping-strategist/SKILL.md +82 -0
  11. package/README.md +41 -0
  12. package/apps/harness-dashboard/app/api/env/route.ts +62 -0
  13. package/apps/harness-dashboard/app/api/log/route.ts +19 -0
  14. package/apps/harness-dashboard/app/api/missions/route.ts +15 -0
  15. package/apps/harness-dashboard/app/api/snapshot/route.ts +15 -0
  16. package/apps/harness-dashboard/app/api/stream/route.ts +71 -0
  17. package/apps/harness-dashboard/app/globals.css +17 -0
  18. package/apps/harness-dashboard/app/layout.tsx +29 -0
  19. package/apps/harness-dashboard/app/page.tsx +35 -0
  20. package/apps/harness-dashboard/components/Drawer.tsx +97 -0
  21. package/apps/harness-dashboard/components/Header.tsx +40 -0
  22. package/apps/harness-dashboard/components/MissionTimeline.tsx +210 -0
  23. package/apps/harness-dashboard/components/OrgTree.tsx +330 -0
  24. package/apps/harness-dashboard/components/Scene.tsx +563 -0
  25. package/apps/harness-dashboard/components/Wordmark.tsx +14 -0
  26. package/apps/harness-dashboard/components/drawer/AgentLogTab.tsx +56 -0
  27. package/apps/harness-dashboard/components/drawer/GotchasTab.tsx +89 -0
  28. package/apps/harness-dashboard/components/drawer/HypothesisTab.tsx +42 -0
  29. package/apps/harness-dashboard/components/drawer/IncidentsTab.tsx +50 -0
  30. package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +92 -0
  31. package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +517 -0
  32. package/apps/harness-dashboard/components/drawer/OwnerHistoryTab.tsx +156 -0
  33. package/apps/harness-dashboard/components/drawer/RoomMetricsTab.tsx +90 -0
  34. package/apps/harness-dashboard/components/drawer/TracksTab.tsx +47 -0
  35. package/apps/harness-dashboard/components/three/ArchiveBoxes.tsx +95 -0
  36. package/apps/harness-dashboard/components/three/DeptBoard.tsx +175 -0
  37. package/apps/harness-dashboard/components/three/Floor3D.tsx +404 -0
  38. package/apps/harness-dashboard/components/three/GoalCard3D.tsx +123 -0
  39. package/apps/harness-dashboard/components/three/HypothesisCards.tsx +71 -0
  40. package/apps/harness-dashboard/components/three/MeetingWhiteboard.tsx +98 -0
  41. package/apps/harness-dashboard/components/three/Minifig3D.tsx +391 -0
  42. package/apps/harness-dashboard/components/three/OpsSiren.tsx +99 -0
  43. package/apps/harness-dashboard/components/three/Stage3D.tsx +104 -0
  44. package/apps/harness-dashboard/components/three/TrackRibbons.tsx +81 -0
  45. package/apps/harness-dashboard/hooks/useHarnessStream.ts +53 -0
  46. package/apps/harness-dashboard/lib/__tests__/company-flow.test.ts +270 -0
  47. package/apps/harness-dashboard/lib/__tests__/harness-state.test.ts +194 -0
  48. package/apps/harness-dashboard/lib/__tests__/i18n.test.ts +16 -0
  49. package/apps/harness-dashboard/lib/__tests__/iso.test.ts +42 -0
  50. package/apps/harness-dashboard/lib/__tests__/safe-json.test.ts +46 -0
  51. package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +159 -0
  52. package/apps/harness-dashboard/lib/__tests__/watcher.test.ts +48 -0
  53. package/apps/harness-dashboard/lib/agent-roster.ts +42 -0
  54. package/apps/harness-dashboard/lib/furniture.ts +165 -0
  55. package/apps/harness-dashboard/lib/harness-root.ts +20 -0
  56. package/apps/harness-dashboard/lib/harness-state.ts +1162 -0
  57. package/apps/harness-dashboard/lib/i18n.ts +26 -0
  58. package/apps/harness-dashboard/lib/iso.ts +150 -0
  59. package/apps/harness-dashboard/lib/log-filter.ts +23 -0
  60. package/apps/harness-dashboard/lib/markdown.tsx +306 -0
  61. package/apps/harness-dashboard/lib/path-planning.ts +72 -0
  62. package/apps/harness-dashboard/lib/safe-json.ts +24 -0
  63. package/apps/harness-dashboard/lib/state-mapping.ts +126 -0
  64. package/apps/harness-dashboard/lib/types.ts +329 -0
  65. package/apps/harness-dashboard/lib/watcher.ts +64 -0
  66. package/apps/harness-dashboard/next-env.d.ts +6 -0
  67. package/apps/harness-dashboard/next.config.mjs +9 -0
  68. package/apps/harness-dashboard/package-lock.json +4280 -0
  69. package/apps/harness-dashboard/package.json +38 -0
  70. package/apps/harness-dashboard/playwright.config.ts +23 -0
  71. package/apps/harness-dashboard/postcss.config.js +6 -0
  72. package/apps/harness-dashboard/tailwind.config.ts +49 -0
  73. package/apps/harness-dashboard/tsconfig.json +24 -0
  74. package/apps/harness-dashboard/vitest.config.ts +15 -0
  75. package/assets/templates/AGENTS-ko /341/204/207/341/205/251/341/206/250/341/204/211/341/205/241/341/204/207/341/205/251/341/206/253.md" +114 -0
  76. package/package.json +11 -1
  77. package/scripts/harness-dashboard-up.sh +24 -4
  78. package/HR-Resource/engineering-engineering-feishu-integration-developer/SKILL.md +0 -615
  79. package/HR-Resource/engineering-engineering-wechat-mini-program-developer/SKILL.md +0 -367
  80. package/HR-Resource/marketing-marketing-baidu-seo-specialist/SKILL.md +0 -243
  81. package/HR-Resource/marketing-marketing-bilibili-content-strategist/SKILL.md +0 -216
  82. package/HR-Resource/marketing-marketing-china-ecommerce-operator/SKILL.md +0 -300
  83. package/HR-Resource/marketing-marketing-china-market-localization-strategist/SKILL.md +0 -300
  84. package/HR-Resource/marketing-marketing-douyin-strategist/SKILL.md +0 -166
  85. package/HR-Resource/marketing-marketing-kuaishou-strategist/SKILL.md +0 -240
  86. package/HR-Resource/marketing-marketing-wechat-official-account/SKILL.md +0 -162
  87. package/HR-Resource/marketing-marketing-weibo-strategist/SKILL.md +0 -257
  88. package/HR-Resource/marketing-marketing-xiaohongshu-specialist/SKILL.md +0 -155
  89. package/HR-Resource/marketing-marketing-zhihu-strategist/SKILL.md +0 -179
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@walwal-harness/dashboard",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Brick Office — walwal-harness 라이브 대시보드 (Phase C)",
6
+ "scripts": {
7
+ "dev:dashboard": "next dev -p 3001",
8
+ "build": "next build",
9
+ "start": "next start -p 3001",
10
+ "lint": "next lint",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "typecheck": "tsc --noEmit",
14
+ "e2e": "playwright test"
15
+ },
16
+ "dependencies": {
17
+ "@react-three/drei": "^10.7.7",
18
+ "@react-three/fiber": "^9.6.1",
19
+ "chokidar": "^4.0.0",
20
+ "next": "^15.0.0",
21
+ "react": "^19.0.0",
22
+ "react-dom": "^19.0.0",
23
+ "three": "^0.184.0"
24
+ },
25
+ "devDependencies": {
26
+ "@playwright/test": "^1.48.0",
27
+ "@types/node": "^22.0.0",
28
+ "@types/react": "^19.0.0",
29
+ "@types/react-dom": "^19.0.0",
30
+ "@types/three": "^0.184.1",
31
+ "@vitest/ui": "^2.1.0",
32
+ "autoprefixer": "^10.4.0",
33
+ "postcss": "^8.4.0",
34
+ "tailwindcss": "^3.4.0",
35
+ "typescript": "^5.6.0",
36
+ "vitest": "^2.1.0"
37
+ }
38
+ }
@@ -0,0 +1,23 @@
1
+ import { defineConfig, devices } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./e2e",
5
+ timeout: 30_000,
6
+ expect: { timeout: 5_000 },
7
+ fullyParallel: false,
8
+ retries: 0,
9
+ reporter: [["list"]],
10
+ use: {
11
+ baseURL: "http://localhost:3001",
12
+ trace: "off",
13
+ },
14
+ webServer: {
15
+ command: "npm run dev:dashboard",
16
+ url: "http://localhost:3001",
17
+ reuseExistingServer: true,
18
+ timeout: 60_000,
19
+ },
20
+ projects: [
21
+ { name: "chromium", use: { ...devices["Desktop Chrome"] } },
22
+ ],
23
+ });
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,49 @@
1
+ import type { Config } from "tailwindcss";
2
+
3
+ const config: Config = {
4
+ content: [
5
+ "./app/**/*.{ts,tsx}",
6
+ "./components/**/*.{ts,tsx}",
7
+ "./hooks/**/*.{ts,tsx}",
8
+ "./lib/**/*.{ts,tsx}",
9
+ ],
10
+ theme: {
11
+ extend: {
12
+ colors: {
13
+ "brick-bg": "#0b1020",
14
+ "brick-floor": "#1a2236",
15
+ "brick-wall": "#2a3450",
16
+ "aura-idle": "#4b5563",
17
+ "aura-typing": "#22d3ee",
18
+ "aura-talking": "#fbbf24",
19
+ "aura-alert": "#ef4444",
20
+ },
21
+ fontFamily: {
22
+ mono: ["ui-monospace", "Menlo", "monospace"],
23
+ },
24
+ keyframes: {
25
+ "aura-pulse": {
26
+ "0%, 100%": { opacity: "0.6" },
27
+ "50%": { opacity: "1" },
28
+ },
29
+ "aura-blink": {
30
+ "0%, 100%": { opacity: "0.4" },
31
+ "50%": { opacity: "1" },
32
+ },
33
+ "alert-shake": {
34
+ "0%, 100%": { transform: "translateX(0)" },
35
+ "25%": { transform: "translateX(-1px)" },
36
+ "75%": { transform: "translateX(1px)" },
37
+ },
38
+ },
39
+ animation: {
40
+ "aura-pulse": "aura-pulse 1.4s ease-in-out infinite",
41
+ "aura-blink": "aura-blink 0.8s ease-in-out infinite",
42
+ "alert-shake": "alert-shake 0.3s ease-in-out infinite",
43
+ },
44
+ },
45
+ },
46
+ plugins: [],
47
+ };
48
+
49
+ export default config;
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": false,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }],
17
+ "paths": {
18
+ "@/*": ["./*"]
19
+ },
20
+ "types": ["node", "vitest/globals"]
21
+ },
22
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
23
+ "exclude": ["node_modules"]
24
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import path from "node:path";
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ environment: "node",
7
+ globals: true,
8
+ include: ["lib/**/*.test.ts", "lib/__tests__/**/*.test.ts"],
9
+ },
10
+ resolve: {
11
+ alias: {
12
+ "@": path.resolve(__dirname, "."),
13
+ },
14
+ },
15
+ });
@@ -0,0 +1,114 @@
1
+ # AGENTS.md — {{PROJECT_NAME}}
2
+ # walwal-harness v7.1 | Company Mode
3
+ # 설치일: {{DATE}} | CLAUDE.md는 이 파일의 심볼릭 링크입니다.
4
+
5
+ ---
6
+
7
+ ## 1. 진입점
8
+
9
+ Owner가 회사에 접근하는 명령은 두 개뿐이다. 그 외의 경로는 없다.
10
+
11
+ | 명령 | 사용 시점 |
12
+ |---|---|
13
+ | `/goal` | 미션 설정, 수정, 추가 |
14
+ | `/hot-fix` | 활성 goal과 독립된 긴급 수정 |
15
+
16
+ `/ceo`, `/cto`, `/cqo`, `/coo`, `/cdo`, `/ops`, `/hiring`은 slash command가 아니다.
17
+ 내부 라우팅은 agent/skill wiring으로만 처리한다.
18
+
19
+ ---
20
+
21
+ ## 2. 행동 전 확인
22
+
23
+ 가정하지 않는다. 불명확한 것을 숨기지 않는다.
24
+
25
+ - 구현 전 가정을 명시한다. 불확실하면 질문한다.
26
+ - 여러 접근이 가능하면 모두 제시한다 — 조용히 선택하지 않는다.
27
+ - 요청을 해결하는 최소한의 변경만 한다. 추측성 scope는 금지.
28
+ - 불명확한 부분이 있으면 멈춘다. 무엇이 불명확한지 명시하고 질문한다.
29
+
30
+ hot-fix: 가장 작은 올바른 패치만. 인접 코드를 "개선"하지 않는다.
31
+ goal: CEO가 CXX에 라우팅하기 전에 검증 가능한 성공 기준을 정의한다.
32
+
33
+ ---
34
+
35
+ ## 3. Company 구조
36
+
37
+ ```
38
+ Owner
39
+ └─ /goal 또는 /hot-fix
40
+ └─ harness-ceo 오케스트레이터 — Owner의 유일한 접점
41
+ ├─ harness-coo 리서치, 가설, 서비스 방향
42
+ ├─ harness-cdo 브랜딩, UI/UX, 디자인 리뷰
43
+ ├─ harness-cto 아키텍처, API, 플랫폼, 구현 총괄
44
+ ├─ harness-cqo 품질 게이트, 회귀, archive, gotcha/convention 관리
45
+ └─ harness-ops 빌드 모니터링, 로그 분석, 서비스 이벤트
46
+ ```
47
+
48
+ 각 CXX는:
49
+ - **독립된 fresh session 컨텍스트**에서 실행된다 — CEO 세션과 메모리를 공유하지 않는다
50
+ - 결정을 `.harness/documents/{mission_name}/{cxx}.md`에 기록한다
51
+ - 모든 전문 작업을 hired worker에게 위임한다 — 직접 실행하지 않는다
52
+ - 필요한 worker가 없으면 `harness-hiring`을 먼저 호출한다
53
+
54
+ CEO는 worker 기록 없이 완료된 산출물을 포함한 CXX 보고서를 거부한다.
55
+
56
+ ---
57
+
58
+ ## 4. 미션 플로우
59
+
60
+ ### Goal
61
+
62
+ 1. CEO가 Owner 요청을 읽고 판단한다: 브레인스토밍 먼저, 또는 즉시 실행.
63
+ 2. CEO가 관련 CXX에게만 범위를 한정한 질문을 전달한다.
64
+ 3. 각 CXX가 worker를 고용하고, 위임하고, 결과를 수집하여 `{cxx}.md`에 기록한다.
65
+ 4. CEO가 CXX 산출물을 종합하여 다음 CXX에 라우팅하거나 Owner에게 보고한다.
66
+
67
+ **완료 기준:** `.harness/documents/{mission_name}/ceo.md`에 최종 Owner 보고가 존재한다.
68
+
69
+ ### Hot Fix
70
+
71
+ 1. CEO가 긴급 요청을 받고 즉시 CTO와 CQO를 소집한다.
72
+ 2. CTO가 최소 패치 경로를 설계하고 구현 worker를 고용한다.
73
+ 3. Worker가 구현한다. CTO가 worker 증거를 검증하고 `cto.md`를 작성한다.
74
+ 4. CQO가 회귀 게이트를 실행한다. `.harness/gotchas/` 또는 `.harness/conventions/`에 교훈을 등록하고 `cqo.md`를 작성한다.
75
+ 5. CQO 판정 **PASS** 이후에만 archive한다.
76
+
77
+ **완료 기준:** `cto.md`, `cqo.md`, 그리고 최소 하나의 신규 gotcha 또는 convention 항목이 존재한다.
78
+
79
+ 주의: harness 문서(ceo.md, cto.md, cqo.md, worker 보고서)에 대한 docmeta skip 판단은 미션 프로토콜 단계를 건너뛸 권한을 부여하지 않는다. 이 파일들은 분석 산출물이 아니라 미션 기록이다.
80
+
81
+ ---
82
+
83
+ ## 5. 하네스 런타임
84
+
85
+ | 경로 | 역할 |
86
+ |---|---|
87
+ | `.harness/documents/{mission}/` | 미션별 CXX 결정 기록 및 worker 보고서 |
88
+ | `.harness/conventions/` | 지속 규칙 (CQO가 작성, 미션을 넘어 유지) |
89
+ | `.harness/gotchas/` | 재발 방지 기록 (CQO가 hot-fix마다 작성) |
90
+ | `.harness/memories/` | 장기 공유 컨텍스트 |
91
+ | `.harness/shared/HR-Resource/` | 채용 가능한 worker skill pool |
92
+ | `.harness/archive/` | CQO 승인 완료 미션 (불변) |
93
+ | `.harness/logs/YYYY-MM-DD/` | OPS 예외 로그 (비정상 케이스만) |
94
+
95
+ `.harness/`는 미션 상태 저장소다. 빌드 산출물이 아니다. 삭제하지 않는다.
96
+
97
+ ---
98
+
99
+ ## 6. 금지 규칙
100
+
101
+ 1. **`{mission}/cto.md` 없이 소스 코드 편집 금지** — CTO의 범위 승인이 있어야 소스 파일을 수정할 수 있다.
102
+ 2. **CXX 사칭 금지** — 현재 모델이 CEO/CTO/CQO를 인라인으로 대행하지 않는다. 설치된 harness skill을 fresh session에서 사용한다.
103
+ 3. **이름 없는 worker 금지** — 모든 전문 작업은 `harness-hiring` → `harness-resource-manager`를 거친다.
104
+ 4. **CQO 판정 없이 archive 금지** — 명시적 PASS가 담긴 `{mission}/cqo.md`가 존재해야 한다.
105
+ 5. **gotcha 등록 생략 금지** — 모든 hot-fix는 `.harness/gotchas/` 또는 `.harness/conventions/`에 최소 하나의 항목을 만든다.
106
+ 6. **미션 중 이 파일 편집 금지** — AGENTS.md를 수정하려면 별도 `/goal`을 제출한다.
107
+
108
+ ---
109
+
110
+ ## 7. 프로젝트 컨텍스트
111
+
112
+ - **기술 스택**: {{TECH_STACK}}
113
+ - **프로젝트 구조**: {{PROJECT_STRUCTURE}}
114
+ - **하네스 설치일**: {{DATE}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.7",
3
+ "version": "7.1.9",
4
4
  "description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -43,6 +43,16 @@
43
43
  "files": [
44
44
  "bin/",
45
45
  "HR-Resource/",
46
+ "apps/harness-dashboard/app/",
47
+ "apps/harness-dashboard/components/",
48
+ "apps/harness-dashboard/hooks/",
49
+ "apps/harness-dashboard/lib/",
50
+ "apps/harness-dashboard/public/",
51
+ "apps/harness-dashboard/*.json",
52
+ "apps/harness-dashboard/*.js",
53
+ "apps/harness-dashboard/*.mjs",
54
+ "apps/harness-dashboard/*.ts",
55
+ "apps/harness-dashboard/*.tsx",
46
56
  "scripts/",
47
57
  "commands/",
48
58
  "assets/",
@@ -2,9 +2,9 @@
2
2
  # walwal-harness — Brick Office dashboard launcher
3
3
  #
4
4
  # 처음 쓰는 사용자도 한 줄로 대시보드를 띄워볼 수 있게 만든 helper.
5
- # walwal-harness CLI 패키지에는 R3F + Next.js 무게 때문에 dashboard 가 미포함이고,
6
- # 본 스크립트가 git sparse-checkout 으로 apps/harness-dashboard/ 만 가져와서
7
- # 사용자 프로젝트 외부 (~/.walwal-harness/dashboard/<project-key>) 에 격리 설치 후 dev 실행한다.
5
+ # npm 패키지에 포함된 apps/harness-dashboard 를 사용자 프로젝트 외부
6
+ # (~/.walwal-harness/dashboard/<project-key>) 에 격리 복사 후 dev 실행한다.
7
+ # 구버전 호환을 위해 패키지에 dashboard 가 없으면 git sparse-checkout 으로 fallback 한다.
8
8
  #
9
9
  # Usage:
10
10
  # bash scripts/harness-dashboard-up.sh # install + dev (port 3001)
@@ -16,6 +16,7 @@ REPO_URL="${WALWAL_HARNESS_REPO:-https://github.com/30eggis/walwal-harness.git}"
16
16
  DASHBOARD_PATH="apps/harness-dashboard"
17
17
  PORT="${PORT:-3001}"
18
18
  REINSTALL=false
19
+ PACKAGE_VERSION="unknown"
19
20
 
20
21
  while [[ $# -gt 0 ]]; do
21
22
  case "$1" in
@@ -40,6 +41,13 @@ fi
40
41
  PROJECT_KEY="$(printf '%s' "${HARNESS_ROOT}" | shasum -a 1 | awk '{print substr($1,1,12)}')"
41
42
  PROJECT_NAME="$(basename "${HARNESS_ROOT}")"
42
43
  LOCAL_DIR="${HOME}/.walwal-harness/dashboard/${PROJECT_NAME}-${PROJECT_KEY}"
44
+ VERSION_FILE="${LOCAL_DIR}/.walwal-dashboard-version"
45
+
46
+ PACKAGE_ROOT="${HARNESS_ROOT}/node_modules/@walwal-harness/cli"
47
+ PACKAGED_DASHBOARD="${PACKAGE_ROOT}/${DASHBOARD_PATH}"
48
+ if [[ -f "${PACKAGE_ROOT}/package.json" ]]; then
49
+ PACKAGE_VERSION="$(node -p "require('${PACKAGE_ROOT}/package.json').version" 2>/dev/null || echo unknown)"
50
+ fi
43
51
 
44
52
  if [[ "$REINSTALL" == "true" ]]; then
45
53
  rm -rf "$LOCAL_DIR"
@@ -48,7 +56,19 @@ fi
48
56
  echo "[brick-office] HARNESS_ROOT = ${HARNESS_ROOT}"
49
57
  echo "[brick-office] dashboard 격리 경로 = ${LOCAL_DIR}"
50
58
 
51
- if [[ ! -d "${LOCAL_DIR}/${DASHBOARD_PATH}" ]]; then
59
+ if [[ -d "${PACKAGED_DASHBOARD}" ]]; then
60
+ INSTALLED_VERSION=""
61
+ if [[ -f "${VERSION_FILE}" ]]; then
62
+ INSTALLED_VERSION="$(cat "${VERSION_FILE}" 2>/dev/null || true)"
63
+ fi
64
+ if [[ ! -d "${LOCAL_DIR}/${DASHBOARD_PATH}" || "${INSTALLED_VERSION}" != "${PACKAGE_VERSION}" ]]; then
65
+ echo "[brick-office] dashboard sync from npm package @walwal-harness/cli@${PACKAGE_VERSION}"
66
+ rm -rf "${LOCAL_DIR:?}/${DASHBOARD_PATH}"
67
+ mkdir -p "${LOCAL_DIR}/apps"
68
+ cp -R "${PACKAGED_DASHBOARD}" "${LOCAL_DIR}/apps/"
69
+ printf '%s\n' "${PACKAGE_VERSION}" > "${VERSION_FILE}"
70
+ fi
71
+ elif [[ ! -d "${LOCAL_DIR}/${DASHBOARD_PATH}" ]]; then
52
72
  echo "[brick-office] 첫 실행 — git sparse-checkout 으로 dashboard 만 가져옵니다 (~5MB)."
53
73
  mkdir -p "${LOCAL_DIR}"
54
74
  cd "${LOCAL_DIR}"