@hasna/loops 0.3.52 → 0.3.53

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/dist/cli/index.js CHANGED
@@ -1567,6 +1567,65 @@ class Store {
1567
1567
  throw new Error(`workflow invocation not found after create: ${id}`);
1568
1568
  return rowToWorkflowInvocation(row);
1569
1569
  }
1570
+ refreshWorkflowInvocationForWorkItem(workItemId, input) {
1571
+ const sourceDedupeKey = input.sourceRef.dedupeKey ?? undefined;
1572
+ if (!sourceDedupeKey)
1573
+ throw new Error("cannot refresh workflow invocation without sourceRef.dedupeKey");
1574
+ const now = nowIso();
1575
+ const claimableStatuses = ["queued", "deferred", "failed", "dead_letter", "cancelled"];
1576
+ const statusBindings = Object.fromEntries(claimableStatuses.map((status, index) => [`$status${index}`, status]));
1577
+ const placeholders = claimableStatuses.map((_, index) => `$status${index}`).join(",");
1578
+ const result = this.db.query(`UPDATE workflow_invocations
1579
+ SET workflow_id=COALESCE($workflowId, workflow_id),
1580
+ template_id=COALESCE($templateId, template_id),
1581
+ source_id=COALESCE($sourceId, source_id),
1582
+ source_json=$sourceJson,
1583
+ subject_kind=$subjectKind,
1584
+ subject_id=COALESCE($subjectId, subject_id),
1585
+ subject_path=COALESCE($subjectPath, subject_path),
1586
+ subject_url=COALESCE($subjectUrl, subject_url),
1587
+ subject_json=$subjectJson,
1588
+ intent=$intent,
1589
+ scope_json=COALESCE($scopeJson, scope_json),
1590
+ output_policy_json=COALESCE($outputPolicyJson, output_policy_json),
1591
+ updated_at=$updated
1592
+ WHERE source_kind=$sourceKind
1593
+ AND source_dedupe_key=$sourceDedupeKey
1594
+ AND EXISTS (
1595
+ SELECT 1
1596
+ FROM workflow_work_items
1597
+ WHERE id=$workItemId
1598
+ AND invocation_id=workflow_invocations.id
1599
+ AND status IN (${placeholders})
1600
+ )`).run({
1601
+ $workItemId: workItemId,
1602
+ $sourceKind: input.sourceRef.kind,
1603
+ $sourceDedupeKey: sourceDedupeKey,
1604
+ $workflowId: input.workflowId ?? null,
1605
+ $templateId: input.templateId ?? null,
1606
+ $sourceId: input.sourceRef.id ?? null,
1607
+ $sourceJson: JSON.stringify(input.sourceRef),
1608
+ $subjectKind: input.subjectRef.kind,
1609
+ $subjectId: input.subjectRef.id ?? null,
1610
+ $subjectPath: input.subjectRef.path ?? null,
1611
+ $subjectUrl: input.subjectRef.url ?? null,
1612
+ $subjectJson: JSON.stringify(input.subjectRef),
1613
+ $intent: input.intent,
1614
+ $scopeJson: input.scope ? JSON.stringify(input.scope) : null,
1615
+ $outputPolicyJson: input.outputPolicy ? JSON.stringify(input.outputPolicy) : null,
1616
+ $updated: now,
1617
+ ...statusBindings
1618
+ });
1619
+ if (result.changes !== 1)
1620
+ throw new Error(`workflow work item is not refreshable: ${workItemId}`);
1621
+ const updated = this.db.query(`SELECT workflow_invocations.*
1622
+ FROM workflow_invocations
1623
+ JOIN workflow_work_items ON workflow_work_items.invocation_id = workflow_invocations.id
1624
+ WHERE workflow_work_items.id = ?`).get(workItemId);
1625
+ if (!updated)
1626
+ throw new Error(`workflow invocation not found after refresh for work item: ${workItemId}`);
1627
+ return rowToWorkflowInvocation(updated);
1628
+ }
1570
1629
  getWorkflowInvocation(id) {
1571
1630
  const row = this.db.query("SELECT * FROM workflow_invocations WHERE id = ?").get(id);
1572
1631
  return row ? rowToWorkflowInvocation(row) : undefined;
@@ -5908,7 +5967,7 @@ function buildScriptInventoryReport(store, opts = {}) {
5908
5967
  // package.json
5909
5968
  var package_default = {
5910
5969
  name: "@hasna/loops",
5911
- version: "0.3.52",
5970
+ version: "0.3.53",
5912
5971
  description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5913
5972
  type: "module",
5914
5973
  main: "dist/index.js",
@@ -8536,8 +8595,9 @@ function routeTodosTaskEvent(event, opts) {
8536
8595
  status: throttle && !throttle.allowed ? "deferred" : "queued",
8537
8596
  lastReason: throttle && !throttle.allowed ? throttle.reason : undefined
8538
8597
  });
8598
+ const refreshedInvocation = store.refreshWorkflowInvocationForWorkItem(workItem.id, invocationInput);
8539
8599
  if (throttle && !throttle.allowed)
8540
- return { kind: "throttled", invocation, workItem, throttle };
8600
+ return { kind: "throttled", invocation: refreshedInvocation, workItem, throttle };
8541
8601
  const workflow = routeWorkflowForStorage(store, workflowBody);
8542
8602
  const loop = store.createLoop({
8543
8603
  ...loopInput,
@@ -8545,13 +8605,13 @@ function routeTodosTaskEvent(event, opts) {
8545
8605
  type: "workflow",
8546
8606
  workflowId: workflow.id,
8547
8607
  input: {
8548
- workflowInvocationId: invocation.id,
8608
+ workflowInvocationId: refreshedInvocation.id,
8549
8609
  workflowWorkItemId: workItem.id
8550
8610
  }
8551
8611
  }
8552
8612
  });
8553
8613
  const admitted = store.admitWorkflowWorkItem(workItem.id, { workflowId: workflow.id, loopId: loop.id, reason: "admitted by todos-task route" });
8554
- return { kind: "created", invocation, workItem: admitted, workflow, loop, throttle };
8614
+ return { kind: "created", invocation: refreshedInvocation, workItem: admitted, workflow, loop, throttle };
8555
8615
  });
