mdmaid-desk 0.1.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +215 -0
  3. package/dist/api-client.d.ts +20 -0
  4. package/dist/api-client.js +264 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api-types.d.ts +51 -0
  7. package/dist/api-types.js +2 -0
  8. package/dist/api-types.js.map +1 -0
  9. package/dist/auth-state.d.ts +2 -0
  10. package/dist/auth-state.js +113 -0
  11. package/dist/auth-state.js.map +1 -0
  12. package/dist/catalog.d.ts +46 -0
  13. package/dist/catalog.js +659 -0
  14. package/dist/catalog.js.map +1 -0
  15. package/dist/cli.d.ts +16 -0
  16. package/dist/cli.js +370 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/daemon-state.d.ts +17 -0
  19. package/dist/daemon-state.js +204 -0
  20. package/dist/daemon-state.js.map +1 -0
  21. package/dist/domain.d.ts +49 -0
  22. package/dist/domain.js +44 -0
  23. package/dist/domain.js.map +1 -0
  24. package/dist/fs-durability.d.ts +2 -0
  25. package/dist/fs-durability.js +35 -0
  26. package/dist/fs-durability.js.map +1 -0
  27. package/dist/package-info.d.ts +1 -0
  28. package/dist/package-info.js +17 -0
  29. package/dist/package-info.js.map +1 -0
  30. package/dist/server.d.ts +18 -0
  31. package/dist/server.js +702 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/sqlite-storage.d.ts +17 -0
  34. package/dist/sqlite-storage.js +342 -0
  35. package/dist/sqlite-storage.js.map +1 -0
  36. package/dist/storage.d.ts +12 -0
  37. package/dist/storage.js +2 -0
  38. package/dist/storage.js.map +1 -0
  39. package/dist/terminal-text.d.ts +9 -0
  40. package/dist/terminal-text.js +156 -0
  41. package/dist/terminal-text.js.map +1 -0
  42. package/dist/tui.d.ts +63 -0
  43. package/dist/tui.js +912 -0
  44. package/dist/tui.js.map +1 -0
  45. package/dist/web-client.d.ts +21 -0
  46. package/dist/web-client.js +337 -0
  47. package/dist/web-client.js.map +1 -0
  48. package/dist/web-styles.d.ts +1 -0
  49. package/dist/web-styles.js +249 -0
  50. package/dist/web-styles.js.map +1 -0
  51. package/package.json +60 -0
