astrocode-workflow 0.1.39 → 0.1.41

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.
@@ -16,7 +16,7 @@ export function createContinuationEnforcer(opts) {
16
16
  const cur = sessions.get(sessionId);
17
17
  if (cur)
18
18
  return cur;
19
- const state = { lastHash: null, lastAtMs: 0, repeats: 0, autoSteps: 0, idleTimer: null };
19
+ const state = { lastHash: null, lastAtMs: 0, repeats: 0, autoSteps: 0, idleTimer: null, periodicTimer: null };
20
20
  sessions.set(sessionId, state);
21
21
  return state;
22
22
  }
@@ -27,6 +27,13 @@ export function createContinuationEnforcer(opts) {
27
27
  s.idleTimer = null;
28
28
  }
29
29
  }
30
+ function clearPeriodicTimer(sessionId) {
31
+ const s = getState(sessionId);
32
+ if (s.periodicTimer) {
33
+ clearInterval(s.periodicTimer);
34
+ s.periodicTimer = null;
35
+ }
36
+ }
30
37
  function scheduleIdleInjection(sessionId) {
31
38
  clearIdleTimer(sessionId);
32
39
  if (!config.continuation.enabled)
@@ -40,6 +47,18 @@ export function createContinuationEnforcer(opts) {
40
47
  void maybeInjectContinue(sessionId, "idle_timer");
41
48
  }, delay);
42
49
  }
50
+ function schedulePeriodicInjection(sessionId) {
51
+ clearPeriodicTimer(sessionId);
52
+ if (!config.continuation.enabled)
53
+ return;
54
+ // Inject every 5 minutes (300,000 ms)
55
+ const interval = 5 * 60 * 1000;
56
+ const s = getState(sessionId);
57
+ s.periodicTimer = setInterval(() => {
58
+ // Fire and forget
59
+ void maybeInjectContinue(sessionId, "periodic_timer");
60
+ }, interval);
61
+ }
43
62
  function shouldDedupe(sessionId, directive) {
44
63
  const s = getState(sessionId);
45
64
  const now = Date.now();
@@ -156,9 +175,11 @@ export function createContinuationEnforcer(opts) {
156
175
  if (type === "session.created") {
157
176
  // When a session is created and there is an active run, nudge.
158
177
  scheduleIdleInjection(sessionId);
178
+ schedulePeriodicInjection(sessionId);
159
179
  }
160
180
  if (type === "session.deleted") {
161
181
  clearIdleTimer(sessionId);
182
+ clearPeriodicTimer(sessionId);
162
183
  sessions.delete(sessionId);
163
184
  }
164
185
  },
@@ -137,9 +137,8 @@ Expected format:
137
137
 
138
138
  Ensure JSON has required fields (stage_key, status) and valid syntax.`;
139
139
  }
140
- if (parsed.astro_json.stage_key !== sk) {
141
- return `❌ Stage Key Mismatch: ASTRO JSON has stage_key="${parsed.astro_json.stage_key}" but expected "${sk}". Update the JSON to match the current stage.`;
142
- }
140
+ // Override stage_key to match the expected stage (agents sometimes get this wrong)
141
+ parsed.astro_json.stage_key = sk;
143
142
  // Context validation (warnings, not errors)
144
143
  if (parsed.astro_json.run_id && parsed.astro_json.run_id !== rid) {
145
144
  console.warn(`[Astrocode] ⚠️ Run ID mismatch in baton: expected "${rid}", got "${parsed.astro_json.run_id}". Proceeding anyway.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astrocode-workflow",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,6 +13,7 @@ type SessionState = {
13
13
  repeats: number;
14
14
  autoSteps: number;
15
15
  idleTimer: NodeJS.Timeout | null;
16
+ periodicTimer: NodeJS.Timeout | null;
16
17
  };
17
18
 
18
19
  type ToolExecuteAfterInput = {
@@ -48,7 +49,7 @@ export function createContinuationEnforcer(opts: {
48
49
  function getState(sessionId: string): SessionState {
49
50
  const cur = sessions.get(sessionId);
50
51
  if (cur) return cur;
51
- const state: SessionState = { lastHash: null, lastAtMs: 0, repeats: 0, autoSteps: 0, idleTimer: null };
52
+ const state: SessionState = { lastHash: null, lastAtMs: 0, repeats: 0, autoSteps: 0, idleTimer: null, periodicTimer: null };
52
53
  sessions.set(sessionId, state);
53
54
  return state;
54
55
  }
@@ -61,6 +62,14 @@ export function createContinuationEnforcer(opts: {
61
62
  }
62
63
  }
63
64
 
65
+ function clearPeriodicTimer(sessionId: string) {
66
+ const s = getState(sessionId);
67
+ if (s.periodicTimer) {
68
+ clearInterval(s.periodicTimer);
69
+ s.periodicTimer = null;
70
+ }
71
+ }
72
+
64
73
  function scheduleIdleInjection(sessionId: string) {
65
74
  clearIdleTimer(sessionId);
66
75
  if (!config.continuation.enabled) return;
@@ -75,6 +84,20 @@ export function createContinuationEnforcer(opts: {
75
84
  }, delay);
76
85
  }
77
86
 
87
+ function schedulePeriodicInjection(sessionId: string) {
88
+ clearPeriodicTimer(sessionId);
89
+ if (!config.continuation.enabled) return;
90
+
91
+ // Inject every 5 minutes (300,000 ms)
92
+ const interval = 5 * 60 * 1000;
93
+
94
+ const s = getState(sessionId);
95
+ s.periodicTimer = setInterval(() => {
96
+ // Fire and forget
97
+ void maybeInjectContinue(sessionId, "periodic_timer");
98
+ }, interval);
99
+ }
100
+
78
101
  function shouldDedupe(sessionId: string, directive: BuiltDirective): boolean {
79
102
  const s = getState(sessionId);
80
103
  const now = Date.now();
@@ -206,10 +229,12 @@ export function createContinuationEnforcer(opts: {
206
229
  if (type === "session.created") {
207
230
  // When a session is created and there is an active run, nudge.
208
231
  scheduleIdleInjection(sessionId);
232
+ schedulePeriodicInjection(sessionId);
209
233
  }
210
234
 
211
235
  if (type === "session.deleted") {
212
236
  clearIdleTimer(sessionId);
237
+ clearPeriodicTimer(sessionId);
213
238
  sessions.delete(sessionId);
214
239
  }
215
240
  },
@@ -174,9 +174,8 @@ Expected format:
174
174
  Ensure JSON has required fields (stage_key, status) and valid syntax.`;
175
175
  }
176
176
 
177
- if (parsed.astro_json.stage_key !== sk) {
178
- return `❌ Stage Key Mismatch: ASTRO JSON has stage_key="${parsed.astro_json.stage_key}" but expected "${sk}". Update the JSON to match the current stage.`;
179
- }
177
+ // Override stage_key to match the expected stage (agents sometimes get this wrong)
178
+ parsed.astro_json.stage_key = sk;
180
179
 
181
180
  // Context validation (warnings, not errors)
182
181
  if (parsed.astro_json.run_id && parsed.astro_json.run_id !== rid) {