@decencia/ch-cli 1.12.1 → 1.13.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.
@@ -3,7 +3,7 @@ name: 2t-decencia-channel-issue-coder
3
3
  description: GitHub issue 1개를 입력으로 받아 끝까지 처리하는 코딩 에이전트. 이슈 읽기 → 소통채널 spec/SQA 확인 → git worktree+브랜치에서 구현 → 자체 소프트리뷰 루프 → unittest + SQA → PR 생성 → 소통채널 workStatus·이슈 기록. 다수 병렬 실행 전제, PR까지만(머지·base 브랜치 직접 push·이슈 close는 사람).
4
4
  tools: Read, Write, Edit, Grep, Glob, Bash, Agent
5
5
  model: opus
6
- version: 1.12.1
6
+ version: 1.13.0
7
7
  ---
8
8
 
9
9
  ## 역할
@@ -3,7 +3,7 @@ name: 2t-decencia-channel-pr-merger
3
3
  description: issue-coder가 낸 PR을 기본 완전 자율로 base 브랜치(기본 브랜치 또는 sprint 통합 브랜치)에 머지하는 에이전트. 핵심 역량은 다수 병렬 worktree가 만든 충돌을 작업 의도 기반(semantic)으로 해결하는 것. CI green+충돌없음이면 바로 squash 머지, 충돌이면 의도대로 해결 후 테스트로 검증하여 머지. 재SQA·전면 재리뷰는 하지 않음. 다수 PR은 직렬 머지.
4
4
  tools: Read, Write, Edit, Grep, Glob, Bash
5
5
  model: opus
6
- version: 1.12.1
6
+ version: 1.13.0
7
7
  ---
8
8
 
9
9
  ## 역할
@@ -3,7 +3,7 @@ name: 2t-decencia-channel-terraformer
3
3
  description: 소통채널을 쓰지 않던 기존 코드베이스를 역분석하여 소통채널 프로젝트로 편입(terraforming)하는 자율 에이전트. 코드가 single source of truth — 코드를 읽어 DB 스키마 → 기능명세(spec) → PRD를 bottom-up으로 역생성한다(SQA 제외). 대량 분석은 서브에이전트 병렬, 코드로 못 메우는 의도는 [추정]으로 채우고 "사람확인 질문 리스트"를 산출물로 남긴다. PR/머지·이슈 발행은 하지 않음.
4
4
  tools: Read, Write, Edit, Grep, Glob, Bash, Agent
5
5
  model: opus
6
- version: 1.12.1
6
+ version: 1.13.0
7
7
  ---
8
8
 
9
9
  ## 역할
