@simplysm/sd-claude 14.0.79 → 14.0.81

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 (96) hide show
  1. package/claude/references/sd-requirement-source-handling.md +17 -17
  2. package/claude/references/sd-simplysm14/README.md +58 -58
  3. package/claude/references/sd-simplysm14/manuals/client-component.md +739 -739
  4. package/claude/references/sd-simplysm14/manuals/client-crud.md +1 -1
  5. package/claude/references/sd-simplysm14/manuals/client-demo.md +1 -1
  6. package/claude/references/sd-simplysm14/manuals/client-setup.md +2 -2
  7. package/claude/references/sd-simplysm14/manuals/client-tab.md +2 -2
  8. package/claude/references/sd-simplysm14/manuals/logging.md +3 -3
  9. package/claude/references/sd-simplysm14/manuals/orm-union.md +7 -7
  10. package/claude/references/sd-simplysm14/manuals/orm.md +75 -75
  11. package/claude/references/sd-simplysm14/manuals/test.md +8 -8
  12. package/claude/rules/sd-base-rules.md +261 -354
  13. package/claude/rules/sd-design-rules.md +44 -0
  14. package/claude/{sd-check-forbidden-files.py → sd-check-edit.py} +2 -1
  15. package/claude/{sd-check-bash.py → sd-check-shell.py} +2 -2
  16. package/claude/settings.json +3 -4
  17. package/claude/skills/sd-commit/SKILL.md +17 -17
  18. package/claude/skills/sd-config/SKILL.md +4 -4
  19. package/claude/skills/sd-demo/SKILL.md +41 -43
  20. package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +99 -0
  21. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +12 -0
  22. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +3 -0
  23. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +150 -0
  24. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +143 -0
  25. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +150 -0
  26. package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +2 -0
  27. package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +12 -0
  28. package/claude/skills/sd-demo/evals/golden.jsonl +1 -5
  29. package/claude/skills/sd-dev/SKILL.md +49 -22
  30. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +8 -0
  31. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
  32. package/claude/skills/sd-dev/evals/fixtures/{case-modify → minimal-ts-pkg}/tsconfig.json +1 -3
  33. package/claude/skills/sd-dev/evals/golden.jsonl +1 -3
  34. package/claude/skills/sd-docs/SKILL.md +8 -8
  35. package/claude/skills/sd-impl/SKILL.md +172 -82
  36. package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +101 -0
  37. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +101 -0
  38. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +46 -0
  39. package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +89 -0
  40. package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +101 -0
  41. package/claude/skills/sd-impl/evals/golden.jsonl +4 -6
  42. package/claude/skills/sd-review/SKILL.md +33 -0
  43. package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +7 -0
  44. package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +4 -0
  45. package/claude/skills/sd-review/evals/golden.jsonl +2 -0
  46. package/claude/skills/sd-skill/SKILL.md +217 -29
  47. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +14 -0
  48. package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
  49. package/claude/skills/sd-skill/evals/golden.jsonl +2 -5
  50. package/claude/skills/sd-spec/SKILL.md +384 -305
  51. package/claude/skills/sd-spec/references/example-spec.md +41 -64
  52. package/claude/skills/sd-unpack/SKILL.md +83 -83
  53. package/claude/skills/sd-use/SKILL.md +4 -4
  54. package/package.json +1 -1
  55. package/claude/output-styles/sd-tone.md +0 -152
  56. package/claude/skills/sd-demo/evals/fixtures/empty/.specs/260513120000_warehouse/spec.md +0 -45
  57. package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/.specs/260513120000_warehouse/spec.md +0 -42
  58. package/claude/skills/sd-demo/evals/fixtures/with-existing-screen/packages/app/src/screens/dashboard/dashboard.view.ts +0 -33
  59. package/claude/skills/sd-demo/evals/fixtures/with-master-screen/.specs/260513120000_warehouse/spec.md +0 -45
  60. package/claude/skills/sd-demo/evals/fixtures/with-master-screen/packages/app/src/screens/dashboard/dashboard.view.ts +0 -33
  61. package/claude/skills/sd-demo/evals/fixtures/with-modal/.specs/260513120000_warehouse/spec.md +0 -75
  62. package/claude/skills/sd-demo/evals/fixtures/with-modal/packages/app/src/screens/dashboard/dashboard.view.ts +0 -33
  63. package/claude/skills/sd-demo/evals/fixtures/with-screens/.specs/260513120000_warehouse/spec.md +0 -45
  64. package/claude/skills/sd-demo/evals/fixtures/with-screens/packages/app/src/screens/dashboard/dashboard.view.ts +0 -33
  65. package/claude/skills/sd-dev/evals/fixtures/case-add/package.json +0 -13
  66. package/claude/skills/sd-dev/evals/fixtures/case-add/src/index.ts +0 -10
  67. package/claude/skills/sd-dev/evals/fixtures/case-add/tests/index.test.ts +0 -11
  68. package/claude/skills/sd-dev/evals/fixtures/case-add/tsconfig.json +0 -12
  69. package/claude/skills/sd-dev/evals/fixtures/case-bug/package.json +0 -13
  70. package/claude/skills/sd-dev/evals/fixtures/case-bug/src/index.ts +0 -10
  71. package/claude/skills/sd-dev/evals/fixtures/case-bug/tests/index.test.ts +0 -11
  72. package/claude/skills/sd-dev/evals/fixtures/case-bug/tsconfig.json +0 -12
  73. package/claude/skills/sd-dev/evals/fixtures/case-modify/package.json +0 -13
  74. package/claude/skills/sd-dev/evals/fixtures/case-modify/src/index.ts +0 -10
  75. package/claude/skills/sd-dev/evals/fixtures/case-modify/tests/index.test.ts +0 -11
  76. package/claude/skills/sd-impl/evals/fixtures/case-001-new-screen/spec.md +0 -55
  77. package/claude/skills/sd-impl/evals/fixtures/case-002-auto-process/spec.md +0 -55
  78. package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/packages/client/src/pages/book-list.ts +0 -22
  79. package/claude/skills/sd-impl/evals/fixtures/case-003-update-screen/spec.md +0 -57
  80. package/claude/skills/sd-impl/evals/fixtures/case-004-ambiguous-spec/spec.md +0 -58
  81. package/claude/skills/sd-impl/evals/fixtures/case-005-id-mismatch/spec.md +0 -52
  82. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.test.ts +0 -10
  83. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/client/src/pages//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.ts +0 -11
  84. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/data-access//352/261/260/353/236/230/354/262/230-/354/240/221/352/267/274.ts +0 -12
  85. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/packages/server/src/models//352/261/260/353/236/230/354/262/230.ts +0 -8
  86. package/claude/skills/sd-impl/evals/fixtures/case-006-with-reference-units/spec.md +0 -77
  87. package/claude/skills/sd-impl/evals/fixtures/case-new/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +0 -101
  88. package/claude/skills/sd-impl/evals/fixtures/case-update/.specs/260514120000_/352/261/260/353/236/230/354/262/230/spec.md +0 -101
  89. package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/250/353/215/270.txt +0 -1
  90. package/claude/skills/sd-impl/evals/fixtures/case-update/src//352/261/260/353/236/230/354/262/230//352/261/260/353/236/230/354/262/230-/353/252/251/353/241/235.txt +0 -1
  91. package/claude/skills/sd-impl/references/spec-cross-check.md +0 -82
  92. package/claude/skills/sd-skill/evals/fixtures/with-existing-review/.claude/skills/review/SKILL.md +0 -14
  93. package/claude/skills/sd-skill/references/eval-authoring.md +0 -81
  94. package/claude/skills/sd-skill/references/eval-run.md +0 -32
  95. package/claude/skills/sd-skill/references/skill-authoring.md +0 -70
  96. /package/claude/skills/{sd-skill/evals/fixtures/empty → sd-dev/evals/fixtures/minimal-ts-pkg/src}/.gitkeep +0 -0
