@atolis-hq/wake 0.3.13 → 0.3.15

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.
@@ -8,20 +8,13 @@ export function createSourceUpdatePort(input) {
8
8
  return (await execute('git', ['status', '--porcelain'], input.repoRoot)).trim().length === 0;
9
9
  },
10
10
  async latestTag() {
11
- const tag = (await execute('git', ['tag', '--sort=-v:refname'], input.repoRoot))
12
- .split(/\r?\n/u)
13
- .find((value) => value.trim().length > 0)
14
- ?.trim();
11
+ const tag = (await candidateTags(execute, input.repoRoot)).at(0);
15
12
  if (tag === undefined)
16
13
  throw new Error('No source version tag is available');
17
14
  return tag;
18
15
  },
19
16
  async candidateTags() {
20
- const output = await execute('git', ['tag', '--sort=-v:refname'], input.repoRoot);
21
- return output
22
- .split(/\r?\n/u)
23
- .map((line) => line.trim())
24
- .filter((line) => line.length > 0);
17
+ return candidateTags(execute, input.repoRoot);
25
18
  },
26
19
  async checkout(tag) {
27
20
  await execute('git', ['checkout', tag], input.repoRoot);
@@ -41,6 +34,14 @@ export function createSourceUpdatePort(input) {
41
34
  },
42
35
  };
43
36
  }
37
+ async function candidateTags(execute, repoRoot) {
38
+ await execute('git', ['fetch', '--tags'], repoRoot);
39
+ const output = await execute('git', ['tag', '--list', 'v*', '--sort=-v:refname'], repoRoot);
40
+ return output
41
+ .split(/\r?\n/u)
42
+ .map((line) => line.trim())
43
+ .filter((line) => line.length > 0);
44
+ }
44
45
  async function runProcess(command, args, cwd) {
45
46
  const result = await execFile(command, args, { cwd, encoding: 'utf8' });
46
47
  return result.stdout;
@@ -108,4 +108,4 @@ export function resolveWakeVersion(options = {}) {
108
108
  return `g${headHash.slice(0, 7)}`;
109
109
  return '0.1.0-dev';
110
110
  }
111
- export const wakeVersion = "g47eaa83";
111
+ export const wakeVersion = "g41ad0c0";
@@ -1,13 +1,15 @@
1
1
  import { selectRunExecutionEvent } from '../../execution/index.js';
2
2
  import { correlationId, EventActorKind, } from '../../kernel/index.js';
3
3
  import { selectOrchestrationEvent } from '../contracts/event-decoder.js';
4
+ import { OrchestrationEventType, } from '../contracts/events.js';
4
5
  import { workflowInstanceId, workflowName, } from '../contracts/identifiers.js';
6
+ import { isWorkflowInstanceStream } from '../contracts/streams.js';
5
7
  const checkpoint = 'reactor:orchestration.watch';
6
8
  export function createWatchReactor(orchestration, journal, checkpoints, runs) {
7
9
  return {
8
10
  async react(event, context) {
9
11
  const causalCycle = orchestrationCausalCycleId(selectOrchestrationEvent(event));
10
- const sourceWorkflowInstanceId = await resolveRunWorkflowInstanceId(event, runs);
12
+ const sourceWorkflowInstanceId = await resolveTriggerWorkflowInstanceId(event, runs);
11
13
  for (const match of await orchestration.listWatchMatches(event, context)) {
12
14
  if (sourceWorkflowInstanceId !== undefined &&
13
15
  match.parent.workflowInstanceId !== sourceWorkflowInstanceId)
@@ -58,11 +60,24 @@ function commandContext(event) {
58
60
  /**
59
61
  * A run-lifecycle event (e.g. `execution.run-succeeded`) fires for every run
60
62
  * in the system, including a watch's own spawned child re-running its own
61
- * activity on retry. Without this, `listWatchMatches` would treat any
63
+ * activity on retry. Without scoping, `listWatchMatches` would treat any
62
64
  * currently-eligible parent's declared event type as a match regardless of
63
65
  * which run actually produced it, causing a child's own retry (or an
64
66
  * unrelated workflow's run) to spuriously re-trigger the same watch.
67
+ *
68
+ * For orchestration events, only `SignalWaitStarted` is scoped to its
69
+ * stream's instance; this is currently the only orchestration event type
70
+ * known to benefit from stream-based filtering. Other orchestration events
71
+ * like `ChildCompleted` are cross-instance coordination facts by design and
72
+ * must fall through unchanged to the async resolver to preserve their
73
+ * existing multi-instance coordination paths.
65
74
  */
75
+ async function resolveTriggerWorkflowInstanceId(event, runs) {
76
+ if (event.eventType === OrchestrationEventType.SignalWaitStarted &&
77
+ isWorkflowInstanceStream(event.stream))
78
+ return event.stream.id;
79
+ return resolveRunWorkflowInstanceId(event, runs);
80
+ }
66
81
  async function resolveRunWorkflowInstanceId(event, runs) {
67
82
  if (runs === undefined)
68
83
  return undefined;
@@ -3,7 +3,14 @@ export async function runSelfUpdate(input) {
3
3
  if (!input.force && (await input.readLedger()) === input.tag)
4
4
  return false;
5
5
  const priorTag = await input.readLedger();
6
- await input.update(input.tag);
6
+ try {
7
+ await input.update(input.tag);
8
+ }
9
+ catch (error) {
10
+ if (priorTag !== null && input.rollback !== undefined)
11
+ await input.rollback(priorTag);
12
+ throw error;
13
+ }
7
14
  if (input.health !== undefined && !(await input.health())) {
8
15
  if (priorTag !== null && input.rollback !== undefined)
9
16
  await input.rollback(priorTag);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolis-hq/wake",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Local autonomous agent control plane for software development",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {