@duckmind/dm-darwin-x64 0.33.0 → 0.33.2

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 (81) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +1 -76
  3. package/package.json +1 -1
  4. package/theme/theme-alps.json +84 -0
  5. package/extensions/dm-chime/README.md +0 -11
  6. package/extensions/dm-chime/docs/protocols.md +0 -107
  7. package/extensions/dm-chime/index.ts +0 -205
  8. package/extensions/dm-chime/package.json +0 -33
  9. package/extensions/dm-phone/README.md +0 -24
  10. package/extensions/dm-phone/index.ts +0 -12
  11. package/extensions/dm-phone/node_modules/.package-lock.json +0 -29
  12. package/extensions/dm-phone/node_modules/ws/LICENSE +0 -20
  13. package/extensions/dm-phone/node_modules/ws/README.md +0 -548
  14. package/extensions/dm-phone/node_modules/ws/browser.js +0 -8
  15. package/extensions/dm-phone/node_modules/ws/index.js +0 -22
  16. package/extensions/dm-phone/node_modules/ws/lib/buffer-util.js +0 -131
  17. package/extensions/dm-phone/node_modules/ws/lib/constants.js +0 -19
  18. package/extensions/dm-phone/node_modules/ws/lib/event-target.js +0 -292
  19. package/extensions/dm-phone/node_modules/ws/lib/extension.js +0 -203
  20. package/extensions/dm-phone/node_modules/ws/lib/limiter.js +0 -55
  21. package/extensions/dm-phone/node_modules/ws/lib/permessage-deflate.js +0 -528
  22. package/extensions/dm-phone/node_modules/ws/lib/receiver.js +0 -760
  23. package/extensions/dm-phone/node_modules/ws/lib/sender.js +0 -607
  24. package/extensions/dm-phone/node_modules/ws/lib/stream.js +0 -161
  25. package/extensions/dm-phone/node_modules/ws/lib/subprotocol.js +0 -62
  26. package/extensions/dm-phone/node_modules/ws/lib/validation.js +0 -152
  27. package/extensions/dm-phone/node_modules/ws/lib/websocket-server.js +0 -562
  28. package/extensions/dm-phone/node_modules/ws/lib/websocket.js +0 -1407
  29. package/extensions/dm-phone/node_modules/ws/package.json +0 -70
  30. package/extensions/dm-phone/node_modules/ws/wrapper.mjs +0 -21
  31. package/extensions/dm-phone/package-lock.json +0 -66
  32. package/extensions/dm-phone/package.json +0 -35
  33. package/extensions/dm-phone/phone-session-pool.ts +0 -8
  34. package/extensions/dm-phone/public/app/attachments.js +0 -233
  35. package/extensions/dm-phone/public/app/autocomplete-controller.js +0 -81
  36. package/extensions/dm-phone/public/app/autocomplete.js +0 -135
  37. package/extensions/dm-phone/public/app/bindings.js +0 -178
  38. package/extensions/dm-phone/public/app/command-catalog.js +0 -76
  39. package/extensions/dm-phone/public/app/commands.js +0 -376
  40. package/extensions/dm-phone/public/app/constants.js +0 -60
  41. package/extensions/dm-phone/public/app/formatters.js +0 -131
  42. package/extensions/dm-phone/public/app/handlers.js +0 -442
  43. package/extensions/dm-phone/public/app/main.js +0 -6
  44. package/extensions/dm-phone/public/app/markdown.js +0 -105
  45. package/extensions/dm-phone/public/app/messages.js +0 -418
  46. package/extensions/dm-phone/public/app/sheet-actions.js +0 -113
  47. package/extensions/dm-phone/public/app/sheet-navigation.js +0 -19
  48. package/extensions/dm-phone/public/app/sheets-view.js +0 -287
  49. package/extensions/dm-phone/public/app/state.js +0 -95
  50. package/extensions/dm-phone/public/app/tool-rendering.js +0 -562
  51. package/extensions/dm-phone/public/app/transport.js +0 -176
  52. package/extensions/dm-phone/public/app/ui.js +0 -417
  53. package/extensions/dm-phone/public/app.js +0 -1
  54. package/extensions/dm-phone/public/icon.svg +0 -15
  55. package/extensions/dm-phone/public/index.html +0 -146
  56. package/extensions/dm-phone/public/manifest.webmanifest +0 -17
  57. package/extensions/dm-phone/public/styles.css +0 -1139
  58. package/extensions/dm-phone/public/sw.js +0 -78
  59. package/extensions/dm-phone/src/extension/duckmind-models.js +0 -264
  60. package/extensions/dm-phone/src/extension/phone-args.ts +0 -121
  61. package/extensions/dm-phone/src/extension/phone-paths.ts +0 -250
  62. package/extensions/dm-phone/src/extension/phone-quota.ts +0 -188
  63. package/extensions/dm-phone/src/extension/phone-runtime.ts +0 -154
  64. package/extensions/dm-phone/src/extension/phone-server-runtime.ts +0 -1217
  65. package/extensions/dm-phone/src/extension/phone-sessions.ts +0 -139
  66. package/extensions/dm-phone/src/extension/phone-static.ts +0 -30
  67. package/extensions/dm-phone/src/extension/phone-tailscale.ts +0 -148
  68. package/extensions/dm-phone/src/extension/phone-theme.ts +0 -85
  69. package/extensions/dm-phone/src/extension/register-phone-child-extension.ts +0 -112
  70. package/extensions/dm-phone/src/extension/register-phone-extension.ts +0 -106
  71. package/extensions/dm-phone/src/extension/types.ts +0 -73
  72. package/extensions/dm-phone/src/session-pool/parent-session-worker.ts +0 -882
  73. package/extensions/dm-phone/src/session-pool/session-pool.ts +0 -470
  74. package/extensions/dm-phone/src/session-pool/session-worker.ts +0 -739
  75. package/extensions/dm-phone/src/session-pool/types.ts +0 -111
  76. package/extensions/dm-phone/src/session-pool/utils.ts +0 -23
  77. package/extensions/dm-phone/test/duckmind-models.test.js +0 -147
  78. package/extensions/dm-thinking-timer/LICENSE +0 -21
  79. package/extensions/dm-thinking-timer/README.md +0 -7
  80. package/extensions/dm-thinking-timer/package.json +0 -20
  81. package/extensions/dm-thinking-timer/thinking-timer.ts +0 -250