@@ -0,0 +1,143 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ ViewEncapsulation,
5
+ effect,
6
+ inject,
7
+ signal,
8
+ untracked,
9
+ } from "@angular/core";
10
+ import {
11
+ injectPermsSignal,
12
+ mark,
13
+ SdCrudListComponent,
14
+ SdSheetColumnDirective,
15
+ SdTextfieldComponent,
16
+ SdToastProvider,
17
+ } from "@simplysm/angular";
18
+
19
+ interface IInventoryMasterItem {
20
+ id: number;
21
+ warehouseCode: string;
22
+ itemCode: string;
23
+ itemName: string;
24
+ active: boolean;
25
+ }
26
+
27
+ interface IFilter {
28
+ searchText: string;
29
+ }
30
+
31
+ @Component({
32
+ selector: "app-inventory-master-list",
33
+ changeDetection: ChangeDetectionStrategy.OnPush,
34
+ encapsulation: ViewEncapsulation.None,
35
+ standalone: true,
36
+ imports: [SdCrudListComponent, SdSheetColumnDirective, SdTextfieldComponent],
37
+ template: `
38
+ <div class="flex-column fill">
39
+ <sd-crud-list
40
+ title="재고 마스터"
41
+ [(ready)]="ready"
42
+ [initialized]="initialized()"
43
+ [(busyCount)]="busyCount"
44
+ [items]="items()"
45
+ [(selectedKeys)]="selectedKeys"
46
+ [(page)]="page"
47
+ [totalPageCount]="pageLength()"
48
+ [(sorts)]="sortingDefs"
49
+ [trackByFn]="trackByFn"
50
+ [restricted]="!perms().includes('use')"
51
+ (filterSubmit)="onFilterSubmit()"
52
+ >
53
+ <ng-template #filterTpl>
54
+ <div class="form-box-inline">
55
+ <div>
56
+ <label>검색</label>
57
+ <sd-textfield [(value)]="filter().searchText" (valueChange)="mark(filter)" />
58
+ </div>
59
+ </div>
60
+ </ng-template>
61
+
62
+ <sd-sheet-column [key]="'warehouseCode'" [header]="'창고'">
63
+ <ng-template [cell]="items()" let-item="item">
64
+ <div class="p-xs-sm">{{ item.warehouseCode }}</div>
65
+ </ng-template>
66
+ </sd-sheet-column>
67
+
68
+ <sd-sheet-column [key]="'itemCode'" [header]="'품목 코드'">
69
+ <ng-template [cell]="items()" let-item="item">
70
+ <div class="p-xs-sm">{{ item.itemCode }}</div>
71
+ </ng-template>
72
+ </sd-sheet-column>
73
+
74
+ <sd-sheet-column [key]="'itemName'" [header]="'품목명'">
75
+ <ng-template [cell]="items()" let-item="item">
76
+ <div class="p-xs-sm">{{ item.itemName }}</div>
77
+ </ng-template>
78
+ </sd-sheet-column>
79
+ </sd-crud-list>
80
+
81
+ @if (initialized() && items().length === 0) {
82
+ <div class="p-default tx-center tx-theme-gray-default">조회된 재고 마스터가 없습니다.</div>
83
+ }
84
+ </div>
85
+ `,
86
+ })
87
+ export class InventoryMasterListComponent {
88
+ private readonly _sdToast = inject(SdToastProvider);
89
+
90
+ perms = injectPermsSignal(["inventory.master"], ["use", "edit"]);
91
+
92
+ ready = signal(false);
93
+ initialized = signal(false);
94
+ busyCount = signal(0);
95
+
96
+ items = signal<IInventoryMasterItem[]>([]);
97
+ selectedKeys = signal<number[]>([]);
98
+ page = signal(0);
99
+ pageLength = signal(0);
100
+ sortingDefs = signal<{ key: string; desc: boolean }[]>([]);
101
+
102
+ filter = signal<IFilter>({ searchText: "" });
103
+ lastFilter = signal<IFilter>({ searchText: "" });
104
+
105
+ trackByFn = (item: IInventoryMasterItem) => item.id;
106
+
107
+ protected readonly mark = mark;
108
+
109
+ constructor() {
110
+ effect(() => {
111
+ if (!this.perms().includes("use") || !this.ready()) {
112
+ this.initialized.set(true);
113
+ return;
114
+ }
115
+
116
+ this.lastFilter();
117
+ this.page();
118
+ this.sortingDefs();
119
+
120
+ void untracked(async () => {
121
+ this.busyCount.update((v) => v + 1);
122
+ await this._sdToast.try(async () => {
123
+ await this._refresh();
124
+ });
125
+ this.busyCount.update((v) => v - 1);
126
+ this.initialized.set(true);
127
+ });
128
+ });
129
+ }
130
+
131
+ onFilterSubmit(): void {
132
+ this.page.set(0);
133
+ this.lastFilter.set({ ...this.filter() });
134
+ }
135
+
136
+ doRefresh(): void {
137
+ if (!this.perms().includes("use")) return;
138
+ mark(this.lastFilter);
139
+ }
140
+
141
+ private async _refresh(): Promise<void> {
142
+ }
143
+ }
@@ -0,0 +1,150 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ ViewEncapsulation,
5
+ effect,
6
+ inject,
7
+ signal,
8
+ untracked,
9
+ } from "@angular/core";
10
+ import {
11
+ injectPermsSignal,
12
+ mark,
13
+ SdCrudListComponent,
14
+ SdSheetColumnDirective,
15
+ SdTextfieldComponent,
16
+ SdToastProvider,
17
+ } from "@simplysm/angular";
18
+
19
+ interface IOutboundItem {
20
+ id: number;
21
+ orderNo: string;
22
+ customerName: string;
23
+ itemName: string;
24
+ quantity: number;
25
+ shippedAt: string;
26
+ }
27
+
28
+ interface IFilter {
29
+ searchText: string;
30
+ }
31
+
32
+ @Component({
33
+ selector: "app-outbound-list",
34
+ changeDetection: ChangeDetectionStrategy.OnPush,
35
+ encapsulation: ViewEncapsulation.None,
36
+ standalone: true,
37
+ imports: [SdCrudListComponent, SdSheetColumnDirective, SdTextfieldComponent],
38
+ template: `
39
+ <div class="flex-column fill">
40
+ <sd-crud-list
41
+ title="출고 내역 조회"
42
+ [(ready)]="ready"
43
+ [initialized]="initialized()"
44
+ [(busyCount)]="busyCount"
45
+ [items]="items()"
46
+ [(selectedKeys)]="selectedKeys"
47
+ [(page)]="page"
48
+ [totalPageCount]="pageLength()"
49
+ [(sorts)]="sortingDefs"
50
+ [trackByFn]="trackByFn"
51
+ [restricted]="!perms().includes('use')"
52
+ (filterSubmit)="onFilterSubmit()"
53
+ >
54
+ <ng-template #filterTpl>
55
+ <div class="form-box-inline">
56
+ <div>
57
+ <label>검색</label>
58
+ <sd-textfield [(value)]="filter().searchText" (valueChange)="mark(filter)" />
59
+ </div>
60
+ </div>
61
+ </ng-template>
62
+
63
+ <sd-sheet-column [key]="'orderNo'" [header]="'출고 번호'">
64
+ <ng-template [cell]="items()" let-item="item">
65
+ <div class="p-xs-sm">{{ item.orderNo }}</div>
66
+ </ng-template>
67
+ </sd-sheet-column>
68
+
69
+ <sd-sheet-column [key]="'customerName'" [header]="'거래처'">
70
+ <ng-template [cell]="items()" let-item="item">
71
+ <div class="p-xs-sm">{{ item.customerName }}</div>
72
+ </ng-template>
73
+ </sd-sheet-column>
74
+
75
+ <sd-sheet-column [key]="'itemName'" [header]="'품목'">
76
+ <ng-template [cell]="items()" let-item="item">
77
+ <div class="p-xs-sm">{{ item.itemName }}</div>
78
+ </ng-template>
79
+ </sd-sheet-column>
80
+
81
+ <sd-sheet-column [key]="'quantity'" [header]="'수량'">
82
+ <ng-template [cell]="items()" let-item="item">
83
+ <div class="p-xs-sm tx-right">{{ item.quantity }}</div>
84
+ </ng-template>
85
+ </sd-sheet-column>
86
+ </sd-crud-list>
87
+
88
+ @if (initialized() && items().length === 0) {
89
+ <div class="p-default tx-center tx-theme-gray-default">조회된 출고 내역이 없습니다.</div>
90
+ }
91
+ </div>
92
+ `,
93
+ })
94
+ export class OutboundListComponent {
95
+ private readonly _sdToast = inject(SdToastProvider);
96
+
97
+ perms = injectPermsSignal(["outbound"], ["use"]);
98
+
99
+ ready = signal(false);
100
+ initialized = signal(false);
101
+ busyCount = signal(0);
102
+
103
+ items = signal<IOutboundItem[]>([]);
104
+ selectedKeys = signal<number[]>([]);
105
+ page = signal(0);
106
+ pageLength = signal(0);
107
+ sortingDefs = signal<{ key: string; desc: boolean }[]>([]);
108
+
109
+ filter = signal<IFilter>({ searchText: "" });
110
+ lastFilter = signal<IFilter>({ searchText: "" });
111
+
112
+ trackByFn = (item: IOutboundItem) => item.id;
113
+
114
+ protected readonly mark = mark;
115
+
116
+ constructor() {
117
+ effect(() => {
118
+ if (!this.perms().includes("use") || !this.ready()) {
119
+ this.initialized.set(true);
120
+ return;
121
+ }
122
+
123
+ this.lastFilter();
124
+ this.page();
125
+ this.sortingDefs();
126
+
127
+ void untracked(async () => {
128
+ this.busyCount.update((v) => v + 1);
129
+ await this._sdToast.try(async () => {
130
+ await this._refresh();
131
+ });
132
+ this.busyCount.update((v) => v - 1);
133
+ this.initialized.set(true);
134
+ });
135
+ });
136
+ }
137
+
138
+ onFilterSubmit(): void {
139
+ this.page.set(0);
140
+ this.lastFilter.set({ ...this.filter() });
141
+ }
142
+
143
+ doRefresh(): void {
144
+ if (!this.perms().includes("use")) return;
145
+ mark(this.lastFilter);
146
+ }
147
+
148
+ private async _refresh(): Promise<void> {
149
+ }
150
+ }
@@ -0,0 +1,12 @@
1
+ import type { SdConfigFn } from "@simplysm/sd-cli";
2
+
3
+ const config: SdConfigFn = () => ({
4
+ packages: {
5
+ "demo-client": {
6
+ target: "client",
7
+ server: 4000,
8
+ },
9
+ },
10
+ });
11
+
12
+ export default config;
@@ -1,5 +1 @@
1
- {"id": "simple-screen", "input": "/sd-demo .specs/260513120000_warehouse/spec.md §4.1 화면을 데모로 만들어줘", "rubric": ["packages/app/src/screens/ 아래에 .ts 파일이 1개 이상 생성되었는가? (.specs/, dashboard/ 하위 제외)", "새로 생성된 .ts 파일의 파일명이 권위 규약(<domain>.list.ts / .detail.ts / .view.ts / .modal.ts / .ts) 중 하나의 형식을 따르는가? (.component.ts 형식이면 FAIL)", "새로 생성된 .ts 파일 적어도 하나의 @Component selector 'app-' prefix 로 시작하는가?", "새로 생성된 .ts 파일 중 적어도 하나에 'standalone: true' 포함되었는가?", "새로 생성된 .ts 파일 적어도 하나의 템플릿에 'sd-textfield' 또는 '<input' 중 하나가 1개 이상 포함되었는가?", "새로 생성된 .ts 파일 적어도 하나에 '// sd-demo: 더미' 로 시작하는 주석이 1 이상 있는가?", "새로 생성된 .ts 파일 적어도 하나에 '// sd-demo: 미구현' 으로 시작하는 주석이 1 이상 있는가?", "기존 packages/app/src/screens/dashboard/dashboard.view.ts 파일이 손실되지 않고 보존되었는가?"], "fixture": "with-screens"}
2
- {"id": "modal-screen", "input": "/sd-demo .specs/260513120000_warehouse/spec.md 의 §4.1 화면을 데모로 만들어줘", "rubric": ["packages/app/src/screens/ 아래에 새 .ts 파일이 2개 이상 생성되었는가? (호출 화면 + 모달 화면, dashboard/ 하위 제외)", "새로 생성된 파일 중 모달 역할 파일이 권위 규약의 '.modal.ts' 접미사를 사용하는가?", "새로 생성된 파일 중 적어도 하나에 'SdModalProvider' 식별자가 포함되었는가?", "새로 생성된 파일 중 적어도 하나에 '_sdModal.showAsync(' 호출 코드가 포함되었는가?", "새로 생성된 파일 중 적어도 하나에 'close' 라는 이름의 output 선언이 포함되었는가?", "기존 packages/app/src/screens/dashboard/dashboard.view.ts 파일이 손실되지 않고 보존되었는가?"], "fixture": "with-modal"}
3
- {"id": "recall-overwrite", "input": "/sd-demo .specs/260513120000_warehouse/spec.md 의 §4.1 화면을 데모로 만들어줘. 이미 파일이 있으면 ① 덮어쓰기 분기로 진행해줘.", "rubric": ["packages/app/src/screens/dashboard/ 디렉토리 안의 화면 파일이 spec §4.1 의 'Total stock' 또는 'Refresh' 중 하나의 문자열을 포함하는가?", "packages/app/src/screens/dashboard/ 디렉토리 안의 화면 파일에 'standalone: true' 가 포함되었는가?", "packages/app/src/screens/dashboard/ 디렉토리 안의 화면 파일에 '// sd-demo:' 로 시작하는 주석이 1개 이상 있는가?"], "fixture": "with-existing-screen"}
4
- {"id": "empty-screen", "input": "/sd-demo .specs/260513120000_warehouse/spec.md 의 §4.1 화면을 데모로 만들어줘", "rubric": ["fixture 안 어딘가에 .ts 파일이 새로 1개 이상 생성되었는가? (.specs/, 메타 파일 제외)", "새로 생성된 파일의 파일명이 권위 규약(<domain>.list.ts / .detail.ts / .view.ts / .modal.ts / .ts) 중 하나의 형식을 따르는가? (.component.ts 형식이면 FAIL)", "새로 생성된 파일 중 적어도 하나의 @Component selector 가 'app-' prefix 로 시작하는가?", "새로 생성된 파일 중 적어도 하나에 'standalone: true' 가 포함되었는가?", "새로 생성된 파일 중 적어도 하나에 'sd-textfield' 또는 '<input' 중 하나가 1개 이상 포함되었는가?", "새로 생성된 파일 중 적어도 하나에 '// sd-demo:' 로 시작하는 주석이 1개 이상 있는가?"], "fixture": "empty"}
5
- {"id": "master-screen", "input": "/sd-demo .specs/260513120000_warehouse/spec.md 의 §4.1 화면을 데모로 만들어줘", "rubric": ["packages/app/src/screens/ 아래에 새 .ts 파일이 1개 이상 생성되었는가? (dashboard/ 하위 제외)", "새로 생성된 파일의 파일명이 권위 규약의 '.list.ts' 접미사를 사용하는가? (마스터 화면은 sd-crud-list 채택이 표준이며 .list.ts 가 권위 규약)", "새로 생성된 .ts 파일 중 적어도 하나의 템플릿에 'sd-crud-list' selector 가 1개 이상 포함되었는가?", "새로 생성된 .ts 파일 중 적어도 하나에 '// sd-demo:' 로 시작하는 주석이 1개 이상 있는가?"], "fixture": "with-master-screen"}
1
+ {"id": "case-001", "input": "/sd-demo .specs/inventory/spec.md §4.1 데모 만들어줘", "rubric": ["fixture 의 `packages/demo-client/src/screens/inventory/` 폴더 안에 화면 컴포넌트 파일이 새로 생성되었는가", "생성된 컴포넌트 파일이 Angular @Component 데코레이터 + selector 가지는가", "생성된 컴포넌트의 template 필터 영역·시트 영역·빈 상태 영역 마크업이 모두 등장하는가", "생성된 컴포넌트의 template답습 화면(출고·입고 조회) 부위 마크업 구조(같은 컴포넌트·같은 클래스 패턴 사용)와 일치하는가", "생성된 파일 본문에 `// sd-demo:` 마커가 1 이상 등장하는가", "events `.claude/references/sd-simplysm14/` 폴더 파일 Read 또는 동등 명령 1 이상 있는가"], "fixture": "inventory-list"}
@@ -1,44 +1,75 @@
1
1
  ---
