@agentshouse/mdruntime 0.1.0-alpha.5 → 0.1.0-alpha.50

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 (129) hide show
  1. package/AGENTS.md +210 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +253 -19
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +2 -1
  6. package/dist/adapter.js.map +1 -1
  7. package/dist/attachment.d.ts +3 -0
  8. package/dist/attachment.d.ts.map +1 -0
  9. package/dist/attachment.js +11 -0
  10. package/dist/attachment.js.map +1 -0
  11. package/dist/bootstrap.d.ts +7 -6
  12. package/dist/bootstrap.d.ts.map +1 -1
  13. package/dist/bootstrap.js +30 -10
  14. package/dist/bootstrap.js.map +1 -1
  15. package/dist/change-set.d.ts +33 -0
  16. package/dist/change-set.d.ts.map +1 -0
  17. package/dist/change-set.js +95 -0
  18. package/dist/change-set.js.map +1 -0
  19. package/dist/change.d.ts +10 -0
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js.map +1 -1
  22. package/dist/client.d.ts +75 -0
  23. package/dist/client.d.ts.map +1 -0
  24. package/dist/client.js +237 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/collection.d.ts +26 -12
  27. package/dist/collection.d.ts.map +1 -1
  28. package/dist/collection.js +78 -31
  29. package/dist/collection.js.map +1 -1
  30. package/dist/connection.d.ts +85 -28
  31. package/dist/connection.d.ts.map +1 -1
  32. package/dist/connection.js +1756 -510
  33. package/dist/connection.js.map +1 -1
  34. package/dist/conversation.d.ts +79 -0
  35. package/dist/conversation.d.ts.map +1 -0
  36. package/dist/conversation.js +635 -0
  37. package/dist/conversation.js.map +1 -0
  38. package/dist/durability.d.ts +8 -3
  39. package/dist/durability.d.ts.map +1 -1
  40. package/dist/durability.js +8 -62
  41. package/dist/durability.js.map +1 -1
  42. package/dist/file.d.ts +20 -0
  43. package/dist/file.d.ts.map +1 -0
  44. package/dist/file.js +149 -0
  45. package/dist/file.js.map +1 -0
  46. package/dist/host.d.ts +14 -0
  47. package/dist/host.d.ts.map +1 -0
  48. package/dist/host.js +213 -0
  49. package/dist/host.js.map +1 -0
  50. package/dist/identity.d.ts +3 -0
  51. package/dist/identity.d.ts.map +1 -0
  52. package/dist/identity.js +23 -0
  53. package/dist/identity.js.map +1 -0
  54. package/dist/index.d.ts +15 -7
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +1 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/memory.d.ts +19 -2
  59. package/dist/memory.d.ts.map +1 -1
  60. package/dist/memory.js +283 -24
  61. package/dist/memory.js.map +1 -1
  62. package/dist/model.d.ts +55 -0
  63. package/dist/model.d.ts.map +1 -0
  64. package/dist/model.js +36 -0
  65. package/dist/model.js.map +1 -0
  66. package/dist/observation.d.ts +25 -0
  67. package/dist/observation.d.ts.map +1 -0
  68. package/dist/observation.js +92 -0
  69. package/dist/observation.js.map +1 -0
  70. package/dist/outcome.d.ts +22 -18
  71. package/dist/outcome.d.ts.map +1 -1
  72. package/dist/outcome.js +1 -11
  73. package/dist/outcome.js.map +1 -1
  74. package/dist/overlay.d.ts +9 -2
  75. package/dist/overlay.d.ts.map +1 -1
  76. package/dist/overlay.js +145 -6
  77. package/dist/overlay.js.map +1 -1
  78. package/dist/paths.d.ts +0 -1
  79. package/dist/paths.d.ts.map +1 -1
  80. package/dist/paths.js +0 -4
  81. package/dist/paths.js.map +1 -1
  82. package/dist/query.d.ts +213 -0
  83. package/dist/query.d.ts.map +1 -0
  84. package/dist/query.js +470 -0
  85. package/dist/query.js.map +1 -0
  86. package/dist/read-side.d.ts +14 -0
  87. package/dist/read-side.d.ts.map +1 -0
  88. package/dist/read-side.js +457 -0
  89. package/dist/read-side.js.map +1 -0
  90. package/dist/refresh.d.ts +4 -4
  91. package/dist/refresh.d.ts.map +1 -1
  92. package/dist/refresh.js +40 -10
  93. package/dist/refresh.js.map +1 -1
  94. package/dist/replica.d.ts +27 -4
  95. package/dist/replica.d.ts.map +1 -1
  96. package/dist/replica.js +255 -13
  97. package/dist/replica.js.map +1 -1
  98. package/dist/room-draft.d.ts +124 -0
  99. package/dist/room-draft.d.ts.map +1 -0
  100. package/dist/room-draft.js +406 -0
  101. package/dist/room-draft.js.map +1 -0
  102. package/dist/rows.d.ts +41 -0
  103. package/dist/rows.d.ts.map +1 -0
  104. package/dist/rows.js +102 -0
  105. package/dist/rows.js.map +1 -0
  106. package/dist/save.d.ts +11 -2
  107. package/dist/save.d.ts.map +1 -1
  108. package/dist/save.js +116 -128
  109. package/dist/save.js.map +1 -1
  110. package/dist/search.d.ts +61 -0
  111. package/dist/search.d.ts.map +1 -0
  112. package/dist/search.js +155 -0
  113. package/dist/search.js.map +1 -0
  114. package/dist/status.d.ts +9 -2
  115. package/dist/status.d.ts.map +1 -1
  116. package/dist/status.js +5 -4
  117. package/dist/status.js.map +1 -1
  118. package/dist/store.d.ts +90 -18
  119. package/dist/store.d.ts.map +1 -1
  120. package/dist/store.js +492 -67
  121. package/dist/store.js.map +1 -1
  122. package/dist/transfer.d.ts +5 -0
  123. package/dist/transfer.d.ts.map +1 -1
  124. package/dist/transfer.js.map +1 -1
  125. package/dist/wire.d.ts +64 -0
  126. package/dist/wire.d.ts.map +1 -0
  127. package/dist/wire.js +145 -0
  128. package/dist/wire.js.map +1 -0
  129. package/package.json +15 -13
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/conversation.ts"],"sourcesContent":["import type {\n AcceptedMessage,\n ConversationAction,\n ConversationCards,\n ConversationEvent,\n ConversationHistoryPage,\n ConversationMessage,\n ConversationStream,\n PlanStep,\n ProcessCommand,\n SessionOption,\n WorkingNote,\n} from './adapter.js';\nimport { conversationChangeSet, type ChangeSet, type MessageChange } from './change-set.js';\nimport { declaredFile, type ChatDraftFile } from './file.js';\nimport type { CallResult } from './outcome.js';\nimport type { DocumentResult, QueryDocument } from './query.js';\nimport type { SearchedMessage } from './search.js';\nimport type { CycleProgress } from './status.js';\nimport type { ChatDraftRecord, HeldConversation, RuntimeStore } from './store.js';\n\nexport type ConversationEntry = {\n conversation: string;\n card: Required<QueryDocument>;\n agent: Required<QueryDocument> | null;\n};\n\nexport type GrowingText = { turn: string; text: string };\n\nexport type ChatDraft = {\n text: string;\n files: readonly ChatDraftFile[];\n};\n\nexport type ConversationOptions = { limit?: number };\n\nexport type ConversationView = {\n conversation: string;\n messages: readonly ConversationMessage[];\n growingText: GrowingText | null;\n workingNote: WorkingNote | null;\n plan: readonly PlanStep[] | null;\n questions: readonly unknown[];\n process: { running: boolean } | null;\n commands: readonly ProcessCommand[];\n options: readonly SessionOption[];\n chatDraft: ChatDraft | null;\n};\n\nexport type ConversationSurface = {\n list(): Promise<readonly ConversationEntry[]>;\n read(conversation: string, options?: ConversationOptions): Promise<ConversationView>;\n create(input: unknown): Promise<CallResult>;\n send(conversation: string): Promise<CallResult>;\n answer(conversation: string, answer: unknown): Promise<CallResult>;\n interrupt(conversation: string): Promise<CallResult>;\n kill(conversation: string): Promise<CallResult>;\n cancel(conversation: string, turn: string): Promise<CallResult>;\n delete(conversation: string): Promise<CallResult>;\n};\n\nexport type ChatDraftSurface = {\n write(conversation: string, draft: ChatDraft): Promise<void>;\n discard(conversation: string): Promise<void>;\n};\n\nexport type ConversationDependencies = {\n cards(): ConversationCards | undefined;\n documents(locator: string): Promise<DocumentResult>;\n call(name: ConversationAction, input: unknown): Promise<CallResult>;\n durably<T>(work: (local: RuntimeStore) => Promise<T>): Promise<T>;\n stream(): ConversationStream | undefined;\n publish(set: ChangeSet): void;\n closed(): boolean;\n};\n\nexport type ConversationStore = {\n surface: ConversationSurface;\n chatDraft: ChatDraftSurface;\n hydrate(held: readonly HeldConversation[], drafts: readonly ChatDraftRecord[]): void;\n reconcile(): Promise<void>;\n catchUp(progress: CycleProgress): Promise<void>;\n current(): boolean;\n reconnected(): void;\n watch(\n conversation: string,\n options: ConversationOptions,\n deliver: (view: ConversationView) => void,\n ): () => void;\n changed(set: ChangeSet): void;\n receive(event: ConversationEvent): void;\n messages(): readonly SearchedMessage[];\n message(conversation: string, identity: string): SearchedMessage | null;\n close(): void;\n};\n\ntype Watcher = {\n notify: (view: ConversationView) => void;\n ready: boolean;\n};\n\ntype Sending = { draft: ChatDraftRecord };\n\ntype Live = {\n growingText: GrowingText | null;\n plan: { turn: string; plan: readonly PlanStep[] } | null;\n workingNote: WorkingNote | null;\n questions: readonly unknown[];\n process: { running: boolean } | null;\n commands: readonly ProcessCommand[];\n options: readonly SessionOption[];\n};\n\nconst QUIET: Live = {\n growingText: null,\n plan: null,\n workingNote: null,\n questions: [],\n process: null,\n commands: [],\n options: [],\n};\n\ntype SharedView = {\n conversation: string;\n limit: number | undefined;\n watchers: Set<Watcher>;\n};\n\nfunction ordered(left: AcceptedMessage, right: AcceptedMessage): number {\n if (left.position !== right.position) return left.position < right.position ? -1 : 1;\n if (left.identity !== right.identity) return left.identity < right.identity ? -1 : 1;\n return 0;\n}\n\nfunction merged(\n held: readonly AcceptedMessage[],\n arriving: readonly AcceptedMessage[],\n): readonly AcceptedMessage[] {\n const byIdentity = new Map(held.map((message) => [message.identity, message]));\n for (const message of arriving) byIdentity.set(message.identity, message);\n return [...byIdentity.values()].sort(ordered);\n}\n\nfunction acceptedMessage(value: unknown): AcceptedMessage | null {\n if (typeof value !== 'object' || value === null) return null;\n const record = value as Partial<Record<keyof AcceptedMessage, unknown>>;\n if (\n typeof record.identity !== 'string' ||\n typeof record.turn !== 'string' ||\n typeof record.position !== 'string' ||\n typeof record.text !== 'string'\n ) {\n return null;\n }\n return {\n identity: record.identity,\n turn: record.turn,\n position: record.position,\n text: record.text,\n message: structuredClone(record.message),\n };\n}\n\nfunction historyPage(value: unknown): ConversationHistoryPage | null {\n if (typeof value !== 'object' || value === null) return null;\n const record = value as { conversation?: unknown; messages?: unknown; next?: unknown };\n if (typeof record.conversation !== 'string' || !Array.isArray(record.messages)) return null;\n if (record.next !== undefined && typeof record.next !== 'string') return null;\n const messages: AcceptedMessage[] = [];\n for (const entry of record.messages) {\n const message = acceptedMessage(entry);\n if (message === null) return null;\n messages.push(message);\n }\n return {\n conversation: record.conversation,\n messages,\n ...(record.next === undefined ? {} : { next: record.next }),\n };\n}\n\nfunction historyPages(result: CallResult): readonly ConversationHistoryPage[] | null {\n if (result.kind !== 'action') return null;\n const answer = result.result;\n if (typeof answer !== 'object' || answer === null) return null;\n const { histories } = answer as { histories?: unknown };\n if (!Array.isArray(histories)) return null;\n const pages: ConversationHistoryPage[] = [];\n for (const entry of histories) {\n const page = historyPage(entry);\n if (page === null) return null;\n pages.push(page);\n }\n return pages;\n}\n\nfunction turnOf(result: CallResult): string | null {\n if (result.kind !== 'action') return null;\n const answer = result.result;\n if (typeof answer !== 'object' || answer === null) return null;\n const record = answer as { turn?: unknown };\n return typeof record.turn === 'string' ? record.turn : null;\n}\n\nfunction limitOf(options: ConversationOptions): number | undefined {\n const { limit } = options;\n if (limit === undefined) return undefined;\n if (!Number.isInteger(limit) || limit < 0) {\n throw new Error(`conversation limit must be a non-negative integer, got ${String(limit)}`);\n }\n return limit;\n}\n\nexport function createConversationStore(deps: ConversationDependencies): ConversationStore {\n const messages = new Map<string, readonly AcceptedMessage[]>();\n const reads = new Map<string, string | null>();\n const drafts = new Map<string, ChatDraftRecord>();\n const sending = new Map<string, Sending>();\n const behind = new Set<string>();\n const gaps = new Map<string, number>();\n const lives = new Map<string, Live>();\n const views = new Map<string, SharedView>();\n let replicated: ReadonlySet<string> = new Set();\n let handedReplicated: string | undefined;\n\n function liveOf(conversation: string): Live {\n return lives.get(conversation) ?? QUIET;\n }\n\n function viewOf(conversation: string, limit: number | undefined): ConversationView {\n const held = messages.get(conversation) ?? [];\n const shown = limit === undefined ? held : held.slice(Math.max(0, held.length - limit));\n const draft = drafts.get(conversation);\n const facts = liveOf(conversation);\n return {\n conversation,\n messages: shown.map(({ identity, turn, text, message }) => ({\n identity,\n turn,\n text,\n message: structuredClone(message),\n })),\n growingText: facts.growingText === null ? null : { ...facts.growingText },\n workingNote: facts.workingNote === null ? null : { ...facts.workingNote },\n plan: structuredClone(facts.plan?.plan ?? null),\n questions: structuredClone(facts.questions),\n process: facts.process === null ? null : { ...facts.process },\n commands: structuredClone(facts.commands),\n options: structuredClone(facts.options),\n chatDraft:\n draft === undefined || draft.turn !== null || sending.get(conversation)?.draft === draft\n ? null\n : { text: draft.text, files: [...draft.files] },\n };\n }\n\n function emit(conversation: string) {\n if (deps.closed()) return;\n for (const view of views.values()) {\n if (view.conversation !== conversation) continue;\n const ready = [...view.watchers].filter((watcher) => watcher.ready);\n if (ready.length === 0) continue;\n const value = viewOf(conversation, view.limit);\n for (const watcher of ready) watcher.notify(value);\n }\n }\n\n function live(conversation: string, change: Partial<Live>) {\n lives.set(conversation, { ...liveOf(conversation), ...change });\n emit(conversation);\n }\n\n function sealTurns(conversation: string, turns: ReadonlySet<string>): boolean {\n const held = lives.get(conversation);\n if (held === undefined) return false;\n const growingText =\n held.growingText !== null && turns.has(held.growingText.turn) ? null : held.growingText;\n const plan = held.plan !== null && turns.has(held.plan.turn) ? null : held.plan;\n if (growingText === held.growingText && plan === held.plan) return false;\n lives.set(conversation, { ...held, growingText, plan });\n return true;\n }\n\n function handReplicated() {\n const stream = deps.stream();\n if (stream === undefined) return;\n const held = [...replicated].sort();\n const named = JSON.stringify(held);\n if (named === handedReplicated) return;\n handedReplicated = named;\n stream.replicate(held);\n }\n\n async function documented(): Promise<readonly Required<QueryDocument>[]> {\n const declaration = deps.cards();\n if (declaration === undefined) return [];\n const { documents } = await deps.documents(declaration.locator);\n return documents.filter(\n (document): document is Required<QueryDocument> => typeof document.type === 'string',\n );\n }\n\n function carded(\n documents: readonly Required<QueryDocument>[],\n ): readonly { conversation: string; card: Required<QueryDocument> }[] {\n const declaration = deps.cards();\n if (declaration === undefined) return [];\n const cards: { conversation: string; card: Required<QueryDocument> }[] = [];\n for (const card of documents) {\n if (card.type !== declaration.type) continue;\n const identity = card.fields[declaration.identity];\n if (typeof identity === 'string') cards.push({ conversation: identity, card });\n }\n return cards;\n }\n\n async function remove(leaving: readonly string[]) {\n await deps.durably(async (local) => {\n await local.dropConversations(leaving);\n const removed: MessageChange[] = [];\n const changed: string[] = [];\n for (const conversation of leaving) {\n for (const message of messages.get(conversation) ?? []) {\n removed.push({ conversation, identity: message.identity });\n }\n if (messages.has(conversation) || drafts.has(conversation) || lives.has(conversation)) {\n changed.push(conversation);\n }\n messages.delete(conversation);\n reads.delete(conversation);\n drafts.delete(conversation);\n behind.delete(conversation);\n lives.delete(conversation);\n }\n if (changed.length > 0) deps.publish(conversationChangeSet(removed, changed));\n });\n }\n\n function gap(conversation: string) {\n gaps.set(conversation, (gaps.get(conversation) ?? 0) + 1);\n behind.add(conversation);\n }\n\n function keep(conversation: string, message: AcceptedMessage) {\n return deps.durably(async (local) => {\n if (!replicated.has(conversation)) return;\n const read = reads.get(conversation);\n const advances =\n read !== undefined &&\n !behind.has(conversation) &&\n (read === null || message.position > read);\n const sealed = drafts.get(conversation)?.turn === message.turn;\n await local.keepMessages({\n conversation,\n messages: [message],\n ...(advances ? { read: message.position } : {}),\n sealed,\n });\n messages.set(conversation, merged(messages.get(conversation) ?? [], [message]));\n if (advances) reads.set(conversation, message.position);\n if (sealed) drafts.delete(conversation);\n sealTurns(conversation, new Set([message.turn]));\n deps.publish(\n conversationChangeSet([{ conversation, identity: message.identity }], [conversation]),\n );\n });\n }\n\n async function readHistories(conversations: readonly string[]): Promise<CallResult | null> {\n const generations = new Map(conversations.map((one) => [one, gaps.get(one) ?? 0]));\n const starts = new Map(conversations.map((one) => [one, reads.get(one)]));\n const arriving = new Map<string, AcceptedMessage[]>();\n const complete = new Set<string>();\n let asking = conversations.map((conversation) => ({\n conversation,\n after: starts.get(conversation) ?? undefined,\n }));\n while (asking.length > 0) {\n const result = await deps.call('conversation.history', {\n conversations: asking.map(({ conversation, after }) => ({\n conversation,\n ...(after === undefined ? {} : { after }),\n })),\n });\n const pages = historyPages(result);\n if (pages === null) return result;\n const asked = new Set(asking.map(({ conversation }) => conversation));\n const following: { conversation: string; after: string | undefined }[] = [];\n for (const page of pages) {\n if (!asked.has(page.conversation)) continue;\n arriving.set(page.conversation, [\n ...(arriving.get(page.conversation) ?? []),\n ...page.messages,\n ]);\n if (page.next === undefined) complete.add(page.conversation);\n else following.push({ conversation: page.conversation, after: page.next });\n }\n asking = following;\n }\n for (const [conversation, held] of arriving) {\n if (!complete.has(conversation)) continue;\n await keepHistory(\n conversation,\n held,\n starts.get(conversation),\n generations.get(conversation) ?? 0,\n );\n }\n return null;\n }\n\n function keepHistory(\n conversation: string,\n arriving: readonly AcceptedMessage[],\n from: string | null | undefined,\n generation: number,\n ): Promise<void> {\n return deps.durably(async (local) => {\n if (!replicated.has(conversation)) return;\n const newest = arriving.reduce<string | null>(\n (top, message) => (top === null || message.position > top ? message.position : top),\n from ?? null,\n );\n const turn = drafts.get(conversation)?.turn;\n const sealed = arriving.some((message) => message.turn === turn);\n await local.keepMessages({ conversation, messages: arriving, read: newest, sealed });\n messages.set(conversation, merged(messages.get(conversation) ?? [], arriving));\n reads.set(conversation, newest);\n if (sealed) drafts.delete(conversation);\n sealTurns(conversation, new Set(arriving.map((message) => message.turn)));\n if ((gaps.get(conversation) ?? 0) === generation) behind.delete(conversation);\n if (arriving.length > 0 || sealed) {\n deps.publish(\n conversationChangeSet(\n arriving.map((message) => ({ conversation, identity: message.identity })),\n [conversation],\n ),\n );\n }\n });\n }\n\n function withDraft(\n conversation: string,\n next: (draft: ChatDraftRecord | undefined) => ChatDraftRecord | null | undefined,\n ): Promise<void> {\n return deps.durably(async (local) => {\n const following = next(drafts.get(conversation));\n if (following === undefined) return;\n if (following === null) {\n await local.dropChatDraft(conversation);\n drafts.delete(conversation);\n } else {\n await local.keepChatDraft(following);\n drafts.set(conversation, following);\n }\n deps.publish(conversationChangeSet([], [conversation]));\n });\n }\n\n function invoke(\n name: ConversationAction,\n conversation: string,\n extra: Readonly<Record<string, unknown>> = {},\n ): Promise<CallResult> {\n return deps.call(name, { conversation, ...extra });\n }\n\n const surface: ConversationSurface = {\n async list() {\n const declaration = deps.cards();\n if (declaration === undefined) return [];\n const documents = await documented();\n const entries: ConversationEntry[] = carded(documents).map(({ conversation, card }) => ({\n conversation,\n card,\n agent:\n documents.find((document) =>\n document.backlinks.some(\n (backlink) => backlink.path === card.path && backlink.field === declaration.agent,\n ),\n ) ?? null,\n }));\n entries.sort((left, right) => (left.conversation < right.conversation ? -1 : 1));\n return entries;\n },\n async read(conversation: string, options: ConversationOptions = {}) {\n const limit = limitOf(options);\n return deps.durably(() => Promise.resolve(viewOf(conversation, limit)));\n },\n create(input: unknown) {\n return deps.call('conversation.create', input);\n },\n async send(conversation: string) {\n const draft = drafts.get(conversation);\n const pending: Sending | undefined = draft === undefined ? undefined : { draft };\n if (pending !== undefined) {\n sending.set(conversation, pending);\n deps.publish(conversationChangeSet([], [conversation]));\n }\n try {\n const files = await Promise.all(\n (draft?.files ?? []).map(async (file) => ({\n ...(await declaredFile(file)),\n blob: file.blob,\n })),\n );\n const result = await invoke('conversation.send', conversation, {\n text: draft?.text ?? '',\n files,\n });\n const turn = turnOf(result);\n if (turn === null || draft === undefined) return result;\n await withDraft(conversation, (current) => {\n if (current !== draft) return undefined;\n const sealed = (messages.get(conversation) ?? []).some(\n (message) => message.turn === turn,\n );\n return sealed ? null : { ...draft, turn };\n });\n return result;\n } finally {\n if (pending !== undefined && sending.get(conversation) === pending) {\n sending.delete(conversation);\n if (drafts.get(conversation) === draft) {\n deps.publish(conversationChangeSet([], [conversation]));\n }\n }\n }\n },\n answer(conversation: string, answer: unknown) {\n return invoke('conversation.answer', conversation, { answer });\n },\n interrupt(conversation: string) {\n return invoke('conversation.interrupt', conversation);\n },\n kill(conversation: string) {\n return invoke('conversation.kill', conversation);\n },\n async cancel(conversation: string, turn: string) {\n const result = await invoke('conversation.cancel', conversation, { turn });\n if (result.kind !== 'action') return result;\n await withDraft(conversation, (current) =>\n current === undefined || current.turn !== turn ? undefined : { ...current, turn: null },\n );\n return result;\n },\n delete(conversation: string) {\n return invoke('conversation.delete', conversation);\n },\n };\n\n const chatDraft: ChatDraftSurface = {\n write(conversation: string, draft: ChatDraft) {\n return withDraft(conversation, () => ({\n conversation,\n text: draft.text,\n files: [...draft.files],\n turn: null,\n }));\n },\n discard(conversation: string) {\n return withDraft(conversation, (current) => (current === undefined ? undefined : null));\n },\n };\n\n return {\n surface,\n chatDraft,\n hydrate(held, stored) {\n messages.clear();\n reads.clear();\n for (const entry of held) {\n messages.set(entry.conversation, [...entry.messages].sort(ordered));\n if (entry.read !== undefined) reads.set(entry.conversation, entry.read);\n }\n drafts.clear();\n for (const record of stored) drafts.set(record.conversation, record);\n },\n async reconcile() {\n const named = new Set(carded(await documented()).map((entry) => entry.conversation));\n const leaving = [\n ...new Set([...replicated, ...messages.keys(), ...reads.keys(), ...drafts.keys()]),\n ].filter((conversation) => !named.has(conversation));\n for (const conversation of named) {\n if (!replicated.has(conversation)) behind.add(conversation);\n }\n replicated = named;\n handReplicated();\n if (leaving.length > 0) await remove(leaving);\n },\n async catchUp(progress) {\n const reading = [...behind].filter((conversation) => replicated.has(conversation)).sort();\n if (reading.length > 0 && !deps.closed()) {\n const failed = await readHistories(reading);\n if (failed?.kind === 'transport-uncertainty') progress.reachable = false;\n }\n if (behind.size > 0) progress.complete = false;\n },\n current() {\n return behind.size === 0;\n },\n reconnected() {\n for (const conversation of replicated) gap(conversation);\n },\n watch(conversation, options, deliver) {\n const limit = limitOf(options);\n const key = JSON.stringify([conversation, limit ?? null]);\n const view = views.get(key) ?? { conversation, limit, watchers: new Set<Watcher>() };\n views.set(key, view);\n const watcher: Watcher = { notify: deliver, ready: false };\n view.watchers.add(watcher);\n void deps\n .durably(() => Promise.resolve())\n .then(() => {\n if (deps.closed() || !view.watchers.has(watcher)) return;\n watcher.ready = true;\n watcher.notify(viewOf(conversation, limit));\n })\n .catch(() => {});\n return () => {\n if (!view.watchers.delete(watcher)) return;\n if (view.watchers.size === 0) views.delete(key);\n };\n },\n changed(set) {\n for (const conversation of set.conversations) emit(conversation);\n },\n receive(event) {\n if (deps.closed()) return;\n const { conversation } = event;\n if (event.kind === 'gap') {\n if (replicated.has(conversation)) gap(conversation);\n if (lives.delete(conversation)) emit(conversation);\n return;\n }\n if (event.kind === 'growing-text') {\n live(conversation, { growingText: { turn: event.turn, text: event.text } });\n return;\n }\n if (event.kind === 'plan') {\n live(conversation, { plan: { turn: event.turn, plan: structuredClone(event.plan) } });\n return;\n }\n if (event.kind === 'working-note') {\n live(conversation, {\n workingNote:\n event.note === null ? null : { noteId: event.note.noteId, text: event.note.text },\n });\n return;\n }\n if (event.kind === 'questions') {\n live(conversation, { questions: structuredClone(event.questions) });\n return;\n }\n if (event.kind === 'process') {\n live(conversation, { process: { running: event.running } });\n return;\n }\n if (event.kind === 'commands') {\n live(conversation, { commands: structuredClone(event.commands) });\n return;\n }\n if (event.kind === 'options') {\n live(conversation, { options: structuredClone(event.options) });\n return;\n }\n const arriving = acceptedMessage(event.message);\n if (arriving === null) return;\n if (replicated.has(conversation)) {\n void keep(conversation, arriving).catch(() => {});\n return;\n }\n if (sealTurns(conversation, new Set([arriving.turn]))) emit(conversation);\n },\n messages() {\n return [...messages].flatMap(([conversation, held]) =>\n held.map(({ identity, text }) => ({ conversation, identity, text })),\n );\n },\n message(conversation, identity) {\n const held = messages.get(conversation)?.find((message) => message.identity === identity);\n return held === undefined ? null : { conversation, identity, text: held.text };\n },\n close() {\n views.clear();\n lives.clear();\n },\n };\n}\n"],"names":["conversationChangeSet","declaredFile","QUIET","growingText","plan","workingNote","questions","process","commands","options","ordered","left","right","position","identity","merged","held","arriving","byIdentity","Map","map","message","set","values","sort","acceptedMessage","value","record","turn","text","structuredClone","historyPage","conversation","Array","isArray","messages","next","undefined","entry","push","historyPages","result","kind","answer","histories","pages","page","turnOf","limitOf","limit","Number","isInteger","Error","String","createConversationStore","deps","reads","drafts","sending","behind","Set","gaps","lives","views","replicated","handedReplicated","liveOf","get","viewOf","shown","slice","Math","max","length","draft","facts","chatDraft","files","emit","closed","view","ready","watchers","filter","watcher","notify","live","change","sealTurns","turns","has","handReplicated","stream","named","JSON","stringify","replicate","documented","declaration","cards","documents","locator","document","type","carded","card","fields","remove","leaving","durably","local","dropConversations","removed","changed","delete","publish","gap","add","keep","read","advances","sealed","keepMessages","readHistories","conversations","generations","one","starts","complete","asking","after","call","asked","following","keepHistory","from","generation","newest","reduce","top","some","withDraft","dropChatDraft","keepChatDraft","invoke","name","extra","surface","list","entries","agent","find","backlinks","backlink","path","field","Promise","resolve","create","input","send","pending","all","file","blob","current","interrupt","kill","cancel","write","discard","hydrate","stored","clear","reconcile","keys","catchUp","progress","reading","failed","reachable","size","reconnected","watch","deliver","key","then","catch","receive","event","note","noteId","running","flatMap","close"],"mappings":"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"}
@@ -1,4 +1,9 @@
1
- export declare function requestPersistentStorage(): Promise<void>;
2
- export declare function detectStorageLoss(stored: string | null): string | null;
3
- export declare function nextGeneration(stored: string | null): string;
1
+ export type RuntimeShell = {
2
+ persistentStorage: boolean;
3
+ generation: string | null;
4
+ keepGeneration(value: string): void | Promise<void>;
5
+ dropGeneration(): void | Promise<void>;
6
+ };
7
+ export declare function detectStorageLoss(stored: string | null, reported: string | null): string | null;
8
+ export declare function nextGeneration(stored: string | null, reported: string | null): string;
4
9
  //# sourceMappingURL=durability.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"AAiCA,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG9D;AAoBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAItE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAS5D"}
