@duckmind/dm-darwin-x64 0.32.9 → 0.33.1

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 (95) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +14 -65
  3. package/extensions/dm-9router-ext/README.md +142 -0
  4. package/extensions/dm-9router-ext/package.json +45 -0
  5. package/extensions/dm-9router-ext/src/index.ts +541 -0
  6. package/extensions/dm-9router-ext/tsconfig.json +17 -0
  7. package/extensions/dm-subagents/package-lock.json +3 -3
  8. package/extensions/dm-tasks/node_modules/.package-lock.json +3 -3
  9. package/extensions/dm-tasks/node_modules/typebox/build/type/script/mapping.d.mts +2 -2
  10. package/extensions/dm-tasks/node_modules/typebox/build/type/script/parser.d.mts +2 -2
  11. package/extensions/dm-tasks/node_modules/typebox/build/type/script/parser.mjs +2 -2
  12. package/extensions/dm-tasks/node_modules/typebox/build/type/types/number.d.mts +1 -1
  13. package/extensions/dm-tasks/node_modules/typebox/build/type/types/number.mjs +1 -1
  14. package/extensions/dm-tasks/node_modules/typebox/build/type/types/record.d.mts +1 -1
  15. package/extensions/dm-tasks/node_modules/typebox/package.json +1 -1
  16. package/extensions/dm-tasks/package-lock.json +3 -3
  17. package/package.json +1 -1
  18. package/theme/theme-alps.json +93 -0
  19. package/extensions/dm-chime/README.md +0 -11
  20. package/extensions/dm-chime/docs/protocols.md +0 -107
  21. package/extensions/dm-chime/index.ts +0 -205
  22. package/extensions/dm-chime/package.json +0 -33
  23. package/extensions/dm-phone/README.md +0 -24
  24. package/extensions/dm-phone/index.ts +0 -12
  25. package/extensions/dm-phone/node_modules/.package-lock.json +0 -29
  26. package/extensions/dm-phone/node_modules/ws/LICENSE +0 -20
  27. package/extensions/dm-phone/node_modules/ws/README.md +0 -548
  28. package/extensions/dm-phone/node_modules/ws/browser.js +0 -8
  29. package/extensions/dm-phone/node_modules/ws/index.js +0 -22
  30. package/extensions/dm-phone/node_modules/ws/lib/buffer-util.js +0 -131
  31. package/extensions/dm-phone/node_modules/ws/lib/constants.js +0 -19
  32. package/extensions/dm-phone/node_modules/ws/lib/event-target.js +0 -292
  33. package/extensions/dm-phone/node_modules/ws/lib/extension.js +0 -203
  34. package/extensions/dm-phone/node_modules/ws/lib/limiter.js +0 -55
  35. package/extensions/dm-phone/node_modules/ws/lib/permessage-deflate.js +0 -528
  36. package/extensions/dm-phone/node_modules/ws/lib/receiver.js +0 -760
  37. package/extensions/dm-phone/node_modules/ws/lib/sender.js +0 -607
  38. package/extensions/dm-phone/node_modules/ws/lib/stream.js +0 -161
  39. package/extensions/dm-phone/node_modules/ws/lib/subprotocol.js +0 -62
  40. package/extensions/dm-phone/node_modules/ws/lib/validation.js +0 -152
  41. package/extensions/dm-phone/node_modules/ws/lib/websocket-server.js +0 -562
  42. package/extensions/dm-phone/node_modules/ws/lib/websocket.js +0 -1407
  43. package/extensions/dm-phone/node_modules/ws/package.json +0 -70
  44. package/extensions/dm-phone/node_modules/ws/wrapper.mjs +0 -21
  45. package/extensions/dm-phone/package-lock.json +0 -66
  46. package/extensions/dm-phone/package.json +0 -35
  47. package/extensions/dm-phone/phone-session-pool.ts +0 -8
  48. package/extensions/dm-phone/public/app/attachments.js +0 -233
  49. package/extensions/dm-phone/public/app/autocomplete-controller.js +0 -81
  50. package/extensions/dm-phone/public/app/autocomplete.js +0 -135
  51. package/extensions/dm-phone/public/app/bindings.js +0 -178
  52. package/extensions/dm-phone/public/app/command-catalog.js +0 -76
  53. package/extensions/dm-phone/public/app/commands.js +0 -376
  54. package/extensions/dm-phone/public/app/constants.js +0 -60
  55. package/extensions/dm-phone/public/app/formatters.js +0 -131
  56. package/extensions/dm-phone/public/app/handlers.js +0 -442
  57. package/extensions/dm-phone/public/app/main.js +0 -6
  58. package/extensions/dm-phone/public/app/markdown.js +0 -105
  59. package/extensions/dm-phone/public/app/messages.js +0 -418
  60. package/extensions/dm-phone/public/app/sheet-actions.js +0 -113
  61. package/extensions/dm-phone/public/app/sheet-navigation.js +0 -19
  62. package/extensions/dm-phone/public/app/sheets-view.js +0 -287
  63. package/extensions/dm-phone/public/app/state.js +0 -95
  64. package/extensions/dm-phone/public/app/tool-rendering.js +0 -562
  65. package/extensions/dm-phone/public/app/transport.js +0 -176
  66. package/extensions/dm-phone/public/app/ui.js +0 -417
  67. package/extensions/dm-phone/public/app.js +0 -1
  68. package/extensions/dm-phone/public/icon.svg +0 -15
  69. package/extensions/dm-phone/public/index.html +0 -146
  70. package/extensions/dm-phone/public/manifest.webmanifest +0 -17
  71. package/extensions/dm-phone/public/styles.css +0 -1139
  72. package/extensions/dm-phone/public/sw.js +0 -78
  73. package/extensions/dm-phone/src/extension/duckmind-models.js +0 -264
  74. package/extensions/dm-phone/src/extension/phone-args.ts +0 -121
  75. package/extensions/dm-phone/src/extension/phone-paths.ts +0 -250
  76. package/extensions/dm-phone/src/extension/phone-quota.ts +0 -188
  77. package/extensions/dm-phone/src/extension/phone-runtime.ts +0 -154
  78. package/extensions/dm-phone/src/extension/phone-server-runtime.ts +0 -1217
  79. package/extensions/dm-phone/src/extension/phone-sessions.ts +0 -139
  80. package/extensions/dm-phone/src/extension/phone-static.ts +0 -30
  81. package/extensions/dm-phone/src/extension/phone-tailscale.ts +0 -148
  82. package/extensions/dm-phone/src/extension/phone-theme.ts +0 -85
  83. package/extensions/dm-phone/src/extension/register-phone-child-extension.ts +0 -112
  84. package/extensions/dm-phone/src/extension/register-phone-extension.ts +0 -106
  85. package/extensions/dm-phone/src/extension/types.ts +0 -73
  86. package/extensions/dm-phone/src/session-pool/parent-session-worker.ts +0 -882
  87. package/extensions/dm-phone/src/session-pool/session-pool.ts +0 -470
  88. package/extensions/dm-phone/src/session-pool/session-worker.ts +0 -739
  89. package/extensions/dm-phone/src/session-pool/types.ts +0 -111
  90. package/extensions/dm-phone/src/session-pool/utils.ts +0 -23
  91. package/extensions/dm-phone/test/duckmind-models.test.js +0 -147
  92. package/extensions/dm-thinking-timer/LICENSE +0 -21
  93. package/extensions/dm-thinking-timer/README.md +0 -7
  94. package/extensions/dm-thinking-timer/package.json +0 -20
  95. 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
- }