2
2
  name: sd-dev
3
- description: 코드 변경 요청을 받아 의도 합의·테스트 우선 구현·검증까지 번에 수행한다. Use when 화면 단위 spec 분석이 필요 없는 라이브러리·CLI·내부 모듈의 기능 추가·수정·버그 수정 요청 시.
3
+ description: 코드 변경 요청을 사용자와 합의 코드 변경분과 테스트로 산출. Use when 화면 단위 spec 분석이 필요 없는 라이브러리·CLI·내부 모듈의 기능 추가·수정·버그 수정 요청 시.
4
4
  ---
5
5
 
6
6
  # sd-dev
7
7
 
8
- spec.md 없이 진행하는 가벼운 코드 작업. 의도 합의가 끝나면 분석·계획·구현·검증까지 사용자 추가 개입 없이 자동.
8
+ spec.md 없이 진행하는 가벼운 코드 작업. 의도 합의 워크플로는 자동 진행 파일 삭제·시연 등 확인성 보고는 단계별 발생. 합의 결과는 대화 메모리에만.
9
9
 
10
10
  ## 워크플로
11
11
 
12
12
  ### 1단계: 의도파악
13
13
 
14
- 사용자 발화를 토대로 무엇을 만들거나 바꿀지 합의. **1건씩 질문 → 답변 → 다음 건** (sd-base-rules "결정 근거"). 합의 결과는 대화 메모리에만.
14
+ 사용자 발화를 토대로 무엇을 만들거나 바꿀지 합의. 다음을 확정해야 진행:
15
15
 
