twinny 0.0.0-dev.260525150705

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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -0
  3. package/README.zh-CN.md +252 -0
  4. package/configs/banner.png +0 -0
  5. package/configs/logo.png +0 -0
  6. package/dist/app/caffeinate.d.ts +28 -0
  7. package/dist/app/caffeinate.js +96 -0
  8. package/dist/app/caffeinate.js.map +1 -0
  9. package/dist/app/daemon.d.ts +1 -0
  10. package/dist/app/daemon.js +44 -0
  11. package/dist/app/daemon.js.map +1 -0
  12. package/dist/app/lark-assets.d.ts +25 -0
  13. package/dist/app/lark-assets.js +108 -0
  14. package/dist/app/lark-assets.js.map +1 -0
  15. package/dist/app/startup-probe.d.ts +17 -0
  16. package/dist/app/startup-probe.js +90 -0
  17. package/dist/app/startup-probe.js.map +1 -0
  18. package/dist/app/wiring.d.ts +122 -0
  19. package/dist/app/wiring.js +694 -0
  20. package/dist/app/wiring.js.map +1 -0
  21. package/dist/cli/commands.d.ts +1 -0
  22. package/dist/cli/commands.js +47 -0
  23. package/dist/cli/commands.js.map +1 -0
  24. package/dist/cli/install-wizard.d.ts +41 -0
  25. package/dist/cli/install-wizard.js +629 -0
  26. package/dist/cli/install-wizard.js.map +1 -0
  27. package/dist/codex/appserver.d.ts +109 -0
  28. package/dist/codex/appserver.js +308 -0
  29. package/dist/codex/appserver.js.map +1 -0
  30. package/dist/codex/goal.d.ts +64 -0
  31. package/dist/codex/goal.js +433 -0
  32. package/dist/codex/goal.js.map +1 -0
  33. package/dist/codex/index.d.ts +6 -0
  34. package/dist/codex/index.js +7 -0
  35. package/dist/codex/index.js.map +1 -0
  36. package/dist/codex/protocol.d.ts +95 -0
  37. package/dist/codex/protocol.js +205 -0
  38. package/dist/codex/protocol.js.map +1 -0
  39. package/dist/codex/thread-name.d.ts +3 -0
  40. package/dist/codex/thread-name.js +27 -0
  41. package/dist/codex/thread-name.js.map +1 -0
  42. package/dist/codex/thread.d.ts +76 -0
  43. package/dist/codex/thread.js +80 -0
  44. package/dist/codex/thread.js.map +1 -0
  45. package/dist/codex/turn.d.ts +166 -0
  46. package/dist/codex/turn.js +746 -0
  47. package/dist/codex/turn.js.map +1 -0
  48. package/dist/config/bootstrap.d.ts +14 -0
  49. package/dist/config/bootstrap.js +56 -0
  50. package/dist/config/bootstrap.js.map +1 -0
  51. package/dist/config/index.d.ts +4 -0
  52. package/dist/config/index.js +5 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/config/loader.d.ts +49 -0
  55. package/dist/config/loader.js +467 -0
  56. package/dist/config/loader.js.map +1 -0
  57. package/dist/config/paths.d.ts +11 -0
  58. package/dist/config/paths.js +43 -0
  59. package/dist/config/paths.js.map +1 -0
  60. package/dist/config/secrets.d.ts +33 -0
  61. package/dist/config/secrets.js +85 -0
  62. package/dist/config/secrets.js.map +1 -0
  63. package/dist/conversation/manager.d.ts +701 -0
  64. package/dist/conversation/manager.js +7673 -0
  65. package/dist/conversation/manager.js.map +1 -0
  66. package/dist/conversation/queue.d.ts +8 -0
  67. package/dist/conversation/queue.js +28 -0
  68. package/dist/conversation/queue.js.map +1 -0
  69. package/dist/conversation/routing.d.ts +11 -0
  70. package/dist/conversation/routing.js +55 -0
  71. package/dist/conversation/routing.js.map +1 -0
  72. package/dist/errors.d.ts +6 -0
  73. package/dist/errors.js +17 -0
  74. package/dist/errors.js.map +1 -0
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.js +4 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/lark/auth.d.ts +41 -0
  79. package/dist/lark/auth.js +132 -0
  80. package/dist/lark/auth.js.map +1 -0
  81. package/dist/lark/browser-auth.d.ts +68 -0
  82. package/dist/lark/browser-auth.js +258 -0
  83. package/dist/lark/browser-auth.js.map +1 -0
  84. package/dist/lark/cards.d.ts +140 -0
  85. package/dist/lark/cards.js +1150 -0
  86. package/dist/lark/cards.js.map +1 -0
  87. package/dist/lark/contact.d.ts +41 -0
  88. package/dist/lark/contact.js +122 -0
  89. package/dist/lark/contact.js.map +1 -0
  90. package/dist/lark/events.d.ts +65 -0
  91. package/dist/lark/events.js +218 -0
  92. package/dist/lark/events.js.map +1 -0
  93. package/dist/lark/files.d.ts +36 -0
  94. package/dist/lark/files.js +191 -0
  95. package/dist/lark/files.js.map +1 -0
  96. package/dist/lark/filters.d.ts +73 -0
  97. package/dist/lark/filters.js +678 -0
  98. package/dist/lark/filters.js.map +1 -0
  99. package/dist/lark/index.d.ts +10 -0
  100. package/dist/lark/index.js +11 -0
  101. package/dist/lark/index.js.map +1 -0
  102. package/dist/lark/messages.d.ts +87 -0
  103. package/dist/lark/messages.js +428 -0
  104. package/dist/lark/messages.js.map +1 -0
  105. package/dist/lark/openapi.d.ts +58 -0
  106. package/dist/lark/openapi.js +206 -0
  107. package/dist/lark/openapi.js.map +1 -0
  108. package/dist/lark/redactor.d.ts +5 -0
  109. package/dist/lark/redactor.js +68 -0
  110. package/dist/lark/redactor.js.map +1 -0
  111. package/dist/lark/types.d.ts +49 -0
  112. package/dist/lark/types.js +18 -0
  113. package/dist/lark/types.js.map +1 -0
  114. package/dist/launchd/install.d.ts +22 -0
  115. package/dist/launchd/install.js +114 -0
  116. package/dist/launchd/install.js.map +1 -0
  117. package/dist/launchd/plist.d.ts +10 -0
  118. package/dist/launchd/plist.js +61 -0
  119. package/dist/launchd/plist.js.map +1 -0
  120. package/dist/lock/index.d.ts +20 -0
  121. package/dist/lock/index.js +74 -0
  122. package/dist/lock/index.js.map +1 -0
  123. package/dist/main.d.ts +2 -0
  124. package/dist/main.js +11 -0
  125. package/dist/main.js.map +1 -0
  126. package/dist/markdown.d.ts +12 -0
  127. package/dist/markdown.js +149 -0
  128. package/dist/markdown.js.map +1 -0
  129. package/dist/observability/health.d.ts +25 -0
  130. package/dist/observability/health.js +187 -0
  131. package/dist/observability/health.js.map +1 -0
  132. package/dist/observability/logs.d.ts +10 -0
  133. package/dist/observability/logs.js +34 -0
  134. package/dist/observability/logs.js.map +1 -0
  135. package/dist/observability/system-notifications.d.ts +25 -0
  136. package/dist/observability/system-notifications.js +33 -0
  137. package/dist/observability/system-notifications.js.map +1 -0
  138. package/dist/profiles/guest.d.ts +19 -0
  139. package/dist/profiles/guest.js +241 -0
  140. package/dist/profiles/guest.js.map +1 -0
  141. package/dist/profiles/index.d.ts +5 -0
  142. package/dist/profiles/index.js +14 -0
  143. package/dist/profiles/index.js.map +1 -0
  144. package/dist/profiles/owner.d.ts +1 -0
  145. package/dist/profiles/owner.js +6 -0
  146. package/dist/profiles/owner.js.map +1 -0
  147. package/dist/store/db.d.ts +10 -0
  148. package/dist/store/db.js +29 -0
  149. package/dist/store/db.js.map +1 -0
  150. package/dist/store/index.d.ts +3 -0
  151. package/dist/store/index.js +4 -0
  152. package/dist/store/index.js.map +1 -0
  153. package/dist/store/migrations.d.ts +13 -0
  154. package/dist/store/migrations.js +79 -0
  155. package/dist/store/migrations.js.map +1 -0
  156. package/dist/store/repositories.d.ts +227 -0
  157. package/dist/store/repositories.js +1384 -0
  158. package/dist/store/repositories.js.map +1 -0
  159. package/dist/telemetry/client.d.ts +60 -0
  160. package/dist/telemetry/client.js +204 -0
  161. package/dist/telemetry/client.js.map +1 -0
  162. package/dist/telemetry/hash.d.ts +1 -0
  163. package/dist/telemetry/hash.js +8 -0
  164. package/dist/telemetry/hash.js.map +1 -0
  165. package/dist/telemetry/index.d.ts +4 -0
  166. package/dist/telemetry/index.js +5 -0
  167. package/dist/telemetry/index.js.map +1 -0
  168. package/dist/telemetry/posthog.d.ts +27 -0
  169. package/dist/telemetry/posthog.js +45 -0
  170. package/dist/telemetry/posthog.js.map +1 -0
  171. package/dist/telemetry/reporter.d.ts +13 -0
  172. package/dist/telemetry/reporter.js +29 -0
  173. package/dist/telemetry/reporter.js.map +1 -0
  174. package/dist/types.d.ts +330 -0
  175. package/dist/types.js +9 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/version.d.ts +1 -0
  178. package/dist/version.js +1 -0
  179. package/dist/version.js.map +1 -0
  180. package/dist/version.json +3 -0
  181. package/dist/workspace/index.d.ts +2 -0
  182. package/dist/workspace/index.js +3 -0
  183. package/dist/workspace/index.js.map +1 -0
  184. package/dist/workspace/manager.d.ts +14 -0
  185. package/dist/workspace/manager.js +69 -0
  186. package/dist/workspace/manager.js.map +1 -0
  187. package/dist/workspace/slug.d.ts +8 -0
  188. package/dist/workspace/slug.js +59 -0
  189. package/dist/workspace/slug.js.map +1 -0
  190. package/migrations/0001_initial.sql +102 -0
  191. package/package.json +85 -0
