@xn-intenton-z2a/agentic-lib 7.4.56 → 7.4.58

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.
@@ -376,6 +376,10 @@ jobs:
376
376
  git config user.name "${TOKEN_USER}"
377
377
  git config user.email "${TOKEN_ID}+${TOKEN_USER}@users.noreply.github.com"
378
378
  git add -A
379
+ # Unstage log/screenshot/state files — these live on the agentic-lib-logs branch
380
+ git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
381
+ git reset HEAD -- agent-log-*.md 2>/dev/null || true
382
+ git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
379
383
  git diff --cached --quiet && echo "No changes" && exit 0
380
384
  VERSION=$(npx @xn-intenton-z2a/agentic-lib version 2>/dev/null || echo "latest")
381
385
  # Problem 1 fix: Don't use [skip ci] when workflow files changed.
@@ -123,6 +123,10 @@ jobs:
123
123
  git config user.name "${TOKEN_USER}"
124
124
  git config user.email "${TOKEN_ID}+${TOKEN_USER}@users.noreply.github.com"
125
125
  git add -A
126
+ # Unstage log/screenshot/state files — these live on the agentic-lib-logs branch
127
+ git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
128
+ git reset HEAD -- agent-log-*.md 2>/dev/null || true
129
+ git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
126
130
  git diff --cached --quiet && echo "No changes" && exit 0
127
131
  VERSION=$(npx @xn-intenton-z2a/agentic-lib version 2>/dev/null || echo "latest")
128
132
  git commit -m "update agentic-lib@${VERSION} [skip ci]"
@@ -281,16 +281,20 @@ jobs:
281
281
  await github.rest.git.deleteRef({ owner, repo, ref: `heads/${pr.head.ref}` });
282
282
  } catch (e) { core.info(`Could not delete branch: ${e.message}`); }
283
283
 