16
- 다음을 확정해야 진행:
16
+ - 작업 종류: 신규 추가 / 기존 수정 / 버그 수정.
17
+ - 대상 파일·모듈·패키지.
18
+ - 변경의 입출력·동작 — 이름·시그니처·예외 동작 등.
17
19
 
18
- - 작업 종류: 신규 추가 / 기존 수정 / 버그 수정
19
- - 대상 파일·모듈·패키지
20
- - 변경의 입출력·동작 — 이름·시그니처·예외 동작 등
21
-
22
- 근거 충분(사용자 발화에 명시 + 기존 코드 패턴 추론 가능)이면 묻지 않고 진행. 외부 자료(시크릿·시안·샘플 데이터)가 필요하면 이 단계에서 요청.
20
+ 근거 충분(사용자 발화 명시 + 기존 코드 패턴 추론 가능)이면 묻지 않고 진행. 부족분은 1건씩 질문 (sd-base-rules "사용자 질의 시"). 외부 자료(시크릿·시안·샘플 데이터)가 필요하면 단계에서 요청.
23
21
 
24
22
  ### 2단계: 분석
25
23
 
26
- 작업 영역의 코드베이스 분석.
24
+ 부재로 워크플로를 멈추지 않음. 발견된 만큼 활용.
25
+
26
+ **A. 라이브러리·개발 매뉴얼**:
27
+ - `@simplysm/*` 14.x — `.claude/references/sd-simplysm14/README.md` 참조.
28
+ - 그 외 framework — 코드베이스 안 동등 위치 문서.
29
+ - 없으면 표준 패턴.
30
+
31
+ **B. 기존 패턴**:
32
+ - 작업 영역 인접 코드의 파일 위치·네이밍·구조·계층 분리 패턴 파악.
33
+ - 동일 의도 기존 사용처 1~2개 Read.
34
+
35
+ **C. 테스트 환경**:
36
+ - 단위 테스트 프로젝트 구분·실행 명령·mocking 패턴 파악.
37
+
38
+ ### 3단계: 작업 분해 표
39
+
40
+ 2단계 분석을 토대로 작업 분해 표 작성. assistant 응답으로 출력 (4단계 입력).
27
41
 
