@team-semicolon/semicolony-cli 4.18.51

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 (164) hide show
  1. package/LICENSE +200 -0
  2. package/NOTICE +8 -0
  3. package/README.md +152 -0
  4. package/dist/bundle.js +2887 -0
  5. package/dist/templates/launchd/ai.semicolony.host-signals-sidecar.plist +40 -0
  6. package/migrations/001_initial.sql +280 -0
  7. package/migrations/002_add_indexes.sql +11 -0
  8. package/migrations/003_add_fk.sql +32 -0
  9. package/migrations/004_session_count_trigger.sql +35 -0
  10. package/migrations/005_bot_workspace_audits.sql +16 -0
  11. package/migrations/006_bot_kb_subscriptions.sql +24 -0
  12. package/migrations/007_flatten_skill_names.sql +16 -0
  13. package/migrations/008_bot_workspace_files.sql +14 -0
  14. package/migrations/009_enforce_flat_skill_names.sql +53 -0
  15. package/migrations/010_bot_delegation.sql +27 -0
  16. package/migrations/011_drop_legacy_tables.sql +35 -0
  17. package/migrations/012_drop_bot_knowledge.sql +16 -0
  18. package/migrations/013_kb_workspace_domains.sql +88 -0
  19. package/migrations/014_timestamp_to_timestamptz.sql +33 -0
  20. package/migrations/015_kb_domain_enforcement.sql +83 -0
  21. package/migrations/016_ontology_redesign.sql +108 -0
  22. package/migrations/017_ontology_instance_model.sql +151 -0
  23. package/migrations/018_type_schema.sql +11 -0
  24. package/migrations/019_test_management.sql +69 -0
  25. package/migrations/020_bot_workspace_standard.sql +174 -0
  26. package/migrations/021_drop_dead_tables.sql +8 -0
  27. package/migrations/021_test_declarative.sql +19 -0
  28. package/migrations/022_bot_ontology_type.sql +38 -0
  29. package/migrations/022_kb_schema_enforcement.sql +77 -0
  30. package/migrations/023_decision_key_cleanup.ts +154 -0
  31. package/migrations/024_embedding_backfill.ts +137 -0
  32. package/migrations/025_kb_flat_keys.sql +33 -0
  33. package/migrations/026_drop_session_log.sql +19 -0
  34. package/migrations/027_kb_manager_skill.sql +22 -0
  35. package/migrations/028_skill_definitions_to_semicolony.sql +19 -0
  36. package/migrations/029_agents_citation_max_lines.sql +6 -0
  37. package/migrations/030_team_ontology.sql +54 -0
  38. package/migrations/031_gfp_tables.sql +101 -0
  39. package/migrations/031_kb_manager_domain_register.sql +12 -0
  40. package/migrations/032_gfp_skill_and_callback.sql +40 -0
  41. package/migrations/032_kebab_case_keys.sql +33 -0
  42. package/migrations/033_skill_workspace_rules.sql +10 -0
  43. package/migrations/034_current_to_date_keys.sql +13 -0
  44. package/migrations/034_current_to_date_keys.ts +104 -0
  45. package/migrations/035_bot_budgets.sql +51 -0
  46. package/migrations/036_gfp_stitch_design.sql +35 -0
  47. package/migrations/037_gfp_qa_sections.sql +13 -0
  48. package/migrations/038_gfp_phase_split.sql +26 -0
  49. package/migrations/039_meeting_audio_data.sql +2 -0
  50. package/migrations/040_bot_commitments.sql +68 -0
  51. package/migrations/041_palette_previews.sql +13 -0
  52. package/migrations/042_gfp_parallel_tracks.sql +37 -0
  53. package/migrations/043_blocker_key.sql +13 -0
  54. package/migrations/044_gfp_stitch_screenshots.sql +9 -0
  55. package/migrations/045_service_table_rename_and_projection.sql +150 -0
  56. package/migrations/046_service_ops_tables.sql +75 -0
  57. package/migrations/047_update_gfp_manager_skill.sql +16 -0
  58. package/migrations/048_service_migration_skill.sql +23 -0
  59. package/migrations/049_service_features.sql +39 -0
  60. package/migrations/050_service_kpi_action_items.sql +87 -0
  61. package/migrations/051_update_service_migration_skill_prompt.sql +9 -0
  62. package/migrations/052_feature_iteration_link.sql +11 -0
  63. package/migrations/052_services_table_rename.sql +149 -0
  64. package/migrations/053_feature_discovery.sql +47 -0
  65. package/migrations/054_deploy_verification.sql +17 -0
  66. package/migrations/055_feature_lifecycle.sql +37 -0
  67. package/migrations/056_service_incident_schema.sql +16 -0
  68. package/migrations/057_decision_date_to_metadata.ts +173 -0
  69. package/migrations/058_incubator_kb_schema.sql +8 -0
  70. package/migrations/059_incubator_sessions.sql +29 -0
  71. package/migrations/060_skill_reference_files.sql +8 -0
  72. package/migrations/061_cron_trigger_bridge.sql +7 -0
  73. package/migrations/062_bot_slack_profiles.sql +21 -0
  74. package/migrations/063_rename_gfp_skills.sql +7 -0
  75. package/migrations/064_bot_cost_log.sql +11 -0
  76. package/migrations/065_hub_spoke_orchestration.sql +35 -0
  77. package/migrations/066_cost_log_commitment.sql +9 -0
  78. package/migrations/067_module_ontology_type.sql +44 -0
  79. package/migrations/068_migrate_incubator_data.sql +32 -0
  80. package/migrations/069_action_items_sot.sql +156 -0
  81. package/migrations/069_cost_log_tokens.sql +45 -0
  82. package/migrations/070_services_sot_columns.sql +78 -0
  83. package/migrations/071_cleanup_deprecated_service_kb.sql +38 -0
  84. package/migrations/072_incubator_heartbeat.sql +12 -0
  85. package/migrations/072_service_role_schema.sql +57 -0
  86. package/migrations/073_service_type_and_platform.sql +8 -0
  87. package/migrations/074_schema_ref_type.sql +16 -0
  88. package/migrations/075_routing_delegation.sql +34 -0
  89. package/migrations/076_meeting_service_link.sql +5 -0
  90. package/migrations/077_agents_ontology_type.sql +93 -0
  91. package/migrations/078_incubator_agent.sql +45 -0
  92. package/migrations/079_drop_audio_blob_url.sql +4 -0
  93. package/migrations/080_kb_metadata_indexing.sql +9 -0
  94. package/migrations/081_person_unification.sql +41 -0
  95. package/migrations/082_discord_channel.sql +3 -0
  96. package/migrations/084_deprecate_kpi_metrics_table.sql +5 -0
  97. package/migrations/085_meeting_target_domain.sql +37 -0
  98. package/migrations/086_skill_routing_new_skills.sql +23 -0
  99. package/migrations/087_skill_routing_second_opinion.sql +8 -0
  100. package/migrations/088_meeting_notion_sync.sql +10 -0
  101. package/migrations/089_bot_commitments_dedup.sql +17 -0
  102. package/migrations/090_incubator_discord_guild.sql +8 -0
  103. package/migrations/091_drop_deprecated_gfp_kpi_views.sql +65 -0
  104. package/migrations/092_ontology_channel_mapping.sql +28 -0
  105. package/migrations/093_update_bot_workspace_paths.sql +15 -0
  106. package/migrations/094_cron_run_tracking.sql +28 -0
  107. package/migrations/095_drop_bot_cron_runs.sql +7 -0
  108. package/migrations/096_kb_pipeline_keys.sql +66 -0
  109. package/migrations/097_drop_empty_service_tables.sql +83 -0
  110. package/migrations/098_migrate_features_materials_drop.sql +119 -0
  111. package/migrations/099_migrate_sections_drop.sql +52 -0
  112. package/migrations/099_seed_cron_poller_tick.sql +14 -0
  113. package/migrations/100_migrate_services_drop.sql +57 -0
  114. package/migrations/101_drop_services.sql +5 -0
  115. package/migrations/102_cost_log_session_dedup.sql +13 -0
  116. package/migrations/103_board.sql +57 -0
  117. package/migrations/104_agent_factory.sql +284 -0
  118. package/migrations/105_kb_notify.sql +44 -0
  119. package/migrations/106_office_id_agents_commands.sql +73 -0
  120. package/migrations/107_agent_service_credentials.sql +79 -0
  121. package/migrations/108_drop_l2_ontology_seeds.sql +16 -0
  122. package/migrations/109_generic_ontology_descriptions.sql +21 -0
  123. package/migrations/110_kb_manager_skill_l2_cleanup.sql +34 -0
  124. package/migrations/111_drop_l2_team_ontology_seeds.sql +20 -0
  125. package/migrations/112_fix_pipeline_schema_and_role_trigger.sql +83 -0
  126. package/migrations/113_kb_history.sql +53 -0
  127. package/migrations/114_runtime_target_columns.sql +26 -0
  128. package/migrations/115_runtime_source_columns.sql +52 -0
  129. package/migrations/116_commitment_pattern_health.sql +81 -0
  130. package/migrations/117_commitment_pattern_alert_claims.sql +33 -0
  131. package/migrations/118_retire_semiclaw_semicolonybot_alias.sql +30 -0
  132. package/migrations/119_commitment_events.sql +51 -0
  133. package/migrations/120_host_signals.sql +51 -0
  134. package/migrations/121_agent_spec_derived_runtime_metadata.sql +68 -0
  135. package/migrations/122_agent_spec_derived_fk_policy.sql +18 -0
  136. package/migrations/123_agent_spec_projection_skip_targets.sql +24 -0
  137. package/migrations/124_bot_commitments_notify.sql +26 -0
  138. package/migrations/125_agent_personas.sql +36 -0
  139. package/migrations/128_entity_relations.sql +125 -0
  140. package/migrations/129_kb_multitenant_gateway.sql +86 -0
  141. package/migrations/130_jewelry_relation_types.sql +36 -0
  142. package/migrations/131_concierge_requests.sql +38 -0
  143. package/migrations/132_kb_supersession.sql +27 -0
  144. package/migrations/133_kb_claims.sql +52 -0
  145. package/migrations/134_migration_registry.sql +18 -0
  146. package/migrations/135_sc_roles.sql +102 -0
  147. package/migrations/136_runtime_tenant_columns.sql +71 -0
  148. package/migrations/137_runtime_backfill_team_semicolon.sql +131 -0
  149. package/migrations/138_runtime_constraints_not_valid.sql +56 -0
  150. package/migrations/139_tenant_vms.sql +31 -0
  151. package/migrations/140_fleet_slots.sql +23 -0
  152. package/migrations/141_provisioning_jobs.sql +29 -0
  153. package/migrations/142_rls_enable_semicolony.sql +129 -0
  154. package/migrations/143_rls_enable_public.sql +54 -0
  155. package/migrations/144_worker_device_registry.sql +211 -0
  156. package/migrations/145_workspace_profile_workstation_policy.sql +39 -0
  157. package/migrations/146_worker_profile_repo_scope.sql +24 -0
  158. package/migrations/147_worker_profile_semo_ops_repo_rename.sql +18 -0
  159. package/migrations/148_momo_runtime_convergence.sql +92 -0
  160. package/migrations/README.md +88 -0
  161. package/migrations-sqlite/kb/001_initial.sql +56 -0
  162. package/migrations-sqlite/ops/001_initial.sql +53 -0
  163. package/migrations-sqlite/ops/002_action_items.sql +48 -0
  164. package/package.json +78 -0