8556
8616
  if (outcome.kind === "deduped") {
8557
8617
  return {
@@ -8752,8 +8812,9 @@ function routeGenericEvent(event, opts) {
8752
8812
  status: throttle && !throttle.allowed ? "deferred" : "queued",
8753
8813
  lastReason: throttle && !throttle.allowed ? throttle.reason : undefined
8754
8814
  });
8815
+ const refreshedInvocation = store.refreshWorkflowInvocationForWorkItem(workItem.id, invocationInput);
8755
8816
  if (throttle && !throttle.allowed)
8756
- return { kind: "throttled", invocation, workItem, throttle };
8817
+ return { kind: "throttled", invocation: refreshedInvocation, workItem, throttle };
8757
8818
  const workflow = routeWorkflowForStorage(store, workflowBody);
8758
8819
  const loop = store.createLoop({
8759
8820
  ...loopInput,
@@ -8761,13 +8822,13 @@ function routeGenericEvent(event, opts) {
8761
8822
  type: "workflow",
8762
8823
  workflowId: workflow.id,
8763
8824
  input: {
8764
- workflowInvocationId: invocation.id,
8825
+ workflowInvocationId: refreshedInvocation.id,
8765
8826
  workflowWorkItemId: workItem.id
8766
8827
  }
8767
8828
  }
8768
8829
  });
8769
8830
  const admitted = store.admitWorkflowWorkItem(workItem.id, { workflowId: workflow.id, loopId: loop.id, reason: "admitted by generic-event route" });
8770
- return { kind: "created", invocation, workItem: admitted, workflow, loop, throttle };
8831
+ return { kind: "created", invocation: refreshedInvocation, workItem: admitted, workflow, loop, throttle };
8771
8832
  });
