@gobing-ai/ts-dual-workflow-engine 0.3.18 → 0.3.20

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.
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAIjD,OAAO,KAAK,EACR,uBAAuB,EAEvB,uBAAuB,EACvB,WAAW,EACX,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACpB,MAAM,SAAS,CAAC;AAEjB,6FAA6F;AAC7F,qBAAa,eAAe;IAKpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IALhC,mFAAmF;IACnF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;gBAGxC,IAAI,EAAE,kBAAkB,EACxB,WAAW,EAAE,0BAA0B;IAG5D,4CAA4C;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI9C,iDAAiD;IAC3C,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAU9F,oCAAoC;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIzF,oCAAoC;IAC9B,QAAQ;IAId,mEAAmE;IAC7D,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAIrG,gFAAgF;IAC1E,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI9E,qFAAqF;IAC/E,SAAS,CACX,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CAAC,IAAI,CAAC;IACV,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B7F,iGAAiG;IACjG,OAAO,CAAC,0BAA0B;IASlC,oFAAoF;YACtE,YAAY;IAY1B,uEAAuE;IACjE,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgC/G,iEAAiE;IAC3D,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IAIhH;;;;;OAKG;IACG,iBAAiB,CACnB,QAAQ,EAAE,uBAAuB,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CAAC,uBAAuB,CAAC;YAsBrB,iBAAiB;IA4E/B;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAiBzB"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAIjD,OAAO,KAAK,EACR,uBAAuB,EAEvB,uBAAuB,EACvB,WAAW,EACX,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACpB,MAAM,SAAS,CAAC;AAGjB,6FAA6F;AAC7F,qBAAa,eAAe;IAKpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IALhC,mFAAmF;IACnF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;gBAGxC,IAAI,EAAE,kBAAkB,EACxB,WAAW,EAAE,0BAA0B;IAG5D,4CAA4C;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI9C,iDAAiD;IAC3C,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAU9F,oCAAoC;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIzF,oCAAoC;IAC9B,QAAQ;IAId,mEAAmE;IAC7D,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAIrG,gFAAgF;IAC1E,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI9E,qFAAqF;IAC/E,SAAS,CACX,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CAAC,IAAI,CAAC;IACV,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B7F,iGAAiG;IACjG,OAAO,CAAC,0BAA0B;IASlC,oFAAoF;YACtE,YAAY;IAY1B,uEAAuE;IACjE,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgC/G,iEAAiE;IAC3D,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC;IAIhH;;;;;OAKG;IACG,iBAAiB,CACnB,QAAQ,EAAE,uBAAuB,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CAAC,uBAAuB,CAAC;YAsBrB,iBAAiB;IA+E/B;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAiBzB"}
package/dist/service.js CHANGED
@@ -3,6 +3,7 @@ import { FSMError, WorkflowResumeError } from './errors.js';
3
3
  import { RunLifecycle } from './run-lifecycle.js';
4
4
  import { StateMachineDriver } from './state-machine.js';
5
5
  import { TransitionFlowDriver } from './transition-flow.js';
6
+ import { resolveTemplates } from './variables.js';
6
7
  /** High-level workflow service for loading, running, and listing persisted workflow runs. */