28
- ### 3단계: 계획
42
+ | 항목 | 요구 | 현재 코드 상태 | 판정 | 매핑 파일 | 의존 |
43
+ | ---- | ---- | -------------- | ---- | --------- | ---- |
29
44
 
30
- 분석을 토대로 TDD 기반 개발 계획 수립.
45
+ **항목 분해 단위**:
46
+ - 함수·메서드 1개당 1줄.
47
+ - 상태값·분기 케이스 1개당 1줄.
48
+ - 입출력 시그니처 1개당 1줄.
49
+ - 버그 1건당 1줄.
50
+
51
+ **컬럼**:
52
+ - **항목**: 분해 단위 1개의 짧은 식별자.
53
+ - **요구**: 1단계 의도파악 합의 내용 인용.
54
+ - **현재 코드 상태**: 코드베이스 조사 결과. 신규는 "없음", 수정은 "있음(어떻게)".
55
+ - **판정**: 없음 / 불일치 / 일치.
56
+ - **매핑 파일**: 작성·갱신될 파일 경로.
57
+ - **의존**: 다른 항목 ID.
31
58
 
32
59
  ### 4단계: TDD 사이클
33
60
 
34
- 작업 시작 **테스트 작성 가능 여부** 판정 — 입출력 명확 + 외부 의존 통제 가능한가.
61
+ 표의 (없음·불일치) 항목만 의존 순서로 진행. 일치 항목은 손대지 않음.
62
+
63
+ 각 작업(= 표 1행) 시작 시 **테스트 작성 가능 여부** 판정 — 입출력 명확 + 외부 의존 통제 가능한가.
35
64
 
