@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.
- package/LICENSE +200 -0
- package/NOTICE +8 -0
- package/README.md +152 -0
- package/dist/bundle.js +2887 -0
- package/dist/templates/launchd/ai.semicolony.host-signals-sidecar.plist +40 -0
- package/migrations/001_initial.sql +280 -0
- package/migrations/002_add_indexes.sql +11 -0
- package/migrations/003_add_fk.sql +32 -0
- package/migrations/004_session_count_trigger.sql +35 -0
- package/migrations/005_bot_workspace_audits.sql +16 -0
- package/migrations/006_bot_kb_subscriptions.sql +24 -0
- package/migrations/007_flatten_skill_names.sql +16 -0
- package/migrations/008_bot_workspace_files.sql +14 -0
- package/migrations/009_enforce_flat_skill_names.sql +53 -0
- package/migrations/010_bot_delegation.sql +27 -0
- package/migrations/011_drop_legacy_tables.sql +35 -0
- package/migrations/012_drop_bot_knowledge.sql +16 -0
- package/migrations/013_kb_workspace_domains.sql +88 -0
- package/migrations/014_timestamp_to_timestamptz.sql +33 -0
- package/migrations/015_kb_domain_enforcement.sql +83 -0
- package/migrations/016_ontology_redesign.sql +108 -0
- package/migrations/017_ontology_instance_model.sql +151 -0
- package/migrations/018_type_schema.sql +11 -0
- package/migrations/019_test_management.sql +69 -0
- package/migrations/020_bot_workspace_standard.sql +174 -0
- package/migrations/021_drop_dead_tables.sql +8 -0
- package/migrations/021_test_declarative.sql +19 -0
- package/migrations/022_bot_ontology_type.sql +38 -0
- package/migrations/022_kb_schema_enforcement.sql +77 -0
- package/migrations/023_decision_key_cleanup.ts +154 -0
- package/migrations/024_embedding_backfill.ts +137 -0
- package/migrations/025_kb_flat_keys.sql +33 -0
- package/migrations/026_drop_session_log.sql +19 -0
- package/migrations/027_kb_manager_skill.sql +22 -0
- package/migrations/028_skill_definitions_to_semicolony.sql +19 -0
- package/migrations/029_agents_citation_max_lines.sql +6 -0
- package/migrations/030_team_ontology.sql +54 -0
- package/migrations/031_gfp_tables.sql +101 -0
- package/migrations/031_kb_manager_domain_register.sql +12 -0
- package/migrations/032_gfp_skill_and_callback.sql +40 -0
- package/migrations/032_kebab_case_keys.sql +33 -0
- package/migrations/033_skill_workspace_rules.sql +10 -0
- package/migrations/034_current_to_date_keys.sql +13 -0
- package/migrations/034_current_to_date_keys.ts +104 -0
- package/migrations/035_bot_budgets.sql +51 -0
- package/migrations/036_gfp_stitch_design.sql +35 -0
- package/migrations/037_gfp_qa_sections.sql +13 -0
- package/migrations/038_gfp_phase_split.sql +26 -0
- package/migrations/039_meeting_audio_data.sql +2 -0
- package/migrations/040_bot_commitments.sql +68 -0
- package/migrations/041_palette_previews.sql +13 -0
- package/migrations/042_gfp_parallel_tracks.sql +37 -0
- package/migrations/043_blocker_key.sql +13 -0
- package/migrations/044_gfp_stitch_screenshots.sql +9 -0
- package/migrations/045_service_table_rename_and_projection.sql +150 -0
- package/migrations/046_service_ops_tables.sql +75 -0
- package/migrations/047_update_gfp_manager_skill.sql +16 -0
- package/migrations/048_service_migration_skill.sql +23 -0
- package/migrations/049_service_features.sql +39 -0
- package/migrations/050_service_kpi_action_items.sql +87 -0
- package/migrations/051_update_service_migration_skill_prompt.sql +9 -0
- package/migrations/052_feature_iteration_link.sql +11 -0
- package/migrations/052_services_table_rename.sql +149 -0
- package/migrations/053_feature_discovery.sql +47 -0
- package/migrations/054_deploy_verification.sql +17 -0
- package/migrations/055_feature_lifecycle.sql +37 -0
- package/migrations/056_service_incident_schema.sql +16 -0
- package/migrations/057_decision_date_to_metadata.ts +173 -0
- package/migrations/058_incubator_kb_schema.sql +8 -0
- package/migrations/059_incubator_sessions.sql +29 -0
- package/migrations/060_skill_reference_files.sql +8 -0
- package/migrations/061_cron_trigger_bridge.sql +7 -0
- package/migrations/062_bot_slack_profiles.sql +21 -0
- package/migrations/063_rename_gfp_skills.sql +7 -0
- package/migrations/064_bot_cost_log.sql +11 -0
- package/migrations/065_hub_spoke_orchestration.sql +35 -0
- package/migrations/066_cost_log_commitment.sql +9 -0
- package/migrations/067_module_ontology_type.sql +44 -0
- package/migrations/068_migrate_incubator_data.sql +32 -0
- package/migrations/069_action_items_sot.sql +156 -0
- package/migrations/069_cost_log_tokens.sql +45 -0
- package/migrations/070_services_sot_columns.sql +78 -0
- package/migrations/071_cleanup_deprecated_service_kb.sql +38 -0
- package/migrations/072_incubator_heartbeat.sql +12 -0
- package/migrations/072_service_role_schema.sql +57 -0
- package/migrations/073_service_type_and_platform.sql +8 -0
- package/migrations/074_schema_ref_type.sql +16 -0
- package/migrations/075_routing_delegation.sql +34 -0
- package/migrations/076_meeting_service_link.sql +5 -0
- package/migrations/077_agents_ontology_type.sql +93 -0
- package/migrations/078_incubator_agent.sql +45 -0
- package/migrations/079_drop_audio_blob_url.sql +4 -0
- package/migrations/080_kb_metadata_indexing.sql +9 -0
- package/migrations/081_person_unification.sql +41 -0
- package/migrations/082_discord_channel.sql +3 -0
- package/migrations/084_deprecate_kpi_metrics_table.sql +5 -0
- package/migrations/085_meeting_target_domain.sql +37 -0
- package/migrations/086_skill_routing_new_skills.sql +23 -0
- package/migrations/087_skill_routing_second_opinion.sql +8 -0
- package/migrations/088_meeting_notion_sync.sql +10 -0
- package/migrations/089_bot_commitments_dedup.sql +17 -0
- package/migrations/090_incubator_discord_guild.sql +8 -0
- package/migrations/091_drop_deprecated_gfp_kpi_views.sql +65 -0
- package/migrations/092_ontology_channel_mapping.sql +28 -0
- package/migrations/093_update_bot_workspace_paths.sql +15 -0
- package/migrations/094_cron_run_tracking.sql +28 -0
- package/migrations/095_drop_bot_cron_runs.sql +7 -0
- package/migrations/096_kb_pipeline_keys.sql +66 -0
- package/migrations/097_drop_empty_service_tables.sql +83 -0
- package/migrations/098_migrate_features_materials_drop.sql +119 -0
- package/migrations/099_migrate_sections_drop.sql +52 -0
- package/migrations/099_seed_cron_poller_tick.sql +14 -0
- package/migrations/100_migrate_services_drop.sql +57 -0
- package/migrations/101_drop_services.sql +5 -0
- package/migrations/102_cost_log_session_dedup.sql +13 -0
- package/migrations/103_board.sql +57 -0
- package/migrations/104_agent_factory.sql +284 -0
- package/migrations/105_kb_notify.sql +44 -0
- package/migrations/106_office_id_agents_commands.sql +73 -0
- package/migrations/107_agent_service_credentials.sql +79 -0
- package/migrations/108_drop_l2_ontology_seeds.sql +16 -0
- package/migrations/109_generic_ontology_descriptions.sql +21 -0
- package/migrations/110_kb_manager_skill_l2_cleanup.sql +34 -0
- package/migrations/111_drop_l2_team_ontology_seeds.sql +20 -0
- package/migrations/112_fix_pipeline_schema_and_role_trigger.sql +83 -0
- package/migrations/113_kb_history.sql +53 -0
- package/migrations/114_runtime_target_columns.sql +26 -0
- package/migrations/115_runtime_source_columns.sql +52 -0
- package/migrations/116_commitment_pattern_health.sql +81 -0
- package/migrations/117_commitment_pattern_alert_claims.sql +33 -0
- package/migrations/118_retire_semiclaw_semicolonybot_alias.sql +30 -0
- package/migrations/119_commitment_events.sql +51 -0
- package/migrations/120_host_signals.sql +51 -0
- package/migrations/121_agent_spec_derived_runtime_metadata.sql +68 -0
- package/migrations/122_agent_spec_derived_fk_policy.sql +18 -0
- package/migrations/123_agent_spec_projection_skip_targets.sql +24 -0
- package/migrations/124_bot_commitments_notify.sql +26 -0
- package/migrations/125_agent_personas.sql +36 -0
- package/migrations/128_entity_relations.sql +125 -0
- package/migrations/129_kb_multitenant_gateway.sql +86 -0
- package/migrations/130_jewelry_relation_types.sql +36 -0
- package/migrations/131_concierge_requests.sql +38 -0
- package/migrations/132_kb_supersession.sql +27 -0
- package/migrations/133_kb_claims.sql +52 -0
- package/migrations/134_migration_registry.sql +18 -0
- package/migrations/135_sc_roles.sql +102 -0
- package/migrations/136_runtime_tenant_columns.sql +71 -0
- package/migrations/137_runtime_backfill_team_semicolon.sql +131 -0
- package/migrations/138_runtime_constraints_not_valid.sql +56 -0
- package/migrations/139_tenant_vms.sql +31 -0
- package/migrations/140_fleet_slots.sql +23 -0
- package/migrations/141_provisioning_jobs.sql +29 -0
- package/migrations/142_rls_enable_semicolony.sql +129 -0
- package/migrations/143_rls_enable_public.sql +54 -0
- package/migrations/144_worker_device_registry.sql +211 -0
- package/migrations/145_workspace_profile_workstation_policy.sql +39 -0
- package/migrations/146_worker_profile_repo_scope.sql +24 -0
- package/migrations/147_worker_profile_semo_ops_repo_rename.sql +18 -0
- package/migrations/148_momo_runtime_convergence.sql +92 -0
- package/migrations/README.md +88 -0
- package/migrations-sqlite/kb/001_initial.sql +56 -0
- package/migrations-sqlite/ops/001_initial.sql +53 -0
- package/migrations-sqlite/ops/002_action_items.sql +48 -0
- package/package.json +78 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
-- 053: Feature Discovery & Conversation Sessions
|
|
2
|
+
-- 기능 발견(크롤링) 및 대화형 기능 생성을 위한 세션 관리 테이블
|
|
3
|
+
BEGIN;
|
|
4
|
+
|
|
5
|
+
-- Feature Discovery Sessions (Playwright 크롤링 기반 기능 발견)
|
|
6
|
+
CREATE TABLE IF NOT EXISTS semicolony.feature_discovery_sessions (
|
|
7
|
+
session_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
8
|
+
service_id UUID NOT NULL REFERENCES semicolony.service_projects(service_id) ON DELETE CASCADE,
|
|
9
|
+
source_url TEXT NOT NULL,
|
|
10
|
+
status VARCHAR(20) NOT NULL DEFAULT 'crawling',
|
|
11
|
+
candidates JSONB DEFAULT '[]',
|
|
12
|
+
confirmed JSONB DEFAULT '[]',
|
|
13
|
+
screenshots JSONB DEFAULT '{}',
|
|
14
|
+
error TEXT,
|
|
15
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
16
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
17
|
+
);
|
|
18
|
+
-- status: crawling | candidates_ready | reviewing | confirmed | failed
|
|
19
|
+
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_fds_service
|
|
21
|
+
ON semicolony.feature_discovery_sessions(service_id, status);
|
|
22
|
+
|
|
23
|
+
-- Feature Conversation Sessions (봇 대화형 기능 생성/스펙 보강)
|
|
24
|
+
CREATE TABLE IF NOT EXISTS semicolony.feature_conversation_sessions (
|
|
25
|
+
session_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
26
|
+
service_id UUID NOT NULL REFERENCES semicolony.service_projects(service_id) ON DELETE CASCADE,
|
|
27
|
+
mode VARCHAR(20) NOT NULL DEFAULT 'create',
|
|
28
|
+
status VARCHAR(20) NOT NULL DEFAULT 'collecting',
|
|
29
|
+
features JSONB DEFAULT '[]',
|
|
30
|
+
slack_channel TEXT,
|
|
31
|
+
slack_thread_ts TEXT,
|
|
32
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
33
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
34
|
+
);
|
|
35
|
+
-- mode: create | enrich
|
|
36
|
+
-- status: collecting | reviewing | confirmed | cancelled
|
|
37
|
+
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_fcs_service
|
|
39
|
+
ON semicolony.feature_conversation_sessions(service_id, status);
|
|
40
|
+
|
|
41
|
+
-- updated_at 트리거
|
|
42
|
+
CREATE TRIGGER trg_fds_updated BEFORE UPDATE ON semicolony.feature_discovery_sessions
|
|
43
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.service_set_updated_at();
|
|
44
|
+
CREATE TRIGGER trg_fcs_updated BEFORE UPDATE ON semicolony.feature_conversation_sessions
|
|
45
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.service_set_updated_at();
|
|
46
|
+
|
|
47
|
+
COMMIT;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Deploy Verification Gate
|
|
2
|
+
-- GFP 인프라 Phase 승인 시 배포 검증 결과를 저장하는 테이블.
|
|
3
|
+
-- InfraClaw 또는 Dashboard API가 검증 결과를 기록하고,
|
|
4
|
+
-- handleInfraTrackApproval()이 Phase 0/2 승인 전 통과 여부를 확인한다.
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS semicolony.deploy_verifications (
|
|
7
|
+
verification_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
8
|
+
service_id UUID NOT NULL REFERENCES semicolony.services(service_id) ON DELETE CASCADE,
|
|
9
|
+
infra_phase INT NOT NULL,
|
|
10
|
+
checks JSONB NOT NULL,
|
|
11
|
+
overall_status TEXT NOT NULL CHECK (overall_status IN ('pass', 'fail')),
|
|
12
|
+
verified_by TEXT NOT NULL,
|
|
13
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_deploy_verif_service
|
|
17
|
+
ON semicolony.deploy_verifications(service_id, infra_phase);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- 055: Feature Lifecycle Pipeline
|
|
2
|
+
--
|
|
3
|
+
-- service_features.status 확장: planned → in-spec → spec-ready → in-dev → in-test → active / deprecated
|
|
4
|
+
-- 상태 전환 감사 로그 테이블 추가
|
|
5
|
+
--
|
|
6
|
+
-- 선행 조건: 049_service_features.sql, 052_services_table_rename.sql
|
|
7
|
+
|
|
8
|
+
BEGIN;
|
|
9
|
+
|
|
10
|
+
-- 1. status 컬럼 확장 (varchar(20) → varchar(30) for 'spec-ready' etc.)
|
|
11
|
+
ALTER TABLE semicolony.service_features
|
|
12
|
+
ALTER COLUMN status TYPE VARCHAR(30);
|
|
13
|
+
|
|
14
|
+
-- 2. CHECK 제약 추가 — 유효 상태값 강제
|
|
15
|
+
ALTER TABLE semicolony.service_features
|
|
16
|
+
ADD CONSTRAINT chk_feature_status
|
|
17
|
+
CHECK (status IN ('planned', 'in-spec', 'spec-ready', 'in-dev', 'in-test', 'active', 'deprecated'));
|
|
18
|
+
|
|
19
|
+
-- 3. 상태 전환 감사 로그
|
|
20
|
+
CREATE TABLE IF NOT EXISTS semicolony.feature_status_transitions (
|
|
21
|
+
transition_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
22
|
+
feature_id UUID NOT NULL REFERENCES semicolony.service_features(feature_id) ON DELETE CASCADE,
|
|
23
|
+
from_status VARCHAR(30) NOT NULL,
|
|
24
|
+
to_status VARCHAR(30) NOT NULL,
|
|
25
|
+
triggered_by VARCHAR(50) NOT NULL DEFAULT 'system', -- 'system' | 'user' | bot_id
|
|
26
|
+
reason TEXT,
|
|
27
|
+
metadata JSONB DEFAULT '{}',
|
|
28
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX idx_feature_transitions_feature
|
|
32
|
+
ON semicolony.feature_status_transitions(feature_id, created_at DESC);
|
|
33
|
+
|
|
34
|
+
COMMENT ON TABLE semicolony.feature_status_transitions IS
|
|
35
|
+
'Feature lifecycle 상태 전환 감사 로그. 누가/언제/왜 상태를 바꿨는지 추적.';
|
|
36
|
+
|
|
37
|
+
COMMIT;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- 056_service_incident_schema.sql
|
|
2
|
+
-- service 타입에 incident (인시던트/장애) collection 키 추가
|
|
3
|
+
-- organization 타입에는 이미 incident가 등록되어 있으나 service 타입에는 누락
|
|
4
|
+
|
|
5
|
+
BEGIN;
|
|
6
|
+
|
|
7
|
+
INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, scheme_description, required, value_hint, sort_order, key_type)
|
|
8
|
+
VALUES
|
|
9
|
+
('service', 'incident', '인시던트/장애 기록', false,
|
|
10
|
+
'서브키: 슬러그. metadata: occurred_at(날짜), severity(p0-p3), status(active/resolved), resolved_at, root_cause',
|
|
11
|
+
50, 'collection')
|
|
12
|
+
ON CONFLICT (type_key, scheme_key) DO UPDATE SET
|
|
13
|
+
scheme_description = EXCLUDED.scheme_description,
|
|
14
|
+
value_hint = EXCLUDED.value_hint;
|
|
15
|
+
|
|
16
|
+
COMMIT;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 057_decision_date_to_metadata.ts
|
|
3
|
+
*
|
|
4
|
+
* decision 엔트리의 날짜를 sub_key에서 metadata.decided_at으로 이동.
|
|
5
|
+
* 중복 엔트리(날짜 반복 suffix 등)를 정리.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npx tsx packages/cli/migrations/057_decision_date_to_metadata.ts --dry-run
|
|
9
|
+
* npx tsx packages/cli/migrations/057_decision_date_to_metadata.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Pool } from 'pg';
|
|
13
|
+
import { kbUpsert, kbDelete } from '../src/kb';
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
|
|
17
|
+
// Load .env manually
|
|
18
|
+
const envPath = path.resolve(process.env.HOME!, '.claude/semicolony/.env');
|
|
19
|
+
if (fs.existsSync(envPath)) {
|
|
20
|
+
for (const line of fs.readFileSync(envPath, 'utf-8').split('\n')) {
|
|
21
|
+
const match = line.match(/^([A-Z_]+)='?(.*?)'?$/);
|
|
22
|
+
if (match) process.env[match[1]] = match[2];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
27
|
+
if (!DATABASE_URL) {
|
|
28
|
+
console.error('DATABASE_URL not set');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DRY_RUN = process.argv.includes('--dry-run');
|
|
33
|
+
|
|
34
|
+
interface DecisionRow {
|
|
35
|
+
kb_id: number;
|
|
36
|
+
sub_key: string;
|
|
37
|
+
content: string;
|
|
38
|
+
metadata: Record<string, unknown> | null;
|
|
39
|
+
created_by: string;
|
|
40
|
+
updated_at: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Extract date prefix and clean slug from sub_key */
|
|
44
|
+
function extractDateAndSlug(subKey: string): {
|
|
45
|
+
date: string | null;
|
|
46
|
+
slug: string;
|
|
47
|
+
} {
|
|
48
|
+
const match = subKey.match(/^(\d{4}-\d{2}-\d{2})\/(.+)$/);
|
|
49
|
+
if (!match) return { date: null, slug: subKey };
|
|
50
|
+
|
|
51
|
+
const rawSlug = match[2];
|
|
52
|
+
|
|
53
|
+
// Remove trailing date suffixes: "-2026-02-17-xxx-2026-02-23-yyy" → base slug only
|
|
54
|
+
// Strategy: find the core slug before any date suffix pattern
|
|
55
|
+
const slug = rawSlug.replace(/(-\d{4}-\d{2}-\d{2}(-[a-z가-힣]+-?)*)+$/, '');
|
|
56
|
+
|
|
57
|
+
return { date: match[1], slug: slug || rawSlug };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function main() {
|
|
61
|
+
const pool = new Pool({ connectionString: DATABASE_URL });
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
// 1. Fetch all decision entries
|
|
65
|
+
const { rows } = await pool.query<DecisionRow>(
|
|
66
|
+
`SELECT kb_id, sub_key, content, metadata, created_by, updated_at::text
|
|
67
|
+
FROM semicolony.knowledge_base
|
|
68
|
+
WHERE domain = 'semicolon' AND key = 'decision'
|
|
69
|
+
ORDER BY sub_key`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
console.log(`📋 Total decision entries: ${rows.length}`);
|
|
73
|
+
|
|
74
|
+
// 2. Group by normalized slug
|
|
75
|
+
const groups = new Map<string, { original: DecisionRow; date: string | null }[]>();
|
|
76
|
+
|
|
77
|
+
let skipCount = 0;
|
|
78
|
+
for (const row of rows) {
|
|
79
|
+
const { date, slug } = extractDateAndSlug(row.sub_key);
|
|
80
|
+
|
|
81
|
+
if (!date) {
|
|
82
|
+
// Already new pattern (no date prefix) — skip but ensure metadata
|
|
83
|
+
skipCount++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const existing = groups.get(slug) || [];
|
|
88
|
+
existing.push({ original: row, date });
|
|
89
|
+
groups.set(slug, existing);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`📊 Entries with date prefix: ${rows.length - skipCount}`);
|
|
93
|
+
console.log(`📊 Already clean (no date): ${skipCount}`);
|
|
94
|
+
console.log(`📊 Unique slugs after normalization: ${groups.size}`);
|
|
95
|
+
|
|
96
|
+
// 3. Process each group
|
|
97
|
+
let migratedCount = 0;
|
|
98
|
+
let deletedDuplicates = 0;
|
|
99
|
+
let errorCount = 0;
|
|
100
|
+
|
|
101
|
+
for (const [slug, entries] of groups) {
|
|
102
|
+
// Pick the best entry: longest content (most complete version)
|
|
103
|
+
entries.sort((a, b) => b.original.content.length - a.original.content.length);
|
|
104
|
+
const best = entries[0];
|
|
105
|
+
|
|
106
|
+
// Build new metadata
|
|
107
|
+
const newMetadata: Record<string, unknown> = {
|
|
108
|
+
...(best.original.metadata || {}),
|
|
109
|
+
decided_at: best.date,
|
|
110
|
+
};
|
|
111
|
+
// Remove old 'date' field if exists (normalize to decided_at)
|
|
112
|
+
if ('date' in newMetadata && newMetadata.date === best.date) {
|
|
113
|
+
delete newMetadata.date;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (DRY_RUN) {
|
|
117
|
+
console.log(
|
|
118
|
+
` [DRY] ${best.original.sub_key} → ${slug} (date: ${best.date}, dupes: ${entries.length - 1})`,
|
|
119
|
+
);
|
|
120
|
+
if (entries.length > 1) {
|
|
121
|
+
for (const dup of entries.slice(1)) {
|
|
122
|
+
console.log(
|
|
123
|
+
` ↳ delete dupe: ${dup.original.sub_key} (${dup.original.content.length} chars)`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
migratedCount++;
|
|
128
|
+
deletedDuplicates += entries.length - 1;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Delete ALL entries in this group (including the best one — we'll re-create it)
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
const delResult = await kbDelete(pool, 'semicolon', 'decision', entry.original.sub_key);
|
|
135
|
+
if (!delResult.deleted) {
|
|
136
|
+
console.error(` ❌ Delete failed: ${entry.original.sub_key} — ${delResult.error}`);
|
|
137
|
+
errorCount++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Re-create with clean slug
|
|
142
|
+
const upsertResult = await kbUpsert(pool, {
|
|
143
|
+
domain: 'semicolon',
|
|
144
|
+
key: 'decision',
|
|
145
|
+
sub_key: slug,
|
|
146
|
+
content: best.original.content,
|
|
147
|
+
metadata: newMetadata,
|
|
148
|
+
created_by: best.original.created_by || 'migration-057',
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (upsertResult.success) {
|
|
152
|
+
migratedCount++;
|
|
153
|
+
deletedDuplicates += entries.length - 1;
|
|
154
|
+
} else {
|
|
155
|
+
console.error(` ❌ Upsert failed: ${slug} — ${upsertResult.error}`);
|
|
156
|
+
errorCount++;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(`\n✅ 결과:`);
|
|
161
|
+
console.log(` 마이그레이션: ${migratedCount}개`);
|
|
162
|
+
console.log(` 중복 제거: ${deletedDuplicates}개`);
|
|
163
|
+
console.log(` 에러: ${errorCount}개`);
|
|
164
|
+
if (DRY_RUN) console.log(` ⚠️ DRY-RUN 모드 — 실제 변경 없음`);
|
|
165
|
+
} finally {
|
|
166
|
+
await pool.end();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
main().catch((err) => {
|
|
171
|
+
console.error('Migration failed:', err);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- 058: Add incubator-status key to service type schema
|
|
2
|
+
-- Allows semicolony kb upsert {service} incubator-status for tracking incubator checkpoints
|
|
3
|
+
|
|
4
|
+
INSERT INTO semicolony.kb_type_schema
|
|
5
|
+
(type_key, scheme_key, scheme_description, required, key_type, source)
|
|
6
|
+
VALUES
|
|
7
|
+
('service', 'incubator-status', '인큐베이터 진행 상태 (CP, 담당봇, 마지막 활동)', false, 'singleton', 'manual')
|
|
8
|
+
ON CONFLICT (type_key, scheme_key) DO NOTHING;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- 059: Incubator Sessions 테이블
|
|
2
|
+
-- 인큐베이터 프로젝트별 Claude Code 세션 관리
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS semicolony.incubator_sessions (
|
|
5
|
+
service_id TEXT PRIMARY KEY,
|
|
6
|
+
service_name TEXT NOT NULL,
|
|
7
|
+
channel TEXT, -- Slack 채널명
|
|
8
|
+
session_dir TEXT NOT NULL, -- 로컬 세션 디렉토리 경로
|
|
9
|
+
status TEXT NOT NULL DEFAULT 'active' -- active | stopped | archived
|
|
10
|
+
CHECK (status IN ('active', 'stopped', 'archived')),
|
|
11
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
12
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
-- 상태 변경 시 updated_at 자동 갱신
|
|
16
|
+
CREATE OR REPLACE FUNCTION semicolony.update_incubator_sessions_timestamp()
|
|
17
|
+
RETURNS TRIGGER AS $$
|
|
18
|
+
BEGIN
|
|
19
|
+
NEW.updated_at = NOW();
|
|
20
|
+
RETURN NEW;
|
|
21
|
+
END;
|
|
22
|
+
$$ LANGUAGE plpgsql;
|
|
23
|
+
|
|
24
|
+
DROP TRIGGER IF EXISTS trg_incubator_sessions_updated ON semicolony.incubator_sessions;
|
|
25
|
+
CREATE TRIGGER trg_incubator_sessions_updated
|
|
26
|
+
BEFORE UPDATE ON semicolony.incubator_sessions
|
|
27
|
+
FOR EACH ROW EXECUTE FUNCTION semicolony.update_incubator_sessions_timestamp();
|
|
28
|
+
|
|
29
|
+
COMMENT ON TABLE semicolony.incubator_sessions IS '인큐베이터 프로젝트별 Claude Code 세션 메타데이터';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- 060: Skill reference files support
|
|
2
|
+
--
|
|
3
|
+
-- reference_files are stored in metadata JSONB: {"reference_files": {"filename.md": "content..."}}
|
|
4
|
+
-- No schema change needed — metadata is already JSONB.
|
|
5
|
+
-- This migration documents the convention.
|
|
6
|
+
|
|
7
|
+
COMMENT ON COLUMN semicolony.skill_definitions.metadata IS
|
|
8
|
+
'JSONB: bot_ids (text[]), reference_files ({filename: content} map, optional)';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- 061: Cron Trigger Bridge
|
|
2
|
+
-- bot_cron_jobs 테이블에 RemoteTrigger 연동 컬럼 추가
|
|
3
|
+
|
|
4
|
+
ALTER TABLE semicolony.bot_cron_jobs
|
|
5
|
+
ADD COLUMN IF NOT EXISTS trigger_id TEXT,
|
|
6
|
+
ADD COLUMN IF NOT EXISTS deploy_status TEXT DEFAULT 'pending',
|
|
7
|
+
ADD COLUMN IF NOT EXISTS last_deploy_at TIMESTAMPTZ;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- 062: Bot Slack Profiles — KB slack-config 엔트리 시딩
|
|
2
|
+
-- 각 봇의 Slack 표시 정체성(username, icon_emoji)을 KB에 저장.
|
|
3
|
+
-- channel-slack, orchestrator, dashboard가 런타임에 이 데이터를 조회하여
|
|
4
|
+
-- chat:write.customize로 봇 정체성을 표시한다.
|
|
5
|
+
|
|
6
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, metadata, created_by)
|
|
7
|
+
VALUES
|
|
8
|
+
('semiclaw', 'slack-config', '', E'username: SemiClaw\nicon_emoji: \":clipboard:\"', '{}', 'migration-062'),
|
|
9
|
+
('planclaw', 'slack-config', '', E'username: PlanClaw\nicon_emoji: \":bar_chart:\"', '{}', 'migration-062'),
|
|
10
|
+
('designclaw', 'slack-config', '', E'username: DesignClaw\nicon_emoji: \":art:\"', '{}', 'migration-062'),
|
|
11
|
+
('workclaw', 'slack-config', '', E'username: WorkClaw\nicon_emoji: \":hammer_and_wrench:\"', '{}', 'migration-062'),
|
|
12
|
+
('reviewclaw', 'slack-config', '', E'username: ReviewClaw\nicon_emoji: \":mag:\"', '{}', 'migration-062'),
|
|
13
|
+
('infraclaw', 'slack-config', '', E'username: InfraClaw\nicon_emoji: \":gear:\"', '{}', 'migration-062'),
|
|
14
|
+
('growthclaw', 'slack-config', '', E'username: GrowthClaw\nicon_emoji: \":chart_with_upwards_trend:\"', '{}', 'migration-062')
|
|
15
|
+
ON CONFLICT (domain, key, sub_key)
|
|
16
|
+
DO UPDATE SET content = EXCLUDED.content, updated_at = now();
|
|
17
|
+
|
|
18
|
+
-- slack_config scheme의 value_hint 업데이트 (username, icon_emoji 필드 명시)
|
|
19
|
+
UPDATE semicolony.kb_type_schema
|
|
20
|
+
SET value_hint = 'YAML: username, icon_emoji, channels[]'
|
|
21
|
+
WHERE type_key = 'bot' AND scheme_key = 'slack-config';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- GFP → 프로젝트 파이프라인 용어 통합: skill_definitions 리네이밍
|
|
2
|
+
-- See: semicolon/decision/gfp-terminology-removal
|
|
3
|
+
|
|
4
|
+
UPDATE semicolony.skill_definitions
|
|
5
|
+
SET name = 'service-project-manager',
|
|
6
|
+
prompt = REPLACE(prompt, '/api/gfp', '/api/projects')
|
|
7
|
+
WHERE name = 'gfp-manager';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS semicolony.bot_cost_log (
|
|
2
|
+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
3
|
+
bot_id TEXT NOT NULL,
|
|
4
|
+
cost_usd NUMERIC(10,6) NOT NULL,
|
|
5
|
+
service_id TEXT,
|
|
6
|
+
model TEXT,
|
|
7
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_bot_cost_log_created ON semicolony.bot_cost_log (created_at);
|
|
11
|
+
CREATE INDEX IF NOT EXISTS idx_bot_cost_log_bot_day ON semicolony.bot_cost_log (bot_id, created_at);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- Hub-and-Spoke 오케스트레이션 지원 스키마 확장
|
|
2
|
+
-- Phase 2: bot_commitments 세션 점유 컬럼
|
|
3
|
+
-- Phase 3: bot_sessions 라이프사이클 추적 컬럼
|
|
4
|
+
-- Phase 5: KB optimistic locking은 CLI 레벨에서 처리 (스키마 변경 불필요, version 컬럼 기존재)
|
|
5
|
+
|
|
6
|
+
-- ── Phase 2: bot_commitments 확장 ──
|
|
7
|
+
|
|
8
|
+
ALTER TABLE semicolony.bot_commitments
|
|
9
|
+
ADD COLUMN IF NOT EXISTS assigned_session TEXT,
|
|
10
|
+
ADD COLUMN IF NOT EXISTS session_owner TEXT,
|
|
11
|
+
ADD COLUMN IF NOT EXISTS pipeline_context JSONB DEFAULT '{}';
|
|
12
|
+
|
|
13
|
+
COMMENT ON COLUMN semicolony.bot_commitments.assigned_session IS '이 commitment를 처리 중인 세션 키';
|
|
14
|
+
COMMENT ON COLUMN semicolony.bot_commitments.session_owner IS '세션 소유자 ({user}-local, {bot}-cron-local 등)';
|
|
15
|
+
COMMENT ON COLUMN semicolony.bot_commitments.pipeline_context IS '파이프라인 컨텍스트 (service_id, phase, section_key 등)';
|
|
16
|
+
|
|
17
|
+
-- ── Phase 3: bot_sessions 확장 ──
|
|
18
|
+
|
|
19
|
+
ALTER TABLE semicolony.bot_sessions
|
|
20
|
+
ADD COLUMN IF NOT EXISTS owner TEXT,
|
|
21
|
+
ADD COLUMN IF NOT EXISTS environment TEXT DEFAULT 'claude-code',
|
|
22
|
+
ADD COLUMN IF NOT EXISTS status TEXT DEFAULT 'active',
|
|
23
|
+
ADD COLUMN IF NOT EXISTS spawned_by TEXT,
|
|
24
|
+
ADD COLUMN IF NOT EXISTS started_at TIMESTAMPTZ DEFAULT NOW(),
|
|
25
|
+
ADD COLUMN IF NOT EXISTS ended_at TIMESTAMPTZ,
|
|
26
|
+
ADD COLUMN IF NOT EXISTS context JSONB DEFAULT '{}';
|
|
27
|
+
|
|
28
|
+
COMMENT ON COLUMN semicolony.bot_sessions.owner IS '세션 소유자 ({user}-local, {bot}-cron-local 등)';
|
|
29
|
+
COMMENT ON COLUMN semicolony.bot_sessions.environment IS '실행 환경 (claude-code, agent-sdk, openclaw)';
|
|
30
|
+
COMMENT ON COLUMN semicolony.bot_sessions.status IS '세션 상태 (active, idle, terminated)';
|
|
31
|
+
COMMENT ON COLUMN semicolony.bot_sessions.spawned_by IS '이 세션을 생성한 상위 세션 키';
|
|
32
|
+
|
|
33
|
+
-- 활성 세션 인덱스
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_bot_sessions_active
|
|
35
|
+
ON semicolony.bot_sessions (bot_id, status) WHERE status = 'active';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- bot_cost_log에 commitment 연동 컬럼 추가
|
|
2
|
+
-- commitment별 비용 집계 및 에스컬레이션 depth 추적
|
|
3
|
+
|
|
4
|
+
ALTER TABLE semicolony.bot_cost_log
|
|
5
|
+
ADD COLUMN IF NOT EXISTS commitment_id TEXT,
|
|
6
|
+
ADD COLUMN IF NOT EXISTS dispatch_depth INT DEFAULT 0;
|
|
7
|
+
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_cost_log_commitment
|
|
9
|
+
ON semicolony.bot_cost_log (commitment_id) WHERE commitment_id IS NOT NULL;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- 067: module 온톨로지 타입 도입
|
|
2
|
+
-- 플랫폼(semicolony) 하위 서브시스템(incubator, voice, meeting, agents 등)을 위한 전용 타입.
|
|
3
|
+
-- parent 컬럼 활성화로 계층 구조 지원.
|
|
4
|
+
|
|
5
|
+
BEGIN;
|
|
6
|
+
|
|
7
|
+
-- 1. module 타입 등록
|
|
8
|
+
INSERT INTO semicolony.ontology_types (type_key, schema, description)
|
|
9
|
+
VALUES ('module', '{}', '플랫폼 하위 모듈/서브시스템')
|
|
10
|
+
ON CONFLICT (type_key) DO NOTHING;
|
|
11
|
+
|
|
12
|
+
-- 2. module 스키마 키 등록
|
|
13
|
+
-- spec은 manual (projection 아님) — 모듈은 PM 파이프라인 밖에서 직접 관리
|
|
14
|
+
INSERT INTO semicolony.kb_type_schema (type_key, scheme_key, key_type, required, scheme_description, sort_order, source) VALUES
|
|
15
|
+
('module', 'base-information', 'singleton', true, '모듈 개요', 1, 'manual'),
|
|
16
|
+
('module', 'status', 'singleton', true, '상태 (active/hold/deprecated)', 2, 'manual'),
|
|
17
|
+
('module', 'tech-stack', 'singleton', false, '기술 스택', 3, 'manual'),
|
|
18
|
+
('module', 'repo', 'singleton', false, 'GitHub 레포지토리', 4, 'manual'),
|
|
19
|
+
('module', 'slack-channel', 'singleton', false, 'Slack 채널', 5, 'manual'),
|
|
20
|
+
('module', 'reference', 'collection', false, '참조 문서', 10, 'manual'),
|
|
21
|
+
('module', 'spec', 'collection', false, '스펙 (수동 관리)', 11, 'manual'),
|
|
22
|
+
('module', 'decision', 'collection', false, '의사결정 기록', 12, 'manual'),
|
|
23
|
+
('module', 'process', 'collection', false, '프로세스', 13, 'manual'),
|
|
24
|
+
('module', 'incident', 'collection', false, '인시던트', 14, 'manual')
|
|
25
|
+
ON CONFLICT (type_key, scheme_key) DO NOTHING;
|
|
26
|
+
|
|
27
|
+
-- 3. parent 컬럼 인덱스 (컬럼은 migration 016에서 이미 추가됨)
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_ontology_parent
|
|
29
|
+
ON semicolony.ontology(parent) WHERE parent IS NOT NULL;
|
|
30
|
+
|
|
31
|
+
-- 4. semicolony-incubator 도메인 등록
|
|
32
|
+
INSERT INTO semicolony.ontology (domain, entity_type, description, service, parent, tags, schema)
|
|
33
|
+
VALUES (
|
|
34
|
+
'semicolony-incubator',
|
|
35
|
+
'module',
|
|
36
|
+
'SEMICOLONY Incubator — 세모 인큐베이터. SEMICOLONY 봇팀 인프라를 활용한 서비스 기획/개발 프로그램.',
|
|
37
|
+
'semicolony',
|
|
38
|
+
'semicolony',
|
|
39
|
+
ARRAY['module', 'incubator'],
|
|
40
|
+
'{}'
|
|
41
|
+
)
|
|
42
|
+
ON CONFLICT (domain) DO NOTHING;
|
|
43
|
+
|
|
44
|
+
COMMIT;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- 068: 인큐베이터 KB 데이터를 semicolony-incubator 모듈 도메인으로 이동
|
|
2
|
+
-- 의존: 067_module_ontology_type.sql (semicolony-incubator 도메인 등록)
|
|
3
|
+
|
|
4
|
+
BEGIN;
|
|
5
|
+
|
|
6
|
+
-- 1. semicolony/project/semicolony-incubator → semicolony-incubator/base-information
|
|
7
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, metadata, created_by, embedding)
|
|
8
|
+
SELECT 'semicolony-incubator', 'base-information', '', content, metadata, 'migration-068', embedding
|
|
9
|
+
FROM semicolony.knowledge_base
|
|
10
|
+
WHERE domain = 'semicolony' AND key = 'project' AND sub_key = 'semicolony-incubator'
|
|
11
|
+
ON CONFLICT (domain, key, sub_key) DO UPDATE
|
|
12
|
+
SET content = EXCLUDED.content, metadata = EXCLUDED.metadata, embedding = EXCLUDED.embedding;
|
|
13
|
+
|
|
14
|
+
-- 2. semicolony/reference/incubator-sandbox → semicolony-incubator/reference/sandbox
|
|
15
|
+
INSERT INTO semicolony.knowledge_base (domain, key, sub_key, content, metadata, created_by, embedding)
|
|
16
|
+
SELECT 'semicolony-incubator', 'reference', 'sandbox', content, metadata, 'migration-068', embedding
|
|
17
|
+
FROM semicolony.knowledge_base
|
|
18
|
+
WHERE domain = 'semicolony' AND key = 'reference' AND sub_key = 'incubator-sandbox'
|
|
19
|
+
ON CONFLICT (domain, key, sub_key) DO UPDATE
|
|
20
|
+
SET content = EXCLUDED.content, metadata = EXCLUDED.metadata, embedding = EXCLUDED.embedding;
|
|
21
|
+
|
|
22
|
+
-- 3. 원본 삭제
|
|
23
|
+
DELETE FROM semicolony.knowledge_base
|
|
24
|
+
WHERE domain = 'semicolony' AND key = 'project' AND sub_key = 'semicolony-incubator';
|
|
25
|
+
|
|
26
|
+
DELETE FROM semicolony.knowledge_base
|
|
27
|
+
WHERE domain = 'semicolony' AND key = 'reference' AND sub_key = 'incubator-sandbox';
|
|
28
|
+
|
|
29
|
+
-- glossary(semicolon/glossary/semicolony-incubator), decision(semicolon/decision/semicolony-incubator-naming)은
|
|
30
|
+
-- 조직 레벨 지식이므로 semicolon에 유지
|
|
31
|
+
|
|
32
|
+
COMMIT;
|