@@ -1 +1 @@
1
- {"version":3,"file":"screens.d.ts","sourceRoot":"","sources":["../../src/commands/screens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqEpC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAY,GAAG,MAAM,CAOzE;AA0QD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAY7D"}
1
+ {"version":3,"file":"screens.d.ts","sourceRoot":"","sources":["../../src/commands/screens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsEpC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAY,GAAG,MAAM,CAOzE;AA0QD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAa7D"}
@@ -5,6 +5,7 @@ exports.registerScreensCommand = registerScreensCommand;
5
5
  const client_1 = require("../client");
6
6
  const output_1 = require("../output");
7
7
  const utils_1 = require("../utils");
8
+ const screens_migrate_1 = require("./screens.migrate");
8
9
  /**
9
10
  * ch screens — 화면(Screen) 리소스 관리 명령 (SCREEN-003)
10
11
  *
@@ -327,7 +328,8 @@ function registerScreensCommand(program) {
327
328
  registerScreensCreate(screens, program);
328
329
  registerScreensUpdate(screens, program);
329
330
  registerScreensDelete(screens, program);
330
- // 확장 지점: 서브커맨드는 위와 같은 register…(screens, program) 함수를 만들어
331
- // 여기에 추가한다 (예: `migrate` — SCREEN-006).
331
+ // migrate는 CRUD가 아니라 이관 오케스트레이션(여러 리소스를 순서대로 쓴다)이라
332
+ // 별도 모듈(screens.migrate.ts)에 두고 여기서 줄로 등록한다 — SCREEN-006.
333
+ (0, screens_migrate_1.registerScreensMigrate)(screens, program);
332
334
  }
333
335
  //# sourceMappingURL=screens.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"screens.js","sourceRoot":"","sources":["../../src/commands/screens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screens.js","sourceRoot":"","sources":["../../src/commands/screens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * `ch screens migrate` — 레거시 프로젝트를 화면 모델로 옮긴다 (SCREEN-006).
4
+ *
5
+ * 하는 일 세 가지, 이 순서로:
6
+ * 1. spec.ui.route를 씨앗으로 화면(screens)을 중복 없이 만든다.
7
+ * 2. 각 명세의 ui.screenRefs에 그 화면 ID를 더한다 (기존 ui 필드는 그대로 다시 실어 보낸다).
8
+ * 3. 전부 성공한 뒤에야 마지막 쓰기로 ch_projects.screensEnabled를 true로 켠다.
9
+ *
10
+ * 지키는 계약:
11
+ * 비파괴 — spec.ui의 기존 필드(figmaNodeId·route·file·access·interactionMap)를 지우지 않는다.
12
+ * PATCH /specs/:id는 ui를 통째로 교체하므로(specs.service의 `updateData['ui'] = ui`)
13
+ * 반드시 읽어서 병합한 뒤 통째로 다시 보낸다. 그래서 롤백은 플래그 한 개만 내리면 된다.
14
+ * --dry-run — 계획만 낸다. 쓰기 요청(POST/PATCH)을 한 건도 보내지 않는다. 읽기는 한다
15
+ * (계획을 서버 데이터로 계산하므로 — 다른 커맨드의 --dry-run과 다른 점이다).
16
+ * 멱등 — 같은 base route의 화면을 두 번 만들지 않고, 이미 걸린 screenRefs는 건드리지 않는다.
17
+ * 출력 — 기계 모드(--json)면 stdout은 계획/결과 JSON 한 문서뿐이고 사람 메시지는 stderr로 간다.
18
+ * 권한 — admin. screensEnabled 토글이 프로젝트 수정(PATCH /projects/current, admin 전용)이다.
19
+ */
20
+ /** 마이그레이션이 읽는 명세의 최소 형태 (REST 응답의 부분집합). */
21
+ export interface MigrateSpec {
22
+ id: string;
23
+ name?: string;
24
+ epic?: string;
25
+ ui?: {
26
+ route?: string;
27
+ access?: string;
28
+ screenRefs?: string[];
29
+ [key: string]: unknown;
30
+ };
31
+ [key: string]: unknown;
32
+ }
33
+ /** 마이그레이션이 읽는 화면의 최소 형태. */
34
+ export interface MigrateScreen {
35
+ id: string;
36
+ name?: string;
37
+ route?: string;
38
+ order?: number;
39
+ epic?: string;
40
+ access?: string;
41
+ [key: string]: unknown;
42
+ }
43
+ export interface PlannedScreen {
44
+ /** 정규화된 base route (화면의 정체성). */
45
+ baseRoute: string;
46
+ /** create = 새로 만든다, reuse = 같은 base route 화면이 이미 있어 재사용한다. */
47
+ action: 'create' | 'reuse';
48
+ /** reuse면 기존 화면 ID. create면 적용 전까지 null (적용 후 서버가 준 ID로 채워진다). */
49
+ screenId: string | null;
50
+ name: string;
51
+ order: number;
52
+ epic?: string;
53
+ access?: string;
54
+ /** create일 때 화면에 남길 비고. reuse면 기존 비고를 보존하므로 없다. */
55
+ note?: string;
56
+ /** route에서 떼어낸 원문 주석 — 괄호 주석("PRD 탭")과 쿼리/프래그먼트("?tab=screens"). */
57
+ annotations: string[];
58
+ /** 이 base route에 묶인 명세 (ID 오름차순). */
59
+ specIds: string[];
60
+ /** 이 화면 ID를 ui.screenRefs에 새로 넣어야 하는 명세 (이미 걸린 것은 빠진다). */
61
+ linkSpecIds: string[];
62
+ /** 묶인 명세들의 epic 값이 갈릴 때의 후보 (하나로 일치하면 epic에 복사되고 여기는 1개). */
63
+ epicCandidates: string[];
64
+ /** 묶인 명세들의 ui.access 후보. */
65
+ accessCandidates: string[];
66
+ /** 같은 base route를 가진 기존 화면이 둘 이상일 때 그 ID들 (첫 화면을 재사용한다). */
67
+ duplicateScreenIds: string[];
68
+ }
69
+ export interface SkippedSpec {
70
+ id: string;
71
+ reason: string;
72
+ }
73
+ export interface MigrationPlan {
74
+ screens: PlannedScreen[];
75
+ skipped: SkippedSpec[];
76
+ screensEnabled: {
77
+ before: boolean;
78
+ after: boolean;
79
+ changed: boolean;
80
+ };
81
+ summary: {
82
+ specsTotal: number;
83
+ specsWithRoute: number;
84
+ screensToCreate: number;
85
+ screensToReuse: number;
86
+ specsToLink: number;
87
+ specsSkipped: number;
88
+ };
89
+ }
90
+ export interface NormalizedRoute {
91
+ /** 정규화된 base route. 얻지 못하면 빈 문자열. */
92
+ baseRoute: string;
93
+ /** 정규화하며 떼어낸 원문 (괄호 주석 내용, 쿼리/프래그먼트). 버리지 않고 화면 비고로 옮긴다. */
94
+ annotations: string[];
95
+ }
96
+ /**
97
+ * route 문자열을 base route로 정규화한다.
98
+ *
99
+ * "/projects/[projectId]/specs (PRD 탭)" → "/projects/[projectId]/specs" + 주석 "PRD 탭"
100
+ * "/projects/[projectId]/specs?tab=screens" → "/projects/[projectId]/specs" + 주석 "?tab=screens"
101
+ * "/projects/" → "/projects"
102
+ * "/" → "/" (루트는 끝 슬래시 제거의 예외)
103
+ *
104
+ * 탭을 base route에서 떼는 이유: 탭은 라우트가 아니라 같은 화면의 URL 쿼리(?tab=)다. 괄호로
105
+ * 적혔든 쿼리로 적혔든 같은 페이지이므로 화면 하나로 묶는다. 원문은 버리지 않고 화면 비고에
106
+ * 남겨, 나중에 사람이 탭을 독립 화면으로 쪼갤지 판단할 근거로 쓴다.
107
+ */
108
+ export declare function normalizeRoute(raw: unknown): NormalizedRoute;
109
+ /** 화면 비고: 씨앗 출처 + 묶인 명세 + 버리지 않은 route 주석 + 갈린 epic/access 후보. */
110
+ export declare function buildScreenNote(planned: {
111
+ specIds: string[];
112
+ annotations: string[];
113
+ epicCandidates: string[];
114
+ accessCandidates: string[];
115
+ epic?: string;
116
+ access?: string;
117
+ }): string;
118
+ /**
119
+ * 계획을 만든다 (읽기만 한 데이터로, 부작용 없이).
120
+ *
121
+ * - route가 없거나 ui가 없는 명세는 화면 없는 기능(배치·API·CLI)이므로 사유와 함께 건너뛴다.
122
+ * - 같은 base route는 화면 하나로 묶는다.
123
+ * - 화면 이름은 묶인 명세 중 ID 오름차순 첫 명세의 이름 (사람이 나중에 고치는 씨앗값).
124
+ * - 화면 순서는 base route 사전순 순번.
125
+ * - epic·access는 묶인 명세의 값이 하나로 일치할 때만 복사하고, 갈리면 비운 채 후보를 비고에 남긴다.
126
+ * - 같은 base route의 화면이 이미 있으면 만들지 않고 재사용한다 (멱등).
127
+ * - route를 가진 명세가 0건이면 화면도 만들지 않고 screensEnabled도 켜지 않는다 (빈 화면 탭 방지).
128
+ */
129
+ export declare function buildMigrationPlan(specs: MigrateSpec[], existingScreens: MigrateScreen[], screensEnabledBefore: boolean): MigrationPlan;
130
+ /** 화면 생성 요청 바디. relatedSpecIds는 서버 전용이라 절대 싣지 않는다(보내면 조용히 버려진다). */
131
+ export declare function buildCreateScreenBody(planned: PlannedScreen): Record<string, unknown>;
132
+ /**
133
+ * 명세에 보낼 ui 병합 결과. 기존 ui를 통째로 다시 실어 보내면서 screenRefs에만 화면 ID를 더한다.
134
+ * PATCH /specs/:id가 ui를 통째로 교체하기 때문에, 이 병합을 빼먹으면 레거시 필드가
135
+ * 에러 없이 사라진다 (비파괴 계약 위반).
136
+ */
137
+ export declare function mergeScreenRef(ui: Record<string, unknown> | undefined, screenId: string): {
138
+ ui: Record<string, unknown>;
139
+ changed: boolean;
140
+ };
141
+ /**
142
+ * `ch screens migrate` 등록. screens.ts의 register…(screens, program) 규약을 따른다.
143
+ */
144
+ export declare function registerScreensMigrate(screens: Command, program: Command): void;
145
+ //# sourceMappingURL=screens.migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screens.migrate.d.ts","sourceRoot":"","sources":["../../src/commands/screens.migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,514 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeRoute = normalizeRoute;
4
+ exports.buildScreenNote = buildScreenNote;
5
+ exports.buildMigrationPlan = buildMigrationPlan;
6
+ exports.buildCreateScreenBody = buildCreateScreenBody;
7
+ exports.mergeScreenRef = mergeScreenRef;
8
+ exports.registerScreensMigrate = registerScreensMigrate;
9
+ const client_1 = require("../client");
10
+ const output_1 = require("../output");
11
+ /** ch-api DTO의 길이 제한 (create-screen.dto.ts) — 넘기면 400이라 CLI가 먼저 접는다. */
12
+ const MAX_NAME = 200;
13
+ const MAX_EPIC = 200;
14
+ const MAX_ACCESS = 200;
15
+ /** 괄호 주석: 반각·전각 괄호 모두. route에 섞인 "(PRD 탭)" 같은 사람 메모다. */
16
+ const ROUTE_COMMENT_RE = /[((][^))]*[))]/g;
17
+ /**
18
+ * route 문자열을 base route로 정규화한다.
19
+ *
20
+ * "/projects/[projectId]/specs (PRD 탭)" → "/projects/[projectId]/specs" + 주석 "PRD 탭"
21
+ * "/projects/[projectId]/specs?tab=screens" → "/projects/[projectId]/specs" + 주석 "?tab=screens"
22
+ * "/projects/" → "/projects"
23
+ * "/" → "/" (루트는 끝 슬래시 제거의 예외)
24
+ *
25
+ * 탭을 base route에서 떼는 이유: 탭은 라우트가 아니라 같은 화면의 URL 쿼리(?tab=)다. 괄호로
26
+ * 적혔든 쿼리로 적혔든 같은 페이지이므로 화면 하나로 묶는다. 원문은 버리지 않고 화면 비고에
27
+ * 남겨, 나중에 사람이 탭을 독립 화면으로 쪼갤지 판단할 근거로 쓴다.
28
+ */
29
+ function normalizeRoute(raw) {
30
+ const annotations = [];
31
+ let s = typeof raw === 'string' ? raw : '';
32
+ // 1. 괄호 주석 분리
33
+ s = s.replace(ROUTE_COMMENT_RE, (match) => {
34
+ const inner = match.slice(1, -1).trim();
35
+ if (inner)
36
+ annotations.push(inner);
37
+ return ' ';
38
+ });
39
+ // 2. 쿼리·프래그먼트 분리 (탭·앵커는 같은 화면이다)
40
+ s = s.trim();
41
+ const cut = s.search(/[?#]/);
42
+ if (cut >= 0) {
43
+ const suffix = s.slice(cut).trim();
44
+ if (suffix)
45
+ annotations.push(suffix);
46
+ s = s.slice(0, cut);
47
+ }
48
+ // 3. 공백·끝 슬래시 정리 (루트 "/"는 예외)
49
+ s = s.trim();
50
+ while (s.length > 1 && s.endsWith('/')) {
51
+ s = s.slice(0, -1);
52
+ }
53
+ return { baseRoute: s, annotations };
54
+ }
55
+ /** 코드유닛 사전순 비교 — 로케일에 흔들리지 않는 결정적 정렬 (ID·route 모두 ASCII). */
56
+ function byAsc(a, b) {
57
+ return a < b ? -1 : a > b ? 1 : 0;
58
+ }
59
+ /** 빈 문자열·공백뿐인 값을 걸러 순서를 유지한 채 중복 제거. */
60
+ function distinctNonEmpty(values) {
61
+ const seen = new Set();
62
+ const out = [];
63
+ for (const v of values) {
64
+ const t = (v ?? '').trim();
65
+ if (!t || seen.has(t))
66
+ continue;
67
+ seen.add(t);
68
+ out.push(t);
69
+ }
70
+ return out;
71
+ }
72
+ /**
73
+ * 묶인 명세들의 값이 "하나로 일치할 때만" 복사한다. 갈리면 undefined(비움).
74
+ *
75
+ * 값이 없는 명세는 반대 의견이 아니라 무응답으로 본다 — 셋 중 둘이 "E3"이고 하나가 비어
76
+ * 있으면 후보는 여전히 하나("E3")이므로 복사한다. 서로 다른 값이 둘 이상일 때만 비운다.
77
+ *
78
+ * 길이 제한을 넘는 값도 복사하지 않는다 — 서버 400으로 마이그레이션이 중간에 죽는 것보다
79
+ * 비워 두고 비고에 후보를 남기는 편이 낫다.
80
+ */
81
+ function unanimous(candidates, maxLength) {
82
+ if (candidates.length !== 1)
83
+ return undefined;
84
+ const only = candidates[0];
85
+ return only.length <= maxLength ? only : undefined;
86
+ }
87
+ /** 화면 비고: 씨앗 출처 + 묶인 명세 + 버리지 않은 route 주석 + 갈린 epic/access 후보. */
88
+ function buildScreenNote(planned) {
89
+ const lines = [
90
+ 'ch screens migrate로 생성 (씨앗: spec.ui.route)',
91
+ `묶인 명세: ${planned.specIds.join(', ')}`,
92
+ ];
93
+ if (planned.annotations.length > 0) {
94
+ lines.push(`레거시 route 주석: ${planned.annotations.join(' / ')}`);
95
+ }
96
+ // 값이 갈려서 비운 경우(후보 2개 이상)와, 하나뿐이지만 길이 제한을 넘겨 못 실은 경우 모두
97
+ // 후보를 남긴다 — 사람이 나중에 화면을 고칠 때 근거가 된다.
98
+ if (!planned.epic && planned.epicCandidates.length > 0) {
99
+ lines.push(`에픽 후보: ${planned.epicCandidates.join(' / ')}`);
100
+ }
101
+ if (!planned.access && planned.accessCandidates.length > 0) {
102
+ lines.push(`접근 권한 후보: ${planned.accessCandidates.join(' / ')}`);
103
+ }
104
+ return lines.join('\n');
105
+ }
106
+ /**
107
+ * 계획을 만든다 (읽기만 한 데이터로, 부작용 없이).
108
+ *
109
+ * - route가 없거나 ui가 없는 명세는 화면 없는 기능(배치·API·CLI)이므로 사유와 함께 건너뛴다.
110
+ * - 같은 base route는 화면 하나로 묶는다.
111
+ * - 화면 이름은 묶인 명세 중 ID 오름차순 첫 명세의 이름 (사람이 나중에 고치는 씨앗값).
112
+ * - 화면 순서는 base route 사전순 순번.
113
+ * - epic·access는 묶인 명세의 값이 하나로 일치할 때만 복사하고, 갈리면 비운 채 후보를 비고에 남긴다.
114
+ * - 같은 base route의 화면이 이미 있으면 만들지 않고 재사용한다 (멱등).
115
+ * - route를 가진 명세가 0건이면 화면도 만들지 않고 screensEnabled도 켜지 않는다 (빈 화면 탭 방지).
116
+ */
117
+ function buildMigrationPlan(specs, existingScreens, screensEnabledBefore) {
118
+ const skipped = [];
119
+ const groups = new Map();
120
+ const sortedSpecs = [...(specs ?? [])]
121
+ .filter((s) => s && typeof s.id === 'string')
122
+ .sort((a, b) => byAsc(a.id, b.id));
123
+ for (const spec of sortedSpecs) {
124
+ const ui = spec.ui;
125
+ if (!ui || typeof ui !== 'object') {
126
+ skipped.push({ id: spec.id, reason: 'ui 없음 — 화면 없는 기능(배치·API·CLI)' });
127
+ continue;
128
+ }
129
+ const raw = typeof ui.route === 'string' ? ui.route : '';
130
+ if (!raw.trim()) {
131
+ skipped.push({ id: spec.id, reason: 'ui.route 없음 — 화면 없는 기능(배치·API·CLI)' });
132
+ continue;
133
+ }
134
+ const { baseRoute, annotations } = normalizeRoute(raw);
135
+ if (!baseRoute) {
136
+ skipped.push({
137
+ id: spec.id,
138
+ reason: `route가 주석뿐이라 base route를 얻지 못함 ("${raw.trim()}")`,
139
+ });
140
+ continue;
141
+ }
142
+ if (!baseRoute.startsWith('/')) {
143
+ skipped.push({
144
+ id: spec.id,
145
+ reason: `route가 "/"로 시작하지 않아 화면 후보에서 제외 ("${raw.trim()}") — 필요하면 ch screens create로 직접 만드세요`,
146
+ });
147
+ continue;
148
+ }
149
+ const group = groups.get(baseRoute) ?? { specs: [], annotations: [] };
150
+ group.specs.push(spec);
151
+ group.annotations.push(...annotations);
152
+ groups.set(baseRoute, group);
153
+ }
154
+ // 기존 화면을 base route로 색인 (멱등의 핵심). route 없는 화면은 마이그레이션 대상 밖이다.
155
+ const screensByRoute = new Map();
156
+ for (const screen of [...(existingScreens ?? [])]
157
+ .filter((s) => s && typeof s.id === 'string')
158
+ .sort((a, b) => byAsc(a.id, b.id))) {
159
+ const { baseRoute } = normalizeRoute(screen.route);
160
+ if (!baseRoute)
161
+ continue;
162
+ const list = screensByRoute.get(baseRoute) ?? [];
163
+ list.push(screen);
164
+ screensByRoute.set(baseRoute, list);
165
+ }
166
+ const baseRoutes = [...groups.keys()].sort(byAsc);
167
+ const screens = baseRoutes.map((baseRoute, index) => {
168
+ const group = groups.get(baseRoute);
169
+ const specIds = group.specs.map((s) => s.id);
170
+ const annotations = distinctNonEmpty(group.annotations);
171
+ const epicCandidates = distinctNonEmpty(group.specs.map((s) => s.epic));
172
+ const accessCandidates = distinctNonEmpty(group.specs.map((s) => s.ui?.access));
173
+ const seedEpic = unanimous(epicCandidates, MAX_EPIC);
174
+ const seedAccess = unanimous(accessCandidates, MAX_ACCESS);
175
+ const seedName = (group.specs[0]?.name ?? '').trim() || baseRoute;
176
+ const name = seedName.slice(0, MAX_NAME);
177
+ const matches = screensByRoute.get(baseRoute) ?? [];
178
+ const existing = matches[0];
179
+ // 재사용 화면은 그대로 둔다(사람이 이미 고쳤을 수 있다) — 그래서 계획에도 "쓸 값"이 아니라
180
+ // "지금 그 화면에 있는 값"을 싣는다. 씨앗값은 새로 만드는 화면에만 쓴다.
181
+ const planned = {
182
+ baseRoute,
183
+ action: existing ? 'reuse' : 'create',
184
+ screenId: existing ? existing.id : null,
185
+ name: existing ? (existing.name ?? name) : name,
186
+ order: existing ? (existing.order ?? index + 1) : index + 1,
187
+ epic: existing ? existing.epic : seedEpic,
188
+ access: existing ? existing.access : seedAccess,
189
+ annotations,
190
+ specIds,
191
+ // 재사용 화면의 비고는 사람이 고쳤을 수 있으니 덮어쓰지 않는다 (create일 때만 씨앗 비고).
192
+ note: existing
193
+ ? undefined
194
+ : buildScreenNote({
195
+ specIds,
196
+ annotations,
197
+ epicCandidates,
198
+ accessCandidates,
199
+ epic: seedEpic,
200
+ access: seedAccess,
201
+ }),
202
+ linkSpecIds: group.specs
203
+ .filter((s) => {
204
+ if (!existing)
205
+ return true; // 새 화면 → 묶인 명세 전부 연결
206
+ const refs = Array.isArray(s.ui?.screenRefs) ? s.ui.screenRefs : [];
207
+ return !refs.includes(existing.id); // 이미 그 화면을 가리키면 그대로 둔다
208
+ })
209
+ .map((s) => s.id),
210
+ epicCandidates,
211
+ accessCandidates,
212
+ duplicateScreenIds: matches.length > 1 ? matches.map((s) => s.id) : [],
213
+ };
214
+ return planned;
215
+ });
216
+ const specsToLink = screens.reduce((n, s) => n + s.linkSpecIds.length, 0);
217
+ const after = screens.length > 0 ? true : screensEnabledBefore;
218
+ return {
219
+ screens,
220
+ skipped,
221
+ screensEnabled: {
222
+ before: screensEnabledBefore,
223
+ after,
224
+ changed: after !== screensEnabledBefore,
225
+ },
226
+ summary: {
227
+ specsTotal: sortedSpecs.length,
228
+ specsWithRoute: screens.reduce((n, s) => n + s.specIds.length, 0),
229
+ screensToCreate: screens.filter((s) => s.action === 'create').length,
230
+ screensToReuse: screens.filter((s) => s.action === 'reuse').length,
231
+ specsToLink,
232
+ specsSkipped: skipped.length,
233
+ },
234
+ };
235
+ }
236
+ /** 화면 생성 요청 바디. relatedSpecIds는 서버 전용이라 절대 싣지 않는다(보내면 조용히 버려진다). */
237
+ function buildCreateScreenBody(planned) {
238
+ return {
239
+ name: planned.name,
240
+ route: planned.baseRoute,
241
+ order: planned.order,
242
+ ...(planned.epic ? { epic: planned.epic } : {}),
243
+ ...(planned.access ? { access: planned.access } : {}),
244
+ ...(planned.note ? { note: planned.note } : {}),
245
+ };
246
+ }
247
+ /**
248
+ * 명세에 보낼 ui 병합 결과. 기존 ui를 통째로 다시 실어 보내면서 screenRefs에만 화면 ID를 더한다.
249
+ * PATCH /specs/:id가 ui를 통째로 교체하기 때문에, 이 병합을 빼먹으면 레거시 필드가
250
+ * 에러 없이 사라진다 (비파괴 계약 위반).
251
+ */
252
+ function mergeScreenRef(ui, screenId) {
253
+ const next = { ...(ui ?? {}) };
254
+ const refs = Array.isArray(next.screenRefs) ? [...next.screenRefs] : [];
255
+ if (refs.includes(screenId)) {
256
+ return { ui: next, changed: false };
257
+ }
258
+ refs.push(screenId);
259
+ next.screenRefs = refs;
260
+ return { ui: next, changed: true };
261
+ }
262
+ // ── 커맨드 ────────────────────────────────────────────────────────────────
263
+ /** 마이그레이션을 중간에 세우는 오류 (screensEnabled를 켜기 전에 멈춘다). */
264
+ class MigrateAbort extends Error {
265
+ }
266
+ /** 기계 모드(=stdout이 순수 JSON이어야 하는 모드)인지. */
267
+ function isMachineOutput(globalOpts) {
268
+ return !!(globalOpts.json || globalOpts.csv || globalOpts.quiet);
269
+ }
270
+ const MIGRATE_HELP = `
271
+ 하는 일 (이 순서, 마지막이 플래그):
272
+ 1. spec.ui.route를 씨앗으로 화면을 중복 없이 만든다 (같은 base route = 한 화면)
273
+ 2. 각 명세의 ui.screenRefs에 화면 ID를 더한다 (기존 ui 필드는 그대로 보존 — 비파괴)
274
+ 3. 전부 성공하면 ch_projects.screensEnabled를 true로 켠다
275
+
276
+ route 정규화:
277
+ "/projects/[projectId]/specs (PRD 탭)" → base route "/projects/[projectId]/specs"
278
+ "/projects/[projectId]/specs?tab=screens" → base route "/projects/[projectId]/specs"
279
+ 괄호 주석·탭 쿼리는 화면 비고에 "레거시 route 주석"으로 남는다 (나중에 화면 분리 판단 근거).
280
+ route가 없는 명세(배치·API·CLI)는 건너뛰고 사유를 결과에 남긴다.
281
+
282
+ 안전장치:
283
+ --dry-run 계획만 출력하고 아무것도 쓰지 않는다 (읽기만 한다)
284
+ --rollback screensEnabled를 false로 내려 레거시 모드로 되돌린다 (화면·screenRefs는 지우지 않는다)
285
+ 재실행해도 같은 base route의 화면을 두 번 만들지 않는다 (멱등)
286
+
287
+ 예시:
288
+ ch screens migrate --dry-run --json # 계획을 기계 모드로 확인
289
+ ch screens migrate # 적용
290
+ ch screens migrate --rollback # 화면 모드만 끄기 (되돌리기)
291
+ `;
292
+ /** 모든 명세를 페이지를 넘겨 가며 읽는다 (perPage 최대 100 — 서버 제한). */
293
+ async function fetchAllSpecs(client) {
294
+ const all = [];
295
+ const MAX_PAGES = 200; // 안전장치: 서버가 hasNext를 잘못 주더라도 무한루프 금지
296
+ for (let page = 1; page <= MAX_PAGES; page++) {
297
+ const { data } = await client.get('/specs', { params: { page, perPage: 100 } });
298
+ const items = Array.isArray(data) ? data : (data?.data ?? []);
299
+ all.push(...items);
300
+ if (!items.length || !data?.pagination?.hasNext)
301
+ break;
302
+ }
303
+ return all;
304
+ }
305
+ async function fetchScreens(client) {
306
+ const { data } = await client.get('/screens');
307
+ return Array.isArray(data) ? data : (data?.data ?? []);
308
+ }
309
+ /** 프로젝트의 현재 screensEnabled. 필드가 없는 레거시 문서는 false로 접는다 (백필하지 않는다). */
310
+ async function fetchScreensEnabled(client) {
311
+ const { data } = await client.get('/projects/current');
312
+ return data?.screensEnabled ?? false;
313
+ }
314
+ /**
315
+ * screensEnabled 토글.
316
+ *
317
+ * 진짜 boolean을 보낸다. ch-api 글로벌 파이프가 enableImplicitConversion을 켜 두어서
318
+ * 문자열 "false"는 Boolean("false") === true로 뒤집힌다 — 롤백이 켜기로 둔갑한다.
319
+ */
320
+ async function setScreensEnabled(client, enabled) {
321
+ await client.patch('/projects/current', { screensEnabled: enabled === true });
322
+ }
323
+ /**
324
+ * 첫 연결 직후 서버가 정말 screenRefs를 저장했는지 확인한다.
325
+ *
326
+ * ch-api의 글로벌 ValidationPipe가 whitelist: true라, SpecUIDto에 screenRefs가 없는 구버전
327
+ * 서버는 그 필드를 400 없이 조용히 버린다. 그러면 migrate는 "성공"하고 연결만 사라진 채
328
+ * screensEnabled가 켜져 — 화면 탭은 뜨는데 명세 연결이 없는 최악의 상태가 된다.
329
+ * 그래서 첫 쓰기 직후 되읽어 확인하고, 아니면 플래그를 켜기 전에 중단한다.
330
+ */
331
+ async function assertScreenRefsPersisted(client, specId, screenId) {
332
+ const { data } = await client.get(`/specs/${specId}`);
333
+ const refs = Array.isArray(data?.ui?.screenRefs) ? data.ui.screenRefs : [];
334
+ if (!refs.includes(screenId)) {
335
+ throw new MigrateAbort(`ch-api가 spec.ui.screenRefs를 저장하지 않았습니다 (${specId} → ${screenId}). ` +
336
+ 'screenRefs를 모르는 구버전 ch-api는 요청 검증기(whitelist)가 그 필드를 조용히 버립니다. ' +
337
+ 'SCREEN-004(spec.ui.screenRefs) 배포 후 다시 실행하세요 — 이미 만들어진 화면은 재실행 시 재사용됩니다. ' +
338
+ 'screensEnabled는 켜지 않았으므로 프로젝트는 레거시 모드 그대로입니다.');
339
+ }
340
+ }
341
+ /** 사람용 출력: 계획/결과 표 + 요약. */
342
+ function printHumanReport(result, dryRun) {
343
+ const tag = dryRun ? '[DRY-RUN] ' : '';
344
+ if (result.screens.length > 0) {
345
+ (0, output_1.printTable)(['route', '동작', 'screenId', '화면명', 'order', '묶인 명세', '연결'], result.screens.map((s) => [
346
+ s.baseRoute,
347
+ s.action === 'create' ? (dryRun ? '생성 예정' : '생성') : '재사용',
348
+ s.screenId ?? '-',
349
+ s.name,
350
+ String(s.order),
351
+ String(s.specIds.length),
352
+ String(s.linkSpecIds.length),
353
+ ]));
354
+ }
355
+ if (result.skipped.length > 0) {
356
+ (0, output_1.printInfo)(`건너뛴 명세 ${result.skipped.length}건 (화면 없는 기능):`);
357
+ (0, output_1.printTable)(['spec', '사유'], result.skipped.map((s) => [s.id, s.reason]));
358
+ }
359
+ const sm = result.summary;
360
+ (0, output_1.printInfo)(`${tag}화면 생성 ${sm.screensToCreate} · 재사용 ${sm.screensToReuse} · ` +
361
+ `명세 연결 ${sm.specsToLink} · 건너뜀 ${sm.specsSkipped}`);
362
+ const flag = result.screensEnabled;
363
+ (0, output_1.printInfo)(`${tag}screensEnabled: ${flag.before} → ${flag.after}` +
364
+ (flag.changed ? '' : ' (변경 없음)'));
365
+ }
366
+ /** 화면 모드 끄기 (--rollback). 화면 문서와 screenRefs는 지우지 않는다. */
367
+ async function runRollback(client, globalOpts, dryRun) {
368
+ const before = await fetchScreensEnabled(client);
369
+ const result = {
370
+ action: 'rollback',
371
+ dryRun,
372
+ screensEnabled: { before, after: false, changed: before !== false },
373
+ };
374
+ if (!dryRun && before) {
375
+ await setScreensEnabled(client, false);
376
+ }
377
+ if (isMachineOutput(globalOpts)) {
378
+ (0, output_1.formatOutput)(result, globalOpts);
379
+ }
380
+ if (dryRun) {
381
+ (0, output_1.printInfo)(before
382
+ ? '[DRY-RUN] screensEnabled를 false로 내립니다 (화면 문서·screenRefs는 그대로 둡니다).'
383
+ : '[DRY-RUN] 이미 레거시 모드입니다 (screensEnabled=false) — 변경 없음.');
384
+ return;
385
+ }
386
+ if (!before) {
387
+ (0, output_1.printInfo)('이미 레거시 모드입니다 (screensEnabled=false) — 변경 없음.');
388
+ return;
389
+ }
390
+ (0, output_1.printSuccess)('화면 모드를 껐습니다 (screensEnabled=false). 화면 문서와 명세의 screenRefs는 지우지 않았습니다 — 다시 켜면 그대로 살아납니다.');
391
+ }
392
+ /** 마이그레이션 본체. */
393
+ async function runMigrate(client, globalOpts, dryRun) {
394
+ const specs = await fetchAllSpecs(client);
395
+ const existingScreens = await fetchScreens(client);
396
+ const before = await fetchScreensEnabled(client);
397
+ const plan = buildMigrationPlan(specs, existingScreens, before);
398
+ const emit = () => {
399
+ const result = { action: 'migrate', dryRun, ...plan };
400
+ if (isMachineOutput(globalOpts)) {
401
+ (0, output_1.formatOutput)(result, globalOpts);
402
+ }
403
+ else {
404
+ printHumanReport(result, dryRun);
405
+ }
406
+ };
407
+ for (const s of plan.screens) {
408
+ if (s.duplicateScreenIds.length > 1) {
409
+ (0, output_1.printWarning)(`base route "${s.baseRoute}"에 화면이 ${s.duplicateScreenIds.length}개 있습니다 ` +
410
+ `(${s.duplicateScreenIds.join(', ')}) — 첫 화면(${s.screenId})을 재사용합니다.`);
411
+ }
412
+ }
413
+ if (dryRun) {
414
+ emit();
415
+ (0, output_1.printInfo)('[DRY-RUN] 계획만 출력했습니다 — 화면·명세·프로젝트 문서를 하나도 쓰지 않았습니다.');
416
+ return;
417
+ }
418
+ if (plan.screens.length === 0) {
419
+ emit();
420
+ (0, output_1.printInfo)('route를 가진 명세가 없습니다 — 화면을 만들지 않고 screensEnabled도 켜지 않았습니다 (변경 없음).');
421
+ return;
422
+ }
423
+ // ── 여기부터 쓰기 ──────────────────────────────────────────────────────
424
+ // 어느 단계에서 실패하든 플래그는 켜지지 않는다 → 프로젝트는 레거시 모드로 남는다(회귀 0).
425
+ // 이미 만든 화면·연결은 다음 실행이 멱등하게 이어받는다.
426
+ let linked = 0;
427
+ try {
428
+ // 1) 화면 생성 (없는 base route만)
429
+ for (const planned of plan.screens) {
430
+ if (planned.action !== 'create')
431
+ continue;
432
+ const { data } = await client.post('/screens', buildCreateScreenBody(planned));
433
+ const id = data?.id;
434
+ if (!id) {
435
+ throw new MigrateAbort(`화면 생성 응답에 id가 없습니다 (route: ${planned.baseRoute}). screensEnabled는 켜지 않았습니다.`);
436
+ }
437
+ planned.screenId = String(id);
438
+ }
439
+ // 2) 명세 연결 — 기존 ui를 되읽어 병합 저장 (통째 교체 금지)
440
+ let verified = false;
441
+ for (const planned of plan.screens) {
442
+ const screenId = planned.screenId;
443
+ if (!screenId)
444
+ continue;
445
+ for (const specId of planned.linkSpecIds) {
446
+ const { data: spec } = await client.get(`/specs/${specId}`);
447
+ const { ui, changed } = mergeScreenRef(spec?.ui, screenId);
448
+ if (!changed)
449
+ continue; // 계획 산출 뒤 누가 먼저 걸어 뒀다면 그대로 둔다 (멱등)
450
+ // 버전 기록은 남기지 않는다: 마이그레이션은 기계적 링크 추가라, 명세마다 새 버전을
451
+ // 찍으면 이력이 통째로 노이즈가 된다 (ch specs update --no-version과 같은 선택).
452
+ await client.patch(`/specs/${specId}?newVersion=false`, { ui });
453
+ linked += 1;
454
+ // 첫 쓰기 직후 한 번만: 서버가 screenRefs를 진짜 저장했는지 확인 (구버전 무성 실패 차단)
455
+ if (!verified) {
456
+ await assertScreenRefsPersisted(client, specId, screenId);
457
+ verified = true;
458
+ }
459
+ }
460
+ }
461
+ // 3) 마지막 쓰기 — 화면 생성·연결이 전부 성공한 뒤에야 플래그를 켠다
462
+ if (plan.screensEnabled.changed) {
463
+ await setScreensEnabled(client, true);
464
+ }
465
+ }
466
+ catch (error) {
467
+ // MigrateAbort는 자기 메시지에 이미 안내를 담고 있다. 그 밖의 실패(HTTP 4xx·5xx 등)는
468
+ // 인터셉터가 원인만 찍으므로, 지금 상태와 다음 행동을 여기서 덧붙인다.
469
+ if (!(error instanceof MigrateAbort)) {
470
+ (0, output_1.printWarning)(`마이그레이션이 중간에 멈췄습니다 (화면 생성 ${plan.screens.filter((s) => s.action === 'create' && s.screenId).length}건, 명세 연결 ${linked}건까지 진행). ` +
471
+ 'screensEnabled는 켜지 않았으므로 프로젝트는 레거시 모드 그대로입니다 — ' +
472
+ '원인을 고쳐 다시 실행하면 이미 만들어진 화면을 재사용해 이어갑니다.');
473
+ }
474
+ throw error;
475
+ }
476
+ // 실제 연결 건수로 요약을 맞춘다 (경합으로 건너뛴 건이 있으면 계획보다 적을 수 있다)
477
+ plan.summary.specsToLink = linked;
478
+ emit();
479
+ (0, output_1.printSuccess)(`마이그레이션 완료 — 화면 ${plan.summary.screensToCreate}개 생성, ` +
480
+ `${plan.summary.screensToReuse}개 재사용, 명세 ${linked}건 연결` +
481
+ (plan.screensEnabled.changed ? ', screensEnabled=true (화면 모드 켬)' : ''));
482
+ }
483
+ /**
484
+ * `ch screens migrate` 등록. screens.ts의 register…(screens, program) 규약을 따른다.
485
+ */
486
+ function registerScreensMigrate(screens, program) {
487
+ screens
488
+ .command('migrate')
489
+ .description('레거시 프로젝트를 화면 모델로 이관 — spec.ui.route를 씨앗으로 화면 생성 + screenRefs 연결 + screensEnabled 켬 (비파괴·멱등, admin)')
490
+ .option('--rollback', 'screensEnabled를 false로 내려 레거시 모드로 되돌린다 (화면 문서·screenRefs는 지우지 않는다)')
491
+ .addHelpText('after', MIGRATE_HELP)
492
+ .action(async (options) => {
493
+ const globalOpts = program.opts();
494
+ const dryRun = !!globalOpts.dryRun;
495
+ try {
496
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
497
+ if (options.rollback) {
498
+ await runRollback(client, globalOpts, dryRun);
499
+ return;
500
+ }
501
+ await runMigrate(client, globalOpts, dryRun);
502
+ }
503
+ catch (error) {
504
+ // HTTP 오류(4xx·5xx)는 client 인터셉터가 stderr 출력 + 종료코드를 세운다.
505
+ // 여기서 잡는 것은 우리가 세운 중단 조건(MigrateAbort)뿐이다. 어느 쪽이든
506
+ // screensEnabled를 켜기 전에 멈추므로 프로젝트는 레거시 모드로 남는다.
507
+ if (error instanceof MigrateAbort) {
508
+ (0, output_1.printError)(error.message);
509
+ process.exitCode = 1;
510
+ }
511
+ }
512
+ });
513
+ }
514
+ //# sourceMappingURL=screens.migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screens.migrate.js","sourceRoot":"","sources":["../../src/commands/screens.migrate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decencia/ch-cli",
3
- "version": "1.12.1",
3
+ "version": "1.13.0",
4
4
  "description": "Decencia Communication Channel CLI",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-change-manager
3
3
  description: 기존 소통채널 프로젝트의 기능 추가/수정을 사용자와 대화로 명확화 → 전파 스킬로 연관 PRD/spec/DB/SQA 일괄 갱신 → 변경으로 생긴 새 할일을 GitHub 이슈로 발행하는 오케스트레이터 스킬. (1)대화로 변경 내용 확정 → (2)[게이트] 영향 범위 확인 후 전파 적용 → (3)[게이트] 할일 목록 확인 후 이슈 발행. "이 기능 바꿀래"·"기획 수정"·"이거 추가해줘(기존 프로젝트)" 류 요청 시.
4
4
  allowed-tools: Bash(ch:*) Bash(git:*) Bash(gh:*) Read Write
5
- version: 1.12.1
5
+ version: 1.13.0
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -10,7 +10,7 @@ description: |
10
10
  (3) 명세·DB·SQA가 서로 어긋나 있는 의심이 들 때 (정합성 점검),
11
11
  (4) PRD 갱신 후 하위 spec/db/SQA로 변경분을 흘려보내야 할 때,
12
12
  (5) Sprint 진행 중 도메인 규칙·스키마가 흔들렸을 때 연쇄 갱신이 필요할 때.
13
- version: 1.12.1
13
+ version: 1.13.0
14
14
  ---
15
15
 
16
16
  <!-- ch-version-gate -->
@@ -7,9 +7,9 @@ description: |
7
7
  (1) spec/db-table/화면(screen)을 CLI로 다룰 때,
8
8
  (2) spec 규모를 Story Point(`--points`)로 매길 때,
9
9
  (3) ch db-tables 명령(list/get/create/update/delete)을 사용할 때,
10
- (4) ch screens 명령(list/get/create/update/delete)으로 화면을 다룰 때,
10
+ (4) ch screens 명령(list/get/create/update/delete/migrate)으로 화면을 다루거나 레거시 프로젝트를 화면 모드로 이관할 때,
11
11
  (5) Spec ID를 JIRA 스타일(`LOGIN-001`)로 직접 지정할 때 (`ch specs create --id`).
12
- version: 1.12.1
12
+ version: 1.13.0
13
13
  ---
14
14
 
15
15
  <!-- ch-version-gate -->
@@ -236,6 +236,11 @@ ch screens update <screenId> --order 3
236
236
  ch screens update <screenId> --entry-points "" # 진입 경로 모두 해제
237
237
 
238
238
  ch screens delete <screenId> # 참조 spec의 ui.screenRefs도 서버가 자동 정리
239
+
240
+ # 레거시 프로젝트 → 화면 모드 이관 (비파괴·멱등, admin)
241
+ ch screens migrate --dry-run # 계획만 (아무것도 쓰지 않는다)
242
+ ch screens migrate # 적용: 화면 생성 → screenRefs 연결 → screensEnabled=true
243
+ ch screens migrate --rollback # 화면 모드만 끄기 (화면·screenRefs는 남는다)
239
244
  ```
240
245
 
241
246
  - `--id`는 JIRA 스타일(`SCR-001`). 패턴 `^[A-Za-z][A-Za-z0-9_]*-[A-Za-z0-9]+$`, 중복 시 409.
@@ -261,6 +266,21 @@ ch screens delete <screenId> # 참조 spec의 ui.screenRefs
261
266
 
262
267
  `ScreenState{name, description?}`의 정의(SSOT)는 db-tables의 `screens` 테이블 문서다.
263
268
 
269
+ ### migrate (레거시 → 화면 모드)
270
+
271
+ `spec.ui.route`를 씨앗으로 화면을 만들고 명세에 연결한 뒤 `screensEnabled`를 켠다. **admin 전용.**
272
+
273
+ - **비파괴**: `spec.ui`의 기존 필드(figmaNodeId·route·file·access·interactionMap)를 하나도 지우지 않는다. 그래서 `--rollback`(플래그만 false)이면 즉시 레거시 동작으로 돌아간다.
274
+ - **route 정규화**: 괄호 주석과 탭 쿼리를 떼어 base route로 묶는다. 같은 base route = 화면 하나 (탭은 라우트가 아니라 `?tab=` 쿼리다).
275
+ - `/projects/[projectId]/specs (PRD 탭)` → `/projects/[projectId]/specs`
276
+ - `/projects/[projectId]/specs?tab=screens` → `/projects/[projectId]/specs`
277
+ - 떼어낸 원문은 화면 `note`에 `레거시 route 주석: PRD 탭 / ?tab=screens`로 남는다 (나중에 화면을 쪼갤 근거).
278
+ - **씨앗값**: 화면명 = 묶인 명세 중 ID 오름차순 첫 명세의 이름, order = base route 사전순 순번. `epic`·`access`는 묶인 명세의 값이 하나로 일치할 때만 복사하고 갈리면 비운 채 후보를 `note`에 남긴다. 전부 사람이 나중에 고치는 값이다.
279
+ - **건너뜀**: route가 없는 명세(배치·API·CLI)는 화면 없는 기능이므로 건너뛰고 사유를 결과에 남긴다.
280
+ - **멱등**: 재실행해도 같은 base route로 화면을 두 번 만들지 않고, 이미 걸린 `screenRefs`는 건드리지 않는다.
281
+ - **쓰기 순서**: 화면 생성 → 명세 연결 → `screensEnabled=true`(항상 마지막). 중간에 실패하면 플래그가 꺼진 채 남아 프로젝트는 레거시 모드 그대로다.
282
+ - `--dry-run`은 계획만 낸다(쓰기 0건). 단, 계획을 서버 데이터로 계산하므로 **읽기 요청은 나간다** — 다른 커맨드의 `--dry-run`과 다른 점이다.
283
+
264
284
  ## 4. 운영 팁
265
285
 
266
286
  - Windows 한글 출력이 비어 보일 때: `ch specs get <id> --json | Out-File spec.json` (PowerShell)
@@ -274,4 +294,5 @@ ch screens delete <screenId> # 참조 spec의 ui.screenRefs
274
294
  - `--db-tables ""`는 모두 해제. 단일 ID 유지하려면 그 ID만 명시.
275
295
  - `relatedSpecIds`를 JSON에 명시해도 서버가 무시 (자동 관리 영역).
276
296
  - `ch screens update --states`도 배열 **통째 교체**다. 상태 하나만 고치려 해도 `ch screens get <id> --json`으로 받아 배열 전체를 넘긴다.
277
- - 화면 SSOT는 `screensEnabled=true`인 프로젝트에서만 screens다. 이 플래그가 꺼진(=기존) 프로젝트는 화면 정보의 SSOT가 여전히 `spec.ui.route`다 — screens를 만들어도 그 프로젝트의 화면 정보가 자동으로 옮겨가지 않는다.
297
+ - 화면 SSOT는 `screensEnabled=true`인 프로젝트에서만 screens다. 이 플래그가 꺼진(=기존) 프로젝트는 화면 정보의 SSOT가 여전히 `spec.ui.route`다 — screens를 만들어도 그 프로젝트의 화면 정보가 자동으로 옮겨가지 않는다. 옮기려면 `ch screens migrate`.
298
+ - `ch screens migrate`의 `--dry-run`은 **읽기 요청을 보낸다**(계획을 서버가 가진 명세로 계산한다). "아무 요청도 안 나간다"가 아니라 "아무것도 쓰지 않는다"가 보장이다.
@@ -8,7 +8,7 @@ description: |
8
8
  (2) DB 테이블 단위로 컬럼·인덱스·보안규칙을 등록·수정할 때,
9
9
  (3) 새 테이블을 추가하면서 전체 인벤토리도 함께 업데이트할 때,
10
10
  (4) spec.dbTableRefs와 양방향 동기화가 필요한 작업 시.
11
- version: 1.12.1
11
+ version: 1.13.0
12
12
  ---
13
13
 
14
14
  <!-- ch-version-gate -->
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-github-issue
3
3
  description: gh CLI로 현재 repo에 GitHub 이슈를 작성한다. 이슈 1개=유형 1개(feat/fix/bug), 표준 본문 양식(작업내용·관련 명세 백링크·완료조건)으로 발행. "이슈 만들어줘"/"깃헙 이슈로 등록해줘" 요청 시, 또는 소통채널 기획·명세 작업 후 처리할 일들을 GitHub 이슈로 옮길 때 사용. 멱등성/중복방지·확인단계는 다루지 않음(요청대로 바로 생성).
4
4
  allowed-tools: Bash(gh:*) Bash(git:*) Read Write
5
- version: 1.12.1
5
+ version: 1.13.0
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-orchestrator
3
3
  description: 소통채널 작업의 단일 진입점(디스패처). 사용자 요청을 듣고 7종(bootstrap·terraformer·change-manager·github-issue·issue-coder·pr-merger·sprint-runner) 중 적절한 곳으로 라우팅하고, 필요하면 여러 단계를 순차 오케스트레이션한다. 대화형 스킬은 메인 세션에서 Skill로, 자율 에이전트는 Agent로 위임. "소통채널 작업 해줘"·"이거 어떻게 처리하지?"처럼 무엇부터 할지 모를 때, 또는 신규기획/코드편입/기획변경/이슈/구현/머지/스프린트실행 어디로든 시작할 때.
4
4
  allowed-tools: Skill Agent Read Bash(ch:*) Bash(gh:*) Bash(git:*)
5
- version: 1.12.1
5
+ version: 1.13.0
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -7,7 +7,7 @@ description: |
7
7
  (1) PRD를 작성하거나 갱신할 때,
8
8
  (2) PRD 구성에서 Epic/스토리 구조를 후속 spec 작성에 매핑할 때,
9
9
  (3) Read-before-Write 규칙으로 PRD content를 안전하게 수정해야 할 때.
10
- version: 1.12.1
10
+ version: 1.13.0
11
11
  ---
12
12
 
13
13
  <!-- ch-version-gate -->
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-project-bootstrap
3
3
  description: 신규 기획을 사용자와 대화하며 step-by-step으로 소통채널 프로젝트로 만드는 오케스트레이터 스킬. (1)대화로 PRD 완성 → 승인 → (2)페이지명세(spec)+DB스키마 → 승인 → (3)SQA 시트. 각 단계 사용자 승인 게이트, 작성 디테일은 기존 2t-decencia-channel-*-v2 스킬을 적극 재사용. "새 기획 만들어줘"·"프로젝트 처음부터 세팅" 류 요청 시.
4
4
  allowed-tools: Bash(ch:*) Bash(git:*) Read Write
5
- version: 1.12.1
5
+ version: 1.13.0
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -11,7 +11,7 @@ description: |
11
11
  (2) UI 메타데이터·비즈니스 로직·DB 참조를 함께 다룰 때,
12
12
  (3) Story 규모를 Story Point(`--points`)로 매길 때,
13
13
  (4) 신규 spec ID를 `LOGIN-001` 같은 JIRA 스타일로 부여하고 싶을 때 (`ch specs create --id`).
14
- version: 1.12.1
14
+ version: 1.13.0
15
15
  ---
16
16
 
17
17
  <!-- ch-version-gate -->
@@ -7,7 +7,7 @@ description: |
7
7
  (1) sprint를 구성할 때,
8
8
  (2) Σ spec.points 기반 sprint 용량 산정이 필요할 때,
9
9
  (3) Epic·도메인·의존성을 함께 고려해 spec을 sprint에 배분할 때.
10
- version: 1.12.1
10
+ version: 1.13.0
11
11
  ---
12
12
 
13
13
  <!-- ch-version-gate -->
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-sprint-runner
3
3
  description: 특정 Sprint를 끝까지 실행(run)하는 오케스트레이터 스킬. Sprint의 spec을 시드로 이슈 목록을 분해·발행(github-issue)하고, GitHub milestone에 묶인 이슈를 상태별로 분류해 issue-coder(병렬)·pr-merger(직렬)로 전진시킨 뒤, 사람확인이 필요한 곳에서 멈춘다. 사람이 확인·체크 후 재호출하면 멱등하게 이어간다(반복 루프). "스프린트 돌려줘"·"sprint N 실행"·"이 스프린트 개발 진행해줘" 류 요청 시.
4
4
  allowed-tools: Skill Agent Read Bash(ch:*) Bash(gh:*) Bash(git:*)
5
- version: 1.12.1
5
+ version: 1.13.0
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -12,7 +12,7 @@ description: |
12
12
  (4) 명세 영역별 완성형 TC 번들(퍼블리싱/프론트/백엔드 디센시아 운영 관점 포함)을 가져다 쓸 때,
13
13
  (5) 새 명세 작업 중 반복 패턴을 발견해 영역별 번들을 보강할 때,
14
14
  (6) Sprint 종료 전 spec별 SQA 통과 여부를 점검할 때.
15
- version: 1.12.1
15
+ version: 1.13.0
16
16
  ---
17
17
 
18
18
  <!-- ch-version-gate -->
@@ -8,7 +8,7 @@ description: |
8
8
  (2) "작업 현황 적어줘", "workStatus 갱신해줘" 요청 시,
9
9
  (3) Sprint 종료 회고나 인수인계용으로 spec별 진행 상태를 정리할 때,
10
10
  (4) `ch specs update --work-status` 또는 웹 "작업 현황" 탭에서 갱신할 때.
11
- version: 1.12.1
11
+ version: 1.13.0
12
12
  ---
13
13
 
14
14
  <!-- ch-version-gate -->