@@ -0,0 +1,174 @@
1
+ -- 020: bot_workspace_standard — 봇 워크스페이스 규격 SoT 테이블
2
+ -- v2.0 규격을 DB로 통합하여 MCP 도구/audit/셸 스크립트가 단일 소스에서 규칙 로드
3
+
4
+ CREATE TABLE IF NOT EXISTS semicolony.bot_workspace_standard (
5
+ id BIGSERIAL PRIMARY KEY,
6
+ path_pattern VARCHAR(255) NOT NULL, -- "SOUL.md", ".claude/", "*.ovpn"
7
+ entry_type VARCHAR(20) NOT NULL, -- 'file' | 'dir' | 'symlink' | 'glob'
8
+ level VARCHAR(20) NOT NULL, -- 'required' | 'optional' | 'forbidden'
9
+ severity VARCHAR(10) NOT NULL DEFAULT 'error', -- 'error' | 'warn'
10
+ category VARCHAR(50) NOT NULL DEFAULT 'structure', -- 'structure' | 'legacy' | 'hygiene'
11
+ bot_scope VARCHAR(20) NOT NULL DEFAULT 'all', -- 'all' | 'include' | 'exclude'
12
+ bot_ids TEXT[] DEFAULT '{}',
13
+ symlink_target TEXT, -- 심링크 타겟 (템플릿: $HOME)
14
+ content_rules JSONB, -- 콘텐츠 검증 규칙
15
+ description TEXT,
16
+ fix_action VARCHAR(50), -- 'create_file' | 'create_dir' | 'create_symlink' | null
17
+ fix_template TEXT, -- --fix 시 생성할 콘텐츠 ($BOT_ID 치환)
18
+ spec_version VARCHAR(20) NOT NULL DEFAULT '2.0',
19
+ created_at TIMESTAMPTZ DEFAULT NOW(),
20
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
21
+ UNIQUE (path_pattern, spec_version)
22
+ );
23
+
24
+ CREATE INDEX IF NOT EXISTS idx_bws_level ON semicolony.bot_workspace_standard(level);
25
+ CREATE INDEX IF NOT EXISTS idx_bws_version ON semicolony.bot_workspace_standard(spec_version);
26
+
27
+ -- ============================================================
28
+ -- Seed data (v2.0 규격 ~35행)
29
+ -- ============================================================
30
+
31
+ INSERT INTO semicolony.bot_workspace_standard (path_pattern, entry_type, level, severity, category, bot_scope, bot_ids, symlink_target, content_rules, description, fix_action, fix_template)
32
+ VALUES
33
+ -- 필수 파일
34
+ ('SOUL.md', 'file', 'required', 'error', 'structure', 'all', '{}', NULL,
35
+ '{"max_lines": 120, "required_sections": ["## Identity", "## R&R", "## KB Lookup", "## Operating Procedures", "## NON-NEGOTIABLE"], "forbidden_patterns": ["U[0-9A-Z]{8,11}", "C[0-9A-Z]{8,11}"]}'::jsonb,
36
+ '봇 페르소나 + R&R + 행동강령', 'create_file',
37
+ '# $BOT_ID — SOUL\n\n## Identity\n\n> TODO\n\n## R&R\n\n> TODO\n\n## KB Lookup\n\n> kb_get/kb_search로 팀 정보 조회\n\n## Operating Procedures\n\n> TODO\n\n## NON-NEGOTIABLE\n\n1. TODO'),
38
+
39
+ ('AGENTS.md', 'symlink', 'required', 'error', 'structure', 'all', '{}',
40
+ '$HOME/.openclaw-shared/AGENTS.md',
41
+ '{"max_lines": 150, "required_patterns": ["Every Session", "KB-First"]}'::jsonb,
42
+ '공통 세션 운영 규칙 (심링크)', 'create_symlink', NULL),
43
+
44
+ ('USER.md', 'file', 'required', 'error', 'structure', 'all', '{}', NULL,
45
+ '{"max_lines": 15}'::jsonb,
46
+ '사용자 컨텍스트', 'create_file',
47
+ '# USER\n\n> TODO: $BOT_ID 사용자 정보'),
48
+
49
+ ('MEMORY.md', 'file', 'required', 'error', 'structure', 'all', '{}', NULL,
50
+ '{"max_lines": 30, "required_patterns": ["KB SoT|KB.*SoT|Single Source"]}'::jsonb,
51
+ 'KB 도메인 인덱스 (main 세션만)', 'create_file',
52
+ '# MEMORY\n\n> KB SoT — 팀 정보는 kb_search/kb_get으로 조회'),
53
+
54
+ ('HEARTBEAT.md', 'file', 'required', 'error', 'structure', 'include', '{semiclaw}', NULL,
55
+ NULL,
56
+ '크론 작업 정의 (semiclaw 전용)', NULL, NULL),
57
+
58
+ ('.claude/settings.json', 'file', 'required', 'error', 'structure', 'all', '{}', NULL,
59
+ '{"required_patterns": ["semicolony-kb"]}'::jsonb,
60
+ 'MCP 서버 설정', NULL, NULL),
61
+
62
+ -- 필수 디렉토리
63
+ ('.claude/', 'dir', 'required', 'error', 'structure', 'all', '{}', NULL, NULL,
64
+ 'Claude 설정 디렉토리', 'create_dir', NULL),
65
+
66
+ ('hooks/', 'dir', 'required', 'error', 'structure', 'all', '{}', NULL, NULL,
67
+ 'OpenClaw 훅', 'create_dir', NULL),
68
+
69
+ ('memory/', 'dir', 'required', 'error', 'structure', 'all', '{}', NULL, NULL,
70
+ '일일로그 디렉토리', 'create_dir', NULL),
71
+
72
+ ('skills/', 'dir', 'required', 'error', 'structure', 'all', '{}', NULL, NULL,
73
+ '봇 전용 스킬', 'create_dir', NULL),
74
+
75
+ -- 선택 디렉토리/파일
76
+ ('scripts/', 'dir', 'optional', 'warn', 'structure', 'all', '{}', NULL, NULL,
77
+ '유틸리티 스크립트', NULL, NULL),
78
+
79
+ ('shared/', 'dir', 'optional', 'warn', 'structure', 'all', '{}', NULL, NULL,
80
+ '공유 리소스 (심링크)', NULL, NULL),
81
+
82
+ ('.gh-pat', 'file', 'optional', 'warn', 'structure', 'all', '{}', NULL, NULL,
83
+ 'GitHub PAT 파일', NULL, NULL),
84
+
85
+ ('.gitignore', 'file', 'optional', 'warn', 'structure', 'all', '{}', NULL, NULL,
86
+ 'Git ignore', NULL, NULL),
87
+
88
+ -- 레거시 파일 (금지)
89
+ ('IDENTITY.md', 'file', 'forbidden', 'error', 'legacy', 'all', '{}', NULL, NULL,
90
+ 'v1 레거시 — SOUL.md ## Identity로 대체됨', NULL, NULL),
91
+
92
+ ('TOOLS.md', 'file', 'forbidden', 'error', 'legacy', 'all', '{}', NULL, NULL,
93
+ 'v1 레거시 — KB lookup 지시로 대체', NULL, NULL),
94
+
95
+ ('RULES.md', 'file', 'forbidden', 'error', 'legacy', 'all', '{}', NULL, NULL,
96
+ 'v1 레거시 — SOUL.md ## NON-NEGOTIABLE로 통합', NULL, NULL),
97
+
98
+ ('CLAUDE.md', 'file', 'forbidden', 'warn', 'legacy', 'all', '{}', NULL, NULL,
99
+ 'v1 레거시 — 프로젝트 .claude/CLAUDE.md에 이미 존재', NULL, NULL),
100
+
101
+ ('BOOTSTRAP.md', 'file', 'forbidden', 'warn', 'legacy', 'all', '{}', NULL, NULL,
102
+ 'v1 레거시', NULL, NULL),
103
+
104
+ -- 위생 (금지)
105
+ ('*/.git', 'glob', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
106
+ '클론된 리포 — workspace에 git clone 금지', NULL, NULL),
107
+
108
+ ('node_modules', 'glob', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
109
+ 'npm install 산출물', NULL, NULL),
110
+
111
+ ('dist/', 'dir', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
112
+ '빌드 산출물', NULL, NULL),
113
+
114
+ ('build/', 'dir', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
115
+ '빌드 산출물', NULL, NULL),
116
+
117
+ ('.next/', 'dir', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
118
+ 'Next.js 빌드 산출물', NULL, NULL),
119
+
120
+ ('out/', 'dir', 'forbidden', 'error', 'hygiene', 'all', '{}', NULL, NULL,
121
+ '빌드 산출물', NULL, NULL),
122
+
123
+ ('*.ovpn', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
124
+ 'VPN 설정 파일 — 보안', NULL, NULL),
125
+
126
+ ('*.pem', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
127
+ '인증서 파일 — 보안', NULL, NULL),
128
+
129
+ ('*.key', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
130
+ '비밀키 파일 — 보안', NULL, NULL),
131
+
132
+ ('credentials/', 'dir', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
133
+ '인증 정보 디렉토리', NULL, NULL),
134
+
135
+ ('*.png', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
136
+ '바이너리 이미지 파일', NULL, NULL),
137
+
138
+ ('*.jpg', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
139
+ '바이너리 이미지 파일', NULL, NULL),
140
+
141
+ ('*.zip', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
142
+ '압축 파일', NULL, NULL),
143
+
144
+ ('*.tgz', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
145
+ '압축 파일', NULL, NULL),
146
+
147
+ ('temp/', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
148
+ '임시 디렉토리', NULL, NULL),
149
+
150
+ ('tmp/', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
151
+ '임시 디렉토리', NULL, NULL),
152
+
153
+ ('*.tmp', 'glob', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
154
+ '임시 파일', NULL, NULL),
155
+
156
+ ('go.mod', 'file', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
157
+ 'Go 모듈 파일 — workspace에 불필요', NULL, NULL),
158
+
159
+ ('go.sum', 'file', 'forbidden', 'warn', 'hygiene', 'all', '{}', NULL, NULL,
160
+ 'Go 체크섬 파일 — workspace에 불필요', NULL, NULL)
161
+
162
+ ON CONFLICT (path_pattern, spec_version) DO UPDATE SET
163
+ entry_type = EXCLUDED.entry_type,
164
+ level = EXCLUDED.level,
165
+ severity = EXCLUDED.severity,
166
+ category = EXCLUDED.category,
167
+ bot_scope = EXCLUDED.bot_scope,
168
+ bot_ids = EXCLUDED.bot_ids,
169
+ symlink_target = EXCLUDED.symlink_target,
170
+ content_rules = EXCLUDED.content_rules,
171
+ description = EXCLUDED.description,
172
+ fix_action = EXCLUDED.fix_action,
173
+ fix_template = EXCLUDED.fix_template,
174
+ updated_at = NOW();
@@ -0,0 +1,8 @@
1
+ -- 021: Drop dead tables
2
+ -- bot_kb_subscriptions: 코드 참조 0건, kb_digest since 파라미터로 대체
3
+ -- bot_knowledge: 012에서 DROP 선언되었으나 잔존 가능
4
+ -- kb_usage_log: 코드 참조 0건, 계획만 있고 미구현
5
+
6
+ DROP TABLE IF EXISTS semicolony.bot_kb_subscriptions;
7
+ DROP TABLE IF EXISTS semicolony.bot_knowledge;
8
+ DROP TABLE IF EXISTS semicolony.kb_usage_log;
@@ -0,0 +1,19 @@
1
+ -- 021_test_declarative.sql
2
+ -- test_suites에 rule_source 컬럼 추가 + workspace-audit을 declarative 타입으로 전환
3
+
4
+ BEGIN;
5
+
6
+ -- runner_path를 nullable로 변경 (declarative는 path 불필요)
7
+ ALTER TABLE semicolony.test_suites ALTER COLUMN runner_path DROP NOT NULL;
8
+
9
+ -- rule_source: declarative 러너가 규칙을 로드할 테이블명
10
+ ALTER TABLE semicolony.test_suites ADD COLUMN IF NOT EXISTS rule_source TEXT;
11
+
12
+ -- workspace-audit을 declarative로 전환
13
+ UPDATE semicolony.test_suites
14
+ SET runner_type = 'declarative',
15
+ runner_path = NULL,
16
+ rule_source = 'bot_workspace_standard'
17
+ WHERE suite_id = 'workspace-audit';
18
+
19
+ COMMIT;
@@ -0,0 +1,38 @@
1
+ -- 022_bot_ontology_type.sql
2
+ -- bot 타입을 온톨로지 + kb_type_schema에 추가하고, 봇을 도메인으로 등록
3
+
4
+ BEGIN;
5
+
6
+ -- 1. ontology_types에 bot 타입 추가
7
+ INSERT INTO semicolony.ontology_types (type_key, description)
8
+ VALUES ('bot', 'OpenClaw 봇 에이전트')
9
+ ON CONFLICT (type_key) DO NOTHING;
10
+
11
+ -- 2. bot 타입 scheme_key 정의 (KB 메타데이터 전용, 워크스페이스 파일은 bot_workspace_standard에서 관리)
12
+ INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, scheme_description, required, value_hint, sort_order) VALUES
13
+ ('bot', 'identity', '봇 기본 정보 (이름, 이모지, 한 줄 설명)', true, 'YAML: name, emoji, tagline', 1),
14
+ ('bot', 'role', 'R&R — 역할 범위, 담당 업무', true, '마크다운: 업무 범위 테이블', 2),
15
+ ('bot', 'status', '현재 상태', true, 'online | offline | maintenance', 3),
16
+ ('bot', 'delegation', '인계 매트릭스 — 역할 밖 요청 라우팅', false, '마크다운: 요청유형 → 인계봇 테이블', 4),
17
+ ('bot', 'gateway_config', '게이트웨이 설정 (포트, 토큰 경로)', false, 'YAML: port, token_path, model', 5),
18
+ ('bot', 'cron_schedule', '크론 작업 목록', false, '마크다운: 스케줄 + 설명 테이블', 6),
19
+ ('bot', 'slack_config', 'Slack 연동 (Bot ID, 채널)', false, 'YAML: bot_id, channels[]', 7)
20
+ ON CONFLICT (type_key, scheme_key) DO UPDATE SET
21
+ scheme_description = EXCLUDED.scheme_description,
22
+ required = EXCLUDED.required,
23
+ value_hint = EXCLUDED.value_hint,
24
+ sort_order = EXCLUDED.sort_order;
25
+
26
+ -- 3. 각 봇을 ontology 도메인으로 등록 (bot_status에서 동적 조회)
27
+ INSERT INTO semicolony.ontology (domain, entity_type, description, service, schema)
28
+ SELECT bot_id, 'bot',
29
+ COALESCE(name, bot_id) || ' — ' || COALESCE(role, 'Bot'),
30
+ bot_id,
31
+ '{}'::jsonb
32
+ FROM semicolony.bot_status
33
+ WHERE bot_id != 'shared'
34
+ ON CONFLICT (domain) DO UPDATE SET
35
+ entity_type = 'bot',
36
+ description = EXCLUDED.description;
37
+
38
+ COMMIT;
@@ -0,0 +1,77 @@
1
+ -- 022_kb_schema_enforcement.sql
2
+ -- KB 키 검증 강화: scheme_key 1뎁스 전환 + key_type 컬럼 추가
3
+ --
4
+ -- 변경 내용:
5
+ -- 1. key_type 컬럼 추가 (singleton | collection)
6
+ -- 2. 기존 변수 패턴({...}) scheme_key → collection으로 마킹
7
+ -- 3. scheme_key를 1뎁스(첫 세그먼트)로 축약
8
+ -- 4. 축약 후 중복 제거
9
+ -- 5. service 타입에 kpi/milestone collection 추가
10
+ --
11
+ -- 선행 조건: 018_type_schema.sql 적용 완료
12
+
13
+ BEGIN;
14
+
15
+ -- ============================================================
16
+ -- 1. key_type 컬럼 추가
17
+ -- ============================================================
18
+
19
+ ALTER TABLE semicolony.kb_type_schema
20
+ ADD COLUMN IF NOT EXISTS key_type VARCHAR(20) DEFAULT 'singleton';
21
+
22
+ -- ============================================================
23
+ -- 2. 기존 데이터 key_type 설정 (변수 포함 = collection)
24
+ -- ============================================================
25
+
26
+ UPDATE semicolony.kb_type_schema
27
+ SET key_type = 'collection'
28
+ WHERE scheme_key LIKE '%{%';
29
+
30
+ -- ============================================================
31
+ -- 3. scheme_key를 1뎁스로 축약 (첫 번째 세그먼트만)
32
+ -- ============================================================
33
+
34
+ UPDATE semicolony.kb_type_schema
35
+ SET scheme_key = SPLIT_PART(scheme_key, '/', 1)
36
+ WHERE scheme_key LIKE '%/%';
37
+
38
+ -- ============================================================
39
+ -- 4. 중복 제거 (축약 후 동일 type_key+scheme_key 병합)
40
+ -- ============================================================
41
+
42
+ DELETE FROM semicolony.kb_type_schema a
43
+ USING semicolony.kb_type_schema b
44
+ WHERE a.id > b.id
45
+ AND a.type_key = b.type_key
46
+ AND a.scheme_key = b.scheme_key;
47
+
48
+ -- 축약 후 collection으로 마킹되지 않은 행도 올바르게 설정
49
+ -- (예: 'team' 은 원래 'team/{name}'이었으므로 collection)
50
+ UPDATE semicolony.kb_type_schema
51
+ SET key_type = 'collection'
52
+ WHERE key_type = 'singleton'
53
+ AND scheme_key IN ('team', 'decision', 'process', 'infra', 'bot-config', 'skill', 'spec', 'memory', 'session-log');
54
+
55
+ -- kpi 타입의 '{YYYY-WNN}' → collection으로 이미 변환됨, 축약 후 '{YYYY-WNN}' 자체가 첫 세그먼트
56
+ -- 이 잔여 항목 정리 (변수 패턴이 첫 세그먼트인 경우 삭제 — collection prefix로 대체 불가)
57
+ DELETE FROM semicolony.kb_type_schema
58
+ WHERE scheme_key LIKE '{%';
59
+
60
+ -- milestone 타입의 '{slug}' 도 동일하게 삭제
61
+ -- (service.milestone collection으로 통합)
62
+
63
+ -- ============================================================
64
+ -- 5. service 타입에 kpi/milestone collection 추가
65
+ -- ============================================================
66
+
67
+ INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, scheme_description, required, value_hint, sort_order, key_type)
68
+ VALUES
69
+ ('service', 'kpi', 'KPI (current/target/주간 스냅샷)', false, 'kpi/current, kpi/target, kpi/2026-W12', 10, 'collection'),
70
+ ('service', 'milestone', '마일스톤 항목', false, 'milestone/blog-auto-gen', 11, 'collection')
71
+ ON CONFLICT (type_key, scheme_key) DO UPDATE SET
72
+ key_type = 'collection',
73
+ scheme_description = EXCLUDED.scheme_description,
74
+ value_hint = EXCLUDED.value_hint,
75
+ sort_order = EXCLUDED.sort_order;
76
+
77
+ COMMIT;
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 023_decision_key_cleanup.ts
4
+ *
5
+ * ~100건의 비표준 decision 키를 표준 형식(decision/{date}/{slug})으로 변환.
6
+ *
7
+ * 변환 규칙:
8
+ * - 이미 decision/{YYYY-MM-DD}/{slug} 형식이면 스킵
9
+ * - content/metadata에서 날짜 추출 시도
10
+ * - 날짜 추출 불가 시 updated_at에서 추출
11
+ * - 키 충돌 시 suffix 추가 (-2, -3, ...)
12
+ *
13
+ * 사용법:
14
+ * npx tsx packages/cli/migrations/023_decision_key_cleanup.ts [--dry-run]
15
+ */
16
+
17
+ import pg from "pg";
18
+
19
+ const DATABASE_URL = process.env.DATABASE_URL;
20
+ if (!DATABASE_URL) {
21
+ console.error("DATABASE_URL 환경변수가 필요합니다");
22
+ process.exit(1);
23
+ }
24
+
25
+ const DRY_RUN = process.argv.includes("--dry-run");
26
+
27
+ const STANDARD_PATTERN = /^decision\/\d{4}-\d{2}-\d{2}\/.+$/;
28
+ const DATE_PATTERN = /(\d{4}-\d{2}-\d{2})/;
29
+
30
+ function slugify(text: string): string {
31
+ return text
32
+ .toLowerCase()
33
+ .replace(/[가-힣]+/g, (match) => match) // keep Korean as-is
34
+ .replace(/[^a-z0-9가-힣\-]/g, "-")
35
+ .replace(/-+/g, "-")
36
+ .replace(/^-|-$/g, "")
37
+ .substring(0, 80);
38
+ }
39
+
40
+ function extractDate(keySlug: string, content: string, metadata: Record<string, unknown> | null): string | null {
41
+ // Try metadata first
42
+ if (metadata) {
43
+ for (const k of ["date", "decided_at", "created_at", "timestamp"]) {
44
+ const val = metadata[k];
45
+ if (typeof val === "string") {
46
+ const match = val.match(DATE_PATTERN);
47
+ if (match) return match[1];
48
+ }
49
+ }
50
+ }
51
+
52
+ // Try key slug (e.g., "메모리 구조 개편 (2026-02-17)")
53
+ const keyMatch = keySlug.match(DATE_PATTERN);
54
+ if (keyMatch) return keyMatch[1];
55
+
56
+ // Try content
57
+ const contentMatch = content.match(DATE_PATTERN);
58
+ if (contentMatch) return contentMatch[1];
59
+
60
+ return null;
61
+ }
62
+
63
+ async function main() {
64
+ const pool = new pg.Pool({ connectionString: DATABASE_URL });
65
+
66
+ try {
67
+ // Find all decision keys in semicolon domain
68
+ const result = await pool.query(`
69
+ SELECT domain, key, content, metadata, updated_at::text
70
+ FROM semicolony.knowledge_base
71
+ WHERE domain = 'semicolon' AND key LIKE 'decision/%'
72
+ ORDER BY key
73
+ `);
74
+
75
+ const rows = result.rows;
76
+ console.log(`총 decision 엔트리: ${rows.length}건`);
77
+
78
+ const nonStandard = rows.filter((r) => !STANDARD_PATTERN.test(r.key));
79
+ console.log(`비표준 키: ${nonStandard.length}건`);
80
+
81
+ if (nonStandard.length === 0) {
82
+ console.log("정리할 항목 없음");
83
+ return;
84
+ }
85
+
86
+ // Collect existing keys to avoid conflicts
87
+ const existingKeys = new Set(rows.map((r) => r.key));
88
+
89
+ let updated = 0;
90
+ let skipped = 0;
91
+
92
+ for (const row of nonStandard) {
93
+ const oldKey = row.key;
94
+ const parts = oldKey.split("/");
95
+
96
+ // Extract the "slug" portion (everything after "decision/")
97
+ const rawSlug = parts.slice(1).join("/");
98
+
99
+ // Extract date
100
+ let date = extractDate(rawSlug, row.content, row.metadata);
101
+ if (!date && row.updated_at) {
102
+ date = row.updated_at.substring(0, 10);
103
+ }
104
+ if (!date) {
105
+ date = "unknown";
106
+ }
107
+
108
+ // If it already has a date as second segment, use that
109
+ if (parts.length >= 3 && DATE_PATTERN.test(parts[1])) {
110
+ // Already has date but may have extra depth — keep as is
111
+ console.log(` 스킵 (이미 날짜 포함): ${oldKey}`);
112
+ skipped++;
113
+ continue;
114
+ }
115
+
116
+ const slug = slugify(rawSlug);
117
+ let newKey = `decision/${date}/${slug}`;
118
+
119
+ // Dedup: if conflict, add suffix
120
+ if (existingKeys.has(newKey) && newKey !== oldKey) {
121
+ let suffix = 2;
122
+ while (existingKeys.has(`${newKey}-${suffix}`)) suffix++;
123
+ newKey = `${newKey}-${suffix}`;
124
+ }
125
+
126
+ if (newKey === oldKey) {
127
+ skipped++;
128
+ continue;
129
+ }
130
+
131
+ console.log(` ${oldKey} → ${newKey}`);
132
+
133
+ if (!DRY_RUN) {
134
+ await pool.query(
135
+ `UPDATE semicolony.knowledge_base SET key = $1 WHERE domain = $2 AND key = $3`,
136
+ [newKey, row.domain, oldKey]
137
+ );
138
+ }
139
+
140
+ existingKeys.delete(oldKey);
141
+ existingKeys.add(newKey);
142
+ updated++;
143
+ }
144
+
145
+ console.log(`\n결과: ${updated}건 변환, ${skipped}건 스킵${DRY_RUN ? " (dry-run)" : ""}`);
146
+ } finally {
147
+ await pool.end();
148
+ }
149
+ }
150
+
151
+ main().catch((err) => {
152
+ console.error("에러:", err);
153
+ process.exit(1);
154
+ });
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 024_embedding_backfill.ts
4
+ *
5
+ * 임베딩 없는 KB 엔트리에 벡터 일괄 생성.
6
+ * OpenAI batch API를 사용하여 효율적으로 처리.
7
+ *
8
+ * 사용법:
9
+ * npx tsx packages/cli/migrations/024_embedding_backfill.ts [--dry-run] [--batch-size=20]
10
+ */
11
+
12
+ import pg from "pg";
13
+
14
+ const DATABASE_URL = process.env.DATABASE_URL;
15
+ const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
16
+
17
+ if (!DATABASE_URL) {
18
+ console.error("DATABASE_URL 환경변수가 필요합니다");
19
+ process.exit(1);
20
+ }
21
+ if (!OPENAI_API_KEY) {
22
+ console.error("OPENAI_API_KEY 환경변수가 필요합니다");
23
+ process.exit(1);
24
+ }
25
+
26
+ const DRY_RUN = process.argv.includes("--dry-run");
27
+ const BATCH_SIZE = parseInt(
28
+ process.argv.find((a) => a.startsWith("--batch-size="))?.split("=")[1] || "20",
29
+ 10
30
+ );
31
+
32
+ const EMBEDDING_MODEL = "text-embedding-3-small";
33
+ const EMBEDDING_DIMENSIONS = 1024;
34
+
35
+ async function generateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {
36
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
37
+ method: "POST",
38
+ headers: {
39
+ Authorization: `Bearer ${OPENAI_API_KEY}`,
40
+ "Content-Type": "application/json",
41
+ },
42
+ body: JSON.stringify({
43
+ model: EMBEDDING_MODEL,
44
+ input: texts.map((t) => t.substring(0, 8000)),
45
+ dimensions: EMBEDDING_DIMENSIONS,
46
+ }),
47
+ });
48
+
49
+ if (!response.ok) {
50
+ const err = await response.text();
51
+ console.error(`API 에러: ${response.status} ${err}`);
52
+ return texts.map(() => null);
53
+ }
54
+
55
+ const data = (await response.json()) as { data?: { embedding: number[] }[] };
56
+ return data.data?.map((d) => d.embedding) || texts.map(() => null);
57
+ }
58
+
59
+ async function main() {
60
+ const pool = new pg.Pool({ connectionString: DATABASE_URL });
61
+
62
+ try {
63
+ const result = await pool.query(`
64
+ SELECT domain, key, content
65
+ FROM semicolony.knowledge_base
66
+ WHERE embedding IS NULL
67
+ ORDER BY domain, key
68
+ `);
69
+
70
+ const rows = result.rows;
71
+ console.log(`임베딩 없는 엔트리: ${rows.length}건`);
72
+
73
+ if (rows.length === 0) {
74
+ console.log("처리할 항목 없음");
75
+ return;
76
+ }
77
+
78
+ if (DRY_RUN) {
79
+ console.log("(dry-run) 실제 처리하지 않음");
80
+ for (const row of rows) {
81
+ console.log(` ${row.domain}/${row.key}`);
82
+ }
83
+ return;
84
+ }
85
+
86
+ let processed = 0;
87
+ let failed = 0;
88
+
89
+ for (let i = 0; i < rows.length; i += BATCH_SIZE) {
90
+ const batch = rows.slice(i, i + BATCH_SIZE);
91
+ const texts = batch.map((r) => `${r.key}: ${r.content}`);
92
+
93
+ console.log(`배치 ${Math.floor(i / BATCH_SIZE) + 1}/${Math.ceil(rows.length / BATCH_SIZE)} (${batch.length}건)...`);
94
+
95
+ const embeddings = await generateEmbeddings(texts);
96
+
97
+ for (let j = 0; j < batch.length; j++) {
98
+ const row = batch[j];
99
+ const embedding = embeddings[j];
100
+
101
+ if (!embedding) {
102
+ console.error(` 실패: ${row.domain}/${row.key}`);
103
+ failed++;
104
+ continue;
105
+ }
106
+
107
+ const embeddingStr = `[${embedding.join(",")}]`;
108
+ await pool.query(
109
+ `UPDATE semicolony.knowledge_base SET embedding = $1::vector WHERE domain = $2 AND key = $3`,
110
+ [embeddingStr, row.domain, row.key]
111
+ );
112
+
113
+ processed++;
114
+ }
115
+
116
+ // Rate limiting: 짧은 대기
117
+ if (i + BATCH_SIZE < rows.length) {
118
+ await new Promise((resolve) => setTimeout(resolve, 500));
119
+ }
120
+ }
121
+
122
+ console.log(`\n결과: ${processed}건 생성, ${failed}건 실패`);
123
+
124
+ // Verify
125
+ const remaining = await pool.query(
126
+ "SELECT COUNT(*)::int as cnt FROM semicolony.knowledge_base WHERE embedding IS NULL"
127
+ );
128
+ console.log(`남은 NULL 임베딩: ${remaining.rows[0].cnt}건`);
129
+ } finally {
130
+ await pool.end();
131
+ }
132
+ }
133
+
134
+ main().catch((err) => {
135
+ console.error("에러:", err);
136
+ process.exit(1);
137
+ });
@@ -0,0 +1,33 @@
1
+ -- 025: KB Flat Key Migration
2
+ -- key + sub_key 분리: key는 scheme_key exact match, sub_key는 계층 식별자
3
+ BEGIN;
4
+
5
+ -- 1. sub_key 컬럼 추가
6
+ ALTER TABLE semicolony.knowledge_base
7
+ ADD COLUMN IF NOT EXISTS sub_key VARCHAR(255) NOT NULL DEFAULT '';
8
+
9
+ -- 2. 기존 Unique constraint 제거 (UPDATE 전에 제거해야 충돌 없음)
10
+ ALTER TABLE semicolony.knowledge_base
11
+ DROP CONSTRAINT IF EXISTS knowledge_base_domain_key_key;
12
+
13
+ -- 3. 기존 collection 키 분리 (첫 '/' 기준)
14
+ UPDATE semicolony.knowledge_base
15
+ SET sub_key = SUBSTRING(key FROM POSITION('/' IN key) + 1),
16
+ key = SPLIT_PART(key, '/', 1)
17
+ WHERE key LIKE '%/%';
18
+
19
+ -- 4. 새 Unique constraint 추가
20
+ ALTER TABLE semicolony.knowledge_base
21
+ ADD CONSTRAINT knowledge_base_domain_key_subkey_key
22
+ UNIQUE (domain, key, sub_key);
23
+
24
+ -- 5. 조회 성능 인덱스
25
+ CREATE INDEX IF NOT EXISTS idx_kb_domain_key ON semicolony.knowledge_base (domain, key);
26
+
27
+ -- 6. 테스트 파이프라인 등록
28
+ INSERT INTO semicolony.test_suites (suite_id, name, layer, runner_type, runner_path, enabled)
29
+ VALUES ('025-flat-keys', '025 KB Flat Key Migration', 'integration', 'tsx',
30
+ 'packages/mcp-kb/test-025-flat-keys.ts', true)
31
+ ON CONFLICT (suite_id) DO NOTHING;
32
+
33
+ COMMIT;
@@ -0,0 +1,19 @@
1
+ BEGIN;
2
+
3
+ -- 1. kb_type_schema에서 session-log 행 제거
4
+ DELETE FROM semicolony.kb_type_schema
5
+ WHERE type_key = 'organization' AND scheme_key = 'session-log';
6
+
7
+ -- 2. ontology_types에서 session-log 타입 제거 (있다면)
8
+ DELETE FROM semicolony.ontology_types WHERE type_key = 'session-log';
9
+
10
+ -- 3. 기존 session-log 데이터 정리
11
+ DELETE FROM semicolony.knowledge_base
12
+ WHERE domain = 'semicolon' AND key = 'session-log';
13
+
14
+ -- 4. semicolon 온톨로지 description에서 session-log 참조 제거
15
+ UPDATE semicolony.ontology
16
+ SET description = REPLACE(description, '/session-log', '')
17
+ WHERE domain = 'semicolon' AND description LIKE '%session-log%';
18
+
19
+ COMMIT;