@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.
- package/.github/workflows/agentic-lib-init.yml +4 -0
- package/.github/workflows/agentic-lib-update.yml +4 -0
- package/.github/workflows/agentic-lib-workflow.yml +44 -21
- package/package.json +1 -1
- package/src/actions/agentic-step/tasks/direct.js +7 -5
- package/src/actions/agentic-step/tasks/implementation-review.js +7 -43
- package/src/actions/agentic-step/tasks/report.js +22 -12
- package/src/seeds/zero-package.json +1 -1
|
@@ -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
|
-
//
|
|
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
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
//
|
|
1360
|
-
const
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
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
|
-
|
|
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.
|
|
1757
|
-
await github.rest.issues.
|
|
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
|
@@ -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
|
|
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
|
-
//
|
|
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:
|
|
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
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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:
|
|
23
|
+
owner, repo, per_page: 50,
|
|
24
24
|
});
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|