284
- // Label associated issue
284
+ // Close associated issues — extract from PR body (Closes #N) and branch name
285
+ const closesMatches = (pr.body || '').matchAll(/(?:Closes|Fixes|Resolves)\s+#(\d+)/gi);
286
+ const issueNums = new Set([...closesMatches].map(m => parseInt(m[1])));
285
287
  const branchPrefix = 'agentic-lib-issue-';
286
288
  if (pr.head.ref.startsWith(branchPrefix)) {
287
- const issueNum = parseInt(pr.head.ref.replace(branchPrefix, ''));
288
- if (issueNum) {
289
- try {
290
- await github.rest.issues.addLabels({ owner, repo, issue_number: issueNum, labels: ['merged'] });
291
- await github.rest.issues.removeLabel({ owner, repo, issue_number: issueNum, name: 'in-progress' });
292
- } catch (e) { /* label may not exist */ }
293
- }
289
+ const branchIssueNum = parseInt(pr.head.ref.replace(branchPrefix, ''));
290
+ if (branchIssueNum) issueNums.add(branchIssueNum);
291
+ }
292
+ for (const issueNum of issueNums) {
293
+ try {
294
+ await github.rest.issues.update({ owner, repo, issue_number: issueNum, state: 'closed' });
295
+ await github.rest.issues.addLabels({ owner, repo, issue_number: issueNum, labels: ['merged'] });
296
+ await github.rest.issues.removeLabel({ owner, repo, issue_number: issueNum, name: 'in-progress' });
297
+ } catch (e) { /* label may not exist */ }
294
298
  }
295
299
  mergedPRs.push(pr.number);
296
300
  } catch (e) {
@@ -1242,6 +1246,10 @@ jobs:
1242
1246
  npm install 2>/dev/null || true
1243
1247
 
1244
1248
  git add -A
1249
+ # Unstage log/screenshot/state files — these live on the agentic-lib-logs branch
1250
+ git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
1251
+ git reset HEAD -- agent-log-*.md 2>/dev/null || true
1252
+ git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
1245
1253
  if ! git diff --cached --quiet; then
1246
1254
  git commit -m "fix-stuck: sync with main (resolve conflicts)"
1247
1255
  git push --force-with-lease origin HEAD:"$BRANCH" 2>&1 && RESOLVED=true
@@ -1317,6 +1325,10 @@ jobs:
1317
1325
  git config user.name 'GitHub Actions[bot]'
1318
1326
  BRANCH=$(git rev-parse --abbrev-ref HEAD)
1319
1327
  git add -A
1328
+ # Unstage log/screenshot/state files — these live on the agentic-lib-logs branch
1329
+ git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
1330
+ git reset HEAD -- agent-log-*.md 2>/dev/null || true
1331
+ git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
1320
1332
  if ! git diff --cached --quiet; then
1321
1333
  git commit -m "agentic-step: fix failing tests / resolve conflicts"
1322
1334
  git push origin HEAD:"$BRANCH" 2>&1 || git push --force-with-lease origin HEAD:"$BRANCH" 2>&1
@@ -1356,16 +1368,20 @@ jobs:
1356
1368
  try {
1357
1369
  await github.rest.git.deleteRef({ owner, repo, ref: `heads/${pr.head.ref}` });
1358
1370
  } catch (e) { /* branch may already be deleted */ }
1359
- // Label associated issue
1360
- const branchPrefix = 'agentic-lib-issue-';
1361
- if (pr.head.ref.startsWith(branchPrefix)) {
1362
- const issueNum = parseInt(pr.head.ref.replace(branchPrefix, ''));
1363
- if (issueNum) {
1364
- try {
1365
- await github.rest.issues.addLabels({ owner, repo, issue_number: issueNum, labels: ['merged'] });
1366
- await github.rest.issues.removeLabel({ owner, repo, issue_number: issueNum, name: 'in-progress' });
1367
- } catch (e) { /* label may not exist */ }
1368
- }
1371
+ // Close associated issues — extract from PR body (Closes #N) and branch name
1372
+ const closesMatches2 = (pr.body || '').matchAll(/(?:Closes|Fixes|Resolves)\s+#(\d+)/gi);
1373
+ const issueNums2 = new Set([...closesMatches2].map(m => parseInt(m[1])));
1374
+ const branchPrefix2 = 'agentic-lib-issue-';
1375
+ if (pr.head.ref.startsWith(branchPrefix2)) {
1376
+ const branchIssueNum = parseInt(pr.head.ref.replace(branchPrefix2, ''));
1377
+ if (branchIssueNum) issueNums2.add(branchIssueNum);
1378
+ }
1379
+ for (const issueNum of issueNums2) {
1380
+ try {
1381
+ await github.rest.issues.update({ owner, repo, issue_number: issueNum, state: 'closed' });
1382
+ await github.rest.issues.addLabels({ owner, repo, issue_number: issueNum, labels: ['merged'] });
1383
+ await github.rest.issues.removeLabel({ owner, repo, issue_number: issueNum, name: 'in-progress' });
1384
+ } catch (e) { /* label may not exist */ }
1369
1385
  }
1370
1386
  return;
1371
1387
  } catch (e) {
@@ -1393,6 +1409,10 @@ jobs:
1393
1409
  git config --local user.email 'action@github.com'
1394
1410
  git config --local user.name 'GitHub Actions[bot]'
1395
1411
  git add -A
1412
+ # Unstage log/screenshot/state files — these live on the agentic-lib-logs branch
1413
+ git reset HEAD -- 'intentïon.md' 'SCREENSHOT_INDEX.png' 2>/dev/null || true
1414
+ git reset HEAD -- agent-log-*.md 2>/dev/null || true
1415
+ git reset HEAD -- agentic-lib-state.toml 2>/dev/null || true
1396
1416
  git commit -m "agentic-step: fix broken main build (run ${{ env.FIX_RUN_ID }})"
1397
1417
  git push -u origin agentic-lib-fix-main-build
1398
1418
  gh pr create \
@@ -1746,15 +1766,18 @@ jobs:
1746
1766
  try {
1747
1767
  await github.rest.pulls.merge({
1748
1768
  owner, repo, pull_number: prNumber, merge_method: 'squash',
1769
+ commit_message: closesLines + '\n\nAutomated transformation.',
1749
1770
  });
1750
1771
  core.info(`Merged PR #${prNumber}`);
1751
1772
  try {
1752
1773
  await github.rest.git.deleteRef({ owner, repo, ref: `heads/${branchName}` });
1753
1774
  } catch (e) {}
1754
- if (issueNumber) {
1775
+ // Close all referenced issues (belt-and-suspenders with Closes keywords)
1776
+ for (const num of issueNumbers) {
1755
1777
  try {
1756
- await github.rest.issues.addLabels({ owner, repo, issue_number: parseInt(issueNumber), labels: ['merged'] });
1757
- await github.rest.issues.removeLabel({ owner, repo, issue_number: parseInt(issueNumber), name: 'in-progress' });
1778
+ await github.rest.issues.update({ owner, repo, issue_number: parseInt(num), state: 'closed' });
1779
+ await github.rest.issues.addLabels({ owner, repo, issue_number: parseInt(num), labels: ['merged'] });
1780
+ await github.rest.issues.removeLabel({ owner, repo, issue_number: parseInt(num), name: 'in-progress' });
1758
1781
  } catch (e) {}
1759
1782
  }
1760
1783
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.4.56",
3
+ "version": "7.4.58",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -70,7 +70,6 @@ async function buildMetricAssessment(ctx, config) {
70
70
  const minResolved = thresholds.minResolvedIssues ?? 1;
71
71
  const maxTodos = thresholds.maxSourceTodos ?? 0;
72
72
  const minCumulativeTransforms = thresholds.minCumulativeTransforms ?? 1;
73
- const acceptanceThreshold = thresholds.acceptanceCriteriaThreshold ?? 50;
74
73
  const requireNoOpenIssues = thresholds.requireNoOpenIssues ?? true;
75
74
  const requireNoOpenPrs = thresholds.requireNoOpenPrs ?? true;
76
75
  const requireNoCriticalGaps = thresholds.requireNoCriticalGaps ?? true;
@@ -83,14 +82,16 @@ async function buildMetricAssessment(ctx, config) {
83
82
  } catch { /* ignore parse errors */ }
84
83
  const criticalGaps = reviewGaps.filter((g) => g.severity === "critical");
85
84
 
86
- // Acceptance criteria from MISSION.md checkboxes (or structured TOML if available)
85
+ // Acceptance criteria informational only (not a mechanical gate).
86
+ // The director LLM reads criteria from MISSION.md and assesses them directly.
87
87
  const { countAcceptanceCriteria } = await import("../../../copilot/telemetry.js");
88
88
  const missionPath = config.paths?.mission?.path || "MISSION.md";
89
89
  const acceptance = countAcceptanceCriteria(missionPath);
90
90
  const acceptancePct = acceptance.total > 0 ? (acceptance.met / acceptance.total) * 100 : 0;
91
- const acceptanceMet = acceptance.total > 0 && acceptancePct >= acceptanceThreshold;
92
91
 
93
- // C6: Removed "Dedicated tests" metric; using cumulative transforms instead
92
+ // FIX-10: Require at least one test file that imports from src/lib/
93
+ const { dedicatedTestCount } = detectDedicatedTests();
94
+
94
95
  const metrics = [
95
96
  { metric: "Open issues", value: ctx.issuesSummary.length, target: 0, met: requireNoOpenIssues ? ctx.issuesSummary.length === 0 : true },
96
97
  { metric: "Open PRs", value: ctx.prsSummary.length, target: 0, met: requireNoOpenPrs ? ctx.prsSummary.length === 0 : true },
@@ -99,7 +100,8 @@ async function buildMetricAssessment(ctx, config) {
99
100
  { metric: "Cumulative transforms", value: ctx.cumulativeTransformationCost, target: minCumulativeTransforms, met: ctx.cumulativeTransformationCost >= minCumulativeTransforms },
100
101
  { metric: "Budget", value: ctx.cumulativeTransformationCost, target: ctx.transformationBudget || "unlimited", met: !(ctx.transformationBudget > 0 && ctx.cumulativeTransformationCost >= ctx.transformationBudget) },
101
102
  { metric: "Implementation review", value: criticalGaps.length === 0 ? "No critical gaps" : `${criticalGaps.length} critical gap(s)`, target: "No critical gaps", met: requireNoCriticalGaps ? criticalGaps.length === 0 : true },
102
- { metric: "Acceptance criteria", value: acceptance.total > 0 ? `${acceptance.met}/${acceptance.total} (${Math.round(acceptancePct)}%)` : "N/A", target: `>= ${acceptanceThreshold}%`, met: acceptanceMet },
103
+ { metric: "Acceptance criteria", value: acceptance.total > 0 ? `${acceptance.met}/${acceptance.total} (${Math.round(acceptancePct)}%)` : "N/A", target: "informational", met: true },
104
+ { metric: "Dedicated test files", value: dedicatedTestCount, target: ">= 1", met: dedicatedTestCount >= 1 },
103
105
  ];
104
106
 
105
107
  const allMet = metrics.every((m) => m.met);
@@ -215,49 +215,13 @@ export async function implementationReview(context) {
215
215
  }
216
216
  }
217
217
 
218
- // Also update MISSION.md checkboxes (best-effort, not critical)
219
- if (metCriteria.length > 0 || metIndices.length > 0) {
220
- try {
221
- const missionPath = config.paths?.mission?.path || "MISSION.md";
222
- const { readFileSync, writeFileSync } = await import("fs");
223
- let missionContent = readFileSync(missionPath, "utf8");
224
- let checkedCount = 0;
225
-
226
- // Index-based update: find the Nth checkbox and check it
227
- if (metIndices.length > 0) {
228
- const lines = missionContent.split("\n");
229
- let checkboxIdx = 0;
230
- for (let i = 0; i < lines.length; i++) {
231
- if (/^- \[ \] /.test(lines[i])) {
232
- checkboxIdx++;
233
- if (metIndices.includes(checkboxIdx)) {
234
- lines[i] = lines[i].replace(/^- \[ \] /, "- [x] ");
235
- checkedCount++;
236
- }
237
- }
238
- }
239
- missionContent = lines.join("\n");
240
- }
241
-
242
- // Text-based update (fallback for backwards compatibility)
243
- if (checkedCount === 0 && metCriteria.length > 0) {
244
- for (const criterionText of metCriteria) {
245
- const escaped = criterionText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").trim();
246
- const re = new RegExp(`- \\[ \\] ${escaped}`);
247
- if (re.test(missionContent)) {
248
- missionContent = missionContent.replace(re, `- [x] ${criterionText.trim()}`);
249
- checkedCount++;
250
- }
251
- }
252
- }
253
-
254
- if (checkedCount > 0) {
255
- writeFileSync(missionPath, missionContent, "utf8");
256
- core.info(`Updated ${checkedCount} acceptance criteria checkboxes in ${missionPath}`);
257
- }
258
- } catch (err) {
259
- core.warning(`Could not update MISSION.md checkboxes: ${err.message}`);
260
- }
218
+ // Log acceptance criteria status (informational no longer writes to MISSION.md
219
+ // to avoid zero-diff commits that inflate transform counts)
220
+ if (metIndices.length > 0) {
221
+ core.info(`Review found ${metIndices.length} acceptance criteria met by index: [${metIndices.join(", ")}]`);
222
+ }
223
+ if (metCriteria.length > 0) {
224
+ core.info(`Review found ${metCriteria.length} acceptance criteria met by text`);
261
225
  }
262
226
 
263
227
  return { textResultForLlm: `Review recorded: ${elements?.length || 0} elements traced, ${gaps?.length || 0} gaps found, ${totalUpdated} criteria checked` };
@@ -20,12 +20,17 @@ const REPORT_DATA_DIR = "/tmp/report-data";
20
20
  async function findLatestInitRun(octokit, owner, repo) {
21
21
  try {
22
22
  const { data } = await octokit.rest.actions.listWorkflowRunsForRepo({
23
- owner, repo, per_page: 20,
23
+ owner, repo, per_page: 50,
24
24
  });
25
- const initRuns = data.workflow_runs
26
- .filter(r => r.name && r.name.includes("agentic-lib-init"))
25
+ // Look for standalone init runs or flow runs (init may be embedded in flow)
26
+ const relevantRuns = data.workflow_runs
27
+ .filter(r => r.name && (r.name.includes("agentic-lib-init") || r.name.includes("agentic-lib-flow")))
27
28
  .sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
28
- if (initRuns.length > 0) return initRuns[0].created_at;
29
+ // Prefer the most recent init run; fall back to the most recent flow run
30
+ const initRun = relevantRuns.find(r => r.name.includes("agentic-lib-init"));
31
+ const flowRun = relevantRuns.find(r => r.name.includes("agentic-lib-flow"));
32
+ const bestRun = initRun || flowRun;
33
+ if (bestRun) return bestRun.created_at;
29
34
  } catch (err) {
30
35
  core.warning(`Could not find init runs: ${err.message}`);
31
36
  }
@@ -47,16 +52,21 @@ async function gatherAndWriteData(octokit, owner, repoName, periodStart, periodE
47
52
  writeFileSync(`${REPORT_DATA_DIR}/state.toml`, stateContent);
48
53
  writeFileSync(`${REPORT_DATA_DIR}/mission.md`, missionContent);
49
54
 
50
- // 2. Workflow runs
55
+ // 2. Workflow runs (paginate up to 200 for long-running scenarios)
51
56
  let workflowRuns = [];
52
57
  try {
53
- const { data } = await octokit.rest.actions.listWorkflowRunsForRepo({
54
- owner, repo: repoName, per_page: 50, created: `${periodStart}..${periodEnd}`,
55
- });
56
- workflowRuns = data.workflow_runs.map(r => ({
57
- id: r.id, name: r.name, status: r.status, conclusion: r.conclusion,
58
- created_at: r.created_at, updated_at: r.updated_at, html_url: r.html_url,
59
- }));
58
+ for (let page = 1; page <= 2; page++) {
59
+ const { data } = await octokit.rest.actions.listWorkflowRunsForRepo({
60
+ owner, repo: repoName, per_page: 100, page, created: `${periodStart}..${periodEnd}`,
61
+ });
62
+ for (const r of data.workflow_runs) {
63
+ workflowRuns.push({
64
+ id: r.id, name: r.name, status: r.status, conclusion: r.conclusion,
65
+ created_at: r.created_at, updated_at: r.updated_at, html_url: r.html_url,
66
+ });
67
+ }
68
+ if (data.workflow_runs.length < 100) break;
69
+ }
60
70
  } catch (err) { core.warning(`Could not list runs: ${err.message}`); }
61
71
  writeFileSync(`${REPORT_DATA_DIR}/workflow-runs.json`, JSON.stringify(workflowRuns, null, 2));
62
72
 
@@ -17,7 +17,7 @@
17
17
  "author": "",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@xn-intenton-z2a/agentic-lib": "^7.4.56"
20
+ "@xn-intenton-z2a/agentic-lib": "^7.4.58"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@playwright/test": "^1.58.0",