7
8
  export class WorkflowService {
8
9
  host;
@@ -167,10 +168,17 @@ export class WorkflowService {
167
168
  }
168
169
  // Evaluate guard if present.
169
170
  if (transition.guard !== undefined) {
170
- const guardResult = await this.host.evaluateGuardResult(transition.guard.kind, transition.guard.options ?? {}, {
171
+ // Resolve ${vars.*} templates in guard options against the workflow's vars —
172
+ // external transitions (requestTransition) must interpolate the same way the
173
+ // driver's firstPassingTransition does (e.g. `spur task check ${vars.wbs}`).
174
+ const resolvedGuardOptions = resolveTemplates(transition.guard.options ?? {}, {
175
+ vars: workflow.vars ?? {},
176
+ env: {},
177
+ });
178
+ const guardResult = await this.host.evaluateGuardResult(transition.guard.kind, resolvedGuardOptions, {
171
179
  runId,
172
180
  current: currentState,
173
- vars: {},
181
+ vars: workflow.vars ?? {},
174
182
  workdir: options?.workdir,
175
183
  });
176
184
  lifecycle.guardEvaluated(currentState, toState, transition.guard.kind, guardResult.passed);
@@ -1,7 +1,7 @@
1
1
  import { runActionSequence } from './action-step.js';
2
2
  import { FSMError } from './errors.js';
3
3
  import { allowedEnv, RunLifecycle } from './run-lifecycle.js';
4
- import { mergeSetVars, mergeVars } from './variables.js';
4
+ import { mergeSetVars, mergeVars, resolveTemplates } from './variables.js';
5
5
  /** State-machine workflow driver with an R7 single control function. */
6
6
  export class StateMachineDriver {
7
7
  options;
@@ -131,7 +131,13 @@ async function firstPassingTransition(transitions, host, context, lifecycle) {
131
131
  for (const transition of transitions) {
132
132
  if (transition.guard === undefined)
133
133
  return transition;
134
- const passed = await host.evaluateGuard(transition.guard.kind, transition.guard.options ?? {}, context);
134
+ // Resolve ${vars.*} templates in guard options before evaluation — guards use the
135
+ // same var interpolation as actions (e.g. `spur task check ${vars.wbs}`).
136
+ const resolvedOptions = resolveTemplates(transition.guard.options ?? {}, {
137
+ vars: context.vars,
138
+ env: {},
139
+ });
140
+ const passed = await host.evaluateGuard(transition.guard.kind, resolvedOptions, context);
135
141
  lifecycle.guardEvaluated(context.current, transition.to, transition.guard.kind, passed);
136
142
  if (passed)
137
143
  return transition;
@@ -1,7 +1,7 @@
1
1
  import { runActionStep } from './action-step.js';
2
2
  import { FSMError } from './errors.js';
3
3
  import { allowedEnv, RunLifecycle } from './run-lifecycle.js';
4
- import { mergeSetVars, mergeVars } from './variables.js';
4
+ import { mergeSetVars, mergeVars, resolveTemplates } from './variables.js';
5
5
  /** Transition-flow workflow driver with an R7 single control function. */
6
6
  export class TransitionFlowDriver {
7
7
  options;
@@ -109,7 +109,13 @@ async function firstPassingEdge(edges, host, context, lifecycle) {
109
109
  for (const edge of edges) {
110
110
  if (edge.condition === undefined)
111
111
  return edge;
112
- const passed = await host.evaluateGuard(edge.condition.kind, edge.condition.options ?? {}, context);
112
+ // Resolve ${vars.*} templates in condition options before evaluation — conditions use
113
+ // the same var interpolation as actions (symmetry with state-machine guard resolution).
114
+ const resolvedOptions = resolveTemplates(edge.condition.options ?? {}, {
115
+ vars: context.vars,
116
+ env: {},
117
+ });
118
+ const passed = await host.evaluateGuard(edge.condition.kind, resolvedOptions, context);
113
119
  lifecycle.guardEvaluated(context.current, edge.to, edge.condition.kind, passed);
114
120
  if (passed)
115
121
  return edge;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-dual-workflow-engine",
3
- "version": "0.3.18",
3
+ "version": "0.3.20",
4
4
  "description": "@gobing-ai/ts-dual-workflow-engine — State-machine and transition-flow workflow runtime.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -48,9 +48,9 @@
48
48
  "release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-dual-workflow-engine-v<version> && git push --tags' && exit 1"
49
49
  },
50
50
  "dependencies": {
51
- "@gobing-ai/ts-db": "^0.3.18",
52
- "@gobing-ai/ts-infra": "^0.3.18",
53
- "@gobing-ai/ts-runtime": "^0.3.18",
51
+ "@gobing-ai/ts-db": "^0.3.20",
52
+ "@gobing-ai/ts-infra": "^0.3.20",
53
+ "@gobing-ai/ts-runtime": "^0.3.20",
54
54
  "zod": "^4.1.0"
55
55
  },
56
56
  "devDependencies": {
package/src/service.ts CHANGED
@@ -14,6 +14,7 @@ import type {
14
14
  WorkflowRunRecord,
15
15
  WorkflowRunResult,
16
16
  } from './types';
17
+ import { resolveTemplates } from './variables';
17
18
 
18
19
  /** High-level workflow service for loading, running, and listing persisted workflow runs. */
19
20
  export class WorkflowService {
@@ -232,16 +233,19 @@ export class WorkflowService {
232
233
 
233
234
  // Evaluate guard if present.
234
235
  if (transition.guard !== undefined) {
235
- const guardResult = await this.host.evaluateGuardResult(
236
- transition.guard.kind,
237
- transition.guard.options ?? {},
238
- {
239
- runId,
240
- current: currentState,
241
- vars: {},
242
- workdir: options?.workdir,
243
- },
244
- );
236
+ // Resolve ${vars.*} templates in guard options against the workflow's vars —
237
+ // external transitions (requestTransition) must interpolate the same way the
238
+ // driver's firstPassingTransition does (e.g. `spur task check ${vars.wbs}`).
239
+ const resolvedGuardOptions = resolveTemplates(transition.guard.options ?? {}, {
240
+ vars: workflow.vars ?? {},
241
+ env: {},
242
+ });
243
+ const guardResult = await this.host.evaluateGuardResult(transition.guard.kind, resolvedGuardOptions, {
244
+ runId,
245
+ current: currentState,
246
+ vars: workflow.vars ?? {},
247
+ workdir: options?.workdir,
248
+ });
245
249
  lifecycle.guardEvaluated(currentState, toState, transition.guard.kind, guardResult.passed);
246
250
  if (!guardResult.passed) {
247
251
  return this.denyTransition(options, runId, currentState, toState, extKey, {
@@ -9,7 +9,7 @@ import type {
9
9
  WorkflowRunOptions,
10
10
  WorkflowRunResult,
11
11
  } from './types';
12
- import { mergeSetVars, mergeVars } from './variables';
12
+ import { mergeSetVars, mergeVars, resolveTemplates } from './variables';
13
13
 
14
14
  /** Dependencies required by the state-machine driver. */
15
15
  export interface StateMachineDriverOptions {
@@ -183,7 +183,13 @@ async function firstPassingTransition(
183
183
  ): Promise<StateMachineWorkflowDef['transitions'][number] | undefined> {
184
184
  for (const transition of transitions) {
185
185
  if (transition.guard === undefined) return transition;
186
- const passed = await host.evaluateGuard(transition.guard.kind, transition.guard.options ?? {}, context);
186
+ // Resolve ${vars.*} templates in guard options before evaluation — guards use the
187
+ // same var interpolation as actions (e.g. `spur task check ${vars.wbs}`).
188
+ const resolvedOptions = resolveTemplates(transition.guard.options ?? {}, {
189
+ vars: context.vars,
190
+ env: {},
191
+ });
192
+ const passed = await host.evaluateGuard(transition.guard.kind, resolvedOptions, context);
187
193
  lifecycle.guardEvaluated(context.current, transition.to, transition.guard.kind, passed);
188
194
  if (passed) return transition;
189
195
  }
@@ -9,7 +9,7 @@ import type {
9
9
  WorkflowRunOptions,
10
10
  WorkflowRunResult,
11
11
  } from './types';
12
- import { mergeSetVars, mergeVars } from './variables';
12
+ import { mergeSetVars, mergeVars, resolveTemplates } from './variables';
13
13
 
14
14
  /** Dependencies required by the transition-flow driver. */
15
15
  export interface TransitionFlowDriverOptions {
@@ -163,7 +163,13 @@ async function firstPassingEdge(
163
163
  ): Promise<TransitionFlowWorkflowDef['edges'][number] | undefined> {
164
164
  for (const edge of edges) {
165
165
  if (edge.condition === undefined) return edge;
166
- const passed = await host.evaluateGuard(edge.condition.kind, edge.condition.options ?? {}, context);
166
+ // Resolve ${vars.*} templates in condition options before evaluation — conditions use
167
+ // the same var interpolation as actions (symmetry with state-machine guard resolution).
168
+ const resolvedOptions = resolveTemplates(edge.condition.options ?? {}, {
169
+ vars: context.vars,
170
+ env: {},
171
+ });
172
+ const passed = await host.evaluateGuard(edge.condition.kind, resolvedOptions, context);
167
173
  lifecycle.guardEvaluated(context.current, edge.to, edge.condition.kind, passed);
168
174
  if (passed) return edge;
169
175
  }