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.
Files changed (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +88 -0
  3. package/README.md +88 -0
  4. package/dist/backend/acp/client.d.ts +149 -0
  5. package/dist/backend/acp/client.js +538 -0
  6. package/dist/backend/acp/client.js.map +1 -0
  7. package/dist/backend/acp/index.d.ts +8 -0
  8. package/dist/backend/acp/index.js +7 -0
  9. package/dist/backend/acp/index.js.map +1 -0
  10. package/dist/backend/acp/lifecycle.d.ts +15 -0
  11. package/dist/backend/acp/lifecycle.js +56 -0
  12. package/dist/backend/acp/lifecycle.js.map +1 -0
  13. package/dist/backend/acp/perm-diff.d.ts +37 -0
  14. package/dist/backend/acp/perm-diff.js +58 -0
  15. package/dist/backend/acp/perm-diff.js.map +1 -0
  16. package/dist/backend/acp/spawn.d.ts +20 -0
  17. package/dist/backend/acp/spawn.js +70 -0
  18. package/dist/backend/acp/spawn.js.map +1 -0
  19. package/dist/cli/adde.d.ts +2 -0
  20. package/dist/cli/adde.js +11 -0
  21. package/dist/cli/adde.js.map +1 -0
  22. package/dist/cli/alias.d.ts +45 -0
  23. package/dist/cli/alias.js +94 -0
  24. package/dist/cli/alias.js.map +1 -0
  25. package/dist/cli/completion.d.ts +4 -0
  26. package/dist/cli/completion.js +209 -0
  27. package/dist/cli/completion.js.map +1 -0
  28. package/dist/cli/init.d.ts +3 -0
  29. package/dist/cli/init.js +114 -0
  30. package/dist/cli/init.js.map +1 -0
  31. package/dist/cli/lane.d.ts +20 -0
  32. package/dist/cli/lane.js +350 -0
  33. package/dist/cli/lane.js.map +1 -0
  34. package/dist/cli/ops.d.ts +5 -0
  35. package/dist/cli/ops.js +230 -0
  36. package/dist/cli/ops.js.map +1 -0
  37. package/dist/cli/prompt.d.ts +15 -0
  38. package/dist/cli/prompt.js +41 -0
  39. package/dist/cli/prompt.js.map +1 -0
  40. package/dist/cli/run.d.ts +5 -0
  41. package/dist/cli/run.js +216 -0
  42. package/dist/cli/run.js.map +1 -0
  43. package/dist/cli/spec.d.ts +48 -0
  44. package/dist/cli/spec.js +98 -0
  45. package/dist/cli/spec.js.map +1 -0
  46. package/dist/core/diagnostics.d.ts +73 -0
  47. package/dist/core/diagnostics.js +333 -0
  48. package/dist/core/diagnostics.js.map +1 -0
  49. package/dist/core/index.d.ts +11 -0
  50. package/dist/core/index.js +9 -0
  51. package/dist/core/index.js.map +1 -0
  52. package/dist/core/injector.d.ts +27 -0
  53. package/dist/core/injector.js +297 -0
  54. package/dist/core/injector.js.map +1 -0
  55. package/dist/core/lane-config.d.ts +80 -0
  56. package/dist/core/lane-config.js +303 -0
  57. package/dist/core/lane-config.js.map +1 -0
  58. package/dist/core/launchd.d.ts +81 -0
  59. package/dist/core/launchd.js +216 -0
  60. package/dist/core/launchd.js.map +1 -0
  61. package/dist/core/messages.d.ts +31 -0
  62. package/dist/core/messages.js +71 -0
  63. package/dist/core/messages.js.map +1 -0
  64. package/dist/core/queue.d.ts +74 -0
  65. package/dist/core/queue.js +227 -0
  66. package/dist/core/queue.js.map +1 -0
  67. package/dist/core/runtime-state.d.ts +52 -0
  68. package/dist/core/runtime-state.js +90 -0
  69. package/dist/core/runtime-state.js.map +1 -0
  70. package/dist/core/session-ledger.d.ts +25 -0
  71. package/dist/core/session-ledger.js +89 -0
  72. package/dist/core/session-ledger.js.map +1 -0
  73. package/dist/core/supervisor.d.ts +41 -0
  74. package/dist/core/supervisor.js +315 -0
  75. package/dist/core/supervisor.js.map +1 -0
  76. package/dist/core/transcript.d.ts +22 -0
  77. package/dist/core/transcript.js +93 -0
  78. package/dist/core/transcript.js.map +1 -0
  79. package/dist/core/update-check.d.ts +25 -0
  80. package/dist/core/update-check.js +142 -0
  81. package/dist/core/update-check.js.map +1 -0
  82. package/dist/core/version.d.ts +7 -0
  83. package/dist/core/version.js +32 -0
  84. package/dist/core/version.js.map +1 -0
  85. package/dist/gate/gate.d.ts +41 -0
  86. package/dist/gate/gate.js +28 -0
  87. package/dist/gate/gate.js.map +1 -0
  88. package/dist/gate/index.d.ts +6 -0
  89. package/dist/gate/index.js +6 -0
  90. package/dist/gate/index.js.map +1 -0
  91. package/dist/shared/conf.d.ts +54 -0
  92. package/dist/shared/conf.js +85 -0
  93. package/dist/shared/conf.js.map +1 -0
  94. package/dist/shared/deny-match.d.ts +19 -0
  95. package/dist/shared/deny-match.js +122 -0
  96. package/dist/shared/deny-match.js.map +1 -0
  97. package/dist/shared/envelope.d.ts +37 -0
  98. package/dist/shared/envelope.js +91 -0
  99. package/dist/shared/envelope.js.map +1 -0
  100. package/dist/shared/errors.d.ts +8 -0
  101. package/dist/shared/errors.js +23 -0
  102. package/dist/shared/errors.js.map +1 -0
  103. package/dist/shared/fs-atomic.d.ts +17 -0
  104. package/dist/shared/fs-atomic.js +31 -0
  105. package/dist/shared/fs-atomic.js.map +1 -0
  106. package/dist/shared/i18n.d.ts +23 -0
  107. package/dist/shared/i18n.js +53 -0
  108. package/dist/shared/i18n.js.map +1 -0
  109. package/dist/shared/locales/en.d.ts +393 -0
  110. package/dist/shared/locales/en.js +447 -0
  111. package/dist/shared/locales/en.js.map +1 -0
  112. package/dist/shared/locales/ko.d.ts +389 -0
  113. package/dist/shared/locales/ko.js +443 -0
  114. package/dist/shared/locales/ko.js.map +1 -0
  115. package/dist/shared/mask.d.ts +6 -0
  116. package/dist/shared/mask.js +28 -0
  117. package/dist/shared/mask.js.map +1 -0
  118. package/dist/shared/notify.d.ts +15 -0
  119. package/dist/shared/notify.js +20 -0
  120. package/dist/shared/notify.js.map +1 -0
  121. package/dist/shared/paths.d.ts +42 -0
  122. package/dist/shared/paths.js +83 -0
  123. package/dist/shared/paths.js.map +1 -0
  124. package/dist/src-adapters/index.d.ts +8 -0
  125. package/dist/src-adapters/index.js +6 -0
  126. package/dist/src-adapters/index.js.map +1 -0
  127. package/dist/src-adapters/markdown.d.ts +80 -0
  128. package/dist/src-adapters/markdown.js +794 -0
  129. package/dist/src-adapters/markdown.js.map +1 -0
  130. package/dist/src-adapters/source.d.ts +33 -0
  131. package/dist/src-adapters/source.js +3 -0
  132. package/dist/src-adapters/source.js.map +1 -0
  133. package/dist/src-adapters/telegram.d.ts +48 -0
  134. package/dist/src-adapters/telegram.js +412 -0
  135. package/dist/src-adapters/telegram.js.map +1 -0
  136. package/package.json +62 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * v1 envelope 스키마·검증·직렬화.
3
+ * 소스 어댑터가 생성하고 큐에 저장하는 레인 메시지 단위.
4
+ */
5
+ /** text 길이 상한(UTF-16 코드유닛) — 초과 시 거부(과대 입력 OOM 방어). */
6
+ const MAX_TEXT_LEN = 256 * 1024;
7
+ /** channel_msg_id 허용 문자셋 — 경로/제어문자 주입 방어. */
8
+ const CHANNEL_MSG_ID_RE = /^[A-Za-z0-9_:-]+$/;
9
+ export function parseEnvelope(json) {
10
+ let raw;
11
+ try {
12
+ raw = JSON.parse(json);
13
+ }
14
+ catch {
15
+ throw new Error("envelope: JSON parse failed");
16
+ }
17
+ if (typeof raw !== "object" || raw === null) {
18
+ throw new Error("envelope: not an object");
19
+ }
20
+ const obj = raw;
21
+ if (obj["v"] !== 1) {
22
+ throw new Error(`envelope: v must be 1, got ${String(obj["v"])}`);
23
+ }
24
+ const required = ["id", "lane", "source", "backend", "engine", "project", "ts", "text"];
25
+ for (const key of required) {
26
+ if (typeof obj[key] !== "string" || obj[key] === "") {
27
+ throw new Error(`envelope: required field "${key}" missing or empty`);
28
+ }
29
+ }
30
+ // 입력 검증·보안 표면(C): 과대 길이·형식·경로주입 거부(fail-closed).
31
+ if (obj["text"].length > MAX_TEXT_LEN) {
32
+ throw new Error(`envelope: text 길이 상한 초과 (${obj["text"].length} > ${MAX_TEXT_LEN})`);
33
+ }
34
+ const replyRef = obj["reply_ref"];
35
+ if (replyRef !== undefined) {
36
+ if (typeof replyRef !== "object" || replyRef === null) {
37
+ throw new Error("envelope: reply_ref must be an object");
38
+ }
39
+ const cmid = replyRef["channel_msg_id"];
40
+ if (typeof cmid !== "string" || !CHANNEL_MSG_ID_RE.test(cmid)) {
41
+ throw new Error("envelope: reply_ref.channel_msg_id 형식 위반");
42
+ }
43
+ }
44
+ const control = obj["control"];
45
+ if (control !== undefined) {
46
+ if (typeof control !== "object" || control === null) {
47
+ throw new Error("envelope: control must be an object");
48
+ }
49
+ const c = control;
50
+ if (c["kind"] !== "clear" &&
51
+ c["kind"] !== "compact" &&
52
+ c["kind"] !== "resume" &&
53
+ c["kind"] !== "sessions") {
54
+ throw new Error(`envelope: control.kind 위반 (${String(c["kind"])})`);
55
+ }
56
+ const sid = c["sessionId"];
57
+ if (sid !== undefined && (typeof sid !== "string" || !CHANNEL_MSG_ID_RE.test(sid))) {
58
+ // 세션 id 는 loadSession·세션 파일 탐색에 쓰인다 — 경로/제어문자 주입 방어(fail-closed).
59
+ throw new Error("envelope: control.sessionId 형식 위반");
60
+ }
61
+ }
62
+ const attachments = obj["attachments"];
63
+ if (attachments !== undefined) {
64
+ if (!Array.isArray(attachments)) {
65
+ throw new Error("envelope: attachments must be an array");
66
+ }
67
+ for (const a of attachments) {
68
+ if (typeof a !== "object" || a === null) {
69
+ throw new Error("envelope: attachment must be an object");
70
+ }
71
+ const at = a;
72
+ if (at["kind"] !== "image" && at["kind"] !== "file") {
73
+ throw new Error(`envelope: attachment.kind 위반 (${String(at["kind"])})`);
74
+ }
75
+ for (const f of ["path", "name", "mime"]) {
76
+ if (typeof at[f] !== "string" || at[f] === "") {
77
+ throw new Error(`envelope: attachment.${f} missing or empty`);
78
+ }
79
+ }
80
+ const name = at["name"];
81
+ if (name.includes("/") || name.includes("\\") || name.includes("..")) {
82
+ throw new Error(`envelope: attachment.name 경로 traversal 금지 (${name})`);
83
+ }
84
+ }
85
+ }
86
+ return raw;
87
+ }
88
+ export function serializeEnvelope(e) {
89
+ return JSON.stringify(e);
90
+ }
91
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/shared/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** unknown 오류 표시 공통 헬퍼 — 인라인 관용구의 단일화(표류 방지). */
2
+ /**
3
+ * unknown 오류를 사람이 읽을 수 있는 문자열로.
4
+ * ACP 오류 등 Error 가 아닌 객체가 올 수 있어 객체는 JSON 으로 펼친다.
5
+ */
6
+ export declare function errMsg(err: unknown): string;
7
+ /** Node fs 오류 코드 추출(없으면 undefined). */
8
+ export declare function errCode(err: unknown): string | undefined;
@@ -0,0 +1,23 @@
1
+ /** unknown 오류 표시 공통 헬퍼 — 인라인 관용구의 단일화(표류 방지). */
2
+ /**
3
+ * unknown 오류를 사람이 읽을 수 있는 문자열로.
4
+ * ACP 오류 등 Error 가 아닌 객체가 올 수 있어 객체는 JSON 으로 펼친다.
5
+ */
6
+ export function errMsg(err) {
7
+ if (err instanceof Error)
8
+ return err.message;
9
+ if (err && typeof err === "object") {
10
+ try {
11
+ return JSON.stringify(err);
12
+ }
13
+ catch {
14
+ return String(err);
15
+ }
16
+ }
17
+ return String(err);
18
+ }
19
+ /** Node fs 오류 코드 추출(없으면 undefined). */
20
+ export function errCode(err) {
21
+ return err?.code;
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/shared/errors.ts"],"names":[],"mappings":"AAAA,iDAAiD;AAEjD;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,GAAY;IACjC,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,OAAQ,GAAyC,EAAE,IAAI,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 같은 디렉터리 tmp→rename 으로 원자 기록 — 부분 쓰기가 최종 경로에 노출되지 않는다.
3
+ * tmp 는 숨김(dot-prefix, 에디터/감시 노출 회피) + pid(프로세스 간 tmp 이름 충돌 회피) + `.tmp`
4
+ * 접미(`.msg`/`.out` 등 접미 필터에 걸리지 않음). 대상 디렉터리는 없으면 생성한다.
5
+ * 같은 프로세스에서 동일 filePath 로의 동시 호출은 tmp 가 겹치므로 호출자가 직렬화해야 한다
6
+ * (현 호출처는 모두 직렬 — 큐 상태 전이·markdown op 체인·단발 생성).
7
+ */
8
+ export declare function atomicWrite(filePath: string, content: string, opts?: {
9
+ mode?: number;
10
+ }): Promise<void>;
11
+ /**
12
+ * 레인 상태·출력·큐 디렉터리를 권한 모드대로 잠근다.
13
+ * private=0700(소유자 전용 — 다중 사용자 호스트에서 타 로컬 유저의 대화/응답 열람 차단),
14
+ * shared=no-op(기존 기본 권한 유지 — 열람 허용을 옵트인한 경우). 부재 디렉터리는 먼저 생성한다.
15
+ * chmod 실패는 흡수하지 않고 전파한다(권한이 의도대로 적용됐는지는 보안 신호 — 호출부가 로그/판단).
16
+ */
17
+ export declare function secureLaneDirs(dirs: string[], mode: "private" | "shared"): Promise<void>;
@@ -0,0 +1,31 @@
1
+ import { chmod, mkdir, rename, writeFile } from "node:fs/promises";
2
+ import { basename, dirname, join } from "node:path";
3
+ /**
4
+ * 같은 디렉터리 tmp→rename 으로 원자 기록 — 부분 쓰기가 최종 경로에 노출되지 않는다.
5
+ * tmp 는 숨김(dot-prefix, 에디터/감시 노출 회피) + pid(프로세스 간 tmp 이름 충돌 회피) + `.tmp`
6
+ * 접미(`.msg`/`.out` 등 접미 필터에 걸리지 않음). 대상 디렉터리는 없으면 생성한다.
7
+ * 같은 프로세스에서 동일 filePath 로의 동시 호출은 tmp 가 겹치므로 호출자가 직렬화해야 한다
8
+ * (현 호출처는 모두 직렬 — 큐 상태 전이·markdown op 체인·단발 생성).
9
+ */
10
+ export async function atomicWrite(filePath, content, opts) {
11
+ const dir = dirname(filePath);
12
+ await mkdir(dir, { recursive: true });
13
+ const tmp = join(dir, `.${basename(filePath)}.${process.pid}.tmp`);
14
+ await writeFile(tmp, content, opts?.mode === undefined ? "utf8" : { encoding: "utf8", mode: opts.mode });
15
+ await rename(tmp, filePath);
16
+ }
17
+ /**
18
+ * 레인 상태·출력·큐 디렉터리를 권한 모드대로 잠근다.
19
+ * private=0700(소유자 전용 — 다중 사용자 호스트에서 타 로컬 유저의 대화/응답 열람 차단),
20
+ * shared=no-op(기존 기본 권한 유지 — 열람 허용을 옵트인한 경우). 부재 디렉터리는 먼저 생성한다.
21
+ * chmod 실패는 흡수하지 않고 전파한다(권한이 의도대로 적용됐는지는 보안 신호 — 호출부가 로그/판단).
22
+ */
23
+ export async function secureLaneDirs(dirs, mode) {
24
+ if (mode !== "private")
25
+ return;
26
+ for (const dir of dirs) {
27
+ await mkdir(dir, { recursive: true });
28
+ await chmod(dir, 0o700);
29
+ }
30
+ }
31
+ //# sourceMappingURL=fs-atomic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-atomic.js","sourceRoot":"","sources":["../../src/shared/fs-atomic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,OAAe,EACf,IAAwB;IAExB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IACnE,MAAM,SAAS,CACb,GAAG,EACH,OAAO,EACP,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAC1E,CAAC;IACF,MAAM,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAc,EAAE,IAA0B;IAC7E,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { en } from "./locales/en.js";
2
+ declare module "i18next" {
3
+ interface CustomTypeOptions {
4
+ defaultNS: "translation";
5
+ resources: {
6
+ translation: typeof en;
7
+ };
8
+ }
9
+ }
10
+ export declare const SUPPORTED_LOCALES: readonly ["en", "ko"];
11
+ export type Locale = (typeof SUPPORTED_LOCALES)[number];
12
+ /** 환경변수에서 로케일 결정. 미지원 값(C·fr 등)은 건너뛰고 다음 후보로 진행한다. */
13
+ export declare function resolveLocale(env?: NodeJS.ProcessEnv): Locale;
14
+ /** 로케일 강제 전환 — 테스트·명시 재설정용. 인라인 리소스라 동기 반영된다. */
15
+ export declare function setLocale(locale: Locale): void;
16
+ export declare function getLocale(): Locale;
17
+ /** 카탈로그 조회. 키·파라미터 타입은 en 리소스에서 유도된다. init 후 캡처 — changeLanguage 를 따라간다(실측 확인). */
18
+ export declare const t: import("i18next").TFunction<["translation", ...never[]], undefined>;
19
+ /**
20
+ * 로케일 고정 t — 레인별 채널 메시지용(LaneConf.lang). locale 미지정·미지원 값이면
21
+ * 전역 로케일 추종 t 를 반환한다(옵트인 기본 불변).
22
+ */
23
+ export declare function tFor(locale?: string): typeof t;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * i18n 로케일 결정·조회 SoT — i18next 단일 인스턴스(인라인 en/ko 리소스).
3
+ * 로케일 우선순위: ADDE_LANG > LC_ALL > LC_MESSAGES > LANG > en (POSIX 관행).
4
+ * 모듈 로드 시 동기 초기화 — 진입점(CLI·데몬·테스트)의 명시 init 불요.
5
+ */
6
+ import i18next from "i18next";
7
+ import { en } from "./locales/en.js";
8
+ import { ko } from "./locales/ko.js";
9
+ export const SUPPORTED_LOCALES = ["en", "ko"];
10
+ /** `ko_KR.UTF-8` 류 POSIX 값에서 언어 코드만 취한다. 미지원 언어는 undefined. */
11
+ function parseLocale(raw) {
12
+ if (!raw)
13
+ return undefined;
14
+ const lang = raw.trim().toLowerCase().split(".")[0]?.split("_")[0];
15
+ return SUPPORTED_LOCALES.includes(lang ?? "")
16
+ ? lang
17
+ : undefined;
18
+ }
19
+ /** 환경변수에서 로케일 결정. 미지원 값(C·fr 등)은 건너뛰고 다음 후보로 진행한다. */
20
+ export function resolveLocale(env = process.env) {
21
+ for (const raw of [env.ADDE_LANG, env.LC_ALL, env.LC_MESSAGES, env.LANG]) {
22
+ const locale = parseLocale(raw);
23
+ if (locale)
24
+ return locale;
25
+ }
26
+ return "en";
27
+ }
28
+ const instance = i18next.createInstance();
29
+ void instance.init({
30
+ lng: resolveLocale(),
31
+ fallbackLng: "en",
32
+ initAsync: false,
33
+ resources: { en: { translation: en }, ko: { translation: ko } },
34
+ interpolation: { escapeValue: false },
35
+ });
36
+ /** 로케일 강제 전환 — 테스트·명시 재설정용. 인라인 리소스라 동기 반영된다. */
37
+ export function setLocale(locale) {
38
+ void instance.changeLanguage(locale);
39
+ }
40
+ export function getLocale() {
41
+ return parseLocale(instance.language) ?? "en";
42
+ }
43
+ /** 카탈로그 조회. 키·파라미터 타입은 en 리소스에서 유도된다. init 후 캡처 — changeLanguage 를 따라간다(실측 확인). */
44
+ export const t = instance.t;
45
+ /**
46
+ * 로케일 고정 t — 레인별 채널 메시지용(LaneConf.lang). locale 미지정·미지원 값이면
47
+ * 전역 로케일 추종 t 를 반환한다(옵트인 기본 불변).
48
+ */
49
+ export function tFor(locale) {
50
+ const parsed = parseLocale(locale);
51
+ return parsed ? instance.getFixedT(parsed) : t;
52
+ }
53
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/shared/i18n.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AASrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;AAGvD,+DAA+D;AAC/D,SAAS,WAAW,CAAC,GAAuB;IAC1C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAQ,iBAAuC,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;QAClE,CAAC,CAAE,IAAe;QAClB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACzE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;AAC1C,KAAK,QAAQ,CAAC,IAAI,CAAC;IACjB,GAAG,EAAE,aAAa,EAAE;IACpB,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE;IAC/D,aAAa,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;CACtC,CAAC,CAAC;AAEH,iDAAiD;AACjD,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,KAAK,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AAChD,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AAE5B;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,MAAe;IAClC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,393 @@
1
+ /**
2
+ * English message catalog. 키 구조의 SoT — 타 로케일은 `satisfies typeof en` 으로
3
+ * 키 패리티를 컴파일 타임 강제한다. 보간은 i18next `{{var}}` 문법.
4
+ */
5
+ export declare const en: {
6
+ usage: {
7
+ main: string;
8
+ up: string;
9
+ down: string;
10
+ restart: string;
11
+ status: string;
12
+ doctor: string;
13
+ logs: string;
14
+ sessions: string;
15
+ completion: string;
16
+ init: string;
17
+ alias: string;
18
+ laneAdd: string;
19
+ laneLs: string;
20
+ laneShow: string;
21
+ laneRm: string;
22
+ daemon: string;
23
+ lane: string;
24
+ };
25
+ cli: {
26
+ cmdError: string;
27
+ laneError: string;
28
+ unknownSub: string;
29
+ unknownCmd: string;
30
+ didYouMean: string;
31
+ };
32
+ completion: {
33
+ unknownShell: string;
34
+ };
35
+ run: {
36
+ laneStartFailed: {
37
+ situation: string;
38
+ action: string;
39
+ };
40
+ unknownCause: string;
41
+ noLanes: {
42
+ situation: string;
43
+ action: string;
44
+ };
45
+ signalShutdown: string;
46
+ shutdownError: {
47
+ situation: string;
48
+ action: string;
49
+ };
50
+ upDone: string;
51
+ statusHint: string;
52
+ downDone: string;
53
+ restartDone: string;
54
+ };
55
+ ops: {
56
+ status: {
57
+ noLanesConf: string;
58
+ noLanesRegistered: string;
59
+ noRunning: string;
60
+ deadWarnAggregate: string;
61
+ staleWarnAggregate: string;
62
+ deadWarnSingle: string;
63
+ staleWarnSingle: string;
64
+ };
65
+ doctor: {
66
+ hint: string;
67
+ summary: string;
68
+ };
69
+ logs: {
70
+ whatEngine: string;
71
+ whatTranscript: string;
72
+ notFound: string;
73
+ empty: string;
74
+ };
75
+ };
76
+ lane: {
77
+ valueRequired: string;
78
+ sourceRetry: string;
79
+ retry: {
80
+ permTier: string;
81
+ fileMode: string;
82
+ lang: string;
83
+ chatId: string;
84
+ allowFrom: string;
85
+ };
86
+ prompt: {
87
+ source: string;
88
+ permTier: string;
89
+ allowlist: string;
90
+ denylist: string;
91
+ safeDefaults: string;
92
+ lang: string;
93
+ token: string;
94
+ cwd: string;
95
+ chatId: string;
96
+ allowFrom: string;
97
+ fileMode: string;
98
+ root: string;
99
+ inbox: string;
100
+ approvals: string;
101
+ outbox: string;
102
+ };
103
+ ttyOnly: {
104
+ situation: string;
105
+ action: string;
106
+ };
107
+ created: string;
108
+ noLanes: string;
109
+ removed: string;
110
+ tokenWritten: string;
111
+ tokenNext: string;
112
+ startHint: string;
113
+ };
114
+ doctor: {
115
+ node: {
116
+ name: string;
117
+ hint: string;
118
+ };
119
+ adapter: {
120
+ name: string;
121
+ missing: string;
122
+ hint: string;
123
+ };
124
+ daemonEntry: {
125
+ name: string;
126
+ missing: string;
127
+ hint: string;
128
+ };
129
+ base: {
130
+ name: string;
131
+ hint: string;
132
+ };
133
+ missingPath: string;
134
+ daemon: {
135
+ name: string;
136
+ registered: string;
137
+ notRunning: string;
138
+ plistOnly: string;
139
+ launchctlOnly: string;
140
+ mismatchHint: string;
141
+ queryFailed: string;
142
+ queryFailedHint: string;
143
+ };
144
+ lanes: {
145
+ name: string;
146
+ none: string;
147
+ addHint: string;
148
+ };
149
+ conf: {
150
+ readFailed: string;
151
+ readFailedHint: string;
152
+ };
153
+ source: {
154
+ unsupported: string;
155
+ hint: string;
156
+ };
157
+ cwd: {
158
+ hint: string;
159
+ };
160
+ token: {
161
+ name: string;
162
+ present: string;
163
+ missing: string;
164
+ hint: string;
165
+ };
166
+ perms: {
167
+ name: string;
168
+ ok: string;
169
+ envLoose: string;
170
+ envHint: string;
171
+ stateLoose: string;
172
+ stateHint: string;
173
+ };
174
+ };
175
+ update: {
176
+ available: string;
177
+ };
178
+ gate: {
179
+ hardDeny: string;
180
+ };
181
+ init: {
182
+ ttyOnly: {
183
+ situation: string;
184
+ action: string;
185
+ };
186
+ intro: string;
187
+ doctorWarn: string;
188
+ aliasPrompt: string;
189
+ aliasNoBin: string;
190
+ aliasCreated: string;
191
+ aliasAlready: string;
192
+ aliasSkipped: string;
193
+ aliasFailed: string;
194
+ projPrompt: string;
195
+ projRetry: string;
196
+ lanePrompt: string;
197
+ laneRetry: string;
198
+ done: string;
199
+ };
200
+ laneConfig: {
201
+ warn: {
202
+ cwdMissing: string;
203
+ mdRootMissingConf: string;
204
+ mdRootNotFound: string;
205
+ mdPathOverlap: string;
206
+ tokenFormat: string;
207
+ permTierUnknown: string;
208
+ autopassBanner: string;
209
+ autopassEmptyDeny: string;
210
+ allowDenyOverlap: string;
211
+ badLang: string;
212
+ telegramNoAuth: string;
213
+ };
214
+ err: {
215
+ emptyIdent: string;
216
+ badIdent: string;
217
+ badSource: string;
218
+ badChatId: string;
219
+ tokenOnlyTelegram: string;
220
+ allowFromOnlyTelegram: string;
221
+ badAllowFrom: string;
222
+ badFileMode: string;
223
+ badAllowTool: string;
224
+ badDenyEntry: string;
225
+ laneExists: string;
226
+ tokenEmpty: string;
227
+ envHasToken: string;
228
+ laneNotFound: string;
229
+ };
230
+ };
231
+ telegram: {
232
+ permPrompt: string;
233
+ enqueueFail: {
234
+ situation: string;
235
+ action: string;
236
+ };
237
+ };
238
+ markdown: {
239
+ enqueueFail: {
240
+ situation: string;
241
+ action: string;
242
+ };
243
+ confRootMissing: string;
244
+ confInboxMissing: string;
245
+ rootNotFound: string;
246
+ pathNotRelative: string;
247
+ controlNoteInCwd: string;
248
+ pathsOverlap: string;
249
+ inboxInsideDir: string;
250
+ badApprovalId: string;
251
+ outMeta: string;
252
+ approvalMeta: string;
253
+ };
254
+ supervisor: {
255
+ noLanesMsg: string;
256
+ alreadyRunning: string;
257
+ autopassDenySome: string;
258
+ autopassDenyEmpty: string;
259
+ autopassBanner: {
260
+ situation: string;
261
+ action: string;
262
+ };
263
+ upStarted: string;
264
+ upSkipped: string;
265
+ downStopped: string;
266
+ };
267
+ launchd: {
268
+ macOnly: {
269
+ situation: string;
270
+ action: string;
271
+ };
272
+ loadFail: {
273
+ situation: string;
274
+ action: string;
275
+ };
276
+ binMissing: {
277
+ situation: string;
278
+ action: string;
279
+ };
280
+ };
281
+ queue: {
282
+ claimFail: {
283
+ situation: string;
284
+ action: string;
285
+ };
286
+ quarantined: string;
287
+ };
288
+ injector: {
289
+ injectFailed: string;
290
+ control: {
291
+ cleared: string;
292
+ compacted: string;
293
+ resumed: string;
294
+ resumeFallback: string;
295
+ resumeMissing: string;
296
+ unsupported: string;
297
+ relaunchFailed: string;
298
+ sessionsHeader: string;
299
+ sessionsItem: string;
300
+ sessionsNoLabel: string;
301
+ sessionsEmpty: string;
302
+ sessionsHint: string;
303
+ };
304
+ failNote: {
305
+ situation: string;
306
+ action: string;
307
+ };
308
+ };
309
+ transcript: {
310
+ commandsUpdated: string;
311
+ };
312
+ acp: {
313
+ spawnFail: {
314
+ situation: string;
315
+ action: string;
316
+ };
317
+ handshakeTimeout: {
318
+ situation: string;
319
+ action: string;
320
+ };
321
+ subscriberError: string;
322
+ bypassAction: string;
323
+ };
324
+ permDiff: {
325
+ queryFailedMsg: string;
326
+ warnLine: string;
327
+ looseEngine: string;
328
+ bypassMsg: string;
329
+ engineUnknown: string;
330
+ };
331
+ log: {
332
+ supervisor: {
333
+ noConf: string;
334
+ heartbeatFail: string;
335
+ ledgerFail: string;
336
+ deadCleanupFail: string;
337
+ channelWarnFail: string;
338
+ injectorStartFail: string;
339
+ runtimeWriteFail: string;
340
+ runtimeRemoveFail: string;
341
+ securePermsFail: string;
342
+ laneStartFail: string;
343
+ };
344
+ queue: {
345
+ quarantineFail: string;
346
+ failedWriteFail: string;
347
+ };
348
+ injector: {
349
+ injectError: string;
350
+ failedWriteFail: string;
351
+ renderError: string;
352
+ advanceError: string;
353
+ failNotifyError: string;
354
+ relaunchError: string;
355
+ };
356
+ telegram: {
357
+ rateLimit: string;
358
+ enqueueError: string;
359
+ answerCallbackError: string;
360
+ unknownCallback: string;
361
+ unauthorizedMessage: string;
362
+ unauthorizedCallback: string;
363
+ noAuthConfigured: string;
364
+ pollError: string;
365
+ alertSendError: string;
366
+ pollLoopEnd: string;
367
+ };
368
+ markdown: {
369
+ quarantineFail: string;
370
+ enqueueError: string;
371
+ alertWriteError: string;
372
+ inboxError: string;
373
+ approvalsError: string;
374
+ pollError: string;
375
+ };
376
+ transcript: {
377
+ auditAppendFail: string;
378
+ appendFail: string;
379
+ };
380
+ acp: {
381
+ engineProcessError: string;
382
+ loadSessionFail: string;
383
+ subscriberError: string;
384
+ transcriptWriteFail: string;
385
+ permDiff: string;
386
+ };
387
+ };
388
+ notify: {
389
+ block: string;
390
+ exception: string;
391
+ warn: string;
392
+ };
393
+ };