@@ -0,0 +1,19 @@
1
+ import { type TomlTable } from "smol-toml";
2
+ import type { OwnerConfig } from "../types.js";
3
+ export interface GuestCodexConfigOptions {
4
+ model?: string;
5
+ modelReasoningEffort?: "minimal" | "low" | "medium" | "high";
6
+ disabledPlugins?: string[];
7
+ disabledSkillPaths?: string[];
8
+ }
9
+ export interface GuestSafetyCheck {
10
+ ok: boolean;
11
+ issues: string[];
12
+ }
13
+ export declare const DEFAULT_GUEST_CODEX_MODEL = "gpt-5.5";
14
+ export declare function createGuestCodexConfigDocument(options?: GuestCodexConfigOptions): TomlTable;
15
+ export declare function serializeGuestCodexConfig(options?: GuestCodexConfigOptions): string;
16
+ export declare function ensureProjectTrust(codexHome: string, cwd: string): Promise<boolean>;
17
+ export declare function ensureWorkspaceTrust(codexHome: string, cwd: string): Promise<boolean>;
18
+ export declare function renderGuestAgents(owner: Pick<OwnerConfig, "openId" | "userId" | "displayName">): string;
19
+ export declare function validateGuestCodexConfigDocument(document: TomlTable): GuestSafetyCheck;
@@ -0,0 +1,241 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parse, stringify } from "smol-toml";
4
+ export const DEFAULT_GUEST_CODEX_MODEL = "gpt-5.5";
5
+ const requiredGuestNetworkDomains = {
6
+ "*": "allow"
7
+ };
8
+ const guestConfigWriteLocks = new Map();
9
+ export function createGuestCodexConfigDocument(options = {}) {
10
+ const document = {
11
+ model: options.model ?? DEFAULT_GUEST_CODEX_MODEL,
12
+ model_reasoning_effort: options.modelReasoningEffort ?? "medium",
13
+ sandbox_mode: "workspace-write",
14
+ approval_policy: "never",
15
+ web_search: "disabled",
16
+ sandbox_workspace_write: {
17
+ network_access: true
18
+ },
19
+ default_permissions: "twinny_guest",
20
+ permissions: {
21
+ twinny_guest: {
22
+ filesystem: {
23
+ ":tmpdir": "write"
24
+ },
25
+ network: {
26
+ enabled: true,
27
+ mode: "full",
28
+ allow_local_binding: true,
29
+ domains: { ...requiredGuestNetworkDomains }
30
+ }
31
+ }
32
+ },
33
+ shell_environment_policy: {
34
+ inherit: "none"
35
+ }
36
+ };
37
+ for (const pluginName of options.disabledPlugins ?? []) {
38
+ document.plugins ??= {};
39
+ const plugins = document.plugins;
40
+ plugins[pluginName] = { enabled: false };
41
+ }
42
+ if (options.disabledSkillPaths?.length) {
43
+ document.skills = {
44
+ config: options.disabledSkillPaths.map((skillPath) => ({ path: skillPath, enabled: false }))
45
+ };
46
+ }
47
+ return document;
48
+ }
49
+ export function serializeGuestCodexConfig(options = {}) {
50
+ return stringify(createGuestCodexConfigDocument(options)) + "\n";
51
+ }
52
+ export async function ensureProjectTrust(codexHome, cwd) {
53
+ const configPath = path.join(codexHome, "config.toml");
54
+ return withCodexConfigWriteLock(configPath, async () => {
55
+ const document = await readCodexConfigDocument(configPath);
56
+ const changed = ensureProjectTrusted(document, cwd);
57
+ return changed ? writeCodexConfigIfChanged(configPath, document) : false;
58
+ });
59
+ }
60
+ export async function ensureWorkspaceTrust(codexHome, cwd) {
61
+ return ensureProjectTrust(codexHome, cwd);
62
+ }
63
+ export function renderGuestAgents(owner) {
64
+ const ownerUserId = owner.userId ? `\n- Owner Feishu user_id: ${owner.userId}` : "";
65
+ return `# Twinny Guest Profile
66
+
67
+ You are running as Twinny's guest Codex profile for a Feishu/Lark P2P conversation.
68
+
69
+ Owner identity:
70
+ - Owner display name: ${owner.displayName}
71
+ - Owner Feishu open_id: ${owner.openId}${ownerUserId}
72
+
73
+ Security boundary:
74
+ - Treat the current workspace as the only writable project context.
75
+ - Do not try to inspect the device owner's home directory, Keychain, SSH keys, Codex state, browser data, or unrelated repositories.
76
+ - Do not request approvals. Twinny runs guest turns with approval_policy = "never".
77
+ - Keep responses focused on the guest user's request and avoid exposing local machine details.
78
+
79
+ Lark output:
80
+ - Use <mention_lark_user>OPEN_ID</mention_lark_user> in your final answer to mention a Feishu/Lark user. Put only the user's Feishu/Lark open_id inside the tag.
81
+ `;
82
+ }
83
+ export function validateGuestCodexConfigDocument(document) {
84
+ const issues = [];
85
+ if (document.sandbox_mode !== "workspace-write") {
86
+ issues.push("guest sandbox_mode must be workspace-write");
87
+ }
88
+ if (document.approval_policy !== "never") {
89
+ issues.push("guest approval_policy must be never");
90
+ }
91
+ if (document.web_search !== "disabled") {
92
+ issues.push("guest web_search must be disabled");
93
+ }
94
+ if (document.default_permissions !== "twinny_guest") {
95
+ issues.push("guest default_permissions must be twinny_guest");
96
+ }
97
+ const networkPermissions = getGuestNetworkPermissions(document);
98
+ if (!networkPermissions) {
99
+ issues.push("guest twinny_guest network permissions are required");
100
+ }
101
+ else {
102
+ if (networkPermissions.enabled !== true) {
103
+ issues.push("guest twinny_guest network.enabled must be true");
104
+ }
105
+ if (networkPermissions.mode !== "full") {
106
+ issues.push("guest twinny_guest network.mode must be full");
107
+ }
108
+ if (networkPermissions.allow_local_binding !== true) {
109
+ issues.push("guest twinny_guest network.allow_local_binding must be true");
110
+ }
111
+ const domains = networkPermissions.domains;
112
+ if (!isTomlTable(domains)) {
113
+ issues.push("guest twinny_guest network.domains must allow all domains");
114
+ }
115
+ else {
116
+ for (const [domain, access] of Object.entries(requiredGuestNetworkDomains)) {
117
+ if (domains[domain] !== access) {
118
+ issues.push(`guest twinny_guest network.domains.${domain} must be ${access}`);
119
+ }
120
+ }
121
+ for (const domain of Object.keys(domains)) {
122
+ if (!(domain in requiredGuestNetworkDomains)) {
123
+ issues.push(`guest twinny_guest network.domains.${domain} must be removed`);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ const filesystemPermissions = getGuestFilesystemPermissions(document);
129
+ if (!filesystemPermissions) {
130
+ issues.push("guest twinny_guest filesystem permissions are required");
131
+ }
132
+ else if (filesystemPermissions[":tmpdir"] !== "write") {
133
+ issues.push("guest twinny_guest filesystem.:tmpdir must be write");
134
+ }
135
+ const shellPolicy = document.shell_environment_policy;
136
+ if (typeof shellPolicy !== "object" || shellPolicy === null || Array.isArray(shellPolicy)) {
137
+ issues.push("guest shell_environment_policy is required");
138
+ }
139
+ else if (shellPolicy.inherit !== "none") {
140
+ issues.push("guest shell_environment_policy.inherit must be none");
141
+ }
142
+ return { ok: issues.length === 0, issues };
143
+ }
144
+ function ensureProjectTrusted(document, cwd) {
145
+ const projects = ensureTomlTable(document, "projects");
146
+ const cwdPath = path.resolve(cwd);
147
+ const existingProject = projects[cwdPath];
148
+ const project = isTomlTable(existingProject) ? existingProject : {};
149
+ if (project.trust_level === "trusted") {
150
+ return false;
151
+ }
152
+ project.trust_level = "trusted";
153
+ projects[cwdPath] = project;
154
+ return true;
155
+ }
156
+ function getGuestNetworkPermissions(document) {
157
+ const permissions = document.permissions;
158
+ if (!isTomlTable(permissions)) {
159
+ return undefined;
160
+ }
161
+ const profile = permissions.twinny_guest;
162
+ if (!isTomlTable(profile)) {
163
+ return undefined;
164
+ }
165
+ const network = profile.network;
166
+ return isTomlTable(network) ? network : undefined;
167
+ }
168
+ function getGuestFilesystemPermissions(document) {
169
+ const permissions = document.permissions;
170
+ if (!isTomlTable(permissions)) {
171
+ return undefined;
172
+ }
173
+ const profile = permissions.twinny_guest;
174
+ if (!isTomlTable(profile)) {
175
+ return undefined;
176
+ }
177
+ const filesystem = profile.filesystem;
178
+ return isTomlTable(filesystem) ? filesystem : undefined;
179
+ }
180
+ async function readCodexConfigDocument(configPath) {
181
+ try {
182
+ return parse(await fs.readFile(configPath, "utf8"));
183
+ }
184
+ catch (error) {
185
+ if (isNodeError(error, "ENOENT")) {
186
+ return {};
187
+ }
188
+ throw error;
189
+ }
190
+ }
191
+ async function writeCodexConfigIfChanged(configPath, document) {
192
+ const content = stringify(document) + "\n";
193
+ try {
194
+ if ((await fs.readFile(configPath, "utf8")) === content) {
195
+ return false;
196
+ }
197
+ }
198
+ catch (error) {
199
+ if (!isNodeError(error, "ENOENT")) {
200
+ throw error;
201
+ }
202
+ }
203
+ await fs.mkdir(path.dirname(configPath), { recursive: true });
204
+ await fs.writeFile(configPath, content, { encoding: "utf8", mode: 0o600 });
205
+ return true;
206
+ }
207
+ function ensureTomlTable(document, key) {
208
+ const existing = document[key];
209
+ if (isTomlTable(existing)) {
210
+ return existing;
211
+ }
212
+ const table = {};
213
+ document[key] = table;
214
+ return table;
215
+ }
216
+ function isTomlTable(value) {
217
+ return typeof value === "object" && value !== null && !Array.isArray(value);
218
+ }
219
+ async function withCodexConfigWriteLock(configPath, operation) {
220
+ const previous = guestConfigWriteLocks.get(configPath) ?? Promise.resolve();
221
+ let releaseCurrent;
222
+ const current = new Promise((resolve) => {
223
+ releaseCurrent = resolve;
224
+ });
225
+ const next = previous.catch(() => undefined).then(() => current);
226
+ guestConfigWriteLocks.set(configPath, next);
227
+ await previous.catch(() => undefined);
228
+ try {
229
+ return await operation();
230
+ }
231
+ finally {
232
+ releaseCurrent();
233
+ if (guestConfigWriteLocks.get(configPath) === next) {
234
+ guestConfigWriteLocks.delete(configPath);
235
+ }
236
+ }
237
+ }
238
+ function isNodeError(error, code) {
239
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
240
+ }
241
+ //# sourceMappingURL=guest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guest.js","sourceRoot":"","sources":["../../src/profiles/guest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type ProfileName, type TwinnyConfig } from "../types.js";
2
+ export declare function defaultProfileForSender(senderOpenId: string, ownerOpenId: string): ProfileName;
3
+ export declare function getProfileCodexHome(config: TwinnyConfig, profile: ProfileName): string;
4
+ export { defaultOwnerCodexTarget } from "./owner.js";
5
+ export { createGuestCodexConfigDocument, DEFAULT_GUEST_CODEX_MODEL, ensureProjectTrust, ensureWorkspaceTrust, ensureWorkspaceTrust as ensureGuestWorkspaceTrust, ensureWorkspaceTrust as ensureGuestWorkspaceProjectTrusted, renderGuestAgents, serializeGuestCodexConfig, validateGuestCodexConfigDocument, type GuestCodexConfigOptions, type GuestSafetyCheck } from "./guest.js";
@@ -0,0 +1,14 @@
1
+ import { GUEST_PROFILE_NAME, HOST_PROFILE_NAME } from "../types.js";
2
+ export function defaultProfileForSender(senderOpenId, ownerOpenId) {
3
+ return senderOpenId === ownerOpenId ? HOST_PROFILE_NAME : GUEST_PROFILE_NAME;
4
+ }
5
+ export function getProfileCodexHome(config, profile) {
6
+ const resolved = config.profiles[profile];
7
+ if (!resolved) {
8
+ throw new Error(`Unknown Twinny profile: ${profile}`);
9
+ }
10
+ return resolved.codexHome;
11
+ }
12
+ export { defaultOwnerCodexTarget } from "./owner.js";
13
+ export { createGuestCodexConfigDocument, DEFAULT_GUEST_CODEX_MODEL, ensureProjectTrust, ensureWorkspaceTrust, ensureWorkspaceTrust as ensureGuestWorkspaceTrust, ensureWorkspaceTrust as ensureGuestWorkspaceProjectTrusted, renderGuestAgents, serializeGuestCodexConfig, validateGuestCodexConfigDocument } from "./guest.js";
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/profiles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAuC,MAAM,aAAa,CAAC;AAEzG,MAAM,UAAU,uBAAuB,CAAC,YAAoB,EAAE,WAAmB;IAC/E,OAAO,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,OAAoB;IAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,QAAQ,CAAC,SAAS,CAAC;AAC5B,CAAC;AAED,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,IAAI,yBAAyB,EACjD,oBAAoB,IAAI,kCAAkC,EAC1D,iBAAiB,EACjB,yBAAyB,EACzB,gCAAgC,EAGjC,MAAM,YAAY,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function defaultOwnerCodexTarget(homeDir?: string): string;
@@ -0,0 +1,6 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ export function defaultOwnerCodexTarget(homeDir = os.homedir()) {
4
+ return path.join(homeDir, ".codex");
5
+ }
6
+ //# sourceMappingURL=owner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner.js","sourceRoot":"","sources":["../../src/profiles/owner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,uBAAuB,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE;IAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import Database from "better-sqlite3";
2
+ import type { RuntimePaths } from "../types.js";
3
+ export type TwinnyDatabase = InstanceType<typeof Database>;
4
+ export interface OpenTwinnyDatabaseOptions {
5
+ migrate?: boolean;
6
+ readonly?: boolean;
7
+ timeoutMs?: number;
8
+ }
9
+ export declare function openTwinnyDatabase(sqliteFile: string, options?: OpenTwinnyDatabaseOptions): TwinnyDatabase;
10
+ export declare function openRuntimeDatabase(paths: Pick<RuntimePaths, "sqliteFile">, options?: OpenTwinnyDatabaseOptions): TwinnyDatabase;
@@ -0,0 +1,29 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { runStoreMigrations } from "./migrations.js";
5
+ export function openTwinnyDatabase(sqliteFile, options = {}) {
6
+ if (!options.readonly) {
7
+ fs.mkdirSync(path.dirname(sqliteFile), { recursive: true });
8
+ }
9
+ const databaseOptions = {};
10
+ if (options.readonly !== undefined) {
11
+ databaseOptions.readonly = options.readonly;
12
+ }
13
+ if (options.timeoutMs !== undefined) {
14
+ databaseOptions.timeout = options.timeoutMs;
15
+ }
16
+ const db = new Database(sqliteFile, databaseOptions);
17
+ db.pragma("foreign_keys = ON");
18
+ if (!options.readonly) {
19
+ db.pragma("journal_mode = WAL");
20
+ if (options.migrate ?? true) {
21
+ runStoreMigrations(db);
22
+ }
23
+ }
24
+ return db;
25
+ }
26
+ export function openRuntimeDatabase(paths, options = {}) {
27
+ return openTwinnyDatabase(paths.sqliteFile, options);
28
+ }
29
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/store/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAUrD,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,UAAqC,EAAE;IAC5F,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,eAAe,GAAqB,EAAE,CAAC;IAC7C,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACnC,eAAe,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC9C,CAAC;IACD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACpC,eAAe,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IAErD,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAE/B,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;YAC5B,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAuC,EAAE,UAAqC,EAAE;IAClH,OAAO,kBAAkB,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./db.js";
2
+ export * from "./migrations.js";
3
+ export * from "./repositories.js";
@@ -0,0 +1,4 @@
1
+ export * from "./db.js";
2
+ export * from "./migrations.js";
3
+ export * from "./repositories.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type Database from "better-sqlite3";
2
+ export interface StoreMigration {
3
+ version: number;
4
+ name: string;
5
+ sql: string;
6
+ }
7
+ export interface RunMigrationsOptions {
8
+ migrations?: StoreMigration[];
9
+ }
10
+ export declare const currentStoreSchemaVersion = 1;
11
+ export declare function loadStoreMigrations(): StoreMigration[];
12
+ export declare function getStoreSchemaVersion(db: Database.Database): number;
13
+ export declare function runStoreMigrations(db: Database.Database, options?: RunMigrationsOptions): number;
@@ -0,0 +1,79 @@
1
+ import fs from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { TwinnyError } from "../errors.js";
4
+ export const currentStoreSchemaVersion = 1;
5
+ const baselineMigrationFile = fileURLToPath(new URL("../../migrations/0001_initial.sql", import.meta.url));
6
+ export function loadStoreMigrations() {
7
+ return [
8
+ {
9
+ version: 1,
10
+ name: "0001_initial",
11
+ sql: fs.readFileSync(baselineMigrationFile, "utf8")
12
+ }
13
+ ];
14
+ }
15
+ export function getStoreSchemaVersion(db) {
16
+ const version = db.pragma("user_version", { simple: true });
17
+ if (typeof version !== "number") {
18
+ throw new TwinnyError("SQLite PRAGMA user_version returned a non-numeric value", "STORE_INVALID_VERSION");
19
+ }
20
+ return version;
21
+ }
22
+ export function runStoreMigrations(db, options = {}) {
23
+ const migrations = [...(options.migrations ?? loadStoreMigrations())].sort((left, right) => left.version - right.version);
24
+ const targetVersion = migrations.at(-1)?.version ?? 0;
25
+ const currentVersion = getStoreSchemaVersion(db);
26
+ if (currentVersion > targetVersion) {
27
+ throw new TwinnyError(`SQLite schema version ${currentVersion} is newer than supported version ${targetVersion}`, "STORE_UNSUPPORTED_VERSION");
28
+ }
29
+ const pending = migrations.filter((migration) => migration.version > currentVersion);
30
+ const migrate = db.transaction(() => {
31
+ let lastVersion = currentVersion;
32
+ if (pending.length === 0) {
33
+ return lastVersion;
34
+ }
35
+ for (const migration of pending) {
36
+ if (migration.version !== lastVersion + 1) {
37
+ throw new TwinnyError(`SQLite migration ${migration.name} is not contiguous after version ${lastVersion}`, "STORE_MIGRATION_GAP");
38
+ }
39
+ db.exec(migration.sql);
40
+ db.pragma(`user_version = ${migration.version}`);
41
+ lastVersion = migration.version;
42
+ }
43
+ return lastVersion;
44
+ });
45
+ const appliedVersion = migrate();
46
+ if (appliedVersion >= currentStoreSchemaVersion) {
47
+ validateBaselineSchema(db);
48
+ }
49
+ return appliedVersion;
50
+ }
51
+ function validateBaselineSchema(db) {
52
+ const requiredColumnsByTable = new Map([
53
+ [
54
+ "conversations",
55
+ ["conversation_key", "type", "chat_id", "name", "profile", "thread_id", "workspace", "profile_codex_home", "response_mode"]
56
+ ],
57
+ [
58
+ "threads",
59
+ ["thread_id", "conversation_key", "profile", "thread_has_rollout", "mode", "status", "name", "goal_status", "model", "effort"]
60
+ ],
61
+ [
62
+ "lark_messages",
63
+ ["event_id", "lark_user_id", "conversation_key", "thread_id", "route_kind", "status", "side_id", "token_usage_json"]
64
+ ]
65
+ ]);
66
+ for (const [tableName, requiredColumns] of requiredColumnsByTable) {
67
+ const columns = getTableColumns(db, tableName);
68
+ for (const columnName of requiredColumns) {
69
+ if (!columns.has(columnName)) {
70
+ throw new TwinnyError(`SQLite schema does not match the 1.0 baseline; reset or manually migrate the pre-1.0 development database before continuing`, "STORE_BASELINE_MISMATCH");
71
+ }
72
+ }
73
+ }
74
+ }
75
+ function getTableColumns(db, tableName) {
76
+ const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
77
+ return new Set(rows.map((row) => row.name));
78
+ }
79
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/store/migrations.ts"],"names":[],"mappings":"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"}