@team-semicolon/semicolony-cli 4.18.65 → 4.18.67
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/dist/bundle.js +909 -912
- package/migrations/172_bot_cost_log_api_equivalent.sql +74 -0
- package/migrations/173_bot_cost_log_worker_grants.sql +29 -0
- package/migrations/174_worker_fleet_board_grants.sql +77 -0
- package/migrations/175_hive_cron_board_grants.sql +16 -0
- package/migrations/176_kf_ops_observer_principal.sql +76 -0
- package/migrations/README.md +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
-- 172: bot_cost_log — API-equivalent 지표 분리 + 캐시 TTL 버킷
|
|
2
|
+
--
|
|
3
|
+
-- 배경 (2026-07-21 실측, semo-ops/docs/superpowers/specs/2026-07-21-ai-usage-tracking-design.md):
|
|
4
|
+
-- 1. cost_usd 는 NOT NULL 이라 "단가 미상"을 표현할 수 없다. 현행 metrics.ts 는 단가를
|
|
5
|
+
-- 찾지 못하면 0 을 기록해, 집계에서 "비용 없음"과 구분되지 않는다. 미상은 NULL 이어야 한다.
|
|
6
|
+
-- 2. cost_usd 에 들어가던 값은 실제 청구액이 아니라 API 정가 환산치다. 구독 표면에서는
|
|
7
|
+
-- 실지출의 약 200배(측정: 월 환산 $41k vs Claude Max 구독료)라, "cost"라는 이름이
|
|
8
|
+
-- 예산·가격 판단을 오도한다. api_equivalent_usd 로 의미를 분리한다.
|
|
9
|
+
-- 3. 캐시 쓰기 단가는 TTL 에 따라 1.25배(5분)와 2배(1시간)로 갈린다. 총합만 저장하면
|
|
10
|
+
-- 환산 오차가 최대 1.6배가 되는데, 실측상 소비의 대부분이 캐시다.
|
|
11
|
+
--
|
|
12
|
+
-- 기존 행은 건드리지 않는다. cost_usd 는 레거시 값 보존용으로 남기고, 신규 적재는
|
|
13
|
+
-- api_equivalent_usd 만 채운다.
|
|
14
|
+
--
|
|
15
|
+
-- 러너가 트랜잭션 경계를 제공하므로 여기서 BEGIN/COMMIT 을 열지 않는다.
|
|
16
|
+
|
|
17
|
+
ALTER TABLE semicolony.bot_cost_log
|
|
18
|
+
ALTER COLUMN cost_usd DROP NOT NULL,
|
|
19
|
+
ADD COLUMN IF NOT EXISTS api_equivalent_usd NUMERIC(12,6),
|
|
20
|
+
ADD COLUMN IF NOT EXISTS cache_creation_1h_tokens INT,
|
|
21
|
+
ADD COLUMN IF NOT EXISTS cache_creation_5m_tokens INT;
|
|
22
|
+
|
|
23
|
+
COMMENT ON COLUMN semicolony.bot_cost_log.api_equivalent_usd IS
|
|
24
|
+
'API list-price equivalent of consumption. NOT actual billed spend: on subscription '
|
|
25
|
+
'surfaces it exceeds real cost by ~200x (measured 2026-07-21). Never sum with ledger '
|
|
26
|
+
'actuals. NULL means the model had no pricing entry — never write 0 for unknown.';
|
|
27
|
+
|
|
28
|
+
COMMENT ON COLUMN semicolony.bot_cost_log.cost_usd IS
|
|
29
|
+
'Legacy column (pre-2026-07-21). Retained for historical rows; new writers use '
|
|
30
|
+
'api_equivalent_usd. Historical values are unreliable — prefix matching priced '
|
|
31
|
+
'claude-opus-4-8 at claude-opus-4 rates.';
|
|
32
|
+
|
|
33
|
+
COMMENT ON COLUMN semicolony.bot_cost_log.cache_creation_1h_tokens IS
|
|
34
|
+
'Cache-write tokens at 1h TTL (2x base input rate). NULL when the source did not '
|
|
35
|
+
'report a TTL breakdown.';
|
|
36
|
+
|
|
37
|
+
COMMENT ON COLUMN semicolony.bot_cost_log.cache_creation_5m_tokens IS
|
|
38
|
+
'Cache-write tokens at 5m TTL (1.25x base input rate). NULL when the source did not '
|
|
39
|
+
'report a TTL breakdown.';
|
|
40
|
+
|
|
41
|
+
-- 뷰 재생성: api_equivalent_usd 와 캐시 토큰 노출.
|
|
42
|
+
-- 기존 컬럼과 순서를 유지하고 뒤에 추가하므로 기존 조회는 그대로 동작한다.
|
|
43
|
+
DROP VIEW IF EXISTS semicolony.bot_cost_daily;
|
|
44
|
+
DROP VIEW IF EXISTS semicolony.bot_cost_summary;
|
|
45
|
+
|
|
46
|
+
CREATE VIEW semicolony.bot_cost_daily AS
|
|
47
|
+
SELECT bot_id,
|
|
48
|
+
created_at::date AS day,
|
|
49
|
+
count(*) AS query_count,
|
|
50
|
+
COALESCE(sum(input_tokens), 0::bigint) AS total_input_tokens,
|
|
51
|
+
COALESCE(sum(output_tokens), 0::bigint) AS total_output_tokens,
|
|
52
|
+
COALESCE(sum(cost_usd), 0::numeric) AS total_cost_usd,
|
|
53
|
+
sum(api_equivalent_usd) AS total_api_equivalent_usd,
|
|
54
|
+
COALESCE(sum(cache_read_tokens), 0::bigint) AS total_cache_read_tokens,
|
|
55
|
+
COALESCE(sum(cache_creation_tokens), 0::bigint) AS total_cache_creation_tokens
|
|
56
|
+
FROM semicolony.bot_cost_log
|
|
57
|
+
GROUP BY bot_id, (created_at::date);
|
|
58
|
+
|
|
59
|
+
CREATE VIEW semicolony.bot_cost_summary AS
|
|
60
|
+
SELECT bot_id,
|
|
61
|
+
date_trunc('month'::text, created_at)::date AS month,
|
|
62
|
+
count(*) AS query_count,
|
|
63
|
+
COALESCE(sum(input_tokens), 0::bigint) AS total_input_tokens,
|
|
64
|
+
COALESCE(sum(output_tokens), 0::bigint) AS total_output_tokens,
|
|
65
|
+
COALESCE(sum(cost_usd), 0::numeric) AS total_cost_usd,
|
|
66
|
+
COALESCE(avg(duration_ms), 0::numeric)::integer AS avg_latency_ms,
|
|
67
|
+
sum(api_equivalent_usd) AS total_api_equivalent_usd,
|
|
68
|
+
COALESCE(sum(cache_read_tokens), 0::bigint) AS total_cache_read_tokens,
|
|
69
|
+
COALESCE(sum(cache_creation_tokens), 0::bigint) AS total_cache_creation_tokens
|
|
70
|
+
FROM semicolony.bot_cost_log
|
|
71
|
+
GROUP BY bot_id, (date_trunc('month'::text, created_at));
|
|
72
|
+
|
|
73
|
+
-- sum(api_equivalent_usd) 은 COALESCE 하지 않는다. 전 행이 미상이면 NULL 이 나와야
|
|
74
|
+
-- "환산 불가"가 집계에서도 0 과 구분된다.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- 173: bot_cost_log — sc_app 최소권한 부여 (SEMO Ops 워커 usage 적재)
|
|
2
|
+
--
|
|
3
|
+
-- 배경: SEMO Ops 워커의 토큰 소비량 배치가 bot_cost_log 로 flush 한다.
|
|
4
|
+
-- 워커의 DATABASE_URL 은 sc_app 이며, 2026-07-21 실측 기준 이 테이블에 SELECT/INSERT
|
|
5
|
+
-- 모두 없다 (has_table_privilege(sc_app, 'semicolony.bot_cost_log', ...) = false).
|
|
6
|
+
-- 소유자 app 은 superuser 이므로, 일상 적재를 app 으로 돌리지 않고 sc_app 에 최소권한만 준다.
|
|
7
|
+
--
|
|
8
|
+
-- UPDATE/DELETE 는 주지 않는다. 적재는 (session_id, message_id) 부분 유니크 인덱스 기반
|
|
9
|
+
-- ON CONFLICT DO NOTHING 이라 갱신·삭제가 필요 없고, 워커가 과거 기록을 고칠 이유도 없다.
|
|
10
|
+
--
|
|
11
|
+
-- id 는 GENERATED ALWAYS AS IDENTITY 이므로 별도 시퀀스 권한이 필요 없다.
|
|
12
|
+
--
|
|
13
|
+
-- 러너가 트랜잭션 경계를 제공하므로 여기서 BEGIN/COMMIT 을 열지 않는다.
|
|
14
|
+
|
|
15
|
+
DO $$
|
|
16
|
+
BEGIN
|
|
17
|
+
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'sc_app') THEN
|
|
18
|
+
RAISE EXCEPTION 'sc_app role missing; cannot grant worker usage privileges';
|
|
19
|
+
END IF;
|
|
20
|
+
|
|
21
|
+
IF (SELECT rolsuper FROM pg_roles WHERE rolname = 'sc_app') THEN
|
|
22
|
+
RAISE EXCEPTION 'sc_app unexpectedly holds superuser; refusing to widen an already-privileged role';
|
|
23
|
+
END IF;
|
|
24
|
+
END
|
|
25
|
+
$$;
|
|
26
|
+
|
|
27
|
+
GRANT SELECT, INSERT ON semicolony.bot_cost_log TO sc_app;
|
|
28
|
+
GRANT SELECT ON semicolony.bot_cost_daily TO sc_app;
|
|
29
|
+
GRANT SELECT ON semicolony.bot_cost_summary TO sc_app;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
-- 174_worker_fleet_board_grants.sql
|
|
2
|
+
--
|
|
3
|
+
-- SEMO Ops 워커 플릿 상황판 전용 DB 롤과 감사 테이블.
|
|
4
|
+
--
|
|
5
|
+
-- 설계: semo-ops docs/superpowers/specs/2026-07-29-semo-ops-worker-fleet-board-design.md
|
|
6
|
+
--
|
|
7
|
+
-- 원칙:
|
|
8
|
+
-- - 대시보드는 admin 롤(app)을 재사용하지 않는다. 전용 롤만 쓴다.
|
|
9
|
+
-- - 쓰기는 "결정 컬럼"으로 제한한다. Gateway(sc_app)가 쓰는 "보고 컬럼"
|
|
10
|
+
-- (applied_release_*, applied_at, last_seen_at, last_doctor_*)은 주지 않는다.
|
|
11
|
+
-- 두 쓰기 주체의 컬럼이 겹치지 않아야 충돌이 구조적으로 불가능하다.
|
|
12
|
+
-- - 비밀번호는 여기서 설정하지 않는다. 운영자가 out-of-band로 ALTER ROLE 한다.
|
|
13
|
+
--
|
|
14
|
+
-- 스키마: semo_ops (team_knowledge_fabric DB). 대시보드 본체가 쓰는 appdb 의
|
|
15
|
+
-- `semicolony` 스키마와 다른 곳이다 — 워커 레지스트리는 Knowledge Fabric 이관으로
|
|
16
|
+
-- semo_ops 에 있다. 과거 마이그레이션(144·167·171)이 `semicolony.` 를 쓰는 것은
|
|
17
|
+
-- 이름 변경 이전에 적용됐기 때문이며, 신규 마이그레이션은 현행 이름을 쓴다.
|
|
18
|
+
--
|
|
19
|
+
-- Safety: additive only. Runner가 BEGIN/COMMIT으로 감싸므로 트랜잭션 구문을 넣지 않는다.
|
|
20
|
+
|
|
21
|
+
DO $$
|
|
22
|
+
BEGIN
|
|
23
|
+
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'sc_fleet_board') THEN
|
|
24
|
+
CREATE ROLE sc_fleet_board LOGIN NOINHERIT;
|
|
25
|
+
END IF;
|
|
26
|
+
END
|
|
27
|
+
$$;
|
|
28
|
+
|
|
29
|
+
COMMENT ON ROLE sc_fleet_board IS
|
|
30
|
+
'SEMO Ops fleet board (dashboard) role. Read-mostly on the worker registry; writes limited to decision columns.';
|
|
31
|
+
|
|
32
|
+
-- LOGIN 롤이라도 CONNECT 권한이 없으면 접속 자체가 거부된다. DB 이름은 환경마다
|
|
33
|
+
-- 다르므로 current_database() 로 동적 부여한다.
|
|
34
|
+
DO $$
|
|
35
|
+
BEGIN
|
|
36
|
+
EXECUTE format('GRANT CONNECT ON DATABASE %I TO sc_fleet_board', current_database());
|
|
37
|
+
END
|
|
38
|
+
$$;
|
|
39
|
+
|
|
40
|
+
GRANT USAGE ON SCHEMA semo_ops TO sc_fleet_board;
|
|
41
|
+
|
|
42
|
+
-- 읽기: 보드가 렌더하는 것 전부.
|
|
43
|
+
GRANT SELECT ON TABLE semo_ops.worker_devices TO sc_fleet_board;
|
|
44
|
+
GRANT SELECT ON TABLE semo_ops.local_hives TO sc_fleet_board;
|
|
45
|
+
GRANT SELECT ON TABLE semo_ops.workspace_profiles TO sc_fleet_board;
|
|
46
|
+
GRANT SELECT ON TABLE semo_ops.worker_profile_releases TO sc_fleet_board;
|
|
47
|
+
|
|
48
|
+
-- 토큰 만료 판정에 필요한 컬럼만. token_hash 는 주지 않는다.
|
|
49
|
+
GRANT SELECT (id, token_prefix, scopes, status, issued_at, expires_at, last_used_at, issued_by)
|
|
50
|
+
ON TABLE semo_ops.gateway_credentials TO sc_fleet_board;
|
|
51
|
+
|
|
52
|
+
-- 쓰기: 결정 컬럼만.
|
|
53
|
+
GRANT UPDATE (status) ON TABLE semo_ops.worker_devices TO sc_fleet_board;
|
|
54
|
+
GRANT UPDATE (status, expiry_at) ON TABLE semo_ops.local_hives TO sc_fleet_board;
|
|
55
|
+
GRANT UPDATE (active_release_id) ON TABLE semo_ops.workspace_profiles TO sc_fleet_board;
|
|
56
|
+
|
|
57
|
+
-- 오퍼레이터 액션 감사. 액션과 같은 트랜잭션에서 기록한다.
|
|
58
|
+
CREATE TABLE IF NOT EXISTS semo_ops.worker_fleet_audits (
|
|
59
|
+
id BIGSERIAL PRIMARY KEY,
|
|
60
|
+
actor_email TEXT NOT NULL,
|
|
61
|
+
action TEXT NOT NULL
|
|
62
|
+
CHECK (action IN ('device.status', 'local_hive.status', 'local_hive.expiry', 'release.activate')),
|
|
63
|
+
target_kind TEXT NOT NULL CHECK (target_kind IN ('device', 'local_hive', 'profile')),
|
|
64
|
+
target_id TEXT NOT NULL,
|
|
65
|
+
before JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
66
|
+
after JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
67
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
COMMENT ON TABLE semo_ops.worker_fleet_audits IS
|
|
71
|
+
'Operator actions taken from the SEMO Ops fleet board. Append-only.';
|
|
72
|
+
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_worker_fleet_audits_target
|
|
74
|
+
ON semo_ops.worker_fleet_audits (target_kind, target_id, created_at DESC);
|
|
75
|
+
|
|
76
|
+
GRANT SELECT, INSERT ON TABLE semo_ops.worker_fleet_audits TO sc_fleet_board;
|
|
77
|
+
GRANT USAGE ON SEQUENCE semo_ops.worker_fleet_audits_id_seq TO sc_fleet_board;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- 175_hive_cron_board_grants.sql
|
|
2
|
+
--
|
|
3
|
+
-- SEMO Ops hive-cron 실행 관측 보드의 읽기 권한.
|
|
4
|
+
--
|
|
5
|
+
-- 설계: semo-ops docs/superpowers/specs/2026-07-29-semo-ops-worker-fleet-board-design.md
|
|
6
|
+
-- (같은 ops 표면의 두 번째 조각)
|
|
7
|
+
--
|
|
8
|
+
-- 원칙:
|
|
9
|
+
-- - 관측 전용이다. 쓰기 권한을 주지 않는다 — 크론 잡 활성/비활성은 이 보드의
|
|
10
|
+
-- 범위가 아니며, 권한을 미리 열어두지 않는다.
|
|
11
|
+
-- - 스키마는 174 와 같은 semo_ops (team_knowledge_fabric DB).
|
|
12
|
+
--
|
|
13
|
+
-- Safety: additive only. Runner가 BEGIN/COMMIT으로 감싸므로 트랜잭션 구문을 넣지 않는다.
|
|
14
|
+
|
|
15
|
+
GRANT SELECT ON TABLE semo_ops.hive_cron_jobs TO sc_fleet_board;
|
|
16
|
+
GRANT SELECT ON TABLE semo_ops.hive_cron_job_runs TO sc_fleet_board;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
-- 176_kf_ops_observer_principal.sql
|
|
2
|
+
--
|
|
3
|
+
-- Knowledge Fabric 임포트 관측용 전용 principal.
|
|
4
|
+
--
|
|
5
|
+
-- 배경: knowledge_fabric 테이블은 FORCE RLS 에 명시적 principal 모델
|
|
6
|
+
-- (owner / app / import_verifier / migrator / query_issuer)을 갖춘 격리
|
|
7
|
+
-- 서브시스템이다. 대시보드 롤(sc_fleet_board)에 GRANT 만 주면 정책 대상이
|
|
8
|
+
-- 아니라 0행만 보인다(2026-07-29 실측). 그래서 GRANT 를 얹는 대신 기존
|
|
9
|
+
-- 규약대로 **전용 principal 을 신설**한다.
|
|
10
|
+
--
|
|
11
|
+
-- 경계:
|
|
12
|
+
-- - SELECT 전용. 쓰기 명령은 정책 자체를 만들지 않는다.
|
|
13
|
+
-- - 대상 테이블 3개(batches/events/items)로 한정한다. relation·approval·
|
|
14
|
+
-- projection 계열은 건드리지 않는다.
|
|
15
|
+
-- - items 는 지식 본문(envelope, record_document)과 acl 을 담고 있어
|
|
16
|
+
-- **집계에 필요한 두 컬럼만** 준다. 본문은 이 principal 로 읽을 수 없다.
|
|
17
|
+
-- - bypassrls 를 주지 않는다. 다른 KF principal 과 같은 지위다.
|
|
18
|
+
--
|
|
19
|
+
-- 정책 술어를 scope GUC 가 아니라 true 로 두는 이유: 이 principal 의 용도가
|
|
20
|
+
-- "임포트 원장 전체를 관측"하는 것이라, scope 를 하나씩 지정하면 새 scope 가
|
|
21
|
+
-- 생겼을 때 보드에서 조용히 사라진다 — 관측 보드에서 가장 위험한 실패다.
|
|
22
|
+
-- SELECT 전용 + 컬럼 제한이라 owner(ALL 명령) 보다 엄격하게 유지된다.
|
|
23
|
+
--
|
|
24
|
+
-- Safety: additive only. Runner가 BEGIN/COMMIT으로 감싸므로 트랜잭션 구문을 넣지 않는다.
|
|
25
|
+
|
|
26
|
+
DO $$
|
|
27
|
+
BEGIN
|
|
28
|
+
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'team_knowledge_fabric_ops_observer') THEN
|
|
29
|
+
CREATE ROLE team_knowledge_fabric_ops_observer LOGIN NOINHERIT;
|
|
30
|
+
END IF;
|
|
31
|
+
END
|
|
32
|
+
$$;
|
|
33
|
+
|
|
34
|
+
COMMENT ON ROLE team_knowledge_fabric_ops_observer IS
|
|
35
|
+
'Read-only observation principal for the SEMO Ops import board. SELECT only, no knowledge bodies.';
|
|
36
|
+
|
|
37
|
+
DO $$
|
|
38
|
+
BEGIN
|
|
39
|
+
EXECUTE format(
|
|
40
|
+
'GRANT CONNECT ON DATABASE %I TO team_knowledge_fabric_ops_observer',
|
|
41
|
+
current_database()
|
|
42
|
+
);
|
|
43
|
+
END
|
|
44
|
+
$$;
|
|
45
|
+
|
|
46
|
+
GRANT USAGE ON SCHEMA knowledge_fabric TO team_knowledge_fabric_ops_observer;
|
|
47
|
+
|
|
48
|
+
GRANT SELECT ON TABLE knowledge_fabric.knowledge_import_batches
|
|
49
|
+
TO team_knowledge_fabric_ops_observer;
|
|
50
|
+
GRANT SELECT ON TABLE knowledge_fabric.knowledge_import_events
|
|
51
|
+
TO team_knowledge_fabric_ops_observer;
|
|
52
|
+
|
|
53
|
+
-- 본문·ACL 제외. 집계에 필요한 컬럼만.
|
|
54
|
+
GRANT SELECT (scope_id, batch_id) ON TABLE knowledge_fabric.knowledge_import_items
|
|
55
|
+
TO team_knowledge_fabric_ops_observer;
|
|
56
|
+
|
|
57
|
+
DROP POLICY IF EXISTS knowledge_import_batches_ops_observer_read
|
|
58
|
+
ON knowledge_fabric.knowledge_import_batches;
|
|
59
|
+
CREATE POLICY knowledge_import_batches_ops_observer_read
|
|
60
|
+
ON knowledge_fabric.knowledge_import_batches
|
|
61
|
+
FOR SELECT TO team_knowledge_fabric_ops_observer
|
|
62
|
+
USING (true);
|
|
63
|
+
|
|
64
|
+
DROP POLICY IF EXISTS knowledge_import_events_ops_observer_read
|
|
65
|
+
ON knowledge_fabric.knowledge_import_events;
|
|
66
|
+
CREATE POLICY knowledge_import_events_ops_observer_read
|
|
67
|
+
ON knowledge_fabric.knowledge_import_events
|
|
68
|
+
FOR SELECT TO team_knowledge_fabric_ops_observer
|
|
69
|
+
USING (true);
|
|
70
|
+
|
|
71
|
+
DROP POLICY IF EXISTS knowledge_import_items_ops_observer_read
|
|
72
|
+
ON knowledge_fabric.knowledge_import_items;
|
|
73
|
+
CREATE POLICY knowledge_import_items_ops_observer_read
|
|
74
|
+
ON knowledge_fabric.knowledge_import_items
|
|
75
|
+
FOR SELECT TO team_knowledge_fabric_ops_observer
|
|
76
|
+
USING (true);
|
package/migrations/README.md
CHANGED
|
@@ -18,6 +18,7 @@ SEMICOLONY CLI의 PostgreSQL 마이그레이션 파일들.
|
|
|
18
18
|
| `166_lease_operations_retire.sql` | `skill_capability_leases` profile→operations CHECK 재생성: operate 프로필에 `skills.release.retire` 추가 |
|
|
19
19
|
| `169_worker_profile_releases.sql` | Immutable SEMO Ops worker profile releases and device rollout state |
|
|
20
20
|
| `170_worker_release_credential_scopes.sql` | Worker credential owner 함수의 허용 범위에 release read/report scope 추가 |
|
|
21
|
+
| `174_worker_fleet_board_grants.sql` | 플릿 상황판 전용 롤 `sc_fleet_board` + 오퍼레이터 액션 감사 테이블 |
|
|
21
22
|
|
|
22
23
|
## 007: Flat Skill Naming
|
|
23
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-semicolon/semicolony-cli",
|
|
3
|
-
"version": "4.18.
|
|
3
|
+
"version": "4.18.67",
|
|
4
4
|
"description": "SemiColony CLI - AI operations and agent orchestration installer",
|
|
5
5
|
"main": "dist/bundle.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"start": "node dist/bundle.js",
|
|
17
17
|
"dev": "ts-node src/index.ts",
|
|
18
18
|
"lint": "eslint src/",
|
|
19
|
+
"pretest": "npm run build",
|
|
19
20
|
"test": "vitest run"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|