@@ -1,188 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import type {
4
- CodexUsageResponse,
5
- PhoneQuotaResponse,
6
- PhoneQuotaWindow,
7
- RateLimitBucket,
8
- UsageWindow,
9
- } from "./types";
10
-
11
- const agentDirFromEnv = process.env.DM_CODING_AGENT_DIR?.trim() || process.env.PI_CODING_AGENT_DIR?.trim();
12
- const agentDir = agentDirFromEnv
13
- ? agentDirFromEnv
14
- : join(process.env.HOME || process.env.USERPROFILE || process.cwd(), ".dm", "agent");
15
- const authFile = join(agentDir, "auth.json");
16
- const codexUsageUrl = "https://chatgpt.com/backend-api/wham/usage";
17
- const sparkModelId = "gpt-5.3-codex-spark";
18
- const sparkLimitName = "GPT-5.3-Codex-Spark";
19
- const missingAuthErrorPrefix = "Missing openai-codex OAuth access/accountId";
20
-
21
- function clampPercent(value: number): number {
22
- return Math.min(100, Math.max(0, value));
23
- }
24
-
25
- function usedToLeftPercent(value: number | null | undefined): number | null {
26
- if (typeof value !== "number" || Number.isNaN(value)) return null;
27
- return clampPercent(100 - value);
28
- }
29
-
30
- function asObject(value: unknown): Record<string, unknown> | null {
31
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
32
- return value as Record<string, unknown>;
33
- }
34
-
35
- function normalizeRateLimitBucket(value: unknown): RateLimitBucket | null {
36
- const record = asObject(value);
37
- if (!record) return null;
38
- if (!("primary_window" in record || "secondary_window" in record || "limit_reached" in record || "allowed" in record)) {
39
- return null;
40
- }
41
- return record as RateLimitBucket;
42
- }
43
-
44
- function extractSparkRateLimitFromEntry(value: unknown): RateLimitBucket | null {
45
- const record = asObject(value);
46
- if (!record) return null;
47
- if (typeof record.limit_name !== "string" || record.limit_name.trim() !== sparkLimitName) return null;
48
- return normalizeRateLimitBucket(record.rate_limit);
49
- }
50
-
51
- function findSparkRateLimitBucket(data: CodexUsageResponse): RateLimitBucket | null {
52
- const additional = data.additional_rate_limits;
53
-
54
- if (Array.isArray(additional)) {
55
- for (const entry of additional) {
56
- const bucket = extractSparkRateLimitFromEntry(entry);
57
- if (bucket) return bucket;
58
- }
59
- return null;
60
- }
61
-
62
- const additionalMap = asObject(additional);
63
- if (!additionalMap) return null;
64
-
65
- for (const value of Object.values(additionalMap)) {
66
- const bucket = extractSparkRateLimitFromEntry(value);
67
- if (bucket) return bucket;
68
- }
69
-
70
- return null;
71
- }
72
-
73
- function selectRateLimitBucket(data: CodexUsageResponse, modelId: string): RateLimitBucket | null {
74
- if (modelId === sparkModelId) {
75
- return findSparkRateLimitBucket(data);
76
- }
77
- return normalizeRateLimitBucket(data.rate_limit);
78
- }
79
-
80
- function getResetSeconds(window: UsageWindow | null | undefined): number | null {
81
- const resetAfterSeconds = window?.reset_after_seconds;
82
- if (typeof resetAfterSeconds === "number" && !Number.isNaN(resetAfterSeconds)) {
83
- return resetAfterSeconds;
84
- }
85
-
86
- const resetAt = window?.reset_at;
87
- if (typeof resetAt !== "number" || Number.isNaN(resetAt)) return null;
88
-
89
- const resetAtSeconds = resetAt > 100_000_000_000 ? resetAt / 1000 : resetAt;
90
- return Math.max(0, resetAtSeconds - Date.now() / 1000);
91
- }
92
-
93
- function buildQuotaWindow(label: "5h" | "7d", window: UsageWindow | null | undefined): PhoneQuotaWindow | null {
94
- const leftPercent = usedToLeftPercent(window?.used_percent);
95
- if (leftPercent === null) return null;
96
-
97
- const roundedLeftPercent = Math.round(leftPercent);
98
- const roundedUsedPercent = Math.round(clampPercent(typeof window?.used_percent === "number" ? window.used_percent : 100 - leftPercent));
99
-
100
- return {
101
- label,
102
- leftPercent: roundedLeftPercent,
103
- usedPercent: roundedUsedPercent,
104
- resetAfterSeconds: getResetSeconds(window),
105
- text: `${roundedLeftPercent}%`,
106
- };
107
- }
108
-
109
- function shouldShowQuotaForModel(provider: string | null | undefined, modelId: string | null | undefined): boolean {
110
- return provider === "openai-codex" && typeof modelId === "string" && /^gpt-/i.test(modelId);
111
- }
112
-
113
- async function loadCodexAuthCredentials(): Promise<{ accessToken: string; accountId: string }> {
114
- const authRaw = await readFile(authFile, "utf8");
115
- const auth = JSON.parse(authRaw) as Record<
116
- string,
117
- | {
118
- type?: string;
119
- access?: string | null;
120
- accountId?: string | null;
121
- account_id?: string | null;
122
- }
123
- | undefined
124
- >;
125
-
126
- const codexEntry = auth["openai-codex"];
127
- const authEntry = codexEntry?.type === "oauth" ? codexEntry : undefined;
128
- const accessToken = authEntry?.access?.trim();
129
- const accountId = (authEntry?.accountId ?? authEntry?.account_id)?.trim();
130
-
131
- if (!accessToken || !accountId) {
132
- throw new Error(`${missingAuthErrorPrefix} in ${authFile}`);
133
- }
134
-
135
- return { accessToken, accountId };
136
- }
137
-
138
- async function requestCodexUsageJson(): Promise<CodexUsageResponse> {
139
- const credentials = await loadCodexAuthCredentials();
140
- const response = await fetch(codexUsageUrl, {
141
- headers: {
142
- accept: "*/*",
143
- authorization: `Bearer ${credentials.accessToken}`,
144
- "chatgpt-account-id": credentials.accountId,
145
- "content-type": "application/json",
146
- "user-agent": "codex-cli",
147
- },
148
- });
149
-
150
- if (!response.ok) {
151
- throw new Error(`Codex usage request failed (${response.status})`);
152
- }
153
-
154
- return (await response.json()) as CodexUsageResponse;
155
- }
156
-
157
- export async function getQuotaForModel(provider: string | null | undefined, modelId: string | null | undefined): Promise<PhoneQuotaResponse> {
158
- if (!shouldShowQuotaForModel(provider, modelId)) {
159
- return {
160
- visible: false,
161
- limited: false,
162
- primaryWindow: null,
163
- secondaryWindow: null,
164
- };
165
- }
166
-
167
- try {
168
- const usage = await requestCodexUsageJson();
169
- const selectedBucket = selectRateLimitBucket(usage, modelId || "");
170
- const primaryWindow = buildQuotaWindow("5h", selectedBucket?.primary_window);
171
- const secondaryWindow = buildQuotaWindow("7d", selectedBucket?.secondary_window);
172
-
173
- return {
174
- visible: Boolean(primaryWindow || secondaryWindow),
175
- limited: selectedBucket?.limit_reached === true || selectedBucket?.allowed === false,
176
- primaryWindow,
177
- secondaryWindow,
178
- };
179
- } catch (error) {
180
- return {
181
- visible: false,
182
- limited: false,
183
- primaryWindow: null,
184
- secondaryWindow: null,
185
- error: error instanceof Error ? error.message : String(error),
186
- };
187
- }
188
- }
@@ -1,154 +0,0 @@
1
- import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import type { PersistedPhoneRuntime } from "./types";
5
-
6
- const runtimeStateDir = join(tmpdir(), "dm-phone-extension");
7
- export const phoneControlStopPath = "/__dm_phone__/control/stop";
8
-
9
- function normalizeControlHost(host: string) {
10
- if (!host || host === "0.0.0.0") return "127.0.0.1";
11
- if (host === "::" || host === "[::]") return "[::1]";
12
- if (host.includes(":") && !host.startsWith("[")) return `[${host}]`;
13
- return host;
14
- }
15
-
16
- export function isLoopbackAddress(address: string | undefined | null) {
17
- if (!address) return false;
18
- return address === "127.0.0.1" || address === "::1" || address === "::ffff:127.0.0.1";
19
- }
20
-
21
- export function buildControlUrl(host: string, port: number, controlToken: string, pathname = phoneControlStopPath) {
22
- const url = new URL(`http://${normalizeControlHost(host)}:${port}`);
23
- url.pathname = pathname;
24
- url.searchParams.set("token", controlToken);
25
- return url;
26
- }
27
-
28
- export function getPersistedRuntimeStatePath(host: string, port: number) {
29
- const hostKey = ["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0", "::", "[::]"].includes(host)
30
- ? "local"
31
- : encodeURIComponent(host);
32
- return join(runtimeStateDir, `${hostKey}-${port}.json`);
33
- }
34
-
35
- export async function readPersistedRuntimeState(host: string, port: number): Promise<PersistedPhoneRuntime | null> {
36
- try {
37
- const payload = await readFile(getPersistedRuntimeStatePath(host, port), "utf8");
38
- const parsed = JSON.parse(payload);
39
- if (!parsed || typeof parsed !== "object") return null;
40
- if (typeof parsed.host !== "string" || typeof parsed.port !== "number" || typeof parsed.controlToken !== "string") {
41
- return null;
42
- }
43
-
44
- return {
45
- pid: typeof parsed.pid === "number" ? parsed.pid : 0,
46
- host: parsed.host,
47
- port: parsed.port,
48
- controlToken: parsed.controlToken,
49
- startedAt: typeof parsed.startedAt === "string" ? parsed.startedAt : "",
50
- };
51
- } catch (error: any) {
52
- if (error?.code === "ENOENT") return null;
53
- return null;
54
- }
55
- }
56
-
57
- export async function writePersistedRuntimeState(host: string, port: number, controlToken: string) {
58
- const nextPath = getPersistedRuntimeStatePath(host, port);
59
- await mkdir(runtimeStateDir, { recursive: true });
60
- await writeFile(nextPath, JSON.stringify({
61
- pid: process.pid,
62
- host,
63
- port,
64
- controlToken,
65
- startedAt: new Date().toISOString(),
66
- } satisfies PersistedPhoneRuntime, null, 2), "utf8");
67
- return nextPath;
68
- }
69
-
70
- export async function removePersistedRuntimeState(pathToRemove: string | null) {
71
- if (!pathToRemove) return;
72
-
73
- try {
74
- await unlink(pathToRemove);
75
- } catch (error: any) {
76
- if (error?.code !== "ENOENT") {
77
- throw error;
78
- }
79
- }
80
- }
81
-
82
- function isProcessRunning(pid: number) {
83
- if (!Number.isInteger(pid) || pid <= 0) return false;
84
- try {
85
- process.kill(pid, 0);
86
- return true;
87
- } catch {
88
- return false;
89
- }
90
- }
91
-
92
- async function waitForPersistedRuntimeShutdown(runtime: PersistedPhoneRuntime, timeoutMs = 2000) {
93
- const deadline = Date.now() + timeoutMs;
94
- while (Date.now() < deadline) {
95
- await new Promise((resolvePromise) => setTimeout(resolvePromise, 100));
96
- try {
97
- const healthUrl = buildControlUrl(runtime.host, runtime.port, runtime.controlToken, "/api/health");
98
- healthUrl.searchParams.delete("token");
99
- await fetch(healthUrl, { method: "GET" });
100
- } catch {
101
- return true;
102
- }
103
- }
104
- return false;
105
- }
106
-
107
- export async function stopPersistedRuntime(host: string, port: number) {
108
- const runtimeStatePath = getPersistedRuntimeStatePath(host, port);
109
- const runtime = await readPersistedRuntimeState(host, port);
110
- if (!runtime) {
111
- return { stopped: false, found: false, message: "No running DM Phone instance was found for this port." };
112
- }
113
-
114
- try {
115
- const response = await fetch(buildControlUrl(runtime.host, runtime.port, runtime.controlToken), {
116
- method: "POST",
117
- });
118
- const payload = await response.json().catch(() => null);
119
- if (!response.ok || !payload || payload.ok !== true) {
120
- return {
121
- stopped: false,
122
- found: true,
123
- message: `DM Phone stop request failed with HTTP ${response.status}.`,
124
- };
125
- }
126
-
127
- const stopped = await waitForPersistedRuntimeShutdown(runtime);
128
- if (!stopped) {
129
- return {
130
- stopped: false,
131
- found: true,
132
- message: "DM Phone received the stop request but is still shutting down. Try /phone-start again in a moment.",
133
- };
134
- }
135
-
136
- await removePersistedRuntimeState(runtimeStatePath);
137
- return { stopped: true, found: true, message: "Stopped the other DM Phone instance." };
138
- } catch (error) {
139
- if (!isProcessRunning(runtime.pid)) {
140
- await removePersistedRuntimeState(runtimeStatePath);
141
- return {
142
- stopped: false,
143
- found: true,
144
- message: "Removed stale DM Phone runtime state. Nothing was listening anymore.",
145
- };
146
- }
147
-
148
- return {
149
- stopped: false,
150
- found: true,
151
- message: error instanceof Error ? error.message : String(error),
152
- };
153
- }
154
- }