36
- - **테스트 가능**: **RED → GREEN → REFACTOR**
37
- - **RED**: 테스트만 작성 → 러너 실행 → 실패 확인. **이 단계에서 구현 파일 절대 손대지 말 것.**
38
- - **GREEN**: 통과하는 최소 구현 → 러너 재실행 → 통과 확인.
65
+ - **테스트 가능**: **RED → GREEN → REFACTOR**.
66
+ - **RED**: 테스트만 작성 → 단위 테스트 실행 → 실패 확인. **이 단계에서 구현 파일 절대 손대지 말 것.**
67
+ - **GREEN**: 통과하는 최소 구현 → 단위 테스트 재실행 → 통과 확인.
39
68
  - **REFACTOR**: 중복·가독성·기존 패턴 정합 정리 → 통과 유지 확인. 정리할 게 없으면 스킵.
40
69
  - **테스트 불가/비효율** (UI 시각·외부 서비스 실호출 등): **구현 → REFACTOR**.
41
70
 
71
+ **의도 모호 발견 시**: 사이클 중 1단계에서 합의되지 않은 모호함 발견 → 즉시 멈추고 1단계 회귀. 자체 판단 채움 금지.
72
+
42
73
  ### 5단계: 코드 정리
43
74
 
44
75
  전체 변경분을 한번 훑어 정돈. 4단계 REFACTOR 가 잡지 못한 횡단 이슈와 작업 잔재가 대상.
@@ -46,14 +77,10 @@ spec.md 없이 진행하는 가벼운 코드 작업. 의도 합의가 끝나면
46
77
  - **횡단 중복**: 작업 사이클 사이에 동일 로직이 흩어져 있으면 합치기.