@@ -0,0 +1,204 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { chmod, lstat, mkdir, open, rename, unlink, } from "node:fs/promises";
4
+ import { basename, dirname, join, resolve } from "node:path";
5
+ import { DeskApiClient } from "./api-client.js";
6
+ import { syncDirectory } from "./fs-durability.js";
7
+ export const DESK_PROTOCOL_VERSION = 1;
8
+ const MAX_DESCRIPTOR_BYTES = 8 * 1024;
9
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "::1", "localhost"]);
10
+ export function daemonDescriptorPath(statePath) {
11
+ return join(dirname(resolve(statePath)), "daemon.json");
12
+ }
13
+ export function descriptorForServer(server) {
14
+ return {
15
+ protocolVersion: DESK_PROTOCOL_VERSION,
16
+ pid: process.pid,
17
+ host: server.host,
18
+ port: server.port,
19
+ token: server.token,
20
+ startedAt: new Date().toISOString(),
21
+ };
22
+ }
23
+ export async function writeDaemonDescriptor(path, descriptor) {
24
+ validateDaemonDescriptor(descriptor);
25
+ const destination = resolve(path);
26
+ const directory = dirname(destination);
27
+ await mkdir(directory, { recursive: true, mode: 0o700 });
28
+ await chmod(directory, 0o700);
29
+ await assertReplaceable(destination);
30
+ const temporary = join(directory, `.${basename(destination)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
31
+ let created = false;
32
+ try {
33
+ const handle = await open(temporary, constants.O_CREAT |
34
+ constants.O_EXCL |
35
+ constants.O_WRONLY |
36
+ constants.O_NOFOLLOW, 0o600);
37
+ created = true;
38
+ try {
39
+ await handle.writeFile(`${JSON.stringify(descriptor)}\n`, "utf8");
40
+ await handle.sync();
41
+ }
42
+ finally {
43
+ await handle.close();
44
+ }
45
+ await chmod(temporary, 0o600);
46
+ await rename(temporary, destination);
47
+ created = false;
48
+ await syncDirectory(directory);
49
+ }
50
+ finally {
51
+ if (created) {
52
+ await unlinkIfPresent(temporary);
53
+ }
54
+ }
55
+ }
56
+ export async function readDaemonDescriptor(path) {
57
+ const destination = resolve(path);
58
+ let info;
59
+ try {
60
+ info = await lstat(destination);
61
+ }
62
+ catch (error) {
63
+ if (isNodeError(error) && error.code === "ENOENT") {
64
+ return undefined;
65
+ }
66
+ throw error;
67
+ }
68
+ if (info.isSymbolicLink() || !info.isFile()) {
69
+ throw new Error("Daemon descriptor must be a regular, non-symlink file");
70
+ }
71
+ if ((info.mode & 0o077) !== 0) {
72
+ throw new Error("Daemon descriptor must have user-only permissions");
73
+ }
74
+ if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
75
+ throw new Error("Daemon descriptor must be owned by the current user");
76
+ }
77
+ if (info.size > MAX_DESCRIPTOR_BYTES) {
78
+ throw new Error("Invalid daemon descriptor");
79
+ }
80
+ const handle = await open(destination, constants.O_RDONLY | constants.O_NOFOLLOW);
81
+ let raw;
82
+ try {
83
+ const opened = await handle.stat();
84
+ if (opened.dev !== info.dev || opened.ino !== info.ino) {
85
+ throw new Error("Daemon descriptor changed while opening");
86
+ }
87
+ raw = await handle.readFile("utf8");
88
+ }
89
+ finally {
90
+ await handle.close();
91
+ }
92
+ let value;
93
+ try {
94
+ value = JSON.parse(raw);
95
+ }
96
+ catch {
97
+ throw new Error("Invalid daemon descriptor");
98
+ }
99
+ if (!isDaemonDescriptor(value)) {
100
+ throw new Error("Invalid daemon descriptor");
101
+ }
102
+ return value;
103
+ }
104
+ export async function removeDaemonDescriptor(path, expected) {
105
+ const current = await readDaemonDescriptor(path);
106
+ if (!current || !sameDescriptor(current, expected)) {
107
+ return false;
108
+ }
109
+ try {
110
+ await unlink(resolve(path));
111
+ return true;
112
+ }
113
+ catch (error) {
114
+ if (isNodeError(error) && error.code === "ENOENT") {
115
+ return false;
116
+ }
117
+ throw error;
118
+ }
119
+ }
120
+ export async function connectToDaemon(statePath) {
121
+ const path = daemonDescriptorPath(statePath);
122
+ const descriptor = await readDaemonDescriptor(path);
123
+ if (!descriptor) {
124
+ return undefined;
125
+ }
126
+ const host = descriptor.host.includes(":")
127
+ ? `[${descriptor.host}]`
128
+ : descriptor.host;
129
+ const client = new DeskApiClient(`http://${host}:${descriptor.port}`, descriptor.token);
130
+ try {
131
+ const health = await client.health(AbortSignal.timeout(1_000));
132
+ if (health.version !== descriptor.protocolVersion) {
133
+ throw new Error("Daemon protocol version does not match its descriptor");
134
+ }
135
+ return client;
136
+ }
137
+ catch {
138
+ await removeDaemonDescriptor(path, descriptor);
139
+ return undefined;
140
+ }
141
+ }
142
+ function validateDaemonDescriptor(value) {
143
+ if (!isDaemonDescriptor(value)) {
144
+ throw new Error("Invalid daemon descriptor");
145
+ }
146
+ }
147
+ function isDaemonDescriptor(value) {
148
+ if (!isRecord(value) || Object.keys(value).length !== 6) {
149
+ return false;
150
+ }
151
+ return (value.protocolVersion === DESK_PROTOCOL_VERSION &&
152
+ typeof value.pid === "number" &&
153
+ Number.isSafeInteger(value.pid) &&
154
+ value.pid > 0 &&
155
+ typeof value.host === "string" &&
156
+ LOOPBACK_HOSTS.has(value.host) &&
157
+ typeof value.port === "number" &&
158
+ Number.isSafeInteger(value.port) &&
159
+ value.port > 0 &&
160
+ value.port <= 65_535 &&
161
+ typeof value.token === "string" &&
162
+ value.token.length >= 8 &&
163
+ typeof value.startedAt === "string" &&
164
+ !Number.isNaN(Date.parse(value.startedAt)));
165
+ }
166
+ async function assertReplaceable(path) {
167
+ try {
168
+ const info = await lstat(path);
169
+ if (info.isSymbolicLink() || !info.isFile()) {
170
+ throw new Error("Daemon descriptor must be a regular, non-symlink file");
171
+ }
172
+ }
173
+ catch (error) {
174
+ if (isNodeError(error) && error.code === "ENOENT") {
175
+ return;
176
+ }
177
+ throw error;
178
+ }
179
+ }
180
+ function sameDescriptor(left, right) {
181
+ return (left.protocolVersion === right.protocolVersion &&
182
+ left.pid === right.pid &&
183
+ left.host === right.host &&
184
+ left.port === right.port &&
185
+ left.token === right.token &&
186
+ left.startedAt === right.startedAt);
187
+ }
188
+ async function unlinkIfPresent(path) {
189
+ try {
190
+ await unlink(path);
191
+ }
192
+ catch (error) {
193
+ if (!isNodeError(error) || error.code !== "ENOENT") {
194
+ throw error;
195
+ }
196
+ }
197
+ }
198
+ function isRecord(value) {
199
+ return typeof value === "object" && value !== null && !Array.isArray(value);
200
+ }
201
+ function isNodeError(error) {
202
+ return error instanceof Error && "code" in error;
203
+ }
204
+ //# sourceMappingURL=daemon-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-state.js","sourceRoot":"","sources":["../src/daemon-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export declare const DOCUMENT_KINDS: readonly ["definition", "brief", "research", "decision", "plan", "contract", "handoff", "progress", "verification", "review", "pr", "showcase", "other"];
2
+ export type DocumentKind = (typeof DOCUMENT_KINDS)[number];
3
+ export declare const ATTENTION_STATES: readonly ["none", "review", "approval", "failure", "changes_requested"];
4
+ export type Attention = (typeof ATTENTION_STATES)[number];
5
+ export type ReadingStatus = "unread" | "reading" | "done";
6
+ export interface ReadingProgress {
7
+ revision: number;
8
+ openedRevision: number | null;
9
+ completedRevision: number | null;
10
+ }
11
+ export interface Workspace {
12
+ id: string;
13
+ name: string;
14
+ root: string;
15
+ artifactRoots: string[];
16
+ }
17
+ export interface StoredDocument extends ReadingProgress {
18
+ id: string;
19
+ workspaceId: string;
20
+ taskId?: string;
21
+ producer?: string;
22
+ kind: DocumentKind;
23
+ title: string;
24
+ path: string;
25
+ attention: Attention;
26
+ tags: string[];
27
+ contentHash: string;
28
+ archivedAt: string | null;
29
+ missingAt: string | null;
30
+ createdAt: string;
31
+ updatedAt: string;
32
+ }
33
+ export interface Document extends StoredDocument {
34
+ status: ReadingStatus;
35
+ }
36
+ export interface DocumentFilters {
37
+ workspaceId?: string;
38
+ taskId?: string;
39
+ tag?: string;
40
+ status?: ReadingStatus;
41
+ kind?: DocumentKind;
42
+ attention?: Attention;
43
+ archived?: boolean;
44
+ missing?: boolean;
45
+ }
46
+ export declare function deriveReadingStatus(progress: ReadingProgress): ReadingStatus;
47
+ export declare function presentDocument(document: StoredDocument): Document;
48
+ export declare function isDocumentKind(value: string): value is DocumentKind;
49
+ export declare function isAttention(value: string): value is Attention;
package/dist/domain.js ADDED
@@ -0,0 +1,44 @@
1
+ export const DOCUMENT_KINDS = [
2
+ "definition",
3
+ "brief",
4
+ "research",
5
+ "decision",
6
+ "plan",
7
+ "contract",
8
+ "handoff",
9
+ "progress",
10
+ "verification",
11
+ "review",
12
+ "pr",
13
+ "showcase",
14
+ "other",
15
+ ];
16
+ export const ATTENTION_STATES = [
17
+ "none",
18
+ "review",
19
+ "approval",
20
+ "failure",
21
+ "changes_requested",
22
+ ];
23
+ export function deriveReadingStatus(progress) {
24
+ if (progress.completedRevision === progress.revision) {
25
+ return "done";
26
+ }
27
+ if (progress.openedRevision === progress.revision) {
28
+ return "reading";
29
+ }
30
+ return "unread";
31
+ }
32
+ export function presentDocument(document) {
33
+ return {
34
+ ...structuredClone(document),
35
+ status: deriveReadingStatus(document),
36
+ };
37
+ }
38
+ export function isDocumentKind(value) {
39
+ return DOCUMENT_KINDS.includes(value);
40
+ }
41
+ export function isAttention(value) {
42
+ return ATTENTION_STATES.includes(value);
43
+ }
44
+ //# sourceMappingURL=domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.js","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY;IACZ,OAAO;IACP,UAAU;IACV,UAAU;IACV,MAAM;IACN,UAAU;IACV,SAAS;IACT,UAAU;IACV,cAAc;IACd,QAAQ;IACR,IAAI;IACJ,UAAU;IACV,OAAO;CACC,CAAC;AAIX,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM;IACN,QAAQ;IACR,UAAU;IACV,SAAS;IACT,mBAAmB;CACX,CAAC;AAkDX,MAAM,UAAU,mBAAmB,CAAC,QAAyB;IAC3D,IAAI,QAAQ,CAAC,iBAAiB,KAAK,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACrD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,CAAC,cAAc,KAAK,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAwB;IACtD,OAAO;QACL,GAAG,eAAe,CAAC,QAAQ,CAAC;QAC5B,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAQ,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAQ,gBAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function syncDirectory(path: string): Promise<void>;
2
+ export declare function isUnsupportedDirectorySyncError(error: unknown, platform: NodeJS.Platform): boolean;
@@ -0,0 +1,35 @@
1
+ import { constants } from "node:fs";
2
+ import { open } from "node:fs/promises";
3
+ const UNSUPPORTED_DIRECTORY_SYNC_CODES = new Set([
4
+ "EINVAL",
5
+ "ENOTSUP",
6
+ "EOPNOTSUPP",
7
+ ]);
8
+ export async function syncDirectory(path) {
9
+ let handle;
10
+ try {
11
+ handle = await open(path, constants.O_RDONLY);
12
+ await handle.sync();
13
+ }
14
+ catch (error) {
15
+ if (!isUnsupportedDirectorySyncError(error, process.platform)) {
16
+ throw error;
17
+ }
18
+ }
19
+ finally {
20
+ await handle?.close();
21
+ }
22
+ }
23
+ export function isUnsupportedDirectorySyncError(error, platform) {
24
+ if (!isNodeError(error) || typeof error.code !== "string") {
25
+ return false;
26
+ }
27
+ if (UNSUPPORTED_DIRECTORY_SYNC_CODES.has(error.code)) {
28
+ return true;
29
+ }
30
+ return (platform === "win32" && (error.code === "EPERM" || error.code === "EISDIR"));
31
+ }
32
+ function isNodeError(error) {
33
+ return error instanceof Error && "code" in error;
34
+ }
35
+ //# sourceMappingURL=fs-durability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-durability.js","sourceRoot":"","sources":["../src/fs-durability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,MAAM,gCAAgC,GAAG,IAAI,GAAG,CAAC;IAC/C,QAAQ;IACR,SAAS;IACT,YAAY;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,+BAA+B,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,KAAc,EACd,QAAyB;IAEzB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,gCAAgC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CACL,QAAQ,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAC5E,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function readPackageVersion(): string;
@@ -0,0 +1,17 @@
1
+ import { readFileSync } from "node:fs";
2
+ function isPackageMetadata(value) {
3
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4
+ return false;
5
+ }
6
+ const version = value.version;
7
+ return typeof version === "string" && /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(version);
8
+ }
9
+ export function readPackageVersion() {
10
+ const packageUrl = new URL("../package.json", import.meta.url);
11
+ const parsed = JSON.parse(readFileSync(packageUrl, "utf8"));
12
+ if (!isPackageMetadata(parsed)) {
13
+ throw new Error("package.json contains an invalid version");
14
+ }
15
+ return parsed.version;
16
+ }
17
+ //# sourceMappingURL=package-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-info.js","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAI,KAAiC,CAAC,OAAO,CAAC;IAC3D,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type Catalog } from "./catalog.js";
2
+ export interface DeskServerOptions {
3
+ catalog: Catalog;
4
+ host?: string;
5
+ port?: number;
6
+ publicUrl?: string;
7
+ token?: string;
8
+ }
9
+ export interface RunningDeskServer {
10
+ close(): Promise<void>;
11
+ host: string;
12
+ port: number;
13
+ token: string;
14
+ url: string;
15
+ webUrl: string;
16
+ }
17
+ export declare function startDeskServer(options: DeskServerOptions): Promise<RunningDeskServer>;
18
+ export declare function normalizePublicUrl(value: string): string;