@earendil-works/pi-durable 1.0.1 → 1.0.3
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.
- package/CHANGELOG.md +36 -0
- package/README.md +21 -5
- package/dist/env/decode.d.ts +16 -0
- package/dist/env/decode.d.ts.map +1 -0
- package/dist/env/decode.js +28 -0
- package/dist/env/decode.js.map +1 -0
- package/dist/env/index.d.ts +155 -3
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js +2 -0
- package/dist/env/index.js.map +1 -1
- package/dist/env/line-scan.d.ts +13 -0
- package/dist/env/line-scan.d.ts.map +1 -0
- package/dist/env/line-scan.js +147 -0
- package/dist/env/line-scan.js.map +1 -0
- package/dist/env/node-watch.d.ts +29 -0
- package/dist/env/node-watch.d.ts.map +1 -0
- package/dist/env/node-watch.js +431 -0
- package/dist/env/node-watch.js.map +1 -0
- package/dist/env/node.d.ts +11 -2
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +284 -21
- package/dist/env/node.js.map +1 -1
- package/dist/harness/agent.d.ts +2 -1
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +5 -0
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +2 -0
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +8 -5
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +4 -1
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/output.d.ts +13 -6
- package/dist/harness/output.d.ts.map +1 -1
- package/dist/harness/output.js +61 -16
- package/dist/harness/output.js.map +1 -1
- package/dist/harness/provider.d.ts +14 -0
- package/dist/harness/provider.d.ts.map +1 -0
- package/dist/harness/provider.js +30 -0
- package/dist/harness/provider.js.map +1 -0
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +12 -4
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/types.d.ts +24 -3
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/view.d.ts +1 -1
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +8 -1
- package/dist/harness/view.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/testing/env-conformance.d.ts +7 -0
- package/dist/testing/env-conformance.d.ts.map +1 -0
- package/dist/testing/env-conformance.js +397 -0
- package/dist/testing/env-conformance.js.map +1 -0
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/runner.d.ts +4 -2
- package/dist/testing/runner.d.ts.map +1 -1
- package/dist/testing/runner.js +9 -0
- package/dist/testing/runner.js.map +1 -1
- package/dist/testing/types.d.ts +18 -0
- package/dist/testing/types.d.ts.map +1 -1
- package/dist/testing/types.js.map +1 -1
- package/dist/tools/bash.d.ts +2 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +5 -2
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/image.d.ts +10 -0
- package/dist/tools/image.d.ts.map +1 -1
- package/dist/tools/image.js +39 -0
- package/dist/tools/image.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +148 -75
- package/dist/tools/read.js.map +1 -1
- package/dist/truncate.d.ts +9 -0
- package/dist/truncate.d.ts.map +1 -1
- package/dist/truncate.js +12 -4
- package/dist/truncate.js.map +1 -1
- package/package.json +3 -3
package/dist/harness/view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/harness/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AttachedReplicatedState, type Context, type JsonValue, replicatedState } from \"@earendil-works/chord\";\nimport { withoutAbortSignal } from \"@earendil-works/chord/context\";\nimport { applyImmutable, type NonEmptyPath, type Op, type Path } from \"@earendil-works/chord/delta\";\nimport { CommittedStateSource, CommittedWatch } from \"../session/observation.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationDocToken,\n\tConversationId,\n\tConversationRecord,\n\tDocumentId,\n\tEntryRecord,\n\tJsonObject,\n\tStorage,\n\tWatchHandle,\n} from \"../types.ts\";\nimport { AgentDoc } from \"./agent.ts\";\nimport { activeEntries, captureContextBounds } from \"./context.ts\";\nimport { InboxDoc } from \"./inbox.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport { UsageDoc } from \"./usage.ts\";\nimport { closedError } from \"./util.ts\";\n\n/** Structural mount of one conversation's active transcript and built-in documents (spec §9.3). */\nexport type ConversationView = {\n\treadonly conversation: ConversationRecord;\n\t/** Raw active entries, as `ContextView.entries`: the head marker, then the non-head entries from its head. */\n\treadonly entries: readonly EntryRecord[];\n\t/** `pi.agent`, `pi.live`, `pi.inbox`, and `pi.usage`, keyed by kind; absent documents are absent. */\n\treadonly docs: Readonly<Record<string, JsonObject>>;\n};\n\n/** Receives each next revision of a mount, and the Session's close. */\nexport type ViewObserver = {\n\tadvance?(value: ConversationView, ops: readonly Op[], context: Context): void;\n\t/** Every publication, after the mount took it; `ops` are the mount's, possibly none. */\n\tpublication?(\n\t\tbefore: ConversationView,\n\t\tafter: ConversationView,\n\t\tops: readonly Op[],\n\t\tpublication: CommitPublication,\n\t\tcontext: Context,\n\t): void;\n\tcloseSession(): void;\n};\n\nconst MOUNTED = [AgentDoc, LiveDoc, InboxDoc, UsageDoc] as unknown as readonly ConversationDocToken<JsonObject>[];\nconst MOUNTED_KINDS: ReadonlySet<string> = new Set(MOUNTED.map((token) => token.definition.kind));\n\n/** One conversation's mount: its current revision, the document incarnations it shows, and its observers. */\ntype Mount = {\n\tvalue: ConversationView;\n\t/** Mounted incarnation and definition version per kind; another incarnation or version is set whole. */\n\treadonly docs: Map<string, { id: DocumentId; version: number }>;\n\treadonly observers: Set<ViewObserver>;\n};\n\nconst VIEWS = new WeakMap<object, ConversationViews>();\n\n/** The view mounts of a Harness, for adapters built on them. */\nexport function conversationViews(harness: object): ConversationViews {\n\tconst views = VIEWS.get(harness);\n\tif (views === undefined) throw new Error(\"Not a Harness\");\n\treturn views;\n}\n\n/**\n * The Harness's conversation view mounts: at most one per conversation, built on the Session line by its first\n * observer and dropped with its last. Each mount advances from the Session's commit publications, which are durable.\n */\nexport class ConversationViews {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\treadonly #mounts = new Map<ConversationId, Mount>();\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, storage: Storage) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tVIEWS.set(session, this);\n\t\tsession.subscribeCommits((publication, context) => {\n\t\t\tfor (const [id, mount] of this.#mounts) advance(id, mount, publication, context);\n\t\t});\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tfor (const mount of this.#mounts.values())\n\t\t\t\tfor (const observer of [...mount.observers]) observer.closeSession();\n\t\t\tthis.#mounts.clear();\n\t\t});\n\t}\n\n\t/** A disposable read-only Chord state of the view. */\n\tasync state(id: ConversationId, context: Context): Promise<AttachedReplicatedState<ConversationView>> {\n\t\tconst { observer, detach } = await this.attach(\n\t\t\tid,\n\t\t\t(value, release) => new CommittedStateSource<ConversationView>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\ttry {\n\t\t\treturn replicatedState(observer);\n\t\t} catch (error) {\n\t\t\tdetach();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** A serialized exact-frame watch of the view; cancelling `context` stops it. */\n\tasync watch(id: ConversationId, context: Context): Promise<WatchHandle<ConversationView>> {\n\t\tconst { observer } = await this.attach(\n\t\t\tid,\n\t\t\t(value, release) => new CommittedWatch<ConversationView>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tobserver.cancel();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\tif (signal !== undefined) observer.observeCancellation(signal);\n\t\treturn observer;\n\t}\n\n\t/**\n\t * Register an observer created from the current revision, atomically on the Session line: it sees every later\n\t * publication and nothing earlier. `create` may read committed Storage, still on the line. `release` drops it, and\n\t * the mount with its last observer.\n\t */\n\tattach<O extends ViewObserver>(\n\t\tid: ConversationId,\n\t\tcreate: (value: ConversationView, release: () => void, storage: Storage) => O | Promise<O>,\n\t\tcontext: Context,\n\t): Promise<{ observer: O; detach: () => void }> {\n\t\treturn this.#session.readOnLine(async () => {\n\t\t\tconst mount = this.#mounts.get(id) ?? (await this.#build(id, context));\n\t\t\tconst detach = (): void => {\n\t\t\t\tmount.observers.delete(observer);\n\t\t\t\tif (mount.observers.size === 0 && this.#mounts.get(id) === mount) this.#mounts.delete(id);\n\t\t\t};\n\t\t\tconst observer = await create(mount.value, detach, this.#storage);\n\t\t\t// Close or cancellation may begin while the mount hydrates; register nothing then.\n\t\t\tif (this.#closed) throw closedError();\n\t\t\tcontext.abortSignal?.throwIfAborted();\n\t\t\tthis.#mounts.set(id, mount);\n\t\t\tmount.observers.add(observer);\n\t\t\treturn { observer, detach };\n\t\t});\n\t}\n\n\tasync #build(id: ConversationId, context: Context): Promise<Mount> {\n\t\tconst conversation = await this.#storage.conversation(id, context);\n\t\tif (conversation === undefined) throw new Error(`Conversation ${id} does not exist`);\n\t\tconst bounds = await captureContextBounds(this.#storage, id, context);\n\t\tconst entries = await activeEntries(this.#storage, id, bounds, context);\n\t\tconst docs: Record<string, JsonObject> = {};\n\t\tconst incarnations = new Map<string, { id: DocumentId; version: number }>();\n\t\tfor (const token of MOUNTED) {\n\t\t\tconst loaded = await this.#session.conversationDocumentOnLine(token, id, context);\n\t\t\tif (loaded === undefined) continue;\n\t\t\tdocs[token.definition.kind] = loaded.value;\n\t\t\tincarnations.set(token.definition.kind, { id: loaded.record.id, version: loaded.version });\n\t\t}\n\t\treturn { value: { conversation, entries, docs }, docs: incarnations, observers: new Set() };\n\t}\n}\n\n/** Derive the mount's operations from one publication, apply them, and hand the revision to every observer. */\nfunction advance(id: ConversationId, mount: Mount, publication: CommitPublication, context: Context): void {\n\tconst docOps: Op[] = [];\n\tconst entryOps: Op[] = [];\n\tlet entries = mount.value.entries;\n\t// Entry writes are published in ID order.\n\tfor (const change of publication.changes) {\n\t\tif (change.type === \"entry\" && change.value.conversationId === id) {\n\t\t\tconst entry = change.value;\n\t\t\tconst value = entry as unknown as JsonValue;\n\t\t\tif (entry.head === undefined) {\n\t\t\t\tentryOps.push([\"p\", [\"entries\"], entries.length, 0, [value]]);\n\t\t\t\tentries = [...entries, entry];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// A head marker keeps the non-head entries from its head, which are always a suffix, and goes in front.\n\t\t\tconst target = entry.head;\n\t\t\tlet kept = entries.findIndex((candidate) => candidate.head === undefined && candidate.id >= target);\n\t\t\tif (kept < 0) kept = entries.length;\n\t\t\tentryOps.push([\"p\", [\"entries\"], 0, kept, [value]]);\n\t\t\tentries = [entry, ...entries.slice(kept)];\n\t\t\tcontinue;\n\t\t}\n\t\tif (change.type !== \"document\" || change.conversationId !== id) continue;\n\t\tconst kind = change.record.kind;\n\t\tif (!MOUNTED_KINDS.has(kind) || change.record.key !== undefined) continue;\n\t\tconst path: NonEmptyPath = [\"docs\", kind];\n\t\tconst mounted = mount.docs.get(kind);\n\t\tif (change.value === null) {\n\t\t\tif (mounted?.id !== change.record.id) continue;\n\t\t\tmount.docs.delete(kind);\n\t\t\tdocOps.push([\"d\", path]);\n\t\t} else if (mounted?.id === change.record.id && mounted.version === change.version) {\n\t\t\tfor (const op of change.ops) docOps.push(prefixed(op, path));\n\t\t} else {\n\t\t\tmount.docs.set(kind, { id: change.record.id, version: change.version! });\n\t\t\tdocOps.push([\"s\", path, change.value]);\n\t\t}\n\t}\n\tconst before = mount.value;\n\tconst ops = [...docOps, ...entryOps];\n\tconst frameContext = withoutAbortSignal(context);\n\tif (ops.length > 0) {\n\t\tconst value = docOps.length === 0 ? mount.value : applyImmutable(mount.value, docOps);\n\t\tmount.value = entries === value.entries ? value : { ...value, entries };\n\t\tfor (const observer of [...mount.observers]) observer.advance?.(mount.value, ops, frameContext);\n\t}\n\tfor (const observer of [...mount.observers]) {\n\t\tobserver.publication?.(before, mount.value, ops, publication, frameContext);\n\t}\n}\n\n/** `op` moved under `prefix`; a root replacement becomes a set of the prefix. */\nfunction prefixed(op: Op, prefix: NonEmptyPath): Op {\n\tconst at = (path: Path): NonEmptyPath => [...prefix, ...path] as unknown as NonEmptyPath;\n\tswitch (op[0]) {\n\t\tcase \"r\":\n\t\t\treturn [\"s\", prefix, op[1]];\n\t\tcase \"p\":\n\t\t\treturn [\"p\", at(op[1]), op[2], op[3], op[4]];\n\t\tcase \"m\":\n\t\t\treturn [\"m\", at(op[1]), op[2]];\n\t\tcase \"s\":\n\t\t\treturn [\"s\", at(op[1]), op[2]];\n\t\tcase \"d\":\n\t\t\treturn [\"d\", at(op[1])];\n\t\tcase \"a\":\n\t\t\treturn [\"a\", at(op[1]), op[2]];\n\t\tcase \"t\":\n\t\t\treturn [\"t\", at(op[1]), op[2]];\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/harness/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AttachedReplicatedState, type Context, type JsonValue, replicatedState } from \"@earendil-works/chord\";\nimport { withoutAbortSignal } from \"@earendil-works/chord/context\";\nimport { applyImmutable, type NonEmptyPath, type Op, type Path } from \"@earendil-works/chord/delta\";\nimport { CommittedStateSource, CommittedWatch } from \"../session/observation.ts\";\nimport type { SessionImpl } from \"../session/session.ts\";\nimport type {\n\tCommitPublication,\n\tConversationDocToken,\n\tConversationId,\n\tConversationRecord,\n\tDocumentId,\n\tEntryRecord,\n\tJsonObject,\n\tStorage,\n\tWatchHandle,\n} from \"../types.ts\";\nimport { AgentDoc } from \"./agent.ts\";\nimport { activeEntries, captureContextBounds } from \"./context.ts\";\nimport { InboxDoc } from \"./inbox.ts\";\nimport { LiveDoc } from \"./live.ts\";\nimport { ProviderDoc } from \"./provider.ts\";\nimport { UsageDoc } from \"./usage.ts\";\nimport { closedError } from \"./util.ts\";\n\n/** Structural mount of one conversation's active transcript and built-in documents (spec §9.3). */\nexport type ConversationView = {\n\treadonly conversation: ConversationRecord;\n\t/** Raw active entries, as `ContextView.entries`: the head marker, then the non-head entries from its head. */\n\treadonly entries: readonly EntryRecord[];\n\t/** Built-in conversation documents keyed by kind; absent documents are absent. */\n\treadonly docs: Readonly<Record<string, JsonObject>>;\n};\n\n/** Receives each next revision of a mount, and the Session's close. */\nexport type ViewObserver = {\n\tadvance?(value: ConversationView, ops: readonly Op[], context: Context): void;\n\t/** Every publication, after the mount took it; `ops` are the mount's, possibly none. */\n\tpublication?(\n\t\tbefore: ConversationView,\n\t\tafter: ConversationView,\n\t\tops: readonly Op[],\n\t\tpublication: CommitPublication,\n\t\tcontext: Context,\n\t): void;\n\tcloseSession(): void;\n};\n\nconst MOUNTED = [\n\tAgentDoc,\n\tLiveDoc,\n\tInboxDoc,\n\tProviderDoc,\n\tUsageDoc,\n] as unknown as readonly ConversationDocToken<JsonObject>[];\nconst MOUNTED_KINDS: ReadonlySet<string> = new Set(MOUNTED.map((token) => token.definition.kind));\n\n/** One conversation's mount: its current revision, the document incarnations it shows, and its observers. */\ntype Mount = {\n\tvalue: ConversationView;\n\t/** Mounted incarnation and definition version per kind; another incarnation or version is set whole. */\n\treadonly docs: Map<string, { id: DocumentId; version: number }>;\n\treadonly observers: Set<ViewObserver>;\n};\n\nconst VIEWS = new WeakMap<object, ConversationViews>();\n\n/** The view mounts of a Harness, for adapters built on them. */\nexport function conversationViews(harness: object): ConversationViews {\n\tconst views = VIEWS.get(harness);\n\tif (views === undefined) throw new Error(\"Not a Harness\");\n\treturn views;\n}\n\n/**\n * The Harness's conversation view mounts: at most one per conversation, built on the Session line by its first\n * observer and dropped with its last. Each mount advances from the Session's commit publications, which are durable.\n */\nexport class ConversationViews {\n\treadonly #session: SessionImpl;\n\treadonly #storage: Storage;\n\treadonly #mounts = new Map<ConversationId, Mount>();\n\t#closed = false;\n\n\tconstructor(session: SessionImpl, storage: Storage) {\n\t\tthis.#session = session;\n\t\tthis.#storage = storage;\n\t\tVIEWS.set(session, this);\n\t\tsession.subscribeCommits((publication, context) => {\n\t\t\tfor (const [id, mount] of this.#mounts) advance(id, mount, publication, context);\n\t\t});\n\t\tsession.subscribeClose(() => {\n\t\t\tthis.#closed = true;\n\t\t\tfor (const mount of this.#mounts.values())\n\t\t\t\tfor (const observer of [...mount.observers]) observer.closeSession();\n\t\t\tthis.#mounts.clear();\n\t\t});\n\t}\n\n\t/** A disposable read-only Chord state of the view. */\n\tasync state(id: ConversationId, context: Context): Promise<AttachedReplicatedState<ConversationView>> {\n\t\tconst { observer, detach } = await this.attach(\n\t\t\tid,\n\t\t\t(value, release) => new CommittedStateSource<ConversationView>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\ttry {\n\t\t\treturn replicatedState(observer);\n\t\t} catch (error) {\n\t\t\tdetach();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/** A serialized exact-frame watch of the view; cancelling `context` stops it. */\n\tasync watch(id: ConversationId, context: Context): Promise<WatchHandle<ConversationView>> {\n\t\tconst { observer } = await this.attach(\n\t\t\tid,\n\t\t\t(value, release) => new CommittedWatch<ConversationView>(value, release),\n\t\t\tcontext,\n\t\t);\n\t\tconst signal = context.abortSignal;\n\t\tif (signal?.aborted) {\n\t\t\tobserver.cancel();\n\t\t\tthrow signal.reason;\n\t\t}\n\t\tif (signal !== undefined) observer.observeCancellation(signal);\n\t\treturn observer;\n\t}\n\n\t/**\n\t * Register an observer created from the current revision, atomically on the Session line: it sees every later\n\t * publication and nothing earlier. `create` may read committed Storage, still on the line. `release` drops it, and\n\t * the mount with its last observer.\n\t */\n\tattach<O extends ViewObserver>(\n\t\tid: ConversationId,\n\t\tcreate: (value: ConversationView, release: () => void, storage: Storage) => O | Promise<O>,\n\t\tcontext: Context,\n\t): Promise<{ observer: O; detach: () => void }> {\n\t\treturn this.#session.readOnLine(async () => {\n\t\t\tconst mount = this.#mounts.get(id) ?? (await this.#build(id, context));\n\t\t\tconst detach = (): void => {\n\t\t\t\tmount.observers.delete(observer);\n\t\t\t\tif (mount.observers.size === 0 && this.#mounts.get(id) === mount) this.#mounts.delete(id);\n\t\t\t};\n\t\t\tconst observer = await create(mount.value, detach, this.#storage);\n\t\t\t// Close or cancellation may begin while the mount hydrates; register nothing then.\n\t\t\tif (this.#closed) throw closedError();\n\t\t\tcontext.abortSignal?.throwIfAborted();\n\t\t\tthis.#mounts.set(id, mount);\n\t\t\tmount.observers.add(observer);\n\t\t\treturn { observer, detach };\n\t\t});\n\t}\n\n\tasync #build(id: ConversationId, context: Context): Promise<Mount> {\n\t\tconst conversation = await this.#storage.conversation(id, context);\n\t\tif (conversation === undefined) throw new Error(`Conversation ${id} does not exist`);\n\t\tconst bounds = await captureContextBounds(this.#storage, id, context);\n\t\tconst entries = await activeEntries(this.#storage, id, bounds, context);\n\t\tconst docs: Record<string, JsonObject> = {};\n\t\tconst incarnations = new Map<string, { id: DocumentId; version: number }>();\n\t\tfor (const token of MOUNTED) {\n\t\t\tconst loaded = await this.#session.conversationDocumentOnLine(token, id, context);\n\t\t\tif (loaded === undefined) continue;\n\t\t\tdocs[token.definition.kind] = loaded.value;\n\t\t\tincarnations.set(token.definition.kind, { id: loaded.record.id, version: loaded.version });\n\t\t}\n\t\treturn { value: { conversation, entries, docs }, docs: incarnations, observers: new Set() };\n\t}\n}\n\n/** Derive the mount's operations from one publication, apply them, and hand the revision to every observer. */\nfunction advance(id: ConversationId, mount: Mount, publication: CommitPublication, context: Context): void {\n\tconst docOps: Op[] = [];\n\tconst entryOps: Op[] = [];\n\tlet entries = mount.value.entries;\n\t// Entry writes are published in ID order.\n\tfor (const change of publication.changes) {\n\t\tif (change.type === \"entry\" && change.value.conversationId === id) {\n\t\t\tconst entry = change.value;\n\t\t\tconst value = entry as unknown as JsonValue;\n\t\t\tif (entry.head === undefined) {\n\t\t\t\tentryOps.push([\"p\", [\"entries\"], entries.length, 0, [value]]);\n\t\t\t\tentries = [...entries, entry];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// A head marker keeps the non-head entries from its head, which are always a suffix, and goes in front.\n\t\t\tconst target = entry.head;\n\t\t\tlet kept = entries.findIndex((candidate) => candidate.head === undefined && candidate.id >= target);\n\t\t\tif (kept < 0) kept = entries.length;\n\t\t\tentryOps.push([\"p\", [\"entries\"], 0, kept, [value]]);\n\t\t\tentries = [entry, ...entries.slice(kept)];\n\t\t\tcontinue;\n\t\t}\n\t\tif (change.type !== \"document\" || change.conversationId !== id) continue;\n\t\tconst kind = change.record.kind;\n\t\tif (!MOUNTED_KINDS.has(kind) || change.record.key !== undefined) continue;\n\t\tconst path: NonEmptyPath = [\"docs\", kind];\n\t\tconst mounted = mount.docs.get(kind);\n\t\tif (change.value === null) {\n\t\t\tif (mounted?.id !== change.record.id) continue;\n\t\t\tmount.docs.delete(kind);\n\t\t\tdocOps.push([\"d\", path]);\n\t\t} else if (mounted?.id === change.record.id && mounted.version === change.version) {\n\t\t\tfor (const op of change.ops) docOps.push(prefixed(op, path));\n\t\t} else {\n\t\t\tmount.docs.set(kind, { id: change.record.id, version: change.version! });\n\t\t\tdocOps.push([\"s\", path, change.value]);\n\t\t}\n\t}\n\tconst before = mount.value;\n\tconst ops = [...docOps, ...entryOps];\n\tconst frameContext = withoutAbortSignal(context);\n\tif (ops.length > 0) {\n\t\tconst value = docOps.length === 0 ? mount.value : applyImmutable(mount.value, docOps);\n\t\tmount.value = entries === value.entries ? value : { ...value, entries };\n\t\tfor (const observer of [...mount.observers]) observer.advance?.(mount.value, ops, frameContext);\n\t}\n\tfor (const observer of [...mount.observers]) {\n\t\tobserver.publication?.(before, mount.value, ops, publication, frameContext);\n\t}\n}\n\n/** `op` moved under `prefix`; a root replacement becomes a set of the prefix. */\nfunction prefixed(op: Op, prefix: NonEmptyPath): Op {\n\tconst at = (path: Path): NonEmptyPath => [...prefix, ...path] as unknown as NonEmptyPath;\n\tswitch (op[0]) {\n\t\tcase \"r\":\n\t\t\treturn [\"s\", prefix, op[1]];\n\t\tcase \"p\":\n\t\t\treturn [\"p\", at(op[1]), op[2], op[3], op[4]];\n\t\tcase \"m\":\n\t\t\treturn [\"m\", at(op[1]), op[2]];\n\t\tcase \"s\":\n\t\t\treturn [\"s\", at(op[1]), op[2]];\n\t\tcase \"d\":\n\t\t\treturn [\"d\", at(op[1])];\n\t\tcase \"a\":\n\t\t\treturn [\"a\", at(op[1]), op[2]];\n\t\tcase \"t\":\n\t\t\treturn [\"t\", at(op[1]), op[2]];\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { defineDoc, defineDocFamily } from "./documents.ts";
|
|
2
2
|
export { AssistantEntry, CompactionEntry, defineEntry, ResetEntry, SystemEntry, ToolResultEntry, UserEntry, } from "./entries.ts";
|
|
3
3
|
export { ConversationBusy, ReadAfterWrite, StorageRejected } from "./errors.ts";
|
|
4
|
-
export { AgentDoc, configure, DEFAULT_COMPACTION_POLICY, DEFAULT_RETRY_POLICY, } from "./harness/agent.ts";
|
|
4
|
+
export { AgentDoc, configure, DEFAULT_COMPACTION_POLICY, DEFAULT_PROGRESS_POLICY, DEFAULT_RETRY_POLICY, } from "./harness/agent.ts";
|
|
5
5
|
export { type CompactionCheckpoint, type CompactionInput, CompactionTask, type SummaryRequest, } from "./harness/compaction.ts";
|
|
6
6
|
export { defineExtension, defineTool, hook, section, wrapSection, wrapTool } from "./harness/define.ts";
|
|
7
7
|
export { type AgentEvent, type AgentEventStream, type MessageChange, type SnapshotEvent, watchEvents, } from "./harness/events.ts";
|
|
@@ -9,10 +9,11 @@ export { type GenerationCheckpoint, type GenerationInput, type GenerationResult,
|
|
|
9
9
|
export { Harness } from "./harness/harness.ts";
|
|
10
10
|
export { InboxDoc, type InboxItem, type InboxState } from "./harness/inbox.ts";
|
|
11
11
|
export { type CompactionStatus, LiveDoc, type LiveState, type ToolSlot } from "./harness/live.ts";
|
|
12
|
+
export { ProviderDoc, type ProviderState } from "./harness/provider.ts";
|
|
12
13
|
export { createRegistry } from "./harness/registry.ts";
|
|
13
14
|
export type { TaskGraph, TaskGraphNode, TaskGraphState, TaskGraphWatch } from "./harness/task-graph.ts";
|
|
14
15
|
export { ToolTask, type ToolTaskCheckpoint, type ToolTaskInput, type ToolTaskResult } from "./harness/tool.ts";
|
|
15
|
-
export type { Agent, AgentChange, AgentState, AnyTask, CompactionHooks, CompactionPolicy, CompactionReason, CompactionResult, ContextView, Conversation, ConversationAbortOptions, ConversationCreateOptions, ConversationHandle, ConversationInit, ConversationRetryPolicy, ConversationStreamOptions, ConversationWatch, EnvTarget, Extension, GenerationHooks, HarnessInspection, HarnessOptions, HarnessSettings, HookApi, HookRegistration, HookResult, HooksOf, InputSubmissionDraft, ModelRef, PromptInput, PromptSection, QueueMode, Registry, RegistryReader, RegistrySnapshot, Settings, SettledSubmissionRecord, SettledTask, Submission, SubmissionDraft, TaskInspection, ToolControl, ToolDiagnostic, ToolExecutionApi, ToolExecutionMode, ToolExecutionResult, ToolHooks, ToolRegistration, UserInput, Wrap, } from "./harness/types.ts";
|
|
16
|
+
export type { Agent, AgentChange, AgentState, AnyTask, CompactionHooks, CompactionPolicy, CompactionReason, CompactionResult, ContextView, Conversation, ConversationAbortOptions, ConversationCreateOptions, ConversationHandle, ConversationInit, ConversationRetryPolicy, ConversationStreamOptions, ConversationWatch, EnvTarget, Extension, GenerationHooks, HarnessInspection, HarnessOptions, HarnessSettings, HookApi, HookRegistration, HookResult, HooksOf, InputSubmissionDraft, ModelRef, ProgressPolicy, PromptInput, PromptSection, QueueMode, Registry, RegistryReader, RegistrySnapshot, Settings, SettledSubmissionRecord, SettledTask, Submission, SubmissionDraft, TaskInspection, ToolControl, ToolDiagnostic, ToolExecutionApi, ToolExecutionMode, ToolExecutionResult, ToolHooks, ToolRegistration, UserInput, Wrap, } from "./harness/types.ts";
|
|
16
17
|
export { UsageDoc, type UsageState } from "./harness/usage.ts";
|
|
17
18
|
export type { ConversationView } from "./harness/view.ts";
|
|
18
19
|
export { createSession } from "./session/session.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { defineDoc, defineDocFamily } from "./documents.js";
|
|
2
2
|
export { AssistantEntry, CompactionEntry, defineEntry, ResetEntry, SystemEntry, ToolResultEntry, UserEntry, } from "./entries.js";
|
|
3
3
|
export { ConversationBusy, ReadAfterWrite, StorageRejected } from "./errors.js";
|
|
4
|
-
export { AgentDoc, configure, DEFAULT_COMPACTION_POLICY, DEFAULT_RETRY_POLICY, } from "./harness/agent.js";
|
|
4
|
+
export { AgentDoc, configure, DEFAULT_COMPACTION_POLICY, DEFAULT_PROGRESS_POLICY, DEFAULT_RETRY_POLICY, } from "./harness/agent.js";
|
|
5
5
|
export { CompactionTask, } from "./harness/compaction.js";
|
|
6
6
|
export { defineExtension, defineTool, hook, section, wrapSection, wrapTool } from "./harness/define.js";
|
|
7
7
|
export { watchEvents, } from "./harness/events.js";
|
|
@@ -9,6 +9,7 @@ export { GenerationTask, } from "./harness/generation.js";
|
|
|
9
9
|
export { Harness } from "./harness/harness.js";
|
|
10
10
|
export { InboxDoc } from "./harness/inbox.js";
|
|
11
11
|
export { LiveDoc } from "./harness/live.js";
|
|
12
|
+
export { ProviderDoc } from "./harness/provider.js";
|
|
12
13
|
export { createRegistry } from "./harness/registry.js";
|
|
13
14
|
export { ToolTask } from "./harness/tool.js";
|
|
14
15
|
export { UsageDoc } from "./harness/usage.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EACN,cAAc,EACd,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EACN,QAAQ,EACR,SAAS,EACT,yBAAyB,EACzB,oBAAoB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGN,cAAc,GAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAKN,WAAW,GACX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIN,cAAc,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAmC,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAyB,OAAO,EAAiC,MAAM,mBAAmB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAoE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EACN,cAAc,EACd,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EACN,QAAQ,EACR,SAAS,EACT,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGN,cAAc,GAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAKN,WAAW,GACX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIN,cAAc,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAmC,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAyB,OAAO,EAAiC,MAAM,mBAAmB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAsB,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAoE,MAAM,mBAAmB,CAAC;AAsD/G,OAAO,EAAE,QAAQ,EAAmB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiFxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { defineDoc, defineDocFamily } from \"./documents.ts\";\nexport {\n\tAssistantEntry,\n\tCompactionEntry,\n\tdefineEntry,\n\tResetEntry,\n\tSystemEntry,\n\tToolResultEntry,\n\tUserEntry,\n} from \"./entries.ts\";\nexport { ConversationBusy, ReadAfterWrite, StorageRejected } from \"./errors.ts\";\nexport {\n\tAgentDoc,\n\tconfigure,\n\tDEFAULT_COMPACTION_POLICY,\n\tDEFAULT_PROGRESS_POLICY,\n\tDEFAULT_RETRY_POLICY,\n} from \"./harness/agent.ts\";\nexport {\n\ttype CompactionCheckpoint,\n\ttype CompactionInput,\n\tCompactionTask,\n\ttype SummaryRequest,\n} from \"./harness/compaction.ts\";\nexport { defineExtension, defineTool, hook, section, wrapSection, wrapTool } from \"./harness/define.ts\";\nexport {\n\ttype AgentEvent,\n\ttype AgentEventStream,\n\ttype MessageChange,\n\ttype SnapshotEvent,\n\twatchEvents,\n} from \"./harness/events.ts\";\nexport {\n\ttype GenerationCheckpoint,\n\ttype GenerationInput,\n\ttype GenerationResult,\n\tGenerationTask,\n} from \"./harness/generation.ts\";\nexport { Harness } from \"./harness/harness.ts\";\nexport { InboxDoc, type InboxItem, type InboxState } from \"./harness/inbox.ts\";\nexport { type CompactionStatus, LiveDoc, type LiveState, type ToolSlot } from \"./harness/live.ts\";\nexport { ProviderDoc, type ProviderState } from \"./harness/provider.ts\";\nexport { createRegistry } from \"./harness/registry.ts\";\nexport type { TaskGraph, TaskGraphNode, TaskGraphState, TaskGraphWatch } from \"./harness/task-graph.ts\";\nexport { ToolTask, type ToolTaskCheckpoint, type ToolTaskInput, type ToolTaskResult } from \"./harness/tool.ts\";\nexport type {\n\tAgent,\n\tAgentChange,\n\tAgentState,\n\tAnyTask,\n\tCompactionHooks,\n\tCompactionPolicy,\n\tCompactionReason,\n\tCompactionResult,\n\tContextView,\n\tConversation,\n\tConversationAbortOptions,\n\tConversationCreateOptions,\n\tConversationHandle,\n\tConversationInit,\n\tConversationRetryPolicy,\n\tConversationStreamOptions,\n\tConversationWatch,\n\tEnvTarget,\n\tExtension,\n\tGenerationHooks,\n\tHarnessInspection,\n\tHarnessOptions,\n\tHarnessSettings,\n\tHookApi,\n\tHookRegistration,\n\tHookResult,\n\tHooksOf,\n\tInputSubmissionDraft,\n\tModelRef,\n\tProgressPolicy,\n\tPromptInput,\n\tPromptSection,\n\tQueueMode,\n\tRegistry,\n\tRegistryReader,\n\tRegistrySnapshot,\n\tSettings,\n\tSettledSubmissionRecord,\n\tSettledTask,\n\tSubmission,\n\tSubmissionDraft,\n\tTaskInspection,\n\tToolControl,\n\tToolDiagnostic,\n\tToolExecutionApi,\n\tToolExecutionMode,\n\tToolExecutionResult,\n\tToolHooks,\n\tToolRegistration,\n\tUserInput,\n\tWrap,\n} from \"./harness/types.ts\";\nexport { UsageDoc, type UsageState } from \"./harness/usage.ts\";\nexport type { ConversationView } from \"./harness/view.ts\";\nexport { createSession } from \"./session/session.ts\";\nexport { MemoryStorage } from \"./storage/memory.ts\";\nexport { defineTask } from \"./tasks.ts\";\nexport type {\n\tCheckpointInfo,\n\tCommitChange,\n\tCommitPublication,\n\tCommonDocDefinition,\n\tContextEdit,\n\tConversationDocFamilyToken,\n\tConversationDocToken,\n\tConversationId,\n\tConversationOwnership,\n\tConversationQuery,\n\tConversationRecord,\n\tCursor,\n\tDocDefinition,\n\tDocFamilyDefinition,\n\tDocFamilyToken,\n\tDocToken,\n\tDocumentAddress,\n\tDocumentCommitChange,\n\tDocumentContent,\n\tDocumentCopySource,\n\tDocumentCreate,\n\tDocumentId,\n\tDocumentObserver,\n\tDocumentPoint,\n\tDocumentQuery,\n\tDocumentReader,\n\tDocumentRecord,\n\tDocumentSemantics,\n\tDocumentState,\n\tDocumentWatch,\n\tEntry,\n\tEntryDraft,\n\tEntryId,\n\tEntryQuery,\n\tEntryRecord,\n\tHookRunner,\n\tId,\n\tJoinPolicy,\n\tJsonObject,\n\tLatestConversationSemantics,\n\tNextTaskState,\n\tPage,\n\tPhaseHandler,\n\tRewindableConversationDocFamilyToken,\n\tRewindableConversationDocToken,\n\tRewindableConversationSemantics,\n\tRunningTask,\n\tSeq,\n\tSession,\n\tSessionDocFamilyToken,\n\tSessionDocToken,\n\tStorage,\n\tStorageWrite,\n\tStoredDocument,\n\tSubmissionCreate,\n\tSubmissionId,\n\tSubmissionQuery,\n\tSubmissionRecord,\n\tSubmissionSettlement,\n\tTableCommitChange,\n\tTask,\n\tTaskDefinition,\n\tTaskDocFamilyToken,\n\tTaskDocToken,\n\tTaskId,\n\tTaskOptions,\n\tTaskOutcome,\n\tTaskOutcomeError,\n\tTaskOwnership,\n\tTaskQuery,\n\tTaskRecord,\n\tTaskRuntime,\n\tTaskState,\n\tTx,\n\tTypedEntry,\n\tTypedEntryDraft,\n\tWatchEnd,\n\tWatchHandle,\n} from \"./types.ts\";\nexport { ROOT_CONVERSATION_ID } from \"./types.ts\";\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EnvConformanceCase, EnvConformanceOptions } from "./types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Creates runner-independent cases for an `ExecutionEnv`. `withEnv` must call and await its callback exactly once per
|
|
4
|
+
* case with an environment whose `cwd` is a fresh, empty, writable directory.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createEnvConformance(options: EnvConformanceOptions): readonly EnvConformanceCase[];
|
|
7
|
+
//# sourceMappingURL=env-conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-conformance.d.ts","sourceRoot":"","sources":["../../src/testing/env-conformance.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAkF5E;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,kBAAkB,EAAE,CAuXlG"}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
2
|
+
import { getOrThrow, } from "../env/index.js";
|
|
3
|
+
const context = BACKGROUND_CONTEXT;
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
function abortedContext() {
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
controller.abort();
|
|
9
|
+
return withAbortSignal(controller.signal, BACKGROUND_CONTEXT);
|
|
10
|
+
}
|
|
11
|
+
function errorCode(result) {
|
|
12
|
+
return result.ok ? undefined : result.error.code;
|
|
13
|
+
}
|
|
14
|
+
async function readAll(env, path, maxEntries) {
|
|
15
|
+
const reader = getOrThrow(await env.openDirReader(path, context));
|
|
16
|
+
const pages = [];
|
|
17
|
+
try {
|
|
18
|
+
for (let page = 0; page < 1000; page++) {
|
|
19
|
+
const next = getOrThrow(await reader.next(maxEntries, context));
|
|
20
|
+
pages.push(next.entries);
|
|
21
|
+
if (next.done)
|
|
22
|
+
return { pages, done: true };
|
|
23
|
+
}
|
|
24
|
+
return { pages, done: false };
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
await reader.close(context);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Whether a change reports `path`: an overflow, or a reported path at or above it. */
|
|
31
|
+
function covers(change, path) {
|
|
32
|
+
if ("overflow" in change)
|
|
33
|
+
return true;
|
|
34
|
+
if (!("paths" in change))
|
|
35
|
+
return false;
|
|
36
|
+
return change.paths.some((reported) => path === reported || path.startsWith(`${reported}/`) || path.startsWith(`${reported}\\`));
|
|
37
|
+
}
|
|
38
|
+
/** Watch `targets` while `run` changes files, with a helper that waits for a change reporting a path. */
|
|
39
|
+
async function watching(env, targets, run) {
|
|
40
|
+
const changes = [];
|
|
41
|
+
const watcher = getOrThrow(await env.watch(targets, (change) => changes.push(change), context));
|
|
42
|
+
try {
|
|
43
|
+
const absolute = async (path) => getOrThrow(await env.absolutePath(path, context));
|
|
44
|
+
await run({
|
|
45
|
+
changes,
|
|
46
|
+
absolute,
|
|
47
|
+
async expectChange(path, change) {
|
|
48
|
+
const target = await absolute(path);
|
|
49
|
+
const from = changes.length;
|
|
50
|
+
await change();
|
|
51
|
+
const deadline = Date.now() + 3000;
|
|
52
|
+
while (!changes.slice(from).some((entry) => covers(entry, target))) {
|
|
53
|
+
if (Date.now() > deadline) {
|
|
54
|
+
throw new Error(`No change reported ${target}; got ${JSON.stringify(changes.slice(from))}`);
|
|
55
|
+
}
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await watcher.close(context);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Creates runner-independent cases for an `ExecutionEnv`. `withEnv` must call and await its callback exactly once per
|
|
67
|
+
* case with an environment whose `cwd` is a fresh, empty, writable directory.
|
|
68
|
+
*/
|
|
69
|
+
export function createEnvConformance(options) {
|
|
70
|
+
const assert = options.assertions;
|
|
71
|
+
const shell = options.shell ?? ["sh", "-c"];
|
|
72
|
+
const symlinks = options.symlinks ?? true;
|
|
73
|
+
const createCase = (name, test, timeoutMs) => ({
|
|
74
|
+
name,
|
|
75
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
76
|
+
run: () => options.withEnv(test),
|
|
77
|
+
});
|
|
78
|
+
// Watch cases wait up to three seconds per step, longer than test runners allow by default.
|
|
79
|
+
const watchCase = (name, test) => createCase(name, test, 30_000);
|
|
80
|
+
const execCollect = async (env, command, cwd) => {
|
|
81
|
+
const output = { stdout: "", stderr: "" };
|
|
82
|
+
const result = await env.exec(command, {
|
|
83
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
84
|
+
onOutput: (text, _context, info) => {
|
|
85
|
+
output[info.stream] += text;
|
|
86
|
+
},
|
|
87
|
+
}, context);
|
|
88
|
+
return { result, ...output };
|
|
89
|
+
};
|
|
90
|
+
const cases = [
|
|
91
|
+
createCase("binary reader reads byte ranges of the opened file", async (env) => {
|
|
92
|
+
getOrThrow(await env.writeFile("data.txt", "hello world", context));
|
|
93
|
+
const reader = getOrThrow(await env.openBinaryReader("data.txt", undefined, context));
|
|
94
|
+
const info = getOrThrow(await reader.info(context));
|
|
95
|
+
assert.partialDeepEqual(info, { name: "data.txt", kind: "file", size: 11 });
|
|
96
|
+
assert.strictEqual(decoder.decode(getOrThrow(await reader.read(0, 5, context))), "hello");
|
|
97
|
+
assert.strictEqual(decoder.decode(getOrThrow(await reader.read(6, 100, context))), "world");
|
|
98
|
+
assert.strictEqual(getOrThrow(await reader.read(11, 4, context)).length, 0);
|
|
99
|
+
assert.strictEqual(getOrThrow(await reader.read(50, 1, context)).length, 0);
|
|
100
|
+
assert.strictEqual(getOrThrow(await reader.read(3, 0, context)).length, 0);
|
|
101
|
+
assert.strictEqual(errorCode(await reader.read(-1, 1, context)), "invalid");
|
|
102
|
+
assert.strictEqual(errorCode(await reader.read(0, 1.5, context)), "invalid");
|
|
103
|
+
assert.strictEqual(errorCode(await reader.read(0, 1, abortedContext())), "aborted");
|
|
104
|
+
await reader.close(context);
|
|
105
|
+
await reader.close(context);
|
|
106
|
+
assert.strictEqual(errorCode(await reader.read(0, 1, context)), "invalid");
|
|
107
|
+
assert.strictEqual(errorCode(await reader.info(context)), "invalid");
|
|
108
|
+
}),
|
|
109
|
+
createCase("binary reader scans lines like decoding the whole file", async (env) => {
|
|
110
|
+
// A byte-order mark, an invalid sequence before a newline, an empty line, a later U+FEFF, and no final newline.
|
|
111
|
+
const bytes = Uint8Array.from([
|
|
112
|
+
0xef, 0xbb, 0xbf, 0x61, 0x0a, 0xe2, 0x82, 0x0a, 0x0a, 0xef, 0xbb, 0xbf, 0x62, 0x0a, 0xc3, 0xa9,
|
|
113
|
+
]);
|
|
114
|
+
getOrThrow(await env.writeFile("lines.txt", bytes, context));
|
|
115
|
+
const lines = new TextDecoder().decode(bytes).split("\n");
|
|
116
|
+
const reader = getOrThrow(await env.openBinaryReader("lines.txt", undefined, context));
|
|
117
|
+
try {
|
|
118
|
+
const ranges = [
|
|
119
|
+
[0, undefined],
|
|
120
|
+
[0, 1],
|
|
121
|
+
[1, 3],
|
|
122
|
+
[2, 3],
|
|
123
|
+
[3, undefined],
|
|
124
|
+
[4, 9],
|
|
125
|
+
];
|
|
126
|
+
for (const [startLine, endLine] of ranges) {
|
|
127
|
+
const scan = getOrThrow(await reader.scanLines({ startLine, ...(endLine === undefined ? {} : { endLine }) }, context));
|
|
128
|
+
const selected = lines.slice(startLine, endLine);
|
|
129
|
+
const range = (from, to) => new TextDecoder("utf-8", { ignoreBOM: from > 0 }).decode(bytes.subarray(from, to));
|
|
130
|
+
assert.strictEqual(scan.newlines, lines.length - 1);
|
|
131
|
+
assert.strictEqual(range(scan.start, scan.end), selected.join("\n"));
|
|
132
|
+
assert.strictEqual(scan.selectedBytes, encoder.encode(selected.join("\n")).length);
|
|
133
|
+
assert.strictEqual(range(scan.start, scan.firstLineEnd), lines[startLine]);
|
|
134
|
+
assert.strictEqual(scan.firstLineBytes, encoder.encode(lines[startLine]).length);
|
|
135
|
+
}
|
|
136
|
+
assert.partialDeepEqual(getOrThrow(await reader.scanLines({ startLine: 9 }, context)), {
|
|
137
|
+
start: bytes.length,
|
|
138
|
+
end: bytes.length,
|
|
139
|
+
selectedBytes: 0,
|
|
140
|
+
});
|
|
141
|
+
assert.strictEqual(errorCode(await reader.scanLines({ startLine: 2, endLine: 2 }, context)), "invalid");
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await reader.close(context);
|
|
145
|
+
}
|
|
146
|
+
}),
|
|
147
|
+
createCase("binary reader keeps reading the file it opened after a rename", async (env) => {
|
|
148
|
+
getOrThrow(await env.writeFile("a.txt", "one", context));
|
|
149
|
+
const reader = getOrThrow(await env.openBinaryReader("a.txt", undefined, context));
|
|
150
|
+
try {
|
|
151
|
+
getOrThrow(await env.renameFile("a.txt", "b.txt", context));
|
|
152
|
+
getOrThrow(await env.writeFile("a.txt", "two", context));
|
|
153
|
+
assert.strictEqual(decoder.decode(getOrThrow(await reader.read(0, 10, context))), "one");
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
await reader.close(context);
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
159
|
+
createCase("binary reader refuses directories, missing files and aborted opens", async (env) => {
|
|
160
|
+
getOrThrow(await env.createDir("dir", undefined, context));
|
|
161
|
+
getOrThrow(await env.writeFile("file.txt", "x", context));
|
|
162
|
+
assert.strictEqual(errorCode(await env.openBinaryReader("dir", undefined, context)), "is_directory");
|
|
163
|
+
assert.strictEqual(errorCode(await env.openBinaryReader("missing.txt", undefined, context)), "not_found");
|
|
164
|
+
assert.strictEqual(errorCode(await env.openBinaryReader("file.txt", undefined, abortedContext())), "aborted");
|
|
165
|
+
}),
|
|
166
|
+
createCase("directory reader pages every entry exactly once", async (env) => {
|
|
167
|
+
const names = ["a.txt", "b.txt", "c.txt", "d.txt", "e.txt"];
|
|
168
|
+
for (const name of names)
|
|
169
|
+
getOrThrow(await env.writeFile(name, name, context));
|
|
170
|
+
getOrThrow(await env.createDir("sub", undefined, context));
|
|
171
|
+
const { pages, done } = await readAll(env, ".", 2);
|
|
172
|
+
assert.ok(done, "directory reader reached the end");
|
|
173
|
+
for (const page of pages)
|
|
174
|
+
assert.ok(page.length <= 2, "page within maxEntries");
|
|
175
|
+
const entries = pages.flat();
|
|
176
|
+
assert.deepEqual(entries.map((entry) => entry.name).sort(), [...names, "sub"].sort());
|
|
177
|
+
assert.strictEqual(entries.find((entry) => entry.name === "sub")?.kind, "directory");
|
|
178
|
+
assert.partialDeepEqual(entries.find((entry) => entry.name === "a.txt"), { kind: "file", size: 5 });
|
|
179
|
+
}),
|
|
180
|
+
createCase("directory reader reports the end and refuses use after close", async (env) => {
|
|
181
|
+
getOrThrow(await env.createDir("empty", undefined, context));
|
|
182
|
+
const reader = getOrThrow(await env.openDirReader("empty", context));
|
|
183
|
+
assert.deepEqual(getOrThrow(await reader.next(10, context)), { entries: [], done: true });
|
|
184
|
+
assert.deepEqual(getOrThrow(await reader.next(10, context)), { entries: [], done: true });
|
|
185
|
+
assert.strictEqual(errorCode(await reader.next(0, context)), "invalid");
|
|
186
|
+
assert.strictEqual(errorCode(await reader.next(1, abortedContext())), "aborted");
|
|
187
|
+
await reader.close(context);
|
|
188
|
+
await reader.close(context);
|
|
189
|
+
assert.strictEqual(errorCode(await reader.next(1, context)), "invalid");
|
|
190
|
+
}),
|
|
191
|
+
createCase("directory reader refuses missing paths and files", async (env) => {
|
|
192
|
+
getOrThrow(await env.writeFile("file.txt", "x", context));
|
|
193
|
+
assert.strictEqual(errorCode(await env.openDirReader("missing", context)), "not_found");
|
|
194
|
+
const file = await env.openDirReader("file.txt", context);
|
|
195
|
+
assert.strictEqual(errorCode(file), "not_directory");
|
|
196
|
+
assert.strictEqual(errorCode(await env.openDirReader(".", abortedContext())), "aborted");
|
|
197
|
+
}),
|
|
198
|
+
createCase("directory reader skips entries removed during enumeration", async (env) => {
|
|
199
|
+
getOrThrow(await env.createDir("dir", undefined, context));
|
|
200
|
+
for (const name of ["x", "y", "z"])
|
|
201
|
+
getOrThrow(await env.writeFile(`dir/${name}`, name, context));
|
|
202
|
+
const reader = getOrThrow(await env.openDirReader("dir", context));
|
|
203
|
+
try {
|
|
204
|
+
for (const name of ["x", "y", "z"])
|
|
205
|
+
getOrThrow(await env.remove(`dir/${name}`, undefined, context));
|
|
206
|
+
const entries = [];
|
|
207
|
+
for (let page = 0; page < 10; page++) {
|
|
208
|
+
const next = getOrThrow(await reader.next(10, context));
|
|
209
|
+
entries.push(...next.entries);
|
|
210
|
+
if (next.done)
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
assert.deepEqual(entries, []);
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
await reader.close(context);
|
|
217
|
+
}
|
|
218
|
+
}),
|
|
219
|
+
watchCase("watch reports a missing file's creation, changes, replacement and removal", async (env) => {
|
|
220
|
+
await watching(env, [{ path: "AGENTS.md" }], async ({ expectChange }) => {
|
|
221
|
+
await expectChange("AGENTS.md", async () => {
|
|
222
|
+
getOrThrow(await env.writeFile("AGENTS.md", "one", context));
|
|
223
|
+
});
|
|
224
|
+
await expectChange("AGENTS.md", async () => {
|
|
225
|
+
getOrThrow(await env.writeFile("AGENTS.md", "two!", context));
|
|
226
|
+
});
|
|
227
|
+
// Editors replace a file by renaming a new one over it.
|
|
228
|
+
await expectChange("AGENTS.md", async () => {
|
|
229
|
+
getOrThrow(await env.writeFile("AGENTS.md.tmp", "three", context));
|
|
230
|
+
getOrThrow(await env.renameFile("AGENTS.md.tmp", "AGENTS.md", context));
|
|
231
|
+
});
|
|
232
|
+
await expectChange("AGENTS.md", async () => {
|
|
233
|
+
getOrThrow(await env.writeFile("AGENTS.md", "four", context));
|
|
234
|
+
});
|
|
235
|
+
await expectChange("AGENTS.md", async () => {
|
|
236
|
+
getOrThrow(await env.remove("AGENTS.md", undefined, context));
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}),
|
|
240
|
+
watchCase("watch reports a missing target whose ancestors are created", async (env) => {
|
|
241
|
+
await watching(env, [{ path: "a/b/c/AGENTS.md" }], async ({ expectChange }) => {
|
|
242
|
+
await expectChange("a/b/c/AGENTS.md", async () => {
|
|
243
|
+
getOrThrow(await env.writeFile("a/b/c/AGENTS.md", "x", context));
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}),
|
|
247
|
+
watchCase("watch follows directories created together with their contents", async (env) => {
|
|
248
|
+
getOrThrow(await env.createDir("skills", undefined, context));
|
|
249
|
+
await watching(env, [{ path: "skills", recursive: true }], async ({ expectChange }) => {
|
|
250
|
+
// Written before any watcher on the new directories can exist.
|
|
251
|
+
await expectChange("skills/a/b/SKILL.md", async () => {
|
|
252
|
+
getOrThrow(await env.writeFile("skills/a/b/SKILL.md", "one", context));
|
|
253
|
+
});
|
|
254
|
+
await expectChange("skills/a/b/SKILL.md", async () => {
|
|
255
|
+
getOrThrow(await env.writeFile("skills/a/b/SKILL.md", "two!", context));
|
|
256
|
+
});
|
|
257
|
+
await expectChange("skills/a/b/c/SKILL.md", async () => {
|
|
258
|
+
getOrThrow(await env.writeFile("skills/a/b/c/SKILL.md", "deeper", context));
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}),
|
|
262
|
+
watchCase("watch keeps watching a path whose parent is renamed and recreated", async (env) => {
|
|
263
|
+
getOrThrow(await env.writeFile("proj/.pi/skills/x.md", "x", context));
|
|
264
|
+
await watching(env, [{ path: "proj/.pi/skills", recursive: true }], async ({ expectChange }) => {
|
|
265
|
+
await expectChange("proj/.pi/skills", async () => {
|
|
266
|
+
getOrThrow(await env.renameFile("proj/.pi", "proj/old", context));
|
|
267
|
+
});
|
|
268
|
+
await expectChange("proj/.pi/skills/y.md", async () => {
|
|
269
|
+
getOrThrow(await env.writeFile("proj/.pi/skills/y.md", "y", context));
|
|
270
|
+
});
|
|
271
|
+
await expectChange("proj/.pi/skills/y.md", async () => {
|
|
272
|
+
getOrThrow(await env.writeFile("proj/.pi/skills/y.md", "yy", context));
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
}),
|
|
276
|
+
watchCase("watch skips excluded entries and reports a rename out of them", async (env) => {
|
|
277
|
+
getOrThrow(await env.createDir("skills", undefined, context));
|
|
278
|
+
const targets = [
|
|
279
|
+
{ path: "skills", recursive: true, exclude: { hidden: true, names: ["node_modules"] } },
|
|
280
|
+
];
|
|
281
|
+
await watching(env, targets, async ({ changes, expectChange, absolute }) => {
|
|
282
|
+
getOrThrow(await env.writeFile("skills/node_modules/dep/SKILL.md", "dep", context));
|
|
283
|
+
getOrThrow(await env.writeFile("skills/.SKILL.md.tmp", "draft", context));
|
|
284
|
+
await expectChange("skills/SKILL.md", async () => {
|
|
285
|
+
getOrThrow(await env.renameFile("skills/.SKILL.md.tmp", "skills/SKILL.md", context));
|
|
286
|
+
});
|
|
287
|
+
const hidden = [await absolute("skills/node_modules"), await absolute("skills/.SKILL.md.tmp")];
|
|
288
|
+
for (const change of changes) {
|
|
289
|
+
if (!("paths" in change))
|
|
290
|
+
continue;
|
|
291
|
+
for (const path of change.paths) {
|
|
292
|
+
assert.ok(!hidden.some((excluded) => path === excluded || path.startsWith(excluded)), `excluded ${path}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}),
|
|
297
|
+
watchCase("watch stops reporting once closed", async (env) => {
|
|
298
|
+
const changes = [];
|
|
299
|
+
const watcher = getOrThrow(await env.watch([{ path: "file.txt" }], (change) => changes.push(change), context));
|
|
300
|
+
assert.ok(watcher.mode === "native" || watcher.mode === "polling", "watcher reports its mode");
|
|
301
|
+
await watcher.close(context);
|
|
302
|
+
await watcher.close(context);
|
|
303
|
+
getOrThrow(await env.writeFile("file.txt", "x", context));
|
|
304
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
305
|
+
assert.deepEqual(changes, []);
|
|
306
|
+
}),
|
|
307
|
+
createCase("argv exec passes arguments to the program without shell parsing", async (env) => {
|
|
308
|
+
const hostile = "it's $(touch pwned) `touch pwned` *; touch pwned";
|
|
309
|
+
const { result, stdout } = await execCollect(env, [
|
|
310
|
+
...shell,
|
|
311
|
+
'printf "%s|%s" "$1" "$2"',
|
|
312
|
+
"argv0",
|
|
313
|
+
hostile,
|
|
314
|
+
"a b",
|
|
315
|
+
]);
|
|
316
|
+
assert.strictEqual(getOrThrow(result).exitCode, 0);
|
|
317
|
+
assert.strictEqual(stdout, `${hostile}|a b`);
|
|
318
|
+
assert.strictEqual(getOrThrow(await env.exists("pwned", context)), false);
|
|
319
|
+
}),
|
|
320
|
+
createCase("exec reports the stream of every chunk in both forms", async (env) => {
|
|
321
|
+
const script = "printf out; printf err >&2; printf more";
|
|
322
|
+
const argv = await execCollect(env, [...shell, script]);
|
|
323
|
+
assert.strictEqual(getOrThrow(argv.result).exitCode, 0);
|
|
324
|
+
assert.strictEqual(argv.stdout, "outmore");
|
|
325
|
+
assert.strictEqual(argv.stderr, "err");
|
|
326
|
+
const string = await execCollect(env, script);
|
|
327
|
+
assert.strictEqual(getOrThrow(string.result).exitCode, 0);
|
|
328
|
+
assert.strictEqual(string.stdout, "outmore");
|
|
329
|
+
assert.strictEqual(string.stderr, "err");
|
|
330
|
+
}),
|
|
331
|
+
createCase("argv exec honors cwd and exit codes", async (env) => {
|
|
332
|
+
getOrThrow(await env.createDir("sub", undefined, context));
|
|
333
|
+
const made = await execCollect(env, [...shell, "printf x > made.txt; exit 3"], "sub");
|
|
334
|
+
assert.strictEqual(getOrThrow(made.result).exitCode, 3);
|
|
335
|
+
assert.strictEqual(getOrThrow(await env.readTextFile("sub/made.txt", context)), "x");
|
|
336
|
+
}),
|
|
337
|
+
createCase("argv exec reports missing programs and empty argv as spawn errors", async (env) => {
|
|
338
|
+
assert.strictEqual(errorCode(await env.exec(["pi-durable-conformance-missing-program"], undefined, context)), "spawn_error");
|
|
339
|
+
assert.strictEqual(errorCode(await env.exec([], undefined, context)), "spawn_error");
|
|
340
|
+
}),
|
|
341
|
+
createCase("windowed exec keeps the exact tail and counts what it skips", async (env) => {
|
|
342
|
+
const lines = 2000;
|
|
343
|
+
const window = { maxBytes: 200, maxLines: 5, minIntervalMs: 0, bytesPerSecond: 1_000_000_000 };
|
|
344
|
+
let bytes = 0;
|
|
345
|
+
let newlines = 0;
|
|
346
|
+
let tail = "";
|
|
347
|
+
const result = await env.exec([...shell, `i=0; while [ $i -lt ${lines} ]; do echo line-$i; i=$((i+1)); done`], {
|
|
348
|
+
window,
|
|
349
|
+
onOutput: (text, _context, info) => {
|
|
350
|
+
if (info.skipped !== undefined) {
|
|
351
|
+
bytes += info.skipped.bytes;
|
|
352
|
+
newlines += info.skipped.newlines;
|
|
353
|
+
const after = encoder.encode(text).length;
|
|
354
|
+
const afterNewlines = text.split("\n").length - 1;
|
|
355
|
+
assert.ok(after > window.maxBytes || afterNewlines > window.maxLines, "a skip is followed by more than the window");
|
|
356
|
+
tail = "";
|
|
357
|
+
}
|
|
358
|
+
bytes += encoder.encode(text).length;
|
|
359
|
+
newlines += text.split("\n").length - 1;
|
|
360
|
+
tail += text;
|
|
361
|
+
},
|
|
362
|
+
}, context);
|
|
363
|
+
assert.strictEqual(getOrThrow(result).exitCode, 0);
|
|
364
|
+
const expected = Array.from({ length: lines }, (_, index) => `line-${index}\n`);
|
|
365
|
+
assert.strictEqual(bytes, expected.join("").length);
|
|
366
|
+
assert.strictEqual(newlines, lines);
|
|
367
|
+
assert.ok(tail.endsWith(expected.slice(-window.maxLines).join("")), "the delivered output ends with the tail");
|
|
368
|
+
}),
|
|
369
|
+
createCase("argv exec distinguishes timeout from abort", async (env) => {
|
|
370
|
+
const timedOut = await env.exec([...shell, "sleep 2"], { timeout: 0.1 }, context);
|
|
371
|
+
assert.strictEqual(errorCode(timedOut), "timeout");
|
|
372
|
+
const controller = new AbortController();
|
|
373
|
+
const running = env.exec([...shell, "sleep 2"], undefined, withAbortSignal(controller.signal, context));
|
|
374
|
+
setTimeout(() => controller.abort(), 100);
|
|
375
|
+
assert.strictEqual(errorCode(await running), "aborted");
|
|
376
|
+
}),
|
|
377
|
+
];
|
|
378
|
+
if (symlinks) {
|
|
379
|
+
cases.push(createCase("binary reader follows symlinks unless noFollow refuses the final one", async (env) => {
|
|
380
|
+
getOrThrow(await env.writeFile("target.txt", "target", context));
|
|
381
|
+
getOrThrow(await env.createDir("sub", undefined, context));
|
|
382
|
+
getOrThrow(await env.writeFile("sub/inner.txt", "inner", context));
|
|
383
|
+
const linked = await env.exec([...shell, "ln -s target.txt link.txt && ln -s sub dirlink"], undefined, context);
|
|
384
|
+
assert.strictEqual(getOrThrow(linked).exitCode, 0);
|
|
385
|
+
const followed = getOrThrow(await env.openBinaryReader("link.txt", undefined, context));
|
|
386
|
+
assert.strictEqual(decoder.decode(getOrThrow(await followed.read(0, 10, context))), "target");
|
|
387
|
+
await followed.close(context);
|
|
388
|
+
assert.strictEqual(errorCode(await env.openBinaryReader("link.txt", { noFollow: true }, context)), "invalid");
|
|
389
|
+
// Only the final component is refused; earlier symlinked directories still resolve.
|
|
390
|
+
const inner = getOrThrow(await env.openBinaryReader("dirlink/inner.txt", { noFollow: true }, context));
|
|
391
|
+
assert.strictEqual(decoder.decode(getOrThrow(await inner.read(0, 10, context))), "inner");
|
|
392
|
+
await inner.close(context);
|
|
393
|
+
}));
|
|
394
|
+
}
|
|
395
|
+
return cases;
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=env-conformance.js.map
|