47
78
  - **인접 코드 패턴 정합**: 코드베이스 컨벤션 vs 실제 작성 — 파일 위치·네이밍·구조.
48
79
  - **불필요한 코드**: 미사용 import·변수·주석, 요구 없는 옵션·추상화 제거. 갱신·덮어쓰기 결과로 어디서도 참조되지 않는 파일도 포함. **단 파일 단위 삭제는 후보 목록을 사용자에게 보고 → 확정분만 삭제** (dynamic import·문서 자산 등 보존분 사용자 제외).
49
- - **매뉴얼 권위 규약**: 코드베이스 매뉴얼 위반 항목 수정.
80
+ - **권위 자료 정합**: 2-A 매뉴얼 위반 항목 수정.
50
81
 
51
82
  정리 후 단위 테스트 재실행 — 회귀 없음 확인.
52
83
 
53
84
  ### 6단계: 검증
54
85
 
55
- 산출물이 브라우저 시연이 필요한 화면·UI 면 사용자에게 dev 서버 실행 요청 → `playwright-cli` 시연. 그 외(라이브러리·CLI·내부 모듈·서버 함수)는 4단계 단위 테스트 통과로 종결.
56
-
57
- ## 운용
58
-
59
- - 결정 근거: `sd-base-rules.md` "결정 근거" 적용.
86
+ 산출물이 브라우저 시연이 필요한 화면·UI 면 사용자에게 dev 서버 실행 요청 → 브라우저 자동화 도구로 시연. 그 외(라이브러리·CLI·내부 모듈·서버 함수)는 4단계 단위 테스트 통과로 종결.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "minimal-ts-pkg",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "test": "node --test tests/"
7
+ }
8
+ }
@@ -4,9 +4,7 @@
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "Bundler",
6
6
  "strict": true,
7
- "esModuleInterop": true,
8
- "skipLibCheck": true,
9
- "verbatimModuleSyntax": true
7
+ "esModuleInterop": true
10
8
  },
11
9
  "include": ["src/**/*", "tests/**/*"]
12
10
  }
@@ -1,3 +1 @@
1
- {"id": "case-add", "input": "/sd-dev toSnakeCase 함수를 추가해줘", "fixture": "case-add", "rubric": ["src/index.ts (또는 src 하위 신규 파일) 에 toSnakeCase 함수가 export 키워드로 추가되었는가?", "tests 디렉토리에 toSnakeCase테스트 케이스가 1 이상 추가되었는가?", "기존 toCamelCase 함수 정의가 src/index.ts 보존되어 있는가?", "vitest run 명령이 Bash 도구로 1회 이상 호출되었고 최종 호출의 종료 코드가 0 인가?"]}
2
- {"id": "case-modify", "input": "/sd-dev toCamelCase 가 공백도 구분자로 처리하게 바꿔줘", "fixture": "case-modify", "rubric": ["src/index.ts 의 toCamelCase 가 공백 문자를 구분자로 인식하도록 변경되었는가? (split 정규식에 공백 포함 또는 동등 처리)", "tests 디렉토리에 공백 구분자 입력 케이스 테스트가 1건 이상 추가되었는가?", "기존 kebab-case 및 snake_case 테스트 케이스가 삭제되지 않고 보존되어 있는가?", "vitest run 명령이 Bash 도구로 1회 이상 호출되었고 최종 호출의 종료 코드가 0 인가?"]}
3
- {"id": "case-bug", "input": "/sd-dev toCamelCase 빈 문자열 입력하면 에러나, 고쳐줘", "fixture": "case-bug", "rubric": ["tests 디렉토리에 빈 문자열 입력 케이스 테스트가 1건 이상 추가되었는가?", "src/index.ts 의 toCamelCase 가 빈 문자열 입력 시 throw 하지 않고 빈 문자열을 반환하도록 수정되었는가?", "최종 vitest run 의 종료 코드가 0 이고 기존 테스트와 신규 빈 문자열 테스트가 모두 통과하는가?"]}
1
+ {"id": "sum-add", "input": "/sd-dev sum 함수 추가해줘. a + b 반환.", "rubric": ["tree.json sum 함수 구현 파일이 src/ 하위 (위치 자유) 에 존재하는가", "tree.json sum 함수 테스트 파일 (위치 자유) 이 존재하는가", "events 테스트 러너 실행 흔적 (Bash node --test 또는 동등 명령) 이 1 이상 있는가", "구현 파일 내용에 sum 함수 정의 export 포함되는가", "테스트 파일 내용에 sum 호출 + 결과 검증 assertion 1개 이상 있는가"], "fixture": "minimal-ts-pkg"}
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: sd-docs
3
- description: `@simplysm/*` 라이브러리 패키지의 API 문서를 `.claude/references/sd-simplysm14/apis/<패키지명>/` 자리에 사용 트리거 기준으로 산출·갱신한다. Use when 라이브러리 API 문서를 새로 작성하거나 코드 변경을 반영해 갱신할 때.
3
+ description: `@simplysm/*` 라이브러리 패키지의 API 문서를 `.claude/references/sd-simplysm14/apis/<패키지명>/` 자리에 사용 트리거 기준으로 산출·갱신. Use when 라이브러리 API 문서를 새로 작성하거나 코드 변경을 반영해 갱신할 때.
4
4
  effort: "low"
