@dtlabs/ai-toolkit 0.22.0 → 0.22.1

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/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
1
  ## 0.1.4 (2026-07-21)
2
+ ## [0.22.1](https://github.com/dtlab-tech/ai-toolkit/compare/v0.22.0...v0.22.1) (2026-10-21)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * **task-executor:** deterministic split-wbs/ render for planDigest stability ([0afbcba](https://github.com/dtlab-tech/ai-toolkit/commit/0afbcba0b0a6d2e09251acd97f6b22b6cc288ce3))
8
+ * **task-executor:** make split-wbs/ in-memory render deterministic for planDigest ([0f500fe](https://github.com/dtlab-tech/ai-toolkit/commit/0f500fe85bff37199601dae2e689f2426a656d6b))
9
+
2
10
  ## [0.22.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.21.2...v0.22.0) (2026-10-21)
3
11
 
4
12
 
@@ -3834,7 +3834,15 @@ function _loadPlanDocs(featureDir, prefix, errorCode, callerLabel) {
3834
3834
  throw _err(code, label + ': failed to load split Work Breakdown "' + wbsDir + '": ' + err.message);
3835
3835
  }
3836
3836
  const phaseDepsMap = computePhaseDependsOn(wb);
3837
- return { md: renderMarkdown(wb, prefix, phaseDepsMap), csv: renderCsv(wb, prefix, phaseDepsMap) };
3837
+ // A stable (not wall-clock) "Generated" value: this in-memory render runs fresh on EVERY
3838
+ // call (unlike the legacy path's render-once-to-disk), so planDigest must be a pure function
3839
+ // of this call's inputs, not of when it happened to run — see renderMarkdown's own doc
3840
+ // comment for the real replan()/execute() digest-mismatch bug this fixes.
3841
+ const generatedAt = fs.statSync(indexPath).mtime.toISOString();
3842
+ return {
3843
+ md: renderMarkdown(wb, prefix, phaseDepsMap, generatedAt),
3844
+ csv: renderCsv(wb, prefix, phaseDepsMap),
3845
+ };
3838
3846
  }
3839
3847
  }
3840
3848
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtlabs/ai-toolkit",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "AI Toolkit — reusable agents and procedures for developers to build AI-powered applications.",
5
5
  "files": [
6
6
  "docs/",
@@ -92,7 +92,17 @@ function buildCommitSubject(task) {
92
92
 
93
93
  // ── Render stubs (implemented in T03–T05) ─────────────────────────────────────
94
94
 
95
- function renderMarkdown(wb, prefix, phaseDepsMap) {
95
+ // generatedAt: optional override for the "Generated" line below, defaulting to the current
96
+ // wall-clock time (unchanged behavior for the CLI entry point's one-shot render-to-disk use).
97
+ // lib/task-executor/index.js's _loadPlanDocs() passes an explicit, stable value (wbs/index.json's
98
+ // own mtime) instead — it re-renders a split wbs/ directory in memory on EVERY execute()/replan()
99
+ // call (the legacy .md/.csv path renders to disk once and is read back unchanged thereafter), and
100
+ // a live timestamp there made planDigest non-deterministic between two calls against the exact
101
+ // same unchanged plan, spuriously tripping REPLAN_PLAN_DIGEST_MISMATCH on a real replan() ->
102
+ // execute() --from-replan-run-id sequence (reported against a real Fincantieri.ISDM.JobScheduler
103
+ // run). mtime still correctly changes the digest if the plan is genuinely edited between calls —
104
+ // exactly the drift planDigest exists to catch.
105
+ function renderMarkdown(wb, prefix, phaseDepsMap, generatedAt) {
96
106
  const DOMAINS = ['BE', 'FE', 'DB', 'DevOps', 'INFRA', 'TEST']
97
107
 
98
108
  function getAgentMinutes(task) {
@@ -176,7 +186,7 @@ function renderMarkdown(wb, prefix, phaseDepsMap) {
176
186
  }
177
187
 
178
188
  const title = wb.title ?? wb.feature ?? prefix
179
- const generated = new Date().toISOString()
189
+ const generated = generatedAt == null ? new Date().toISOString() : generatedAt
180
190
  const L = []
181
191
 
182
192
  // ── Title ──