Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"imports": {
"@executablemd/durable-streams": "../durable-streams/mod.ts",
"@executablemd/runtime": "../runtime/mod.ts",
"@effectionx/context-api": "../vendor/context-api/mod.ts",
"@effectionx/context-api": "npm:@effectionx/context-api@0.6.0",
"acorn": "npm:acorn@^8.16.0",
"gray-matter": "npm:gray-matter@^4.0.3",
"magic-string": "npm:magic-string@^0.30.21",
Expand Down
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"dependencies": {
"@executablemd/durable-streams": "workspace:*",
"@executablemd/runtime": "workspace:*",
"@effectionx/context-api": "workspace:*"
"@effectionx/context-api": "0.6.0"
}
}
6 changes: 6 additions & 0 deletions core/src/run-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { daemonFactory } from "./modifiers/daemon.ts";
import { EvalEnvCtx, EvalScopeCtx } from "./eval-env.ts";
import type { EvalEnv } from "./eval-env.ts";
import { useEvalScope } from "@effectionx/scope-eval";
import { Stdio } from "@effectionx/process";

// Re-export gray-matter — we use it for YAML frontmatter extraction
import matter from "gray-matter";
Expand Down Expand Up @@ -416,6 +417,11 @@ export function* runDocument(options: RunDocumentOptions): Operation<DocumentExe
},
});

yield* Stdio.around({
*stdout() {},
*stderr() {},
});

// Create per-document eval scope (spec §3.1).
// Created in the same scope as durableRun so that DurableCtx
// (set by durableRun) is visible to eval code that calls
Expand Down
24 changes: 12 additions & 12 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@
"@durable-streams/client": "npm:@durable-streams/client@^0.2.2",
"@effectionx/bdd/node": "./test-support/bdd.ts",
"@effectionx/bdd/expect": "./test-support/expect.ts",
"@effectionx/test-adapter": "npm:@effectionx/test-adapter@^0.7.3",
"@effectionx/test-adapter": "npm:@effectionx/test-adapter@0.7.4",
"effection": "npm:effection@4.1.0-alpha.7",
"effection/experimental": "npm:effection@4.1.0-alpha.7/experimental",
"@executablemd/durable-streams": "./durable-streams/mod.ts",
"@executablemd/runtime": "./runtime/mod.ts",
"@executablemd/runtime/test": "./runtime/test/mod.ts",
"@executablemd/code-review-agent": "./packages/code-review-agent/mod.ts",
"@effectionx/context-api": "./vendor/context-api/mod.ts",
"@effectionx/converge": "npm:@effectionx/converge@^0.1.3",
"@effectionx/fetch": "npm:@effectionx/fetch@^0.1.2",
"@effectionx/fs": "npm:@effectionx/fs@0.2.2",
"@effectionx/middleware": "npm:@effectionx/middleware@0.1.0",
"@effectionx/node": "npm:@effectionx/node@^0.2.2",
"@effectionx/process": "npm:@effectionx/process@^0.7.3",
"@effectionx/scope-eval": "npm:@effectionx/scope-eval@^0.1.2",
"@effectionx/stream-helpers": "npm:@effectionx/stream-helpers@^0.8.1",
"@effectionx/timebox": "npm:@effectionx/timebox@^0.4.2",
"@effectionx/context-api": "npm:@effectionx/context-api@0.6.0",
"@effectionx/converge": "npm:@effectionx/converge@0.1.4",
"@effectionx/fetch": "npm:@effectionx/fetch@0.2.0",
"@effectionx/fs": "npm:@effectionx/fs@0.3.0",
"@effectionx/middleware": "npm:@effectionx/middleware@0.1.1",
"@effectionx/node": "npm:@effectionx/node@0.2.4",
"@effectionx/process": "npm:@effectionx/process@0.8.1",
"@effectionx/scope-eval": "npm:@effectionx/scope-eval@0.1.3",
"@effectionx/stream-helpers": "npm:@effectionx/stream-helpers@0.8.3",
"@effectionx/timebox": "npm:@effectionx/timebox@0.4.3",
"configliere": "npm:configliere@^0.2.3",
"expect": "npm:expect@^30",
"@std/expect": "npm:expect@^30",
Expand All @@ -37,7 +37,7 @@
"build": "deno compile --node-modules-dir=none --exclude-unused-npm --exclude .opencode --exclude .internal --allow-all --output dist/xmd cli/src/cli.ts",
"test": "deno test --allow-all core/tests/ durable-streams/tests/ packages/code-review-agent/tests/",
"check": "deno check core/mod.ts",
"lint": "npx oxlint -c .oxlintrc.json core/src/ cli/src/ durable-streams/ runtime/ && npx oxfmt --check core/src/ cli/src/ durable-streams/ runtime/ vendor/ test-support/",
"lint": "npx oxlint -c .oxlintrc.json core/src/ cli/src/ durable-streams/ runtime/ && npx oxfmt --check core/src/ cli/src/ durable-streams/ runtime/ test-support/",
"review": "deno run --allow-all cli/src/cli.ts run .reviews/ReviewPR.md --component-dir .reviews/components --component-dir .reviews/policies --component-dir core/components -j .reviews/journal.jsonl",
"review:local": "deno run --allow-all cli/src/cli.ts run .reviews/ReviewPR.local.md --component-dir .reviews/components --component-dir .reviews/policies --component-dir core/components -j .reviews/journal.local.jsonl",
"analyze": "deno run --allow-all cli/src/cli.ts run .reviews/AnalyzeRepo.md --component-dir .reviews/components --component-dir .reviews/policies --component-dir core/components -j .reviews/journal.analyze.jsonl",
Expand Down
133 changes: 80 additions & 53 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 27 additions & 24 deletions durable-streams/combinators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
* See protocol spec §7 (structured concurrency), §10 (race semantics).
*/

