adde-acp 0.1.3
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 +21 -0
- package/README.ko.md +88 -0
- package/README.md +88 -0
- package/dist/backend/acp/client.d.ts +149 -0
- package/dist/backend/acp/client.js +538 -0
- package/dist/backend/acp/client.js.map +1 -0
- package/dist/backend/acp/index.d.ts +8 -0
- package/dist/backend/acp/index.js +7 -0
- package/dist/backend/acp/index.js.map +1 -0
- package/dist/backend/acp/lifecycle.d.ts +15 -0
- package/dist/backend/acp/lifecycle.js +56 -0
- package/dist/backend/acp/lifecycle.js.map +1 -0
- package/dist/backend/acp/perm-diff.d.ts +37 -0
- package/dist/backend/acp/perm-diff.js +58 -0
- package/dist/backend/acp/perm-diff.js.map +1 -0
- package/dist/backend/acp/spawn.d.ts +20 -0
- package/dist/backend/acp/spawn.js +70 -0
- package/dist/backend/acp/spawn.js.map +1 -0
- package/dist/cli/adde.d.ts +2 -0
- package/dist/cli/adde.js +11 -0
- package/dist/cli/adde.js.map +1 -0
- package/dist/cli/alias.d.ts +45 -0
- package/dist/cli/alias.js +94 -0
- package/dist/cli/alias.js.map +1 -0
- package/dist/cli/completion.d.ts +4 -0
- package/dist/cli/completion.js +209 -0
- package/dist/cli/completion.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +114 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/lane.d.ts +20 -0
- package/dist/cli/lane.js +350 -0
- package/dist/cli/lane.js.map +1 -0
- package/dist/cli/ops.d.ts +5 -0
- package/dist/cli/ops.js +230 -0
- package/dist/cli/ops.js.map +1 -0
- package/dist/cli/prompt.d.ts +15 -0
- package/dist/cli/prompt.js +41 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/run.d.ts +5 -0
- package/dist/cli/run.js +216 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/spec.d.ts +48 -0
- package/dist/cli/spec.js +98 -0
- package/dist/cli/spec.js.map +1 -0
- package/dist/core/diagnostics.d.ts +73 -0
- package/dist/core/diagnostics.js +333 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/injector.d.ts +27 -0
- package/dist/core/injector.js +297 -0
- package/dist/core/injector.js.map +1 -0
- package/dist/core/lane-config.d.ts +80 -0
- package/dist/core/lane-config.js +303 -0
- package/dist/core/lane-config.js.map +1 -0
- package/dist/core/launchd.d.ts +81 -0
- package/dist/core/launchd.js +216 -0
- package/dist/core/launchd.js.map +1 -0
- package/dist/core/messages.d.ts +31 -0
- package/dist/core/messages.js +71 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/queue.d.ts +74 -0
- package/dist/core/queue.js +227 -0
- package/dist/core/queue.js.map +1 -0
- package/dist/core/runtime-state.d.ts +52 -0
- package/dist/core/runtime-state.js +90 -0
- package/dist/core/runtime-state.js.map +1 -0
- package/dist/core/session-ledger.d.ts +25 -0
- package/dist/core/session-ledger.js +89 -0
- package/dist/core/session-ledger.js.map +1 -0
- package/dist/core/supervisor.d.ts +41 -0
- package/dist/core/supervisor.js +315 -0
- package/dist/core/supervisor.js.map +1 -0
- package/dist/core/transcript.d.ts +22 -0
- package/dist/core/transcript.js +93 -0
- package/dist/core/transcript.js.map +1 -0
- package/dist/core/update-check.d.ts +25 -0
- package/dist/core/update-check.js +142 -0
- package/dist/core/update-check.js.map +1 -0
- package/dist/core/version.d.ts +7 -0
- package/dist/core/version.js +32 -0
- package/dist/core/version.js.map +1 -0
- package/dist/gate/gate.d.ts +41 -0
- package/dist/gate/gate.js +28 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/index.d.ts +6 -0
- package/dist/gate/index.js +6 -0
- package/dist/gate/index.js.map +1 -0
- package/dist/shared/conf.d.ts +54 -0
- package/dist/shared/conf.js +85 -0
- package/dist/shared/conf.js.map +1 -0
- package/dist/shared/deny-match.d.ts +19 -0
- package/dist/shared/deny-match.js +122 -0
- package/dist/shared/deny-match.js.map +1 -0
- package/dist/shared/envelope.d.ts +37 -0
- package/dist/shared/envelope.js +91 -0
- package/dist/shared/envelope.js.map +1 -0
- package/dist/shared/errors.d.ts +8 -0
- package/dist/shared/errors.js +23 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/fs-atomic.d.ts +17 -0
- package/dist/shared/fs-atomic.js +31 -0
- package/dist/shared/fs-atomic.js.map +1 -0
- package/dist/shared/i18n.d.ts +23 -0
- package/dist/shared/i18n.js +53 -0
- package/dist/shared/i18n.js.map +1 -0
- package/dist/shared/locales/en.d.ts +393 -0
- package/dist/shared/locales/en.js +447 -0
- package/dist/shared/locales/en.js.map +1 -0
- package/dist/shared/locales/ko.d.ts +389 -0
- package/dist/shared/locales/ko.js +443 -0
- package/dist/shared/locales/ko.js.map +1 -0
- package/dist/shared/mask.d.ts +6 -0
- package/dist/shared/mask.js +28 -0
- package/dist/shared/mask.js.map +1 -0
- package/dist/shared/notify.d.ts +15 -0
- package/dist/shared/notify.js +20 -0
- package/dist/shared/notify.js.map +1 -0
- package/dist/shared/paths.d.ts +42 -0
- package/dist/shared/paths.js +83 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/src-adapters/index.d.ts +8 -0
- package/dist/src-adapters/index.js +6 -0
- package/dist/src-adapters/index.js.map +1 -0
- package/dist/src-adapters/markdown.d.ts +80 -0
- package/dist/src-adapters/markdown.js +794 -0
- package/dist/src-adapters/markdown.js.map +1 -0
- package/dist/src-adapters/source.d.ts +33 -0
- package/dist/src-adapters/source.js +3 -0
- package/dist/src-adapters/source.js.map +1 -0
- package/dist/src-adapters/telegram.d.ts +48 -0
- package/dist/src-adapters/telegram.js +412 -0
- package/dist/src-adapters/telegram.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 업데이트 알림 — npm 레지스트리의 최신 배포판을 현재 버전과 비교해 안내 문구를 만든다.
|
|
3
|
+
* 결과는 base 아래 .update-check.json 에 캐시(기본 24h)해 매 호출 네트워크를 피한다.
|
|
4
|
+
* 보조 기능이므로 모든 실패(오프라인·타임아웃·파싱)를 흡수한다 — 조회 실패로 CLI 를 막지 않는다.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { atomicWrite } from "../shared/fs-atomic.js";
|
|
9
|
+
import { defaultBase } from "../shared/paths.js";
|
|
10
|
+
import { readVersion } from "./version.js";
|
|
11
|
+
import { t } from "../shared/i18n.js";
|
|
12
|
+
/** dist-tag latest 를 직접 반환하는 레지스트리 엔드포인트. */
|
|
13
|
+
const REGISTRY_URL = "https://registry.npmjs.org/adde-acp/latest";
|
|
14
|
+
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
15
|
+
const FETCH_TIMEOUT_MS = 1500;
|
|
16
|
+
const CACHE_FILE = ".update-check.json";
|
|
17
|
+
function parseSemver(v) {
|
|
18
|
+
const noBuild = v.trim().replace(/^v/, "").split("+")[0] ?? "";
|
|
19
|
+
const dash = noBuild.indexOf("-");
|
|
20
|
+
const coreStr = dash === -1 ? noBuild : noBuild.slice(0, dash);
|
|
21
|
+
const preStr = dash === -1 ? "" : noBuild.slice(dash + 1);
|
|
22
|
+
const core = coreStr.split(".").map((n) => Number(n));
|
|
23
|
+
if (core.length === 0 || core.some((n) => !Number.isInteger(n) || n < 0))
|
|
24
|
+
return null;
|
|
25
|
+
return { core, pre: preStr === "" ? [] : preStr.split(".") };
|
|
26
|
+
}
|
|
27
|
+
/** 프리릴리스 식별자 비교(semver): 숫자<영숫자, 숫자끼리 수치비교, 그 외 사전순, 더 짧은 쪽이 낮음. */
|
|
28
|
+
function comparePre(a, b) {
|
|
29
|
+
// 프리릴리스 없음(정식) > 프리릴리스 있음. 둘 다 없으면 동등.
|
|
30
|
+
if (a.length === 0 && b.length === 0)
|
|
31
|
+
return 0;
|
|
32
|
+
if (a.length === 0)
|
|
33
|
+
return 1;
|
|
34
|
+
if (b.length === 0)
|
|
35
|
+
return -1;
|
|
36
|
+
const len = Math.max(a.length, b.length);
|
|
37
|
+
for (let i = 0; i < len; i++) {
|
|
38
|
+
const x = a[i];
|
|
39
|
+
const y = b[i];
|
|
40
|
+
if (x === undefined)
|
|
41
|
+
return -1; // 더 짧은 쪽이 낮음
|
|
42
|
+
if (y === undefined)
|
|
43
|
+
return 1;
|
|
44
|
+
const nx = /^\d+$/.test(x);
|
|
45
|
+
const ny = /^\d+$/.test(y);
|
|
46
|
+
if (nx && ny) {
|
|
47
|
+
const d = Number(x) - Number(y);
|
|
48
|
+
if (d !== 0)
|
|
49
|
+
return d < 0 ? -1 : 1;
|
|
50
|
+
}
|
|
51
|
+
else if (nx !== ny) {
|
|
52
|
+
return nx ? -1 : 1; // 순수 숫자 식별자는 영숫자보다 낮은 우선순위
|
|
53
|
+
}
|
|
54
|
+
else if (x !== y) {
|
|
55
|
+
return x < y ? -1 : 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
/** a<b → -1, a>b → 1, 같음/비교불가 → 0. 프리릴리스는 동일 core 의 정식 릴리스보다 낮다. */
|
|
61
|
+
export function compareSemver(a, b) {
|
|
62
|
+
const pa = parseSemver(a);
|
|
63
|
+
const pb = parseSemver(b);
|
|
64
|
+
if (!pa || !pb)
|
|
65
|
+
return 0;
|
|
66
|
+
const len = Math.max(pa.core.length, pb.core.length);
|
|
67
|
+
for (let i = 0; i < len; i++) {
|
|
68
|
+
const d = (pa.core[i] ?? 0) - (pb.core[i] ?? 0);
|
|
69
|
+
if (d !== 0)
|
|
70
|
+
return d < 0 ? -1 : 1;
|
|
71
|
+
}
|
|
72
|
+
return comparePre(pa.pre, pb.pre);
|
|
73
|
+
}
|
|
74
|
+
async function readCache(path) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
77
|
+
if (typeof parsed.checkedAt === "number" && typeof parsed.latest === "string") {
|
|
78
|
+
return { checkedAt: parsed.checkedAt, latest: parsed.latest };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// 캐시 부재·파싱 실패 — 조회로 진행(보조).
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
async function fetchLatest(fetchImpl) {
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetchImpl(REGISTRY_URL, {
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
headers: { accept: "application/json" },
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok)
|
|
95
|
+
return null;
|
|
96
|
+
const body = (await res.json());
|
|
97
|
+
return typeof body.version === "string" ? body.version : null;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 업데이트 여부 판정 — 새 버전이 있으면 {current, latest}, 없으면 null.
|
|
108
|
+
* 캐시가 신선하면 캐시만 사용, 오래됐고 allowNetwork 면 레지스트리 조회 후 캐시 갱신.
|
|
109
|
+
*/
|
|
110
|
+
export async function checkForUpdate(opts = {}) {
|
|
111
|
+
const optOut = opts.optOut ?? process.env["ADDE_NO_UPDATE_CHECK"];
|
|
112
|
+
if (optOut)
|
|
113
|
+
return null;
|
|
114
|
+
const base = opts.base ?? defaultBase();
|
|
115
|
+
const current = opts.currentVersion ?? readVersion();
|
|
116
|
+
const now = opts.now ?? Date.now();
|
|
117
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
118
|
+
const cachePath = join(base, CACHE_FILE);
|
|
119
|
+
let latest = null;
|
|
120
|
+
const cache = await readCache(cachePath);
|
|
121
|
+
if (cache && now - cache.checkedAt < ttlMs) {
|
|
122
|
+
latest = cache.latest;
|
|
123
|
+
}
|
|
124
|
+
else if (opts.allowNetwork) {
|
|
125
|
+
latest = await fetchLatest(opts.fetchImpl ?? fetch);
|
|
126
|
+
if (latest) {
|
|
127
|
+
await atomicWrite(cachePath, JSON.stringify({ checkedAt: now, latest })).catch(() => { });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (cache) {
|
|
131
|
+
// 네트워크 비허용(비대화형)이라도 오래된 캐시값으로 안내는 가능.
|
|
132
|
+
latest = cache.latest;
|
|
133
|
+
}
|
|
134
|
+
if (!latest)
|
|
135
|
+
return null;
|
|
136
|
+
return compareSemver(current, latest) < 0 ? { current, latest } : null;
|
|
137
|
+
}
|
|
138
|
+
/** 업데이트 안내 문구. 표면 계층이 stdout 에 덧붙인다. */
|
|
139
|
+
export function formatUpdateNotice(notice) {
|
|
140
|
+
return t("update.available", { current: notice.current, latest: notice.latest });
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/core/update-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* package.json 의 version 을 버전 SoT 로 읽는다.
|
|
3
|
+
* 모듈 위치에서 상위로 올라가며 package.json 을 탐색하므로 src(tsx) · dist · 전역 설치 모두에서 동작한다
|
|
4
|
+
* (npm 은 package.json 을 항상 패키지에 포함하므로 설치본에서도 확실히 존재).
|
|
5
|
+
* 버전 표시는 보조 기능이므로 미발견·파싱 실패 시 "unknown" 으로 흡수한다(에러 전파 대상 아님).
|
|
6
|
+
*/
|
|
7
|
+
export declare function readVersion(): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/**
|
|
5
|
+
* package.json 의 version 을 버전 SoT 로 읽는다.
|
|
6
|
+
* 모듈 위치에서 상위로 올라가며 package.json 을 탐색하므로 src(tsx) · dist · 전역 설치 모두에서 동작한다
|
|
7
|
+
* (npm 은 package.json 을 항상 패키지에 포함하므로 설치본에서도 확실히 존재).
|
|
8
|
+
* 버전 표시는 보조 기능이므로 미발견·파싱 실패 시 "unknown" 으로 흡수한다(에러 전파 대상 아님).
|
|
9
|
+
*/
|
|
10
|
+
export function readVersion() {
|
|
11
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
for (let i = 0; i < 8; i += 1) {
|
|
13
|
+
const candidate = join(dir, "package.json");
|
|
14
|
+
if (existsSync(candidate)) {
|
|
15
|
+
try {
|
|
16
|
+
const version = JSON.parse(readFileSync(candidate, "utf8")).version;
|
|
17
|
+
if (typeof version === "string" && version.length > 0)
|
|
18
|
+
return version;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// 파싱 실패는 흡수 — 보조 기능이므로 unknown 으로 폴백
|
|
22
|
+
}
|
|
23
|
+
return "unknown";
|
|
24
|
+
}
|
|
25
|
+
const parent = dirname(dir);
|
|
26
|
+
if (parent === dir)
|
|
27
|
+
break;
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
return "unknown";
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;gBACpE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,OAAO,CAAC;YACxE,CAAC;YAAC,MAAM,CAAC;gBACP,qCAAqC;YACvC,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fail-closed 권한 게이트.
|
|
3
|
+
* Promise.race([userDecision, timeout]).
|
|
4
|
+
* timeout/sendMessage 오류/도달 실패 → decision:deny (default).
|
|
5
|
+
* allow 는 명시적 사용자 콜백 수신 시에만.
|
|
6
|
+
* 기본 타임아웃 = 600초(10분) (레인 conf 에서 재정의 가능).
|
|
7
|
+
*/
|
|
8
|
+
export interface PermRequest {
|
|
9
|
+
v: 1;
|
|
10
|
+
id: string;
|
|
11
|
+
lane: string;
|
|
12
|
+
channel: "telegram" | "markdown";
|
|
13
|
+
tool: string;
|
|
14
|
+
detail: string;
|
|
15
|
+
cwd: string;
|
|
16
|
+
ts: string;
|
|
17
|
+
}
|
|
18
|
+
export interface PermResponse {
|
|
19
|
+
id: string;
|
|
20
|
+
decision: "allow" | "deny";
|
|
21
|
+
reason?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 기본 게이트 타임아웃 — 600초(10분). 테스트 주입 가능하도록 export. */
|
|
24
|
+
export declare const DEFAULT_GATE_TIMEOUT_MS = 600000;
|
|
25
|
+
export type SendPermPrompt = (req: PermRequest) => Promise<void>;
|
|
26
|
+
export interface GateOptions {
|
|
27
|
+
sendPermPrompt: SendPermPrompt;
|
|
28
|
+
/**
|
|
29
|
+
* 사용자 결정을 기다리는 Promise 반환 함수.
|
|
30
|
+
* 테스트에서 주입 가능하도록 함수로 분리(모킹 용이성).
|
|
31
|
+
*/
|
|
32
|
+
waitForDecision: () => Promise<"allow" | "deny">;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 권한 게이트 — fail-closed.
|
|
37
|
+
* sendPermPrompt 가 채널에 inline 버튼을 전송하고, waitForDecision() 반환 Promise 는
|
|
38
|
+
* 콜백 수신 시 resolve 된다.
|
|
39
|
+
* timeout 또는 sendPermPrompt 오류 → deny.
|
|
40
|
+
*/
|
|
41
|
+
export declare function gateRequestDecision(req: PermRequest, opts: GateOptions): Promise<PermResponse>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fail-closed 권한 게이트.
|
|
3
|
+
* Promise.race([userDecision, timeout]).
|
|
4
|
+
* timeout/sendMessage 오류/도달 실패 → decision:deny (default).
|
|
5
|
+
* allow 는 명시적 사용자 콜백 수신 시에만.
|
|
6
|
+
* 기본 타임아웃 = 600초(10분) (레인 conf 에서 재정의 가능).
|
|
7
|
+
*/
|
|
8
|
+
/** 기본 게이트 타임아웃 — 600초(10분). 테스트 주입 가능하도록 export. */
|
|
9
|
+
export const DEFAULT_GATE_TIMEOUT_MS = 600_000;
|
|
10
|
+
/**
|
|
11
|
+
* 권한 게이트 — fail-closed.
|
|
12
|
+
* sendPermPrompt 가 채널에 inline 버튼을 전송하고, waitForDecision() 반환 Promise 는
|
|
13
|
+
* 콜백 수신 시 resolve 된다.
|
|
14
|
+
* timeout 또는 sendPermPrompt 오류 → deny.
|
|
15
|
+
*/
|
|
16
|
+
export async function gateRequestDecision(req, opts) {
|
|
17
|
+
const { sendPermPrompt, waitForDecision, timeoutMs = DEFAULT_GATE_TIMEOUT_MS } = opts;
|
|
18
|
+
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve("deny"), timeoutMs));
|
|
19
|
+
try {
|
|
20
|
+
await sendPermPrompt(req);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { id: req.id, decision: "deny", reason: "채널 전송 오류 — fail-closed deny" };
|
|
24
|
+
}
|
|
25
|
+
const decision = await Promise.race([waitForDecision(), timeoutPromise]);
|
|
26
|
+
return { id: req.id, decision };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/gate/gate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmBH,oDAAoD;AACpD,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAc/C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAgB,EAChB,IAAiB;IAEjB,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,SAAS,GAAG,uBAAuB,EAAE,GAAG,IAAI,CAAC;IAEtF,MAAM,cAAc,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE,CACrD,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAC7C,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IACzE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 권한 게이트 — ACP 권한요청을 채널 승인으로 라우팅하고 allow/deny 를 반환한다.
|
|
3
|
+
* fail-closed: 타임아웃·오류·채널 도달 실패의 기본값은 deny.
|
|
4
|
+
*/
|
|
5
|
+
export { gateRequestDecision, DEFAULT_GATE_TIMEOUT_MS } from "./gate.js";
|
|
6
|
+
export type { PermRequest, PermResponse, SendPermPrompt, GateOptions } from "./gate.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gate/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 레인 .conf 파싱 (INI 형식).
|
|
3
|
+
* 계약 03 §7: source/backend/engine/channel/perm_tier/acp_version/allowlist/denylist.
|
|
4
|
+
* 누락 필드 기본값 적용, 알 수 없는 키 무시(forward-compat).
|
|
5
|
+
* cwd: 레인별 엔진 작업 폴더(프로젝트 폴더 매핑). 미지정 시 슈퍼바이저 실행 cwd.
|
|
6
|
+
* markdown 전용: root/inbox/approvals/outbox. chat_id: telegram 회신 대상.
|
|
7
|
+
*/
|
|
8
|
+
export interface LaneConf {
|
|
9
|
+
source: string;
|
|
10
|
+
backend: string;
|
|
11
|
+
engine: string;
|
|
12
|
+
channel: string;
|
|
13
|
+
perm_tier: string;
|
|
14
|
+
acp_version: string;
|
|
15
|
+
allowlist: string[];
|
|
16
|
+
/** perm_tier=autopass 에서 채널 승인으로 폴백할 도구명 목록(그 외 도구는 자동 허용). */
|
|
17
|
+
denylist: string[];
|
|
18
|
+
/**
|
|
19
|
+
* 방어심화 하드-거부 목록 — 매칭 도구는 티어 무관하게 즉시 거부(채널 승인 프롬프트도 없음).
|
|
20
|
+
* denylist(autopass 에서 "물어봄")보다 강함. acp 티어의 실수 승인 방지용. `Tool`/`Tool(글롭)` 형식.
|
|
21
|
+
*/
|
|
22
|
+
hard_deny: string[];
|
|
23
|
+
/** 레인별 엔진 작업 폴더(절대경로). 미지정 시 undefined → 슈퍼바이저 cwd. */
|
|
24
|
+
cwd?: string;
|
|
25
|
+
/** telegram 회신 대상 chat id (문자열 보존, 어댑터가 숫자 변환). */
|
|
26
|
+
chat_id?: string;
|
|
27
|
+
/** markdown 루트 디렉터리(절대경로, 예: Obsidian vault). */
|
|
28
|
+
root?: string;
|
|
29
|
+
/** markdown 입력 노트(root 상대). */
|
|
30
|
+
inbox?: string;
|
|
31
|
+
/** markdown 승인 노트(root 상대). 미지정 시 inbox 형제 approvals.md. */
|
|
32
|
+
approvals?: string;
|
|
33
|
+
/** markdown 출력 디렉터리(root 상대). 미지정 시 inbox 형제 out/. */
|
|
34
|
+
outbox?: string;
|
|
35
|
+
/** 레인별 채널 메시지 로케일(en|ko). 미지정 시 전역 로케일. */
|
|
36
|
+
lang?: string;
|
|
37
|
+
/**
|
|
38
|
+
* telegram 인바운드 발신자 허용 목록(CSV, 숫자 user/chat id). chat_id 와 합쳐 authorizedIds 구성.
|
|
39
|
+
* 그룹/멀티 발신자 확장용. 미지정+chat_id 부재 시 인바운드 fail-closed(전부 무시).
|
|
40
|
+
*/
|
|
41
|
+
allow_from?: string;
|
|
42
|
+
/**
|
|
43
|
+
* 상태·출력·큐 디렉터리 권한 모드. private=0700(기본, 소유자 전용) / shared=0755(다중 사용자 열람 허용).
|
|
44
|
+
* 미지정 시 private(secure-by-default).
|
|
45
|
+
*/
|
|
46
|
+
file_mode?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function parseLaneConf(text: string): LaneConf;
|
|
49
|
+
/**
|
|
50
|
+
* LaneConf → .conf INI 텍스트 직렬화. parseLaneConf 의 역연산.
|
|
51
|
+
* 필수 키는 항상, optional 키는 값이 있을 때만, allowlist 는 비어있지 않을 때만 출력.
|
|
52
|
+
* parseLaneConf(serializeLaneConf(c)) 는 c 와 동치(round-trip 안정).
|
|
53
|
+
*/
|
|
54
|
+
export declare function serializeLaneConf(conf: LaneConf): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 레인 .conf 파싱 (INI 형식).
|
|
3
|
+
* 계약 03 §7: source/backend/engine/channel/perm_tier/acp_version/allowlist/denylist.
|
|
4
|
+
* 누락 필드 기본값 적용, 알 수 없는 키 무시(forward-compat).
|
|
5
|
+
* cwd: 레인별 엔진 작업 폴더(프로젝트 폴더 매핑). 미지정 시 슈퍼바이저 실행 cwd.
|
|
6
|
+
* markdown 전용: root/inbox/approvals/outbox. chat_id: telegram 회신 대상.
|
|
7
|
+
*/
|
|
8
|
+
export function parseLaneConf(text) {
|
|
9
|
+
const conf = {};
|
|
10
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
11
|
+
const line = rawLine.trim();
|
|
12
|
+
if (!line || line.startsWith("#") || line.startsWith(";"))
|
|
13
|
+
continue;
|
|
14
|
+
const eqIdx = line.indexOf("=");
|
|
15
|
+
if (eqIdx === -1)
|
|
16
|
+
continue;
|
|
17
|
+
const key = line.slice(0, eqIdx).trim();
|
|
18
|
+
const value = line.slice(eqIdx + 1).trim();
|
|
19
|
+
if (key)
|
|
20
|
+
conf[key] = value;
|
|
21
|
+
}
|
|
22
|
+
const parseToolList = (raw) => raw
|
|
23
|
+
.split(",")
|
|
24
|
+
.map((s) => s.trim())
|
|
25
|
+
.filter((s) => s.length > 0);
|
|
26
|
+
const result = {
|
|
27
|
+
source: conf["source"] ?? "",
|
|
28
|
+
backend: conf["backend"] ?? "",
|
|
29
|
+
engine: conf["engine"] ?? "",
|
|
30
|
+
channel: conf["channel"] ?? "",
|
|
31
|
+
perm_tier: conf["perm_tier"] ?? "acp",
|
|
32
|
+
acp_version: conf["acp_version"] ?? "v1",
|
|
33
|
+
allowlist: parseToolList(conf["allowlist"] ?? ""),
|
|
34
|
+
denylist: parseToolList(conf["denylist"] ?? ""),
|
|
35
|
+
hard_deny: parseToolList(conf["hard_deny"] ?? ""),
|
|
36
|
+
};
|
|
37
|
+
// optional 필드는 존재할 때만 채운다(부재 = undefined).
|
|
38
|
+
for (const key of OPTIONAL_KEYS) {
|
|
39
|
+
const value = conf[key];
|
|
40
|
+
if (value !== undefined && value.length > 0) {
|
|
41
|
+
result[key] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
/** parse/serialize 가 공유하는 optional 키 목록(순서 = 직렬화 순서). */
|
|
47
|
+
const OPTIONAL_KEYS = [
|
|
48
|
+
"cwd",
|
|
49
|
+
"chat_id",
|
|
50
|
+
"root",
|
|
51
|
+
"inbox",
|
|
52
|
+
"approvals",
|
|
53
|
+
"outbox",
|
|
54
|
+
"lang",
|
|
55
|
+
"allow_from",
|
|
56
|
+
"file_mode",
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* LaneConf → .conf INI 텍스트 직렬화. parseLaneConf 의 역연산.
|
|
60
|
+
* 필수 키는 항상, optional 키는 값이 있을 때만, allowlist 는 비어있지 않을 때만 출력.
|
|
61
|
+
* parseLaneConf(serializeLaneConf(c)) 는 c 와 동치(round-trip 안정).
|
|
62
|
+
*/
|
|
63
|
+
export function serializeLaneConf(conf) {
|
|
64
|
+
const lines = [
|
|
65
|
+
`source=${conf.source}`,
|
|
66
|
+
`backend=${conf.backend}`,
|
|
67
|
+
`engine=${conf.engine}`,
|
|
68
|
+
`channel=${conf.channel}`,
|
|
69
|
+
`perm_tier=${conf.perm_tier}`,
|
|
70
|
+
`acp_version=${conf.acp_version}`,
|
|
71
|
+
];
|
|
72
|
+
if (conf.allowlist.length > 0)
|
|
73
|
+
lines.push(`allowlist=${conf.allowlist.join(",")}`);
|
|
74
|
+
if (conf.denylist.length > 0)
|
|
75
|
+
lines.push(`denylist=${conf.denylist.join(",")}`);
|
|
76
|
+
if (conf.hard_deny.length > 0)
|
|
77
|
+
lines.push(`hard_deny=${conf.hard_deny.join(",")}`);
|
|
78
|
+
for (const key of OPTIONAL_KEYS) {
|
|
79
|
+
const value = conf[key];
|
|
80
|
+
if (value !== undefined && value.length > 0)
|
|
81
|
+
lines.push(`${key}=${value}`);
|
|
82
|
+
}
|
|
83
|
+
return lines.join("\n") + "\n";
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=conf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conf.js","sourceRoot":"","sources":["../../src/shared/conf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface DenyEntry {
|
|
2
|
+
tool: string;
|
|
3
|
+
/** 괄호 안 글롭. 없으면 도구 전체 매칭. */
|
|
4
|
+
glob?: string;
|
|
5
|
+
}
|
|
6
|
+
/** `"Bash(git push*)"` | `"Bash"` → {tool, glob?}. 형식 위반 시 null. */
|
|
7
|
+
export declare function parseDenyEntry(entry: string): DenyEntry | null;
|
|
8
|
+
/**
|
|
9
|
+
* denylist 매칭 — 하나라도 걸리면 true(채널 승인 폴백).
|
|
10
|
+
* 파싱 불가 항목은 전 도구 매칭으로 처리한다(fail-closed) — 손편집 오타가 자동 허용 구멍이
|
|
11
|
+
* 되는 대신 전 요청이 채널로 가서 즉시 표면화된다. 생성 시점 검증(lane-config)이 1차 방어.
|
|
12
|
+
*/
|
|
13
|
+
export declare function matchesDenylist(denylist: string[] | undefined, toolName: string, rawInput: unknown): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* autopass 내장 기본 denylist — 파괴적 셸 명령(sudo·rm -rf·git 강제 변경)과
|
|
16
|
+
* 자격증명 저장소 읽기(ssh·aws·npm·gh·kube·docker·gcloud 토큰/키)를 채널 승인으로 폴백시킨다.
|
|
17
|
+
* git clean -fdx 는 -fd* 글롭이 포섭한다. 셸 체이닝은 matchesDenylist 의 세그먼트 매칭이 포섭한다.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_AUTOPASS_DENYLIST: readonly string[];
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* denylist 항목 파싱·매칭 — `Tool`(도구 전체) 또는 `Tool(glob)`(대표 인자 글롭).
|
|
3
|
+
* 실패 방향 = 채널 승인 폴백이므로 판단 불가(파싱 불가·매핑 없음·인자 부재)는
|
|
4
|
+
* 매칭으로 간주한다(fail-closed — 과매칭은 "물어봄"일 뿐 위험하지 않다).
|
|
5
|
+
*/
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
/** 도구별 대표 인자 필드. 매핑 없는 도구에 패턴을 걸면 도구명 일치만으로 매칭. */
|
|
8
|
+
const PRIMARY_ARG_FIELD = {
|
|
9
|
+
Bash: "command",
|
|
10
|
+
Read: "file_path",
|
|
11
|
+
Write: "file_path",
|
|
12
|
+
Edit: "file_path",
|
|
13
|
+
MultiEdit: "file_path",
|
|
14
|
+
NotebookRead: "notebook_path",
|
|
15
|
+
NotebookEdit: "notebook_path",
|
|
16
|
+
WebFetch: "url",
|
|
17
|
+
};
|
|
18
|
+
/** `"Bash(git push*)"` | `"Bash"` → {tool, glob?}. 형식 위반 시 null. */
|
|
19
|
+
export function parseDenyEntry(entry) {
|
|
20
|
+
const m = /^([A-Za-z0-9_.-]+)(?:\((.+)\))?$/.exec(entry);
|
|
21
|
+
if (!m || !m[1])
|
|
22
|
+
return null;
|
|
23
|
+
const tool = m[1];
|
|
24
|
+
const glob = m[2];
|
|
25
|
+
return glob !== undefined ? { tool, glob } : { tool };
|
|
26
|
+
}
|
|
27
|
+
/** 글롭 → 전체 문자열 앵커 정규식. `*`·`**` 동일 취급(임의 문자열 — 경로 구분자 포함, 과매칭=안전 방향). */
|
|
28
|
+
function globToRegExp(glob) {
|
|
29
|
+
const escaped = glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*+/g, ".*");
|
|
30
|
+
return new RegExp(`^${escaped}$`);
|
|
31
|
+
}
|
|
32
|
+
function globMatches(glob, value) {
|
|
33
|
+
if (globToRegExp(glob).test(value))
|
|
34
|
+
return true;
|
|
35
|
+
// 선행 ~ 는 홈 확장 변형도 매칭 — 경로 인자가 절대경로로 도착하는 경우 대비.
|
|
36
|
+
if (glob.startsWith("~/") || glob.startsWith("~*")) {
|
|
37
|
+
if (globToRegExp(homedir() + glob.slice(1)).test(value))
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 셸 명령을 제어 연산자(`;` `&&` `||` `|` `&` 개행)와 그룹·명령치환 경계
|
|
44
|
+
* (`(` `)` `{` `}` `$(` 백틱)로 분해해 체이닝·서브셸·그룹의 하위 명령을 개별 후보로 낸다.
|
|
45
|
+
* 각 세그먼트의 선행 환경변수 대입(`FOO=1 sudo …`)은 제거해 실제 실행 명령 토큰이 앞에 오도록 한다.
|
|
46
|
+
* 앵커 글롭이 전체 문자열만 봤을 때 `cd /tmp && sudo rm -rf /`·`(sudo rm -rf /)` 같은
|
|
47
|
+
* 체이닝·서브셸이 위험 패턴을 우회하던 문제를 막는다(과분리=더 많은 후보 대조=안전 방향).
|
|
48
|
+
* best-effort 다 — 따옴표를 인식하지 않으므로 인용부 안 연산자에서도 분리한다(과매칭=안전).
|
|
49
|
+
*/
|
|
50
|
+
function shellSegments(command) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const raw of command.split(/(?:&&|\|\||[;&|(){}\n]|`)/)) {
|
|
53
|
+
const seg = raw.replace(/^\s*(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)+/, "").trim();
|
|
54
|
+
if (seg)
|
|
55
|
+
out.push(seg);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
/** 셸 명령(command) 전용 매칭 — 전체 문자열 + 각 세그먼트를 글롭에 대조. */
|
|
60
|
+
function commandGlobMatch(glob, command) {
|
|
61
|
+
if (globMatches(glob, command))
|
|
62
|
+
return true;
|
|
63
|
+
for (const seg of shellSegments(command)) {
|
|
64
|
+
if (globMatches(glob, seg))
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* denylist 매칭 — 하나라도 걸리면 true(채널 승인 폴백).
|
|
71
|
+
* 파싱 불가 항목은 전 도구 매칭으로 처리한다(fail-closed) — 손편집 오타가 자동 허용 구멍이
|
|
72
|
+
* 되는 대신 전 요청이 채널로 가서 즉시 표면화된다. 생성 시점 검증(lane-config)이 1차 방어.
|
|
73
|
+
*/
|
|
74
|
+
export function matchesDenylist(denylist, toolName, rawInput) {
|
|
75
|
+
for (const raw of denylist ?? []) {
|
|
76
|
+
const entry = parseDenyEntry(raw.trim());
|
|
77
|
+
if (!entry)
|
|
78
|
+
return true;
|
|
79
|
+
// 도구명은 대소문자 무시 비교 — 오타(bash)로 매칭이 스킵되면 자동 허용(위험 방향)으로 새므로
|
|
80
|
+
// 넓게 잡는다(과매칭=채널 승인, 안전 방향).
|
|
81
|
+
if (entry.tool.toLowerCase() !== toolName.toLowerCase())
|
|
82
|
+
continue;
|
|
83
|
+
if (entry.glob === undefined)
|
|
84
|
+
return true;
|
|
85
|
+
const field = PRIMARY_ARG_FIELD[toolName];
|
|
86
|
+
if (!field)
|
|
87
|
+
return true;
|
|
88
|
+
const arg = rawInput && typeof rawInput === "object"
|
|
89
|
+
? rawInput[field]
|
|
90
|
+
: undefined;
|
|
91
|
+
if (typeof arg !== "string")
|
|
92
|
+
return true;
|
|
93
|
+
// Bash 명령(command)은 세그먼트 분해 매칭 — 체이닝·선행대입 우회 차단. 경로·URL 은 전체 문자열.
|
|
94
|
+
const hit = field === "command" ? commandGlobMatch(entry.glob, arg) : globMatches(entry.glob, arg);
|
|
95
|
+
if (hit)
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* autopass 내장 기본 denylist — 파괴적 셸 명령(sudo·rm -rf·git 강제 변경)과
|
|
102
|
+
* 자격증명 저장소 읽기(ssh·aws·npm·gh·kube·docker·gcloud 토큰/키)를 채널 승인으로 폴백시킨다.
|
|
103
|
+
* git clean -fdx 는 -fd* 글롭이 포섭한다. 셸 체이닝은 matchesDenylist 의 세그먼트 매칭이 포섭한다.
|
|
104
|
+
*/
|
|
105
|
+
export const DEFAULT_AUTOPASS_DENYLIST = [
|
|
106
|
+
"Bash(sudo *)",
|
|
107
|
+
"Bash(rm -rf /*)",
|
|
108
|
+
"Bash(rm -rf ~*)",
|
|
109
|
+
"Bash(rm -rf .*)",
|
|
110
|
+
"Bash(git push --force*)",
|
|
111
|
+
"Bash(git push -f*)",
|
|
112
|
+
"Bash(git reset --hard*)",
|
|
113
|
+
"Bash(git clean -fd*)",
|
|
114
|
+
"Read(~/.ssh/**)",
|
|
115
|
+
"Read(~/.aws/**)",
|
|
116
|
+
"Read(~/.npmrc)",
|
|
117
|
+
"Read(~/.config/gh/hosts.yml)",
|
|
118
|
+
"Read(~/.kube/config)",
|
|
119
|
+
"Read(~/.docker/config.json)",
|
|
120
|
+
"Read(~/.config/gcloud/**)",
|
|
121
|
+
];
|
|
122
|
+
//# sourceMappingURL=deny-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deny-match.js","sourceRoot":"","sources":["../../src/shared/deny-match.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1 envelope 스키마·검증·직렬화.
|
|
3
|
+
* 소스 어댑터가 생성하고 큐에 저장하는 레인 메시지 단위.
|
|
4
|
+
*/
|
|
5
|
+
export interface Attachment {
|
|
6
|
+
kind: "image" | "file";
|
|
7
|
+
path: string;
|
|
8
|
+
name: string;
|
|
9
|
+
mime: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ReplyRef {
|
|
12
|
+
channel_msg_id: string;
|
|
13
|
+
thread?: string;
|
|
14
|
+
}
|
|
15
|
+
/** 세션 제어 요청 — 일반 프롬프트 대신 세션 조작(clear/compact/resume/sessions 목록)을 수행하는 envelope. */
|
|
16
|
+
export interface ControlRequest {
|
|
17
|
+
kind: "clear" | "compact" | "resume" | "sessions";
|
|
18
|
+
/** resume 대상 세션 id (kind=resume 전용). */
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Envelope {
|
|
22
|
+
v: 1;
|
|
23
|
+
id: string;
|
|
24
|
+
lane: string;
|
|
25
|
+
source: "telegram" | "markdown";
|
|
26
|
+
backend: "acp";
|
|
27
|
+
engine: string;
|
|
28
|
+
project: string;
|
|
29
|
+
ts: string;
|
|
30
|
+
text: string;
|
|
31
|
+
attachments?: Attachment[];
|
|
32
|
+
reply_ref?: ReplyRef;
|
|
33
|
+
/** 존재 시 제어 envelope — injector 가 프롬프트 주입 대신 세션 제어를 수행(큐 직렬 순서 보존). */
|
|
34
|
+
control?: ControlRequest;
|
|
35
|
+
}
|
|
36
|
+
export declare function parseEnvelope(json: string): Envelope;
|
|
37
|
+
export declare function serializeEnvelope(e: Envelope): string;
|