@asc-agent/runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +22 -0
- package/dist/adapters/claude-code/binding.d.ts +5 -0
- package/dist/adapters/claude-code/binding.js +14 -0
- package/dist/adapters/claude-code/guard.d.ts +54 -0
- package/dist/adapters/claude-code/guard.js +295 -0
- package/dist/adapters/claude-code/install.d.ts +67 -0
- package/dist/adapters/claude-code/install.js +231 -0
- package/dist/adapters/claude-code/observer.d.ts +38 -0
- package/dist/adapters/claude-code/observer.js +77 -0
- package/dist/adapters/claude-code/probe.d.ts +53 -0
- package/dist/adapters/claude-code/probe.js +129 -0
- package/dist/adapters/claude-code/skill.d.ts +8 -0
- package/dist/adapters/claude-code/skill.js +267 -0
- package/dist/adapters/fixture-work/index.d.ts +34 -0
- package/dist/adapters/fixture-work/index.js +78 -0
- package/dist/adapters/github/adapter.d.ts +32 -0
- package/dist/adapters/github/adapter.js +95 -0
- package/dist/adapters/github/client.d.ts +30 -0
- package/dist/adapters/github/client.js +90 -0
- package/dist/adapters/github/context.d.ts +44 -0
- package/dist/adapters/github/context.js +170 -0
- package/dist/adapters/github/event-source.d.ts +55 -0
- package/dist/adapters/github/event-source.js +183 -0
- package/dist/adapters/github/scm.d.ts +50 -0
- package/dist/adapters/github/scm.js +104 -0
- package/dist/adapters/gitlab/adapter.d.ts +36 -0
- package/dist/adapters/gitlab/adapter.js +117 -0
- package/dist/adapters/gitlab/client.d.ts +30 -0
- package/dist/adapters/gitlab/client.js +47 -0
- package/dist/adapters/gitlab/ports.d.ts +40 -0
- package/dist/adapters/gitlab/ports.js +186 -0
- package/dist/adapters/jam/adapter.d.ts +53 -0
- package/dist/adapters/jam/adapter.js +144 -0
- package/dist/adapters/jam/event-source.d.ts +28 -0
- package/dist/adapters/jam/event-source.js +65 -0
- package/dist/adapters/jam/mcp-client.d.ts +50 -0
- package/dist/adapters/jam/mcp-client.js +218 -0
- package/dist/adapters/jam/ports.d.ts +51 -0
- package/dist/adapters/jam/ports.js +167 -0
- package/dist/adapters/local/identity.d.ts +27 -0
- package/dist/adapters/local/identity.js +40 -0
- package/dist/adapters/local/presentation.d.ts +14 -0
- package/dist/adapters/local/presentation.js +42 -0
- package/dist/adapters/markdown/layout.d.ts +15 -0
- package/dist/adapters/markdown/layout.js +49 -0
- package/dist/adapters/markdown/serialize.d.ts +9 -0
- package/dist/adapters/markdown/serialize.js +120 -0
- package/dist/adapters/markdown/state-store.d.ts +23 -0
- package/dist/adapters/markdown/state-store.js +316 -0
- package/dist/adapters/mattermost/client.d.ts +23 -0
- package/dist/adapters/mattermost/client.js +54 -0
- package/dist/adapters/mattermost/presentation.d.ts +43 -0
- package/dist/adapters/mattermost/presentation.js +88 -0
- package/dist/adapters/memory/mocks.d.ts +87 -0
- package/dist/adapters/memory/mocks.js +163 -0
- package/dist/adapters/memory/runtime-binding.d.ts +23 -0
- package/dist/adapters/memory/runtime-binding.js +118 -0
- package/dist/adapters/memory/state-store.d.ts +17 -0
- package/dist/adapters/memory/state-store.js +125 -0
- package/dist/adapters/text/renderer.d.ts +7 -0
- package/dist/adapters/text/renderer.js +81 -0
- package/dist/adapters/webhook/ingress.d.ts +103 -0
- package/dist/adapters/webhook/ingress.js +150 -0
- package/dist/cli/asc.d.ts +16 -0
- package/dist/cli/asc.js +2914 -0
- package/dist/cli/identity-config.d.ts +7 -0
- package/dist/cli/identity-config.js +31 -0
- package/dist/composition/observe.d.ts +21 -0
- package/dist/composition/observe.js +72 -0
- package/dist/composition/registry.d.ts +33 -0
- package/dist/composition/registry.js +62 -0
- package/dist/composition/runtime.d.ts +63 -0
- package/dist/composition/runtime.js +155 -0
- package/dist/core/approval/service.d.ts +17 -0
- package/dist/core/approval/service.js +129 -0
- package/dist/core/attach/bootstrap.d.ts +102 -0
- package/dist/core/attach/bootstrap.js +178 -0
- package/dist/core/attach/init.d.ts +29 -0
- package/dist/core/attach/init.js +100 -0
- package/dist/core/attach/setup-plan.d.ts +125 -0
- package/dist/core/attach/setup-plan.js +177 -0
- package/dist/core/attach/setup.d.ts +40 -0
- package/dist/core/attach/setup.js +140 -0
- package/dist/core/binding/types.d.ts +93 -0
- package/dist/core/binding/types.js +74 -0
- package/dist/core/distribution/release.d.ts +15 -0
- package/dist/core/distribution/release.js +27 -0
- package/dist/core/distribution/runtime-install.d.ts +50 -0
- package/dist/core/distribution/runtime-install.js +90 -0
- package/dist/core/distribution/runtime-select.d.ts +74 -0
- package/dist/core/distribution/runtime-select.js +149 -0
- package/dist/core/execution/executor.d.ts +51 -0
- package/dist/core/execution/executor.js +106 -0
- package/dist/core/execution/grant.d.ts +42 -0
- package/dist/core/execution/grant.js +78 -0
- package/dist/core/model/entities.d.ts +872 -0
- package/dist/core/model/entities.js +285 -0
- package/dist/core/model/ids.d.ts +41 -0
- package/dist/core/model/ids.js +50 -0
- package/dist/core/model/transitions.d.ts +26 -0
- package/dist/core/model/transitions.js +124 -0
- package/dist/core/monitor/coverage.d.ts +111 -0
- package/dist/core/monitor/coverage.js +129 -0
- package/dist/core/monitor/engine.d.ts +134 -0
- package/dist/core/monitor/engine.js +574 -0
- package/dist/core/monitor/health-alerts.d.ts +35 -0
- package/dist/core/monitor/health-alerts.js +88 -0
- package/dist/core/monitor/investigation.d.ts +82 -0
- package/dist/core/monitor/investigation.js +232 -0
- package/dist/core/monitor/observation.d.ts +79 -0
- package/dist/core/monitor/observation.js +110 -0
- package/dist/core/monitor/relevance.d.ts +47 -0
- package/dist/core/monitor/relevance.js +100 -0
- package/dist/core/monitor/signals.d.ts +59 -0
- package/dist/core/monitor/signals.js +105 -0
- package/dist/core/operator/local-operator.d.ts +60 -0
- package/dist/core/operator/local-operator.js +82 -0
- package/dist/core/operator/preflight.d.ts +60 -0
- package/dist/core/operator/preflight.js +139 -0
- package/dist/core/operator/proceed.d.ts +98 -0
- package/dist/core/operator/proceed.js +167 -0
- package/dist/core/operator/progress.d.ts +124 -0
- package/dist/core/operator/progress.js +135 -0
- package/dist/core/operator/render.d.ts +34 -0
- package/dist/core/operator/render.js +170 -0
- package/dist/core/operator/runtime-binding.d.ts +61 -0
- package/dist/core/operator/runtime-binding.js +22 -0
- package/dist/core/policy/ownership.d.ts +44 -0
- package/dist/core/policy/ownership.js +46 -0
- package/dist/core/policy/policy.d.ts +99 -0
- package/dist/core/policy/policy.js +147 -0
- package/dist/core/policy/remote-freeze.d.ts +101 -0
- package/dist/core/policy/remote-freeze.js +151 -0
- package/dist/core/policy/scope.d.ts +23 -0
- package/dist/core/policy/scope.js +93 -0
- package/dist/core/presentation/digest.d.ts +98 -0
- package/dist/core/presentation/digest.js +160 -0
- package/dist/core/resolver/load.d.ts +121 -0
- package/dist/core/resolver/load.js +246 -0
- package/dist/core/resolver/render.d.ts +4 -0
- package/dist/core/resolver/render.js +62 -0
- package/dist/core/resolver/resolve.d.ts +42 -0
- package/dist/core/resolver/resolve.js +51 -0
- package/dist/core/resolver/version.d.ts +22 -0
- package/dist/core/resolver/version.js +49 -0
- package/dist/core/runtime/audit.d.ts +374 -0
- package/dist/core/runtime/audit.js +454 -0
- package/dist/core/runtime/claims.d.ts +115 -0
- package/dist/core/runtime/claims.js +153 -0
- package/dist/core/runtime/closure.d.ts +73 -0
- package/dist/core/runtime/closure.js +162 -0
- package/dist/core/runtime/controller.d.ts +40 -0
- package/dist/core/runtime/controller.js +121 -0
- package/dist/core/runtime/escalation.d.ts +188 -0
- package/dist/core/runtime/escalation.js +322 -0
- package/dist/core/runtime/execution-state.d.ts +43 -0
- package/dist/core/runtime/execution-state.js +81 -0
- package/dist/core/runtime/front.d.ts +95 -0
- package/dist/core/runtime/front.js +144 -0
- package/dist/core/runtime/orchestrator.d.ts +54 -0
- package/dist/core/runtime/orchestrator.js +98 -0
- package/dist/core/runtime/query.d.ts +184 -0
- package/dist/core/runtime/query.js +213 -0
- package/dist/core/runtime/report.d.ts +33 -0
- package/dist/core/runtime/report.js +108 -0
- package/dist/core/runtime/session.d.ts +156 -0
- package/dist/core/runtime/session.js +281 -0
- package/dist/core/runtime/store-ops.d.ts +22 -0
- package/dist/core/runtime/store-ops.js +26 -0
- package/dist/core/view/build-view.d.ts +36 -0
- package/dist/core/view/build-view.js +131 -0
- package/dist/core/view/decision-view.d.ts +564 -0
- package/dist/core/view/decision-view.js +103 -0
- package/dist/core/workspace/identity.d.ts +82 -0
- package/dist/core/workspace/identity.js +133 -0
- package/dist/core/workspace/index-store.d.ts +140 -0
- package/dist/core/workspace/index-store.js +125 -0
- package/dist/core/workspace/migrate.d.ts +73 -0
- package/dist/core/workspace/migrate.js +123 -0
- package/dist/core/workspace/resolve.d.ts +34 -0
- package/dist/core/workspace/resolve.js +89 -0
- package/dist/ports/adapter.d.ts +35 -0
- package/dist/ports/adapter.js +12 -0
- package/dist/ports/approval.d.ts +98 -0
- package/dist/ports/approval.js +7 -0
- package/dist/ports/change-context.d.ts +22 -0
- package/dist/ports/change-context.js +8 -0
- package/dist/ports/event-source.d.ts +42 -0
- package/dist/ports/event-source.js +6 -0
- package/dist/ports/inventory.d.ts +53 -0
- package/dist/ports/inventory.js +12 -0
- package/dist/ports/presentation.d.ts +62 -0
- package/dist/ports/presentation.js +13 -0
- package/dist/ports/renderer.d.ts +23 -0
- package/dist/ports/renderer.js +7 -0
- package/dist/ports/resource-context.d.ts +51 -0
- package/dist/ports/resource-context.js +9 -0
- package/dist/ports/scm.d.ts +40 -0
- package/dist/ports/scm.js +6 -0
- package/dist/ports/state-store.d.ts +97 -0
- package/dist/ports/state-store.js +12 -0
- package/dist/presets/balanced.json +8 -0
- package/dist/presets/conservative.json +9 -0
- package/dist/presets/lightweight.json +8 -0
- package/dist/profiles/example-team/profile.json +101 -0
- package/dist/profiles/pilot-local/profile.json +56 -0
- package/dist/schemas/profile.d.ts +631 -0
- package/dist/schemas/profile.js +287 -0
- package/package.json +55 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// Profile / Preset / Override 스키마.
|
|
2
|
+
//
|
|
3
|
+
// 형식은 JSON이다. 사람이 쓰는 설정이라 주석이 아쉽지만, 파서를 하나 더 들이지 않는 값이
|
|
4
|
+
// 더 컸다 — 설명은 이 스키마의 주석과 `$comment` 필드가 진다. 읽기만 바꾸면 되므로
|
|
5
|
+
// YAML이 필요해지면 로더 한 곳만 늘리면 된다.
|
|
6
|
+
//
|
|
7
|
+
// 여기서 가장 중요한 것은 **무엇이 들어오면 안 되는가**다 (OM §4.2). Profile은 정적
|
|
8
|
+
// 설정이고 Runtime 상태나 개인 비밀이 아니다. 그 경계를 스키마가 직접 막는다 —
|
|
9
|
+
// 문서로만 적어 두면 언젠가 누가 편하다는 이유로 토큰을 적어 넣는다.
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { GENERIC_SIGNALS } from "../core/monitor/signals.js";
|
|
12
|
+
import { DECISION_DOMAIN } from "../core/policy/ownership.js";
|
|
13
|
+
import { parseScope } from "../core/policy/scope.js";
|
|
14
|
+
import { CLOSURE_ITEM_ID } from "../core/runtime/closure.js";
|
|
15
|
+
const Priority = z.enum(['P0', 'P1', 'P2']);
|
|
16
|
+
const Signal = z.enum(GENERIC_SIGNALS);
|
|
17
|
+
/** Runtime 상태·개인 비밀이 설정 파일에 섞이는 것을 막는다 (OM §4.2·§4.5). */
|
|
18
|
+
const FORBIDDEN_KEYS = [
|
|
19
|
+
'activeSession',
|
|
20
|
+
'activeSessions',
|
|
21
|
+
'queue',
|
|
22
|
+
'inbox',
|
|
23
|
+
'handoff',
|
|
24
|
+
'cursor',
|
|
25
|
+
'eventIds',
|
|
26
|
+
'token',
|
|
27
|
+
'apiToken',
|
|
28
|
+
'secret',
|
|
29
|
+
'password',
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* 파싱 **전에** 원본을 훑는다. zod는 모르는 키를 먼저 떼어내므로, 파싱 결과를 보면
|
|
33
|
+
* 금지 키는 이미 사라진 뒤다 — 조용히 무시되는 것이 가장 나쁜 결과다.
|
|
34
|
+
*/
|
|
35
|
+
function rejectRuntimeAndSecrets(schema) {
|
|
36
|
+
const guard = z.unknown().superRefine((value, ctx) => {
|
|
37
|
+
const walk = (node, path) => {
|
|
38
|
+
if (node === null || typeof node !== 'object')
|
|
39
|
+
return;
|
|
40
|
+
for (const [key, child] of Object.entries(node)) {
|
|
41
|
+
const lowered = key.toLowerCase();
|
|
42
|
+
const hit = FORBIDDEN_KEYS.find((f) => lowered === f.toLowerCase());
|
|
43
|
+
if (hit) {
|
|
44
|
+
ctx.addIssue({
|
|
45
|
+
code: z.ZodIssueCode.custom,
|
|
46
|
+
path: [...path, key],
|
|
47
|
+
message: `'${key}' 는 Runtime 상태이거나 비밀이라 이 파일에 둘 수 없다. ` +
|
|
48
|
+
`상태는 .asc/ 에, 비밀은 환경변수나 자격 저장소에 둔다 (OM §4.2·§4.5).`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
walk(child, [...path, key]);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
walk(value, []);
|
|
55
|
+
});
|
|
56
|
+
return guard.pipe(schema);
|
|
57
|
+
}
|
|
58
|
+
/** 정본 한 갈래. 프로젝트는 하나가 아니라 집합을 갖는다 (OM §8). */
|
|
59
|
+
export const CanonicalSourceSpec = z.object({
|
|
60
|
+
id: z.string().min(1),
|
|
61
|
+
provider: z.enum(['git', 'github']),
|
|
62
|
+
remote: z.string().optional(),
|
|
63
|
+
ref: z.string().optional(),
|
|
64
|
+
paths: z.array(z.string()).default([]),
|
|
65
|
+
$comment: z.string().optional(),
|
|
66
|
+
});
|
|
67
|
+
/** Profile이 마무리 항목을 선언하는 관례 키 (B-20). */
|
|
68
|
+
const CLOSURE_CHECKLIST_KEY = 'closureChecklist';
|
|
69
|
+
const PolicySpec = z.object({
|
|
70
|
+
hardDeny: z.array(z.string()).default([]),
|
|
71
|
+
softDeny: z.array(z.string()).default([]),
|
|
72
|
+
allow: z.array(z.string()).default([]),
|
|
73
|
+
roleScopes: z.record(z.array(z.string())).default({}),
|
|
74
|
+
settings: z.record(z.union([z.string(), z.number(), z.boolean()])).default({}),
|
|
75
|
+
lockedSettings: z.array(z.string()).default([]),
|
|
76
|
+
/**
|
|
77
|
+
* 계층마다 합집합으로 쌓이는 이름 목록. 병합은 Core에 이미 있는데 여기 선언이 없어
|
|
78
|
+
* Profile로 채울 길이 없었다. 관례 키 `closureChecklist` — 세션이 끝난 뒤 확인해야 할
|
|
79
|
+
* 프로젝트 마무리 항목 id (B-20).
|
|
80
|
+
*
|
|
81
|
+
* 항목 id 문법을 **여기서** 막는 이유: 잘못된 선언을 회수 시점까지 끌고 가면 세션이
|
|
82
|
+
* 끝나고 나서야 "이 항목은 쓸 수 없다"를 알게 된다. resolve는 선언이 들어오는 입구이고,
|
|
83
|
+
* 여기서 막으면 잘못된 값이 profile.lock에 고정되지도 않는다.
|
|
84
|
+
*
|
|
85
|
+
* default를 주지 않는 이유: 파싱 결과 객체가 바뀌면 profile digest가 달라져
|
|
86
|
+
* 기존 attach가 전부 LOCK_DRIFT로 멈춘다.
|
|
87
|
+
*/
|
|
88
|
+
unionLists: z
|
|
89
|
+
.record(z.array(z.string()))
|
|
90
|
+
.optional()
|
|
91
|
+
.superRefine((lists, ctx) => {
|
|
92
|
+
for (const item of lists?.[CLOSURE_CHECKLIST_KEY] ?? []) {
|
|
93
|
+
if (CLOSURE_ITEM_ID.test(item))
|
|
94
|
+
continue;
|
|
95
|
+
ctx.addIssue({
|
|
96
|
+
code: z.ZodIssueCode.custom,
|
|
97
|
+
path: [CLOSURE_CHECKLIST_KEY],
|
|
98
|
+
message: `마무리 항목 id로 쓸 수 없다: '${item}' (허용: A-Z a-z 0-9 . _ -)`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
export const ProjectProfile = rejectRuntimeAndSecrets(z.object({
|
|
104
|
+
schemaVersion: z.literal(1),
|
|
105
|
+
$comment: z.string().optional(),
|
|
106
|
+
id: z.string().min(1),
|
|
107
|
+
requires: z
|
|
108
|
+
.object({ asc: z.string().optional(), capabilities: z.array(z.string()).default([]) })
|
|
109
|
+
.default({ capabilities: [] }),
|
|
110
|
+
optionalCapabilities: z.array(z.string()).default([]),
|
|
111
|
+
project: z.object({
|
|
112
|
+
scm: z.string().min(1),
|
|
113
|
+
repository: z.string().min(1),
|
|
114
|
+
}),
|
|
115
|
+
/**
|
|
116
|
+
* 빈 집합은 "canonical 검증이 성립하지 않는 프로젝트"다 — 세션 발급·시작에서 정본
|
|
117
|
+
* 대조가 통째로 빠진다. fixture·로컬 실험 전용이며, 실 프로젝트는 반드시 선언하라.
|
|
118
|
+
*/
|
|
119
|
+
canonical: z.object({ sources: z.array(CanonicalSourceSpec).default([]) }).default({ sources: [] }),
|
|
120
|
+
monitor: z
|
|
121
|
+
.object({
|
|
122
|
+
/** provider 어휘 → Generic Signal. Adapter가 내놓는 표를 여기서 고른다 (OM §10.6). */
|
|
123
|
+
reasonSignals: z.record(Signal).default({}),
|
|
124
|
+
priorityLabels: z.record(Priority).default({}),
|
|
125
|
+
escalationLabels: z.array(z.string()).default([]),
|
|
126
|
+
signalPriority: z.record(Signal, Priority).default({}),
|
|
127
|
+
inboxSignals: z.array(Signal).optional(),
|
|
128
|
+
})
|
|
129
|
+
.default({ reasonSignals: {}, priorityLabels: {}, escalationLabels: [], signalPriority: {} }),
|
|
130
|
+
workflow: z
|
|
131
|
+
.object({
|
|
132
|
+
blockSource: z.string().optional(),
|
|
133
|
+
taskSource: z.array(z.string()).default([]),
|
|
134
|
+
$comment: z.string().optional(),
|
|
135
|
+
})
|
|
136
|
+
.default({ taskSource: [] }),
|
|
137
|
+
policy: PolicySpec.default({
|
|
138
|
+
hardDeny: [],
|
|
139
|
+
softDeny: [],
|
|
140
|
+
allow: [],
|
|
141
|
+
roleScopes: {},
|
|
142
|
+
settings: {},
|
|
143
|
+
lockedSettings: [],
|
|
144
|
+
}),
|
|
145
|
+
/**
|
|
146
|
+
* 책임 지도 — 역할 → 쓰기 영역과 결정권 (C-04 §6). 매 세션 사람이 owner·authority를
|
|
147
|
+
* 손으로 적지 않아도 되게 하는 **선언**이며, 이것만으로는 아무것도 막지 않는다.
|
|
148
|
+
*
|
|
149
|
+
* Preset·Override에는 두지 않는다. 책임 지도는 팀의 사실이라 개인 설정이 이것을 바꾸면
|
|
150
|
+
* 사람마다 다른 결정권자를 보게 되고, 그때부터는 누구 말이 맞는지 정할 방법이 없다.
|
|
151
|
+
*
|
|
152
|
+
* default를 주지 않는 이유는 `unionLists`와 같다 — 파싱 결과 객체가 바뀌면 profile
|
|
153
|
+
* digest가 달라져 기존 attach가 전부 LOCK_DRIFT로 멈춘다. Session의 `.default([])`와
|
|
154
|
+
* 성격이 다르다: 저쪽은 이미 저장된 entity를 읽는 문제이고, 이쪽은 설정 identity를
|
|
155
|
+
* 보존하는 문제다.
|
|
156
|
+
*/
|
|
157
|
+
ownership: z
|
|
158
|
+
.record(z.object({
|
|
159
|
+
paths: z.array(z.string()).default([]),
|
|
160
|
+
authorities: z.array(z.string()).default([]),
|
|
161
|
+
}))
|
|
162
|
+
.optional()
|
|
163
|
+
.superRefine((map, ctx) => {
|
|
164
|
+
for (const [role, spec] of Object.entries(map ?? {})) {
|
|
165
|
+
if (spec.paths.length === 0 && spec.authorities.length === 0) {
|
|
166
|
+
ctx.addIssue({
|
|
167
|
+
code: z.ZodIssueCode.custom,
|
|
168
|
+
path: [role],
|
|
169
|
+
message: `'${role}' 은 쓰기 영역도 결정권도 없다 — 선언할 것이 없으면 적지 않는다.`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
for (const path of spec.paths) {
|
|
173
|
+
if (parseScope(path))
|
|
174
|
+
continue;
|
|
175
|
+
ctx.addIssue({
|
|
176
|
+
code: z.ZodIssueCode.custom,
|
|
177
|
+
path: [role, 'paths'],
|
|
178
|
+
message: `범위 문법이 아니다: '${path}' (허용: **, prefix/**, prefix/*, 정확한 경로)`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
for (const domain of spec.authorities) {
|
|
182
|
+
if (DECISION_DOMAIN.test(domain))
|
|
183
|
+
continue;
|
|
184
|
+
ctx.addIssue({
|
|
185
|
+
code: z.ZodIssueCode.custom,
|
|
186
|
+
path: [role, 'authorities'],
|
|
187
|
+
message: `decision domain 이름으로 쓸 수 없다: '${domain}' (소문자 kebab-case)`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}),
|
|
192
|
+
/**
|
|
193
|
+
* Resource Binding 역할 배정 (C-09 §3). 프로젝트는 외부 시스템을 하나만 쓰지 않는다 —
|
|
194
|
+
* 코드가 한 곳, 작업 항목이 다른 곳, 전달이 또 다른 곳일 수 있다.
|
|
195
|
+
*
|
|
196
|
+
* **역할은 사람이 정한다.** 어느 binding이 code-primary인지 ASC가 추론하지 않는다.
|
|
197
|
+
* adapter가 발견하는 것은 "여기 붙을 수 있다"까지이고, 그것이 무슨 역할인지는 정책이다.
|
|
198
|
+
*
|
|
199
|
+
* `project.scm`은 하위호환으로 남지만 runtime 조립의 중심이 아니다.
|
|
200
|
+
*
|
|
201
|
+
* ownership과 같은 이유로 default를 주지 않는다 — 파싱 결과가 바뀌면 profile digest가
|
|
202
|
+
* 달라져 기존 attach가 전부 LOCK_DRIFT로 멈춘다 (C-04 §6.3).
|
|
203
|
+
*/
|
|
204
|
+
bindings: z
|
|
205
|
+
.array(z.object({
|
|
206
|
+
/** 'code-primary' | 'work' | 'presentation' … 자유 문자열이다. */
|
|
207
|
+
role: z.string().min(1),
|
|
208
|
+
/** adapter id. Core는 이 값으로 분기하지 않는다 — 조립은 Composition의 몫이다. */
|
|
209
|
+
adapter: z.string().min(1),
|
|
210
|
+
/** 문법은 adapter 소관. Core는 문자열로만 다룬다. */
|
|
211
|
+
resource: z.string().min(1),
|
|
212
|
+
}))
|
|
213
|
+
.optional()
|
|
214
|
+
.superRefine((bindings, ctx) => {
|
|
215
|
+
// 같은 역할을 둘이 주장하면 어느 쪽인지 정할 수 없다. 선언 입구에서 막는다 —
|
|
216
|
+
// 회수 시점에 AMBIGUOUS_BINDING으로 만나면 이미 늦다.
|
|
217
|
+
const seen = new Set();
|
|
218
|
+
for (const binding of bindings ?? []) {
|
|
219
|
+
if (seen.has(binding.role)) {
|
|
220
|
+
ctx.addIssue({
|
|
221
|
+
code: z.ZodIssueCode.custom,
|
|
222
|
+
message: `역할 '${binding.role}' 이 두 번 선언됐다 — 하나로 정하라.`,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
seen.add(binding.role);
|
|
226
|
+
}
|
|
227
|
+
}),
|
|
228
|
+
/** 프로젝트 용어를 Core 개념에 붙인다. 사람이 읽는 문서에만 쓰인다. */
|
|
229
|
+
terminology: z.record(z.string()).default({}),
|
|
230
|
+
}));
|
|
231
|
+
/** 운영 성향. HARD DENY는 여기서 풀 수 없다 (OM §4.3). */
|
|
232
|
+
export const OperationalPreset = rejectRuntimeAndSecrets(z.object({
|
|
233
|
+
schemaVersion: z.literal(1),
|
|
234
|
+
id: z.string().min(1),
|
|
235
|
+
$comment: z.string().optional(),
|
|
236
|
+
policy: PolicySpec.partial().default({}),
|
|
237
|
+
}));
|
|
238
|
+
/**
|
|
239
|
+
* 개인 몫. 같은 Profile을 쓰는 팀원끼리 여기만 달라진다 (OM §4.4).
|
|
240
|
+
* 비밀은 값이 아니라 참조로만 적는다 — `tokenEnv` 는 이름이지 토큰이 아니다.
|
|
241
|
+
*/
|
|
242
|
+
export const UserOverride = rejectRuntimeAndSecrets(z.object({
|
|
243
|
+
schemaVersion: z.literal(1),
|
|
244
|
+
$comment: z.string().optional(),
|
|
245
|
+
identity: z.record(z.string()).default({}),
|
|
246
|
+
/** "나"로 인정할 계정들. Monitor의 신호 판정에 쓰인다. */
|
|
247
|
+
monitorIdentities: z.array(z.string()).default([]),
|
|
248
|
+
controller: z
|
|
249
|
+
.object({
|
|
250
|
+
/** 승인 권한자 → `채널:actor` 목록 (OM §11.6). */
|
|
251
|
+
identities: z.record(z.array(z.string())).default({}),
|
|
252
|
+
})
|
|
253
|
+
.default({ identities: {} }),
|
|
254
|
+
approval: z
|
|
255
|
+
.object({
|
|
256
|
+
preferredChannel: z.string().optional(),
|
|
257
|
+
messenger: z.object({ provider: z.string(), tokenEnv: z.string() }).optional(),
|
|
258
|
+
})
|
|
259
|
+
.default({}),
|
|
260
|
+
monitor: z
|
|
261
|
+
.object({
|
|
262
|
+
realtime: z.boolean().optional(),
|
|
263
|
+
/**
|
|
264
|
+
* 내가 맡은 ownership 역할들 (C-04 §6의 역할 이름). 관련성 판정에서 "내 영역"의
|
|
265
|
+
* 기준이 된다 — 팀 공통 사실이 아니라 개인 사실이라 Profile이 아니라 여기 산다.
|
|
266
|
+
*
|
|
267
|
+
* `.optional()`인 이유: 기존 override 파일의 parse 결과를 바꾸지 않기 위해서다.
|
|
268
|
+
* 기본값을 주면 없던 키가 생겨 overrideDigest가 흔들리고, 아무것도 고치지
|
|
269
|
+
* 않은 사용자가 LOCK_DRIFT를 본다.
|
|
270
|
+
*/
|
|
271
|
+
roles: z.array(z.string()).optional(),
|
|
272
|
+
})
|
|
273
|
+
.default({}),
|
|
274
|
+
policy: PolicySpec.partial().default({}),
|
|
275
|
+
}));
|
|
276
|
+
/** attach 재현성 metadata (OM §4.9). Resolver만 쓴다. */
|
|
277
|
+
export const ProfileLock = z.object({
|
|
278
|
+
schemaVersion: z.literal(1),
|
|
279
|
+
ascCore: z.object({ version: z.string(), commit: z.string().optional() }),
|
|
280
|
+
profile: z.object({ id: z.string(), source: z.string(), digest: z.string() }),
|
|
281
|
+
preset: z.object({ id: z.string(), source: z.string(), digest: z.string() }).optional(),
|
|
282
|
+
overrideDigest: z.string().optional(),
|
|
283
|
+
adapters: z.record(z.string()).default({}),
|
|
284
|
+
capabilities: z.array(z.string()).default([]),
|
|
285
|
+
configurationDigest: z.string(),
|
|
286
|
+
generatedAt: z.string(),
|
|
287
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@asc-agent/runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ASC (Agent Session Control) — local-first human-in-the-loop agent control plane: core, CLI, and adapters",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent",
|
|
7
|
+
"control-plane",
|
|
8
|
+
"human-in-the-loop",
|
|
9
|
+
"claude-code",
|
|
10
|
+
"local-first",
|
|
11
|
+
"session"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/colosair/asc#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/colosair/asc/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/colosair/asc.git",
|
|
20
|
+
"directory": "packages/runtime"
|
|
21
|
+
},
|
|
22
|
+
"author": "colosair (https://github.com/colosair)",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"bin": {
|
|
25
|
+
"asc": "./dist/cli/asc.js"
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/cli/asc.js",
|
|
28
|
+
"types": "./dist/cli/asc.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/cli/asc.d.ts",
|
|
32
|
+
"default": "./dist/cli/asc.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=24"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "node scripts/build.mjs",
|
|
44
|
+
"prepack": "node scripts/build.mjs",
|
|
45
|
+
"test": "node --test \"tests/*.test.ts\"",
|
|
46
|
+
"dist:smoke": "node scripts/dist-smoke.mjs"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"zod": "^3.25.76"
|
|
50
|
+
},
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
}
|
|
55
|
+
}
|