import { all as effectionAll, race as effectionRace, spawn, suspend, useScope } from "effection";
import {
all as effectionAll,
ensure,
race as effectionRace,
spawn,
suspend,
useScope,
} from "effection";
import type { Operation, Task } from "effection";
import { type DurableContext, DurableCtx } from "./context.ts";
import { ephemeral } from "./ephemeral.ts";
Expand Down Expand Up @@ -69,7 +76,7 @@ function* runDurableChild<T extends WorkflowValue>(
// parent combinator (race/all) will cancel this child as part of
// normal structured concurrency teardown, just like the original
// run. The Close(cancelled) event already exists in the journal,
// so we skip re-emitting it (the finally block checks for this).
// so we skip re-emitting it (the ensure teardown checks for this).
//
// INVARIANT: This branch is only reachable when a parent combinator
// (durableRace or durableAll with a failed sibling) will cancel this
Expand All @@ -91,16 +98,31 @@ function* runDurableChild<T extends WorkflowValue>(
childCounter: 0,
});

// Track whether we completed normally or via error, so that
// the finally block can detect cancellation (the remaining case).
let closeEvent: Close | undefined;

yield* ensure(function* () {
// closeEvent still undefined means the child was cancelled before the
// normal-return or catch path ran.
if (!closeEvent) {
closeEvent = {
type: "close",
coroutineId: childId,
result: { status: "cancelled" },
};
}

// Don't re-emit a Close event if one already exists in the journal
// (e.g., a cancelled child being replayed via suspend()).
if (!replayIndex.hasClose(childId)) {
yield* stream.append(closeEvent!);
}
});

try {
// Run the child workflow. DurableEffects inside the child read
// DurableCtx from the scope, so they'll use childId.
const result: T = yield* childWorkflow();

// Record Close(ok) — will be appended in finally
closeEvent = {
type: "close",
coroutineId: childId,
Expand All @@ -109,7 +131,6 @@ function* runDurableChild<T extends WorkflowValue>(

return result;
} catch (error) {
// Record Close(err) — will be appended in finally
closeEvent = {
type: "close",
coroutineId: childId,
Expand All @@ -120,24 +141,6 @@ function* runDurableChild<T extends WorkflowValue>(
};

throw error;
} finally {
// If closeEvent is still undefined, the generator was cancelled
// (Effection called iterator.return(), skipping both the normal
// return path and the catch block).
if (!closeEvent) {
closeEvent = {
type: "close",
coroutineId: childId,
result: { status: "cancelled" },
};
}

// Don't re-emit a Close event if one already exists in the journal
// (e.g., a cancelled child being replayed via suspend()).
if (!replayIndex.hasClose(childId)) {
// Append the Close event.
yield* stream.append(closeEvent!);
}
}
}

Expand Down
Loading
Loading