8772
8833
  if (outcome.kind === "deduped") {
8773
8834
  return {
@@ -1567,6 +1567,65 @@ class Store {
1567
1567
  throw new Error(`workflow invocation not found after create: ${id}`);
1568
1568
  return rowToWorkflowInvocation(row);
1569
1569
  }
1570
+ refreshWorkflowInvocationForWorkItem(workItemId, input) {
1571
+ const sourceDedupeKey = input.sourceRef.dedupeKey ?? undefined;
1572
+ if (!sourceDedupeKey)
1573
+ throw new Error("cannot refresh workflow invocation without sourceRef.dedupeKey");
1574
+ const now = nowIso();
1575
+ const claimableStatuses = ["queued", "deferred", "failed", "dead_letter", "cancelled"];
1576
+ const statusBindings = Object.fromEntries(claimableStatuses.map((status, index) => [`$status${index}`, status]));
1577
+ const placeholders = claimableStatuses.map((_, index) => `$status${index}`).join(",");
1578
+ const result = this.db.query(`UPDATE workflow_invocations
1579
+ SET workflow_id=COALESCE($workflowId, workflow_id),
1580
+ template_id=COALESCE($templateId, template_id),
1581
+ source_id=COALESCE($sourceId, source_id),
1582
+ source_json=$sourceJson,
1583
+ subject_kind=$subjectKind,
1584
+ subject_id=COALESCE($subjectId, subject_id),
1585
+ subject_path=COALESCE($subjectPath, subject_path),
1586
+ subject_url=COALESCE($subjectUrl, subject_url),
1587
+ subject_json=$subjectJson,
1588
+ intent=$intent,
1589
+ scope_json=COALESCE($scopeJson, scope_json),
1590
+ output_policy_json=COALESCE($outputPolicyJson, output_policy_json),
1591
+ updated_at=$updated
1592
+ WHERE source_kind=$sourceKind
1593
+ AND source_dedupe_key=$sourceDedupeKey
1594
+ AND EXISTS (
1595
+ SELECT 1
1596
+ FROM workflow_work_items
1597
+ WHERE id=$workItemId
1598
+ AND invocation_id=workflow_invocations.id
1599
+ AND status IN (${placeholders})
1600
+ )`).run({
1601
+ $workItemId: workItemId,
1602
+ $sourceKind: input.sourceRef.kind,
1603
+ $sourceDedupeKey: sourceDedupeKey,
1604
+ $workflowId: input.workflowId ?? null,
1605
+ $templateId: input.templateId ?? null,
1606
+ $sourceId: input.sourceRef.id ?? null,
1607
+ $sourceJson: JSON.stringify(input.sourceRef),
1608
+ $subjectKind: input.subjectRef.kind,
1609
+ $subjectId: input.subjectRef.id ?? null,
1610
+ $subjectPath: input.subjectRef.path ?? null,
1611
+ $subjectUrl: input.subjectRef.url ?? null,
1612
+ $subjectJson: JSON.stringify(input.subjectRef),
1613
+ $intent: input.intent,
1614
+ $scopeJson: input.scope ? JSON.stringify(input.scope) : null,
1615
+ $outputPolicyJson: input.outputPolicy ? JSON.stringify(input.outputPolicy) : null,
1616
+ $updated: now,
1617
+ ...statusBindings
1618
+ });
1619
+ if (result.changes !== 1)
1620
+ throw new Error(`workflow work item is not refreshable: ${workItemId}`);
1621
+ const updated = this.db.query(`SELECT workflow_invocations.*
1622
+ FROM workflow_invocations
1623
+ JOIN workflow_work_items ON workflow_work_items.invocation_id = workflow_invocations.id
1624
+ WHERE workflow_work_items.id = ?`).get(workItemId);
1625
+ if (!updated)
1626
+ throw new Error(`workflow invocation not found after refresh for work item: ${workItemId}`);
1627
+ return rowToWorkflowInvocation(updated);
1628
+ }
1570
1629
  getWorkflowInvocation(id) {
1571
1630
  const row = this.db.query("SELECT * FROM workflow_invocations WHERE id = ?").get(id);
1572
1631
  return row ? rowToWorkflowInvocation(row) : undefined;
@@ -5240,7 +5299,7 @@ function enableStartup(result) {
5240
5299
  // package.json
5241
5300
  var package_default = {
5242
5301
  name: "@hasna/loops",
5243
- version: "0.3.52",
5302
+ version: "0.3.53",
5244
5303
  description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5245
5304
  type: "module",
5246
5305
  main: "dist/index.js",
package/dist/index.js CHANGED
@@ -1565,6 +1565,65 @@ class Store {
1565
1565
  throw new Error(`workflow invocation not found after create: ${id}`);
1566
1566
  return rowToWorkflowInvocation(row);
1567
1567
  }
1568
+ refreshWorkflowInvocationForWorkItem(workItemId, input) {
1569
+ const sourceDedupeKey = input.sourceRef.dedupeKey ?? undefined;
1570
+ if (!sourceDedupeKey)
1571
+ throw new Error("cannot refresh workflow invocation without sourceRef.dedupeKey");
1572
+ const now = nowIso();
1573
+ const claimableStatuses = ["queued", "deferred", "failed", "dead_letter", "cancelled"];
1574
+ const statusBindings = Object.fromEntries(claimableStatuses.map((status, index) => [`$status${index}`, status]));
1575
+ const placeholders = claimableStatuses.map((_, index) => `$status${index}`).join(",");
1576
+ const result = this.db.query(`UPDATE workflow_invocations
1577
+ SET workflow_id=COALESCE($workflowId, workflow_id),
1578
+ template_id=COALESCE($templateId, template_id),
1579
+ source_id=COALESCE($sourceId, source_id),
1580
+ source_json=$sourceJson,
1581
+ subject_kind=$subjectKind,
1582
+ subject_id=COALESCE($subjectId, subject_id),
1583
+ subject_path=COALESCE($subjectPath, subject_path),
1584
+ subject_url=COALESCE($subjectUrl, subject_url),
1585
+ subject_json=$subjectJson,
1586
+ intent=$intent,
1587
+ scope_json=COALESCE($scopeJson, scope_json),
1588
+ output_policy_json=COALESCE($outputPolicyJson, output_policy_json),
1589
+ updated_at=$updated
1590
+ WHERE source_kind=$sourceKind
1591
+ AND source_dedupe_key=$sourceDedupeKey
1592
+ AND EXISTS (
1593
+ SELECT 1
1594
+ FROM workflow_work_items
1595
+ WHERE id=$workItemId
1596
+ AND invocation_id=workflow_invocations.id
1597
+ AND status IN (${placeholders})
1598
+ )`).run({
1599
+ $workItemId: workItemId,
1600
+ $sourceKind: input.sourceRef.kind,
1601
+ $sourceDedupeKey: sourceDedupeKey,
1602
+ $workflowId: input.workflowId ?? null,
1603
+ $templateId: input.templateId ?? null,
1604
+ $sourceId: input.sourceRef.id ?? null,
1605
+ $sourceJson: JSON.stringify(input.sourceRef),
1606
+ $subjectKind: input.subjectRef.kind,
1607
+ $subjectId: input.subjectRef.id ?? null,
1608
+ $subjectPath: input.subjectRef.path ?? null,
1609
+ $subjectUrl: input.subjectRef.url ?? null,
1610
+ $subjectJson: JSON.stringify(input.subjectRef),
1611
+ $intent: input.intent,
1612
+ $scopeJson: input.scope ? JSON.stringify(input.scope) : null,
1613
+ $outputPolicyJson: input.outputPolicy ? JSON.stringify(input.outputPolicy) : null,
1614
+ $updated: now,
1615
+ ...statusBindings
1616
+ });
1617
+ if (result.changes !== 1)
1618
+ throw new Error(`workflow work item is not refreshable: ${workItemId}`);
1619
+ const updated = this.db.query(`SELECT workflow_invocations.*
1620
+ FROM workflow_invocations
1621
+ JOIN workflow_work_items ON workflow_work_items.invocation_id = workflow_invocations.id
1622
+ WHERE workflow_work_items.id = ?`).get(workItemId);
1623
+ if (!updated)
1624
+ throw new Error(`workflow invocation not found after refresh for work item: ${workItemId}`);
1625
+ return rowToWorkflowInvocation(updated);
1626
+ }
1568
1627
  getWorkflowInvocation(id) {
1569
1628
  const row = this.db.query("SELECT * FROM workflow_invocations WHERE id = ?").get(id);
1570
1629
  return row ? rowToWorkflowInvocation(row) : undefined;
@@ -104,6 +104,7 @@ export declare class Store {
104
104
  private maybeArchiveGeneratedRouteWorkflow;
105
105
  private maybeArchiveTerminalGeneratedRouteWorkflow;
106
106
  createWorkflowInvocation(input: CreateWorkflowInvocationInput): WorkflowInvocation;
107
+ refreshWorkflowInvocationForWorkItem(workItemId: string, input: CreateWorkflowInvocationInput): WorkflowInvocation;
107
108
  getWorkflowInvocation(id: string): WorkflowInvocation | undefined;
108
109
  listWorkflowInvocations(opts?: {
109
110
  limit?: number;
package/dist/lib/store.js CHANGED
@@ -1565,6 +1565,65 @@ class Store {
1565
1565
  throw new Error(`workflow invocation not found after create: ${id}`);
1566
1566
  return rowToWorkflowInvocation(row);
1567
1567
  }
1568
+ refreshWorkflowInvocationForWorkItem(workItemId, input) {
1569
+ const sourceDedupeKey = input.sourceRef.dedupeKey ?? undefined;
1570
+ if (!sourceDedupeKey)
1571
+ throw new Error("cannot refresh workflow invocation without sourceRef.dedupeKey");
1572
+ const now = nowIso();
1573
+ const claimableStatuses = ["queued", "deferred", "failed", "dead_letter", "cancelled"];
1574
+ const statusBindings = Object.fromEntries(claimableStatuses.map((status, index) => [`$status${index}`, status]));
1575
+ const placeholders = claimableStatuses.map((_, index) => `$status${index}`).join(",");
1576
+ const result = this.db.query(`UPDATE workflow_invocations
1577
+ SET workflow_id=COALESCE($workflowId, workflow_id),
1578
+ template_id=COALESCE($templateId, template_id),
1579
+ source_id=COALESCE($sourceId, source_id),
1580
+ source_json=$sourceJson,
1581
+ subject_kind=$subjectKind,
1582
+ subject_id=COALESCE($subjectId, subject_id),
1583
+ subject_path=COALESCE($subjectPath, subject_path),
1584
+ subject_url=COALESCE($subjectUrl, subject_url),
1585
+ subject_json=$subjectJson,
1586
+ intent=$intent,
1587
+ scope_json=COALESCE($scopeJson, scope_json),
1588
+ output_policy_json=COALESCE($outputPolicyJson, output_policy_json),
1589
+ updated_at=$updated
1590
+ WHERE source_kind=$sourceKind
1591
+ AND source_dedupe_key=$sourceDedupeKey
1592
+ AND EXISTS (
1593
+ SELECT 1
1594
+ FROM workflow_work_items
1595
+ WHERE id=$workItemId
1596
+ AND invocation_id=workflow_invocations.id
1597
+ AND status IN (${placeholders})
1598
+ )`).run({
1599
+ $workItemId: workItemId,
1600
+ $sourceKind: input.sourceRef.kind,
1601
+ $sourceDedupeKey: sourceDedupeKey,
1602
+ $workflowId: input.workflowId ?? null,
1603
+ $templateId: input.templateId ?? null,
1604
+ $sourceId: input.sourceRef.id ?? null,
1605
+ $sourceJson: JSON.stringify(input.sourceRef),
1606
+ $subjectKind: input.subjectRef.kind,
1607
+ $subjectId: input.subjectRef.id ?? null,
1608
+ $subjectPath: input.subjectRef.path ?? null,
1609
+ $subjectUrl: input.subjectRef.url ?? null,
1610
+ $subjectJson: JSON.stringify(input.subjectRef),
1611
+ $intent: input.intent,
1612
+ $scopeJson: input.scope ? JSON.stringify(input.scope) : null,
1613
+ $outputPolicyJson: input.outputPolicy ? JSON.stringify(input.outputPolicy) : null,
1614
+ $updated: now,
1615
+ ...statusBindings
1616
+ });
1617
+ if (result.changes !== 1)
1618
+ throw new Error(`workflow work item is not refreshable: ${workItemId}`);
1619
+ const updated = this.db.query(`SELECT workflow_invocations.*
1620
+ FROM workflow_invocations
1621
+ JOIN workflow_work_items ON workflow_work_items.invocation_id = workflow_invocations.id
1622
+ WHERE workflow_work_items.id = ?`).get(workItemId);
1623
+ if (!updated)
1624
+ throw new Error(`workflow invocation not found after refresh for work item: ${workItemId}`);
1625
+ return rowToWorkflowInvocation(updated);
1626
+ }
1568
1627
  getWorkflowInvocation(id) {
1569
1628
  const row = this.db.query("SELECT * FROM workflow_invocations WHERE id = ?").get(id);
1570
1629
  return row ? rowToWorkflowInvocation(row) : undefined;
package/dist/sdk/index.js CHANGED
@@ -1565,6 +1565,65 @@ class Store {
1565
1565
  throw new Error(`workflow invocation not found after create: ${id}`);
1566
1566
  return rowToWorkflowInvocation(row);
1567
1567
  }
1568
+ refreshWorkflowInvocationForWorkItem(workItemId, input) {
1569
+ const sourceDedupeKey = input.sourceRef.dedupeKey ?? undefined;
1570
+ if (!sourceDedupeKey)
1571
+ throw new Error("cannot refresh workflow invocation without sourceRef.dedupeKey");
1572
+ const now = nowIso();
1573
+ const claimableStatuses = ["queued", "deferred", "failed", "dead_letter", "cancelled"];
1574
+ const statusBindings = Object.fromEntries(claimableStatuses.map((status, index) => [`$status${index}`, status]));
1575
+ const placeholders = claimableStatuses.map((_, index) => `$status${index}`).join(",");
1576
+ const result = this.db.query(`UPDATE workflow_invocations
1577
+ SET workflow_id=COALESCE($workflowId, workflow_id),
1578
+ template_id=COALESCE($templateId, template_id),
1579
+ source_id=COALESCE($sourceId, source_id),
1580
+ source_json=$sourceJson,
1581
+ subject_kind=$subjectKind,
1582
+ subject_id=COALESCE($subjectId, subject_id),
1583
+ subject_path=COALESCE($subjectPath, subject_path),
1584
+ subject_url=COALESCE($subjectUrl, subject_url),
1585
+ subject_json=$subjectJson,
1586
+ intent=$intent,
1587
+ scope_json=COALESCE($scopeJson, scope_json),
1588
+ output_policy_json=COALESCE($outputPolicyJson, output_policy_json),
1589
+ updated_at=$updated
1590
+ WHERE source_kind=$sourceKind
1591
+ AND source_dedupe_key=$sourceDedupeKey
1592
+ AND EXISTS (
1593
+ SELECT 1
1594
+ FROM workflow_work_items
1595
+ WHERE id=$workItemId
1596
+ AND invocation_id=workflow_invocations.id
1597
+ AND status IN (${placeholders})
1598
+ )`).run({
1599
+ $workItemId: workItemId,
1600
+ $sourceKind: input.sourceRef.kind,
1601
+ $sourceDedupeKey: sourceDedupeKey,
1602
+ $workflowId: input.workflowId ?? null,
1603
+ $templateId: input.templateId ?? null,
1604
+ $sourceId: input.sourceRef.id ?? null,
1605
+ $sourceJson: JSON.stringify(input.sourceRef),
1606
+ $subjectKind: input.subjectRef.kind,
1607
+ $subjectId: input.subjectRef.id ?? null,
1608
+ $subjectPath: input.subjectRef.path ?? null,
1609
+ $subjectUrl: input.subjectRef.url ?? null,
1610
+ $subjectJson: JSON.stringify(input.subjectRef),
1611
+ $intent: input.intent,
1612
+ $scopeJson: input.scope ? JSON.stringify(input.scope) : null,
1613
+ $outputPolicyJson: input.outputPolicy ? JSON.stringify(input.outputPolicy) : null,
1614
+ $updated: now,
1615
+ ...statusBindings
1616
+ });
1617
+ if (result.changes !== 1)
1618
+ throw new Error(`workflow work item is not refreshable: ${workItemId}`);
1619
+ const updated = this.db.query(`SELECT workflow_invocations.*
1620
+ FROM workflow_invocations
1621
+ JOIN workflow_work_items ON workflow_work_items.invocation_id = workflow_invocations.id
1622
+ WHERE workflow_work_items.id = ?`).get(workItemId);
1623
+ if (!updated)
1624
+ throw new Error(`workflow invocation not found after refresh for work item: ${workItemId}`);
1625
+ return rowToWorkflowInvocation(updated);
1626
+ }
1568
1627
  getWorkflowInvocation(id) {
1569
1628
  const row = this.db.query("SELECT * FROM workflow_invocations WHERE id = ?").get(id);
1570
1629
  return row ? rowToWorkflowInvocation(row) : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/loops",
3
- "version": "0.3.52",
3
+ "version": "0.3.53",
4
4
  "description": "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",