1
+ {"version":3,"file":"durability.d.ts","sourceRoot":"","sources":["../src/durability.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,cAAc,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG/F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGrF"}
@@ -1,65 +1,11 @@
1
- const ASKED = 'mdruntime:persistent-storage';
2
- const GENERATION = 'mdruntime:generation';
3
- const STORAGE_LOSS_STATEMENT = 'Unsynchronized Drafts and Pending Changes were lost.';
4
- function remembered() {
5
- try {
6
- return window.localStorage.getItem(ASKED);
7
- } catch {
8
- return null;
9
- }
10
- }
11
- function remember() {
12
- try {
13
- window.localStorage.setItem(ASKED, '1');
14
- } catch {
15
- return;
16
- }
17
- }
18
- async function ask() {
19
- if (remembered() !== null) return;
20
- const persist = window.navigator.storage?.persist;
21
- if (typeof persist !== 'function') return;
22
- remember();
23
- try {
24
- await persist.call(window.navigator.storage);
25
- } catch {
26
- return;
27
- }
28
- }
29
- export async function requestPersistentStorage() {
30
- if (typeof window === 'undefined') return;
31
- await window.navigator.locks.request('mdruntime-persist', ask);
32
- }
33
- function readGeneration() {
34
- if (typeof window === 'undefined') return null;
35
- try {
36
- return window.localStorage.getItem(GENERATION);
37
- } catch {
38
- return null;
39
- }
40
- }
41
- function writeGeneration(value) {
42
- if (typeof window === 'undefined') return;
43
- try {
44
- window.localStorage.setItem(GENERATION, value);
45
- } catch {
46
- return;
47
- }
48
- }
49
- export function detectStorageLoss(stored) {
50
- const remembered = readGeneration();
51
- if (remembered === null || remembered === stored) return null;
52
- return STORAGE_LOSS_STATEMENT;
53
- }
54
- export function nextGeneration(stored) {
55
- const remembered = readGeneration();
56
- if (stored !== null && (remembered === null || remembered === stored)) {
57
- writeGeneration(stored);
58
- return stored;
59
- }
60
- const next = crypto.randomUUID();
61
- writeGeneration(next);
62
- return next;
1
+ const STORAGE_LOSS_CODE = 'storage-loss';
2
+ export function detectStorageLoss(stored, reported) {
3
+ if (reported === null || reported === stored) return null;
4
+ return STORAGE_LOSS_CODE;
5
+ }
6
+ export function nextGeneration(stored, reported) {
7
+ if (stored !== null && (reported === null || reported === stored)) return stored;
8
+ return crypto.randomUUID();
63
9
  }
64
10
 
65
11
  //# sourceMappingURL=durability.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/durability.ts"],"sourcesContent":["const ASKED = 'mdruntime:persistent-storage';\nconst GENERATION = 'mdruntime:generation';\n\nconst STORAGE_LOSS_STATEMENT = 'Unsynchronized Drafts and Pending Changes were lost.';\n\nfunction remembered(): string | null {\n try {\n return window.localStorage.getItem(ASKED);\n } catch {\n return null;\n }\n}\n\nfunction remember(): void {\n try {\n window.localStorage.setItem(ASKED, '1');\n } catch {\n return;\n }\n}\n\nasync function ask(): Promise<void> {\n if (remembered() !== null) return;\n const persist = window.navigator.storage?.persist;\n if (typeof persist !== 'function') return;\n remember();\n try {\n await persist.call(window.navigator.storage);\n } catch {\n return;\n }\n}\n\nexport async function requestPersistentStorage(): Promise<void> {\n if (typeof window === 'undefined') return;\n await window.navigator.locks.request('mdruntime-persist', ask);\n}\n\nfunction readGeneration(): string | null {\n if (typeof window === 'undefined') return null;\n try {\n return window.localStorage.getItem(GENERATION);\n } catch {\n return null;\n }\n}\n\nfunction writeGeneration(value: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(GENERATION, value);\n } catch {\n return;\n }\n}\n\nexport function detectStorageLoss(stored: string | null): string | null {\n const remembered = readGeneration();\n if (remembered === null || remembered === stored) return null;\n return STORAGE_LOSS_STATEMENT;\n}\n\nexport function nextGeneration(stored: string | null): string {\n const remembered = readGeneration();\n if (stored !== null && (remembered === null || remembered === stored)) {\n writeGeneration(stored);\n return stored;\n }\n const next = crypto.randomUUID();\n writeGeneration(next);\n return next;\n}\n"],"names":["ASKED","GENERATION","STORAGE_LOSS_STATEMENT","remembered","window","localStorage","getItem","remember","setItem","ask","persist","navigator","storage","call","requestPersistentStorage","locks","request","readGeneration","writeGeneration","value","detectStorageLoss","stored","nextGeneration","next","crypto","randomUUID"],"mappings":"AAAA,MAAMA,QAAQ;AACd,MAAMC,aAAa;AAEnB,MAAMC,yBAAyB;AAE/B,SAASC;IACP,IAAI;QACF,OAAOC,OAAOC,YAAY,CAACC,OAAO,CAACN;IACrC,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASO;IACP,IAAI;QACFH,OAAOC,YAAY,CAACG,OAAO,CAACR,OAAO;IACrC,EAAE,OAAM;QACN;IACF;AACF;AAEA,eAAeS;IACb,IAAIN,iBAAiB,MAAM;IAC3B,MAAMO,UAAUN,OAAOO,SAAS,CAACC,OAAO,EAAEF;IAC1C,IAAI,OAAOA,YAAY,YAAY;IACnCH;IACA,IAAI;QACF,MAAMG,QAAQG,IAAI,CAACT,OAAOO,SAAS,CAACC,OAAO;IAC7C,EAAE,OAAM;QACN;IACF;AACF;AAEA,OAAO,eAAeE;IACpB,IAAI,OAAOV,WAAW,aAAa;IACnC,MAAMA,OAAOO,SAAS,CAACI,KAAK,CAACC,OAAO,CAAC,qBAAqBP;AAC5D;AAEA,SAASQ;IACP,IAAI,OAAOb,WAAW,aAAa,OAAO;IAC1C,IAAI;QACF,OAAOA,OAAOC,YAAY,CAACC,OAAO,CAACL;IACrC,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASiB,gBAAgBC,KAAa;IACpC,IAAI,OAAOf,WAAW,aAAa;IACnC,IAAI;QACFA,OAAOC,YAAY,CAACG,OAAO,CAACP,YAAYkB;IAC1C,EAAE,OAAM;QACN;IACF;AACF;AAEA,OAAO,SAASC,kBAAkBC,MAAqB;IACrD,MAAMlB,aAAac;IACnB,IAAId,eAAe,QAAQA,eAAekB,QAAQ,OAAO;IACzD,OAAOnB;AACT;AAEA,OAAO,SAASoB,eAAeD,MAAqB;IAClD,MAAMlB,aAAac;IACnB,IAAII,WAAW,QAASlB,CAAAA,eAAe,QAAQA,eAAekB,MAAK,GAAI;QACrEH,gBAAgBG;QAChB,OAAOA;IACT;IACA,MAAME,OAAOC,OAAOC,UAAU;IAC9BP,gBAAgBK;IAChB,OAAOA;AACT"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/durability.ts"],"sourcesContent":["const STORAGE_LOSS_CODE = 'storage-loss';\n\nexport type RuntimeShell = {\n persistentStorage: boolean;\n generation: string | null;\n keepGeneration(value: string): void | Promise<void>;\n dropGeneration(): void | Promise<void>;\n};\n\nexport function detectStorageLoss(stored: string | null, reported: string | null): string | null {\n if (reported === null || reported === stored) return null;\n return STORAGE_LOSS_CODE;\n}\n\nexport function nextGeneration(stored: string | null, reported: string | null): string {\n if (stored !== null && (reported === null || reported === stored)) return stored;\n return crypto.randomUUID();\n}\n"],"names":["STORAGE_LOSS_CODE","detectStorageLoss","stored","reported","nextGeneration","crypto","randomUUID"],"mappings":"AAAA,MAAMA,oBAAoB;AAS1B,OAAO,SAASC,kBAAkBC,MAAqB,EAAEC,QAAuB;IAC9E,IAAIA,aAAa,QAAQA,aAAaD,QAAQ,OAAO;IACrD,OAAOF;AACT;AAEA,OAAO,SAASI,eAAeF,MAAqB,EAAEC,QAAuB;IAC3E,IAAID,WAAW,QAASC,CAAAA,aAAa,QAAQA,aAAaD,MAAK,GAAI,OAAOA;IAC1E,OAAOG,OAAOC,UAAU;AAC1B"}
package/dist/file.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ export type ChatDraftFile = {
2
+ name: string;
3
+ blob: Blob;
4
+ };
5
+ export type FileDeclaration = {
6
+ name: string;
7
+ mediaType: string;
8
+ byteLength: number;
9
+ contentHash: string;
10
+ width?: number;
11
+ height?: number;
12
+ };
13
+ export type Extent = {
14
+ width: number;
15
+ height: number;
16
+ };
17
+ export declare function extentOf(bytes: Uint8Array): Extent | null;
18
+ export declare function hexDigest(digest: ArrayBuffer): string;
19
+ export declare function declaredFile(file: ChatDraftFile): Promise<FileDeclaration>;
20
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA2GvD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAQzD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAErD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAUhF"}
package/dist/file.js ADDED
@@ -0,0 +1,149 @@
1
+ const PNG_SIGNATURE = [
2
+ 0x89,
3
+ 0x50,
4
+ 0x4e,
5
+ 0x47,
6
+ 0x0d,
7
+ 0x0a,
8
+ 0x1a,
9
+ 0x0a
10
+ ];
11
+ const WEBP_SYNC = [
12
+ 0x9d,
13
+ 0x01,
14
+ 0x2a
15
+ ];
16
+ const SHAPELESS_JPEG_MARKERS = new Set([
17
+ 0xc4,
18
+ 0xc8,
19
+ 0xcc
20
+ ]);
21
+ const BMFF_CONTAINERS = new Set([
22
+ 'meta',
23
+ 'iprp',
24
+ 'ipco'
25
+ ]);
26
+ function starts(bytes, signature, at = 0) {
27
+ return signature.every((value, index)=>bytes[at + index] === value);
28
+ }
29
+ function text(bytes, at, length) {
30
+ return String.fromCharCode(...bytes.subarray(at, at + length));
31
+ }
32
+ function bigEndian(bytes, at, length) {
33
+ let value = 0;
34
+ for(let index = 0; index < length; index += 1)value = value * 256 + (bytes[at + index] ?? 0);
35
+ return value;
36
+ }
37
+ function littleEndian(bytes, at, length) {
38
+ let value = 0;
39
+ for(let index = length - 1; index >= 0; index -= 1)value = value * 256 + (bytes[at + index] ?? 0);
40
+ return value;
41
+ }
42
+ function pngExtent(bytes) {
43
+ if (bytes.length < 24 || !starts(bytes, PNG_SIGNATURE)) return null;
44
+ if (text(bytes, 12, 4) !== 'IHDR') return null;
45
+ return {
46
+ width: bigEndian(bytes, 16, 4),
47
+ height: bigEndian(bytes, 20, 4)
48
+ };
49
+ }
50
+ function gifExtent(bytes) {
51
+ if (bytes.length < 10 || text(bytes, 0, 3) !== 'GIF') return null;
52
+ return {
53
+ width: littleEndian(bytes, 6, 2),
54
+ height: littleEndian(bytes, 8, 2)
55
+ };
56
+ }
57
+ function jpegExtent(bytes) {
58
+ if (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8) return null;
59
+ let at = 2;
60
+ while(at + 9 < bytes.length){
61
+ if (bytes[at] !== 0xff) return null;
62
+ const marker = bytes[at + 1] ?? 0;
63
+ if (marker === 0xd8 || marker === 0x01 || marker >= 0xd0 && marker <= 0xd7) {
64
+ at += 2;
65
+ continue;
66
+ }
67
+ const length = bigEndian(bytes, at + 2, 2);
68
+ if (marker >= 0xc0 && marker <= 0xcf && !SHAPELESS_JPEG_MARKERS.has(marker)) {
69
+ return {
70
+ width: bigEndian(bytes, at + 7, 2),
71
+ height: bigEndian(bytes, at + 5, 2)
72
+ };
73
+ }
74
+ if (length < 2) return null;
75
+ at += 2 + length;
76
+ }
77
+ return null;
78
+ }
79
+ function webpExtent(bytes) {
80
+ if (bytes.length < 30 || text(bytes, 0, 4) !== 'RIFF' || text(bytes, 8, 4) !== 'WEBP') return null;
81
+ const chunk = text(bytes, 12, 4);
82
+ if (chunk === 'VP8X') {
83
+ return {
84
+ width: littleEndian(bytes, 24, 3) + 1,
85
+ height: littleEndian(bytes, 27, 3) + 1
86
+ };
87
+ }
88
+ if (chunk === 'VP8 ' && starts(bytes, WEBP_SYNC, 23)) {
89
+ return {
90
+ width: littleEndian(bytes, 26, 2) & 0x3fff,
91
+ height: littleEndian(bytes, 28, 2) & 0x3fff
92
+ };
93
+ }
94
+ if (chunk === 'VP8L' && bytes[20] === 0x2f) {
95
+ const packed = littleEndian(bytes, 21, 4);
96
+ return {
97
+ width: (packed & 0x3fff) + 1,
98
+ height: (packed >>> 14 & 0x3fff) + 1
99
+ };
100
+ }
101
+ return null;
102
+ }
103
+ function spatialExtent(bytes, from, to) {
104
+ let at = from;
105
+ while(at + 8 <= to){
106
+ const size = bigEndian(bytes, at, 4);
107
+ const name = text(bytes, at + 4, 4);
108
+ const end = size === 0 ? to : at + size;
109
+ if (size === 1 || end <= at || end > to) return null;
110
+ if (name === 'ispe') {
111
+ if (end < at + 20) return null;
112
+ return {
113
+ width: bigEndian(bytes, at + 12, 4),
114
+ height: bigEndian(bytes, at + 16, 4)
115
+ };
116
+ }
117
+ if (BMFF_CONTAINERS.has(name)) {
118
+ const inner = spatialExtent(bytes, at + (name === 'meta' ? 12 : 8), end);
119
+ if (inner !== null) return inner;
120
+ }
121
+ at = end;
122
+ }
123
+ return null;
124
+ }
125
+ function bmffExtent(bytes) {
126
+ if (bytes.length < 16 || text(bytes, 4, 4) !== 'ftyp') return null;
127
+ return spatialExtent(bytes, 0, bytes.length);
128
+ }
129
+ export function extentOf(bytes) {
130
+ return pngExtent(bytes) ?? jpegExtent(bytes) ?? gifExtent(bytes) ?? webpExtent(bytes) ?? bmffExtent(bytes);
131
+ }
132
+ export function hexDigest(digest) {
133
+ return [
134
+ ...new Uint8Array(digest)
135
+ ].map((value)=>value.toString(16).padStart(2, '0')).join('');
136
+ }
137
+ export async function declaredFile(file) {
138
+ const bytes = new Uint8Array(await file.blob.arrayBuffer());
139
+ const extent = file.blob.type.startsWith('image/') ? extentOf(bytes) : null;
140
+ return {
141
+ name: file.name,
142
+ mediaType: file.blob.type,
143
+ byteLength: bytes.byteLength,
144
+ contentHash: hexDigest(await crypto.subtle.digest('SHA-256', bytes)),
145
+ ...extent === null ? {} : extent
146
+ };
147
+ }
148
+
149
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/file.ts"],"sourcesContent":["export type ChatDraftFile = {\n name: string;\n blob: Blob;\n};\n\nexport type FileDeclaration = {\n name: string;\n mediaType: string;\n byteLength: number;\n contentHash: string;\n width?: number;\n height?: number;\n};\n\nexport type Extent = { width: number; height: number };\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\nconst WEBP_SYNC = [0x9d, 0x01, 0x2a];\nconst SHAPELESS_JPEG_MARKERS = new Set([0xc4, 0xc8, 0xcc]);\nconst BMFF_CONTAINERS = new Set(['meta', 'iprp', 'ipco']);\n\nfunction starts(bytes: Uint8Array, signature: readonly number[], at = 0): boolean {\n return signature.every((value, index) => bytes[at + index] === value);\n}\n\nfunction text(bytes: Uint8Array, at: number, length: number): string {\n return String.fromCharCode(...bytes.subarray(at, at + length));\n}\n\nfunction bigEndian(bytes: Uint8Array, at: number, length: number): number {\n let value = 0;\n for (let index = 0; index < length; index += 1) value = value * 256 + (bytes[at + index] ?? 0);\n return value;\n}\n\nfunction littleEndian(bytes: Uint8Array, at: number, length: number): number {\n let value = 0;\n for (let index = length - 1; index >= 0; index -= 1)\n value = value * 256 + (bytes[at + index] ?? 0);\n return value;\n}\n\nfunction pngExtent(bytes: Uint8Array): Extent | null {\n if (bytes.length < 24 || !starts(bytes, PNG_SIGNATURE)) return null;\n if (text(bytes, 12, 4) !== 'IHDR') return null;\n return { width: bigEndian(bytes, 16, 4), height: bigEndian(bytes, 20, 4) };\n}\n\nfunction gifExtent(bytes: Uint8Array): Extent | null {\n if (bytes.length < 10 || text(bytes, 0, 3) !== 'GIF') return null;\n return { width: littleEndian(bytes, 6, 2), height: littleEndian(bytes, 8, 2) };\n}\n\nfunction jpegExtent(bytes: Uint8Array): Extent | null {\n if (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8) return null;\n let at = 2;\n while (at + 9 < bytes.length) {\n if (bytes[at] !== 0xff) return null;\n const marker = bytes[at + 1] ?? 0;\n if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {\n at += 2;\n continue;\n }\n const length = bigEndian(bytes, at + 2, 2);\n if (marker >= 0xc0 && marker <= 0xcf && !SHAPELESS_JPEG_MARKERS.has(marker)) {\n return { width: bigEndian(bytes, at + 7, 2), height: bigEndian(bytes, at + 5, 2) };\n }\n if (length < 2) return null;\n at += 2 + length;\n }\n return null;\n}\n\nfunction webpExtent(bytes: Uint8Array): Extent | null {\n if (bytes.length < 30 || text(bytes, 0, 4) !== 'RIFF' || text(bytes, 8, 4) !== 'WEBP')\n return null;\n const chunk = text(bytes, 12, 4);\n if (chunk === 'VP8X') {\n return {\n width: littleEndian(bytes, 24, 3) + 1,\n height: littleEndian(bytes, 27, 3) + 1,\n };\n }\n if (chunk === 'VP8 ' && starts(bytes, WEBP_SYNC, 23)) {\n return {\n width: littleEndian(bytes, 26, 2) & 0x3fff,\n height: littleEndian(bytes, 28, 2) & 0x3fff,\n };\n }\n if (chunk === 'VP8L' && bytes[20] === 0x2f) {\n const packed = littleEndian(bytes, 21, 4);\n return { width: (packed & 0x3fff) + 1, height: ((packed >>> 14) & 0x3fff) + 1 };\n }\n return null;\n}\n\nfunction spatialExtent(bytes: Uint8Array, from: number, to: number): Extent | null {\n let at = from;\n while (at + 8 <= to) {\n const size = bigEndian(bytes, at, 4);\n const name = text(bytes, at + 4, 4);\n const end = size === 0 ? to : at + size;\n if (size === 1 || end <= at || end > to) return null;\n if (name === 'ispe') {\n if (end < at + 20) return null;\n return { width: bigEndian(bytes, at + 12, 4), height: bigEndian(bytes, at + 16, 4) };\n }\n if (BMFF_CONTAINERS.has(name)) {\n const inner = spatialExtent(bytes, at + (name === 'meta' ? 12 : 8), end);\n if (inner !== null) return inner;\n }\n at = end;\n }\n return null;\n}\n\nfunction bmffExtent(bytes: Uint8Array): Extent | null {\n if (bytes.length < 16 || text(bytes, 4, 4) !== 'ftyp') return null;\n return spatialExtent(bytes, 0, bytes.length);\n}\n\nexport function extentOf(bytes: Uint8Array): Extent | null {\n return (\n pngExtent(bytes) ??\n jpegExtent(bytes) ??\n gifExtent(bytes) ??\n webpExtent(bytes) ??\n bmffExtent(bytes)\n );\n}\n\nexport function hexDigest(digest: ArrayBuffer): string {\n return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, '0')).join('');\n}\n\nexport async function declaredFile(file: ChatDraftFile): Promise<FileDeclaration> {\n const bytes = new Uint8Array(await file.blob.arrayBuffer());\n const extent = file.blob.type.startsWith('image/') ? extentOf(bytes) : null;\n return {\n name: file.name,\n mediaType: file.blob.type,\n byteLength: bytes.byteLength,\n contentHash: hexDigest(await crypto.subtle.digest('SHA-256', bytes)),\n ...(extent === null ? {} : extent),\n };\n}\n"],"names":["PNG_SIGNATURE","WEBP_SYNC","SHAPELESS_JPEG_MARKERS","Set","BMFF_CONTAINERS","starts","bytes","signature","at","every","value","index","text","length","String","fromCharCode","subarray","bigEndian","littleEndian","pngExtent","width","height","gifExtent","jpegExtent","marker","has","webpExtent","chunk","packed","spatialExtent","from","to","size","name","end","inner","bmffExtent","extentOf","hexDigest","digest","Uint8Array","map","toString","padStart","join","declaredFile","file","blob","arrayBuffer","extent","type","startsWith","mediaType","byteLength","contentHash","crypto","subtle"],"mappings":"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"}
package/dist/host.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { type MdRuntimeOptions } from './connection.js';
2
+ import { type RuntimePort } from './wire.js';
3
+ export type MdRuntimeHostOptions = MdRuntimeOptions & {
4
+ deploymentFacts?: unknown;
5
+ };
6
+ export type MdRuntimeHost = {
7
+ replaceDeploymentFacts(value: unknown): void;
8
+ attach(port: RuntimePort, app: string, release?: string): () => void;
9
+ endAuthorization(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ };
12
+ export declare function serveMdRuntime(options: MdRuntimeHostOptions): MdRuntimeHost;
13
+ export type { RuntimePort } from './wire.js';
14
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAML,KAAK,WAAW,EAIjB,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,aAAa,GAAG;IAC1B,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7C,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IACrE,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB,CAAC;AAuFF,wBAAgB,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAwH3E;AAED,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
package/dist/host.js ADDED
@@ -0,0 +1,213 @@
1
+ import { composeRuntime } from './connection.js';
2
+ import { removeRuntimeStore } from './store.js';
3
+ import { AUTHORIZATION_ENDED, carried, envelope, PROTOCOL_MISMATCH, request } from './wire.js';
4
+ function answered(md, app, writtenBy, member, input, deploymentFacts) {
5
+ switch(member){
6
+ case 'rooms':
7
+ return md.rooms();
8
+ case 'slots':
9
+ return md.slots();
10
+ case 'query':
11
+ return md.query(input[0]);
12
+ case 'search':
13
+ return md.search(input[0]);
14
+ case 'types':
15
+ return md.types(input[0]);
16
+ case 'syncStatus':
17
+ return md.syncStatus();
18
+ case 'serviceMode':
19
+ return md.serviceMode();
20
+ case 'save':
21
+ return md.save(input[0], input[1], writtenBy);
22
+ case 'outcome':
23
+ return md.outcome(input[0]);
24
+ case 'history':
25
+ return md.history(input[0], input[1], input[2]);
26
+ case 'call':
27
+ return md.call(input[0], input[1]);
28
+ case 'reached':
29
+ return md.reached(input[0], input[1], input[2]);
30
+ case 'log':
31
+ return md.log();
32
+ case 'storageLoss':
33
+ return md.storageLoss();
34
+ case 'deploymentFacts':
35
+ return structuredClone(deploymentFacts);
36
+ case 'persistence':
37
+ return md.persistence();
38
+ case 'reauthorize':
39
+ return md.reauthorize();
40
+ case 'roomDraft.list':
41
+ return md.roomDraft.list();
42
+ case 'roomDraft.read':
43
+ return md.roomDraft.read(input[0], input[1]);
44
+ case 'roomDraft.write':
45
+ return md.roomDraft.write(input[0], input[1], input[2], input[3]);
46
+ case 'roomDraft.discard':
47
+ return md.roomDraft.discard(input[0], input[1], input[2]);
48
+ case 'presentation.read':
49
+ return md.presentation.read(app);
50
+ case 'presentation.write':
51
+ return md.presentation.write(app, input[0]);
52
+ case 'conversation.list':
53
+ return md.conversation.list();
54
+ case 'conversation.read':
55
+ return md.conversation.read(input[0], input[1]);
56
+ case 'conversation.create':
57
+ return md.conversation.create(input[0]);
58
+ case 'conversation.send':
59
+ return md.conversation.send(input[0]);
60
+ case 'conversation.answer':
61
+ return md.conversation.answer(input[0], input[1]);
62
+ case 'conversation.interrupt':
63
+ return md.conversation.interrupt(input[0]);
64
+ case 'conversation.kill':
65
+ return md.conversation.kill(input[0]);
66
+ case 'conversation.cancel':
67
+ return md.conversation.cancel(input[0], input[1]);
68
+ case 'conversation.delete':
69
+ return md.conversation.delete(input[0]);
70
+ case 'chatDraft.write':
71
+ return md.chatDraft.write(input[0], input[1]);
72
+ case 'chatDraft.discard':
73
+ return md.chatDraft.discard(input[0]);
74
+ }
75
+ }
76
+ export function serveMdRuntime(options) {
77
+ let deploymentFacts = structuredClone(options.deploymentFacts);
78
+ const closing = new AbortController();
79
+ const close = ()=>{
80
+ closing.abort();
81
+ };
82
+ options.signal?.addEventListener('abort', close, {
83
+ once: true
84
+ });
85
+ if (options.signal?.aborted === true) close();
86
+ const runtime = composeRuntime({
87
+ ...options,
88
+ signal: closing.signal
89
+ });
90
+ const { md, watch } = runtime;
91
+ const attachments = new Map();
92
+ let authorized = true;
93
+ const factsObservers = new Set();
94
+ const watchFacts = (deliver)=>{
95
+ factsObservers.add(deliver);
96
+ deliver(structuredClone(deploymentFacts));
97
+ return ()=>{
98
+ factsObservers.delete(deliver);
99
+ };
100
+ };
101
+ function attach(port, app, release) {
102
+ if (!authorized) throw new Error(AUTHORIZATION_ENDED);
103
+ const writtenBy = release === undefined ? undefined : {
104
+ app,
105
+ release
106
+ };
107
+ const subscriptions = new Map();
108
+ let serving = true;
109
+ const send = (message)=>{
110
+ port.postMessage(envelope(message));
111
+ };
112
+ const detach = ()=>{
113
+ if (!serving) return;
114
+ serving = false;
115
+ for (const end of subscriptions.values())end();
116
+ subscriptions.clear();
117
+ attachments.delete(detach);
118
+ };
119
+ const serve = async (message)=>{
120
+ if (message.kind === 'hello') return;
121
+ if (message.kind === 'stop') {
122
+ subscriptions.get(message.id)?.();
123
+ subscriptions.delete(message.id);
124
+ return;
125
+ }
126
+ try {
127
+ if (message.kind !== 'observe' || message.topic !== 'room-drafts') await md.loaded();
128
+ if (message.kind === 'observe') {
129
+ const { id, topic } = message;
130
+ let resolved = false;
131
+ const deliver = (value)=>{
132
+ if (!serving) return;
133
+ send(resolved ? {
134
+ kind: 'event',
135
+ id,
136
+ value
137
+ } : {
138
+ kind: 'result',
139
+ id,
140
+ value
141
+ });
142
+ resolved = true;
143
+ };
144
+ subscriptions.set(id, topic === 'deployment-facts' ? watchFacts(deliver) : watch(topic, topic === 'presentation' ? [
145
+ app
146
+ ] : message.input, deliver));
147
+ return;
148
+ }
149
+ const value = await answered(md, app, writtenBy, message.member, message.input, deploymentFacts);
150
+ if (serving) send({
151
+ kind: 'result',
152
+ id: message.id,
153
+ value
154
+ });
155
+ } catch (error) {
156
+ if (serving) {
157
+ send({
158
+ kind: 'failure',
159
+ id: message.id,
160
+ message: error instanceof Error ? error.message : String(error)
161
+ });
162
+ }
163
+ }
164
+ };
165
+ port.addEventListener('message', (event)=>{
166
+ if (!serving) return;
167
+ const wire = carried(event.data);
168
+ if (wire === null) return;
169
+ if (!wire.matching) {
170
+ send({
171
+ kind: 'refusal',
172
+ refusal: PROTOCOL_MISMATCH
173
+ });
174
+ detach();
175
+ return;
176
+ }
177
+ const message = request(wire.message);
178
+ if (message === null) return;
179
+ void serve(message);
180
+ });
181
+ port.addEventListener('close', detach);
182
+ port.start();
183
+ attachments.set(detach, send);
184
+ return detach;
185
+ }
186
+ return {
187
+ attach,
188
+ replaceDeploymentFacts (value) {
189
+ if (!authorized) throw new Error(AUTHORIZATION_ENDED);
190
+ deploymentFacts = structuredClone(value);
191
+ for (const deliver of factsObservers)deliver(structuredClone(deploymentFacts));
192
+ },
193
+ async endAuthorization () {
194
+ authorized = false;
195
+ for (const [detach, send] of [
196
+ ...attachments
197
+ ]){
198
+ send({
199
+ kind: 'ended'
200
+ });
201
+ detach();
202
+ }
203
+ close();
204
+ await removeRuntimeStore();
205
+ await options.shell.dropGeneration();
206
+ },
207
+ stop () {
208
+ return runtime.stop();
209
+ }
210
+ };
211
+ }
212
+
213
+ //# sourceMappingURL=host.js.map