@xn-intenton-z2a/agentic-lib 7.1.77 → 7.1.79
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-bot.yml +14 -1
- package/.github/workflows/agentic-lib-test.yml +44 -0
- package/bin/agentic-lib.js +2 -0
- package/package.json +1 -1
- package/src/actions/agentic-step/action.yml +8 -0
- package/src/actions/agentic-step/index.js +4 -0
- package/src/actions/agentic-step/tasks/discussions.js +32 -4
- package/src/seeds/zero-behaviour.test.js +14 -0
- package/src/seeds/zero-package.json +3 -1
- package/src/seeds/zero-playwright.config.js +19 -0
|
@@ -129,7 +129,7 @@ jobs:
|
|
|
129
129
|
echo "result=fail" >> $GITHUB_OUTPUT
|
|
130
130
|
fi
|
|
131
131
|
|
|
132
|
-
- name: Get discussion URL
|
|
132
|
+
- name: Get discussion URL and trigger comment
|
|
133
133
|
id: discussion-url
|
|
134
134
|
uses: actions/github-script@v8
|
|
135
135
|
with:
|
|
@@ -140,6 +140,17 @@ jobs:
|
|
|
140
140
|
}
|
|
141
141
|
core.setOutput('url', url);
|
|
142
142
|
|
|
143
|
+
// Extract trigger comment info from event payload
|
|
144
|
+
const comment = context.payload.comment;
|
|
145
|
+
if (comment) {
|
|
146
|
+
core.setOutput('comment-node-id', comment.node_id || '');
|
|
147
|
+
core.setOutput('comment-created-at', comment.created_at || '');
|
|
148
|
+
core.info(`Trigger comment: node_id=${comment.node_id}, created_at=${comment.created_at}`);
|
|
149
|
+
} else {
|
|
150
|
+
core.setOutput('comment-node-id', '');
|
|
151
|
+
core.setOutput('comment-created-at', '');
|
|
152
|
+
}
|
|
153
|
+
|
|
143
154
|
- name: Skip if comment is from bot
|
|
144
155
|
id: guard
|
|
145
156
|
shell: bash
|
|
@@ -163,6 +174,8 @@ jobs:
|
|
|
163
174
|
config: ${{ env.configPath }}
|
|
164
175
|
instructions: ".github/agentic-lib/agents/agent-discussion-bot.md"
|
|
165
176
|
discussion-url: ${{ steps.discussion-url.outputs.url }}
|
|
177
|
+
comment-node-id: ${{ steps.discussion-url.outputs.comment-node-id }}
|
|
178
|
+
comment-created-at: ${{ steps.discussion-url.outputs.comment-created-at }}
|
|
166
179
|
model: ${{ needs.params.outputs.model }}
|
|
167
180
|
|
|
168
181
|
dispatch-supervisor:
|
|
@@ -12,6 +12,8 @@ name: agentic-lib-test
|
|
|
12
12
|
run-name: "agentic-lib-test [${{ github.ref_name }}]"
|
|
13
13
|
|
|
14
14
|
on:
|
|
15
|
+
schedule:
|
|
16
|
+
- cron: "10 * * * *"
|
|
15
17
|
#@dist push:
|
|
16
18
|
#@dist branches: [main]
|
|
17
19
|
#@dist pull_request:
|
|
@@ -19,6 +21,9 @@ on:
|
|
|
19
21
|
workflow_call:
|
|
20
22
|
workflow_dispatch:
|
|
21
23
|
|
|
24
|
+
permissions:
|
|
25
|
+
contents: write
|
|
26
|
+
|
|
22
27
|
jobs:
|
|
23
28
|
test:
|
|
24
29
|
runs-on: ubuntu-latest
|
|
@@ -45,3 +50,42 @@ jobs:
|
|
|
45
50
|
|
|
46
51
|
- name: Run tests
|
|
47
52
|
run: ${{ steps.config.outputs.test-command }}
|
|
53
|
+
|
|
54
|
+
behaviour:
|
|
55
|
+
if: github.repository != 'xn-intenton-z2a/agentic-lib'
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
container: mcr.microsoft.com/playwright:v1.58.2-noble
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v6
|
|
60
|
+
|
|
61
|
+
- name: Install dependencies
|
|
62
|
+
run: npm ci
|
|
63
|
+
|
|
64
|
+
- name: Build website
|
|
65
|
+
run: npm run build:web
|
|
66
|
+
|
|
67
|
+
- name: Run behaviour tests
|
|
68
|
+
run: npm run test:behaviour
|
|
69
|
+
env:
|
|
70
|
+
HOME: /root
|
|
71
|
+
|
|
72
|
+
- name: Push screenshot on main
|
|
73
|
+
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
|
|
74
|
+
run: |
|
|
75
|
+
git config user.name "github-actions[bot]"
|
|
76
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
77
|
+
git add SCREENSHOT_INDEX.png
|
|
78
|
+
git diff --cached --quiet && echo "No screenshot changes" && exit 0
|
|
79
|
+
git commit -m "test: update SCREENSHOT_INDEX.png [skip ci]"
|
|
80
|
+
for attempt in 1 2 3; do
|
|
81
|
+
git push origin HEAD:main && break
|
|
82
|
+
echo "Push failed (attempt $attempt) — pulling and retrying"
|
|
83
|
+
git pull --rebase origin main || {
|
|
84
|
+
echo "Rebase conflict — aborting rebase and retrying"
|
|
85
|
+
git rebase --abort 2>/dev/null || true
|
|
86
|
+
}
|
|
87
|
+
sleep $((attempt * 2))
|
|
88
|
+
if [ "$attempt" -eq 3 ]; then
|
|
89
|
+
echo "::warning::Failed to push screenshot after 3 attempts"
|
|
90
|
+
fi
|
|
91
|
+
done
|
package/bin/agentic-lib.js
CHANGED
|
@@ -952,6 +952,8 @@ function initPurge(seedsDir, missionName, initTimestamp) {
|
|
|
952
952
|
"zero-main.test.js": "tests/unit/main.test.js",
|
|
953
953
|
"zero-index.html": "src/web/index.html",
|
|
954
954
|
"zero-web.test.js": "tests/unit/web.test.js",
|
|
955
|
+
"zero-behaviour.test.js": "tests/behaviour/homepage.test.js",
|
|
956
|
+
"zero-playwright.config.js": "playwright.config.js",
|
|
955
957
|
"zero-SOURCES.md": "SOURCES.md",
|
|
956
958
|
"zero-package.json": "package.json",
|
|
957
959
|
"zero-README.md": "README.md",
|
package/package.json
CHANGED
|
@@ -38,6 +38,14 @@ inputs:
|
|
|
38
38
|
discussion-url:
|
|
39
39
|
description: "GitHub Discussion URL (for discussions task)"
|
|
40
40
|
required: false
|
|
41
|
+
comment-node-id:
|
|
42
|
+
description: "Node ID of the triggering discussion comment (for precise trigger identification)"
|
|
43
|
+
required: false
|
|
44
|
+
default: ""
|
|
45
|
+
comment-created-at:
|
|
46
|
+
description: "Timestamp of the triggering discussion comment (ISO 8601)"
|
|
47
|
+
required: false
|
|
48
|
+
default: ""
|
|
41
49
|
model:
|
|
42
50
|
description: "Copilot SDK model to use"
|
|
43
51
|
required: false
|
|
@@ -45,6 +45,8 @@ async function run() {
|
|
|
45
45
|
const writablePathsOverride = core.getInput("writable-paths");
|
|
46
46
|
const testCommandInput = core.getInput("test-command");
|
|
47
47
|
const discussionUrl = core.getInput("discussion-url");
|
|
48
|
+
const commentNodeId = core.getInput("comment-node-id");
|
|
49
|
+
const commentCreatedAt = core.getInput("comment-created-at");
|
|
48
50
|
const model = core.getInput("model");
|
|
49
51
|
|
|
50
52
|
core.info(`agentic-step: task=${task}, model=${model}`);
|
|
@@ -80,6 +82,8 @@ async function run() {
|
|
|
80
82
|
writablePaths,
|
|
81
83
|
testCommand,
|
|
82
84
|
discussionUrl,
|
|
85
|
+
commentNodeId,
|
|
86
|
+
commentCreatedAt,
|
|
83
87
|
model,
|
|
84
88
|
octokit: github.getOctokit(process.env.GITHUB_TOKEN),
|
|
85
89
|
repo: github.context.repo,
|
|
@@ -28,6 +28,7 @@ async function fetchDiscussion(octokit, discussionUrl, commentsLimit = 10) {
|
|
|
28
28
|
body
|
|
29
29
|
comments(last: ${commentsLimit}) {
|
|
30
30
|
nodes {
|
|
31
|
+
id
|
|
31
32
|
body
|
|
32
33
|
author { login }
|
|
33
34
|
createdAt
|
|
@@ -53,7 +54,7 @@ async function fetchDiscussion(octokit, discussionUrl, commentsLimit = 10) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
function buildPrompt(discussionUrl, discussion, context, t, repoContext) {
|
|
57
|
+
function buildPrompt(discussionUrl, discussion, context, t, repoContext, triggerComment) {
|
|
57
58
|
const { config, instructions } = context;
|
|
58
59
|
const { title, body, comments } = discussion;
|
|
59
60
|
|
|
@@ -84,8 +85,18 @@ function buildPrompt(discussionUrl, discussion, context, t, repoContext) {
|
|
|
84
85
|
if (humanComments.length > 0) {
|
|
85
86
|
parts.push("", "### Conversation History");
|
|
86
87
|
for (const c of humanComments) {
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
// Identify the triggering comment: match by node_id, then by createdAt, then fall back to latest
|
|
89
|
+
let isTrigger = false;
|
|
90
|
+
if (triggerComment?.nodeId && c.id) {
|
|
91
|
+
isTrigger = c.id === triggerComment.nodeId;
|
|
92
|
+
} else if (triggerComment?.createdAt && c.createdAt) {
|
|
93
|
+
isTrigger = c.createdAt === triggerComment.createdAt;
|
|
94
|
+
} else {
|
|
95
|
+
isTrigger = c === latestHumanComment;
|
|
96
|
+
}
|
|
97
|
+
const prefix = isTrigger ? ">>> **[TRIGGER — RESPOND TO THIS]** " : "";
|
|
98
|
+
const nodeIdTag = c.id ? ` [node:${c.id}]` : "";
|
|
99
|
+
parts.push(`${prefix}**${c.author?.login || "unknown"}** (${c.createdAt})${nodeIdTag}:\n${c.body}`);
|
|
89
100
|
}
|
|
90
101
|
}
|
|
91
102
|
|
|
@@ -248,7 +259,24 @@ export async function discussions(context) {
|
|
|
248
259
|
discussion.comments = discussion.comments.filter((c) => new Date(c.createdAt) >= initDate);
|
|
249
260
|
}
|
|
250
261
|
|
|
251
|
-
|
|
262
|
+
// Extract trigger comment info from multiple sources:
|
|
263
|
+
// 1. Event payload (discussion_comment event) — most reliable
|
|
264
|
+
// 2. Explicit inputs (comment-node-id, comment-created-at) — for workflow_dispatch
|
|
265
|
+
// 3. Fall back to latest human comment (handled in buildPrompt)
|
|
266
|
+
const triggerComment = {};
|
|
267
|
+
const eventComment = context.github?.payload?.comment;
|
|
268
|
+
if (eventComment) {
|
|
269
|
+
triggerComment.nodeId = eventComment.node_id || "";
|
|
270
|
+
triggerComment.createdAt = eventComment.created_at || "";
|
|
271
|
+
triggerComment.body = eventComment.body || "";
|
|
272
|
+
triggerComment.login = eventComment.user?.login || "";
|
|
273
|
+
core.info(`Trigger comment from event payload: ${triggerComment.login} at ${triggerComment.createdAt}`);
|
|
274
|
+
}
|
|
275
|
+
// Explicit inputs override event payload (workflow_dispatch or workflow_call may pass these)
|
|
276
|
+
if (context.commentNodeId) triggerComment.nodeId = context.commentNodeId;
|
|
277
|
+
if (context.commentCreatedAt) triggerComment.createdAt = context.commentCreatedAt;
|
|
278
|
+
|
|
279
|
+
const prompt = buildPrompt(discussionUrl, discussion, context, t, repoContext, triggerComment);
|
|
252
280
|
const { content, tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
|
|
253
281
|
model,
|
|
254
282
|
systemMessage:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (C) 2025-2026 Polycode Limited
|
|
3
|
+
import { test, expect } from "@playwright/test";
|
|
4
|
+
|
|
5
|
+
test("homepage returns 200 and renders", async ({ page }) => {
|
|
6
|
+
const response = await page.goto("/");
|
|
7
|
+
expect(response.status()).toBe(200);
|
|
8
|
+
|
|
9
|
+
await expect(page.locator("#lib-name")).toBeVisible();
|
|
10
|
+
await expect(page.locator("#lib-version")).toBeVisible();
|
|
11
|
+
await expect(page.locator("#demo-output")).toBeVisible();
|
|
12
|
+
|
|
13
|
+
await page.screenshot({ path: "SCREENSHOT_INDEX.png", fullPage: true });
|
|
14
|
+
});
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"build:web": "mkdir -p docs && touch docs/.nojekyll && cp -r src/web/* docs/ 2>/dev/null || true && node --input-type=commonjs -p \"var p=require('./package.json');['name','version','description'].map(function(k){return 'export const '+k+' = '+JSON.stringify(p[k])+';'}).join('\\n')\" > docs/lib-meta.js",
|
|
10
10
|
"test": "vitest --run tests/unit/*.test.js",
|
|
11
11
|
"test:unit": "vitest --run --coverage tests/unit/*.test.js",
|
|
12
|
+
"test:behaviour": "npx playwright test --config playwright.config.js",
|
|
12
13
|
"start": "npm run build:web && npx serve docs",
|
|
13
14
|
"start:cli": "node src/lib/main.js"
|
|
14
15
|
},
|
|
@@ -16,9 +17,10 @@
|
|
|
16
17
|
"author": "",
|
|
17
18
|
"license": "MIT",
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@xn-intenton-z2a/agentic-lib": "^7.1.
|
|
20
|
+
"@xn-intenton-z2a/agentic-lib": "^7.1.79"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
23
|
+
"@playwright/test": "^1.58.0",
|
|
22
24
|
"@vitest/coverage-v8": "^4.0.18",
|
|
23
25
|
"vitest": "^4.0.18"
|
|
24
26
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (C) 2025-2026 Polycode Limited
|
|
3
|
+
import { defineConfig } from "@playwright/test";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
testDir: "tests/behaviour",
|
|
7
|
+
timeout: 30000,
|
|
8
|
+
use: {
|
|
9
|
+
baseURL: "http://localhost:3000",
|
|
10
|
+
},
|
|
11
|
+
webServer: {
|
|
12
|
+
command: "npx serve docs -l 3000",
|
|
13
|
+
port: 3000,
|
|
14
|
+
reuseExistingServer: true,
|
|
15
|
+
},
|
|
16
|
+
projects: [
|
|
17
|
+
{ name: "chromium", use: { browserName: "chromium" } },
|
|
18
|
+
],
|
|
19
|
+
});
|