5
5
  ---
6
6
 
7
7
  # sd-docs
8
8
 
9
- `@simplysm/*` 라이브러리 패키지의 API 문서를 코드 진실에 맞춰 산출·갱신한다. 메인 에이전트가 패키지 목록 추출과 상위 README 인덱스 갱신을 담당하고, 패키지별 산출은 subagent 1개씩 병렬 위임한다.
9
+ `@simplysm/*` 라이브러리 패키지의 API 문서를 코드 진실에 맞춰 산출·갱신함. 메인 에이전트가 패키지 목록 추출과 상위 README 인덱스 갱신을 담당하고, 패키지별 산출은 subagent 1개씩 병렬 위임함.
10
10
 
11
11
  ## 산출 자리
12
12
 
@@ -18,14 +18,14 @@ effort: "low"
18
18
 
19
19
  ### 1. 패키지 목록 추출
20
20
 
21
- 워크스페이스 루트의 `packages/*/package.json` 을 모두 읽어 다음 두 리스트를 만든다.
21
+ 워크스페이스 루트의 `packages/*/package.json` 을 모두 읽어 다음 두 리스트를 만듦.
22
22
 
23
23
  - **public 리스트**: `private: true` 가 아닌 패키지. 각 항목 = `{ name, dir }`.
24
24
  - **private 리스트**: `private: true` 인 패키지. 인덱스에서 제외하기 위해 보관.
25
25
 
26
26
  ### 2. 패키지별 subagent 병렬 호출
27
27
 
28
- `public 리스트` 의 패키지 수만큼 `general-purpose` subagent 호출을 **단일 메시지 안에서 병렬**로 보낸다. 각 호출 프롬프트는 [references/subagent-prompt.md](references/subagent-prompt.md) 의 양식을 그대로 사용하고, `<PACKAGE_NAME>` 과 `<PACKAGE_DIR>` 만 치환한다.
28
+ `public 리스트` 의 패키지 수만큼 `general-purpose` subagent 호출을 **단일 메시지 안에서 병렬**로 보냄. 각 호출 프롬프트는 [references/subagent-prompt.md](references/subagent-prompt.md) 의 양식을 그대로 사용하고, `<PACKAGE_NAME>` 과 `<PACKAGE_DIR>` 만 치환함.
29
29
 
30
30
  각 subagent 의 산출 (풀 재작성 모드 — 기존 파일 참고 없이 처음부터 작성):
31
31
 
@@ -33,24 +33,24 @@ effort: "low"
33
33
  - 필요 시 `apis/<패키지명>/<군명>.md` 재작성. 코드에서 사라진 군의 파일은 삭제.
34
34
  - 결과 보고 1단락 (산출 파일 목록, 분할 발생 여부, 한 줄 트리거 요약).
35
35
 
36
- **범위 한정**: subagent 는 `apis/<패키지명>/` 자리만 다룬다. 상위 `.claude/references/sd-simplysm14/README.md` 는 건드리지 않는다 (메인 에이전트가 §3 에서 처리).
36
+ **범위 한정**: subagent 는 `apis/<패키지명>/` 자리만 다룸. 상위 `.claude/references/sd-simplysm14/README.md` 는 건드리지 않음 (메인 에이전트가 §3 에서 처리).
37
37
 
38
38
  ### 3. 상위 README 의 "패키지 인덱스" 섹션 갱신 (파일 보존 + 섹션 내 항목만 갱신)
39
39
 
40
- `.claude/references/sd-simplysm14/README.md` 는 **풀 재작성 대상 아님**. 파일 본문·다른 섹션은 그대로 보존, "패키지 인덱스" 섹션의 항목 리스트만 재구성한다.
40
+ `.claude/references/sd-simplysm14/README.md` 는 **풀 재작성 대상 아님**. 파일 본문·다른 섹션은 그대로 보존, "패키지 인덱스" 섹션의 항목 리스트만 재구성함.
41
41
 
42
42
  모든 subagent 완료 후:
43
43
 
44
44
  - **갱신 대상**: "패키지 인덱스" 섹션 본문(항목 리스트)만.
45
45
  - **건드리지 않음**: 섹션 머리(`## 패키지 인덱스`), 다른 모든 섹션, 파일 상단/하단 텍스트.
46
- - **항목 형식**: `- **<패키지명>** — <한 줄 트리거 요약>. 자세히: [apis/<패키지명>/README.md](./apis/<패키지명>/README.md)`
46
+ - **항목 형식**: `- **<패키지명>** — <한 줄 트리거 요약>. 자세히: [apis/<패키지명>/README.md](./apis/<패키지명>/README.md)`.
47
47
  - **순서**: 패키지명 알파벳순.
48
48
  - **포함**: `public 리스트` 만.
49
49
  - **제외**: `private 리스트` 의 패키지, 코드베이스에 더 이상 존재하지 않는 패키지.
50
50
 
51
51
  ### 4. 사용자 보고
52
52
 
53
- 다음 항목을 짧게 정리해 출력한다.
53
+ 다음 항목을 짧게 정리해 출력함.
54
54
 
55
55
  - 재작성된 패키지 목록 (= `public 리스트` 전체. 풀 재작성 모드 — 매번 모든 패키지 산출).
56
56
  - 분할 발생(`<군명>.md` 가 생긴) 패키지 목록.