@xn-intenton-z2a/agentic-lib 7.1.11 → 7.1.13
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/README.md +8 -11
- package/package.json +1 -1
- package/src/actions/agentic-step/safety.js +1 -1
- package/src/actions/agentic-step/tasks/discussions.js +25 -0
- package/src/workflows/agent-discussions-bot.yml +1 -7
- package/src/workflows/agent-flow-fix-code.yml +1 -1
- package/src/workflows/ci-automerge.yml +2 -99
package/README.md
CHANGED
|
@@ -57,20 +57,15 @@ your-repo/
|
|
|
57
57
|
├── agentic-lib.toml # [INIT] Config (created once, never overwritten)
|
|
58
58
|
│
|
|
59
59
|
├── .github/
|
|
60
|
-
│ ├── workflows/ # [INIT]
|
|
60
|
+
│ ├── workflows/ # [INIT] 8 workflow files (always overwritten)
|
|
61
61
|
│ │ ├── agent-flow-transform.yml # Core: transform code toward the mission
|
|
62
62
|
│ │ ├── agent-flow-maintain.yml # Core: maintain features and library
|
|
63
63
|
│ │ ├── agent-flow-review.yml # Core: review and close resolved issues
|
|
64
64
|
│ │ ├── agent-flow-fix-code.yml # Core: fix failing tests
|
|
65
65
|
│ │ ├── agent-discussions-bot.yml # Bot: respond to GitHub Discussions
|
|
66
66
|
│ │ ├── agent-supervisor.yml # Supervisor: orchestrate the pipeline
|
|
67
|
-
│ │ ├── agent-archive-intentïon.yml # Archive the activity log
|
|
68
|
-
│ │ ├── ci-test.yml # CI: run tests
|
|
69
67
|
│ │ ├── ci-automerge.yml # CI: auto-merge passing PRs
|
|
70
|
-
│ │
|
|
71
|
-
│ │ ├── ci-update.yml # CI: dependency updates
|
|
72
|
-
│ │ ├── ci-init.yml # CI: pull latest infrastructure
|
|
73
|
-
│ │ └── publish-packages.yml # Release: npm publish
|
|
68
|
+
│ │ └── test.yml # CI: run tests
|
|
74
69
|
│ │
|
|
75
70
|
│ └── agentic-lib/ # [INIT] Internal infrastructure (always overwritten)
|
|
76
71
|
│ ├── actions/
|
|
@@ -95,6 +90,8 @@ your-repo/
|
|
|
95
90
|
- **[USER]** -- Your files. `init` never touches these. `init --purge` resets them to seed state.
|
|
96
91
|
- **[GENERATED]** -- Created by the agentic workflows during operation.
|
|
97
92
|
|
|
93
|
+
Your repository should also have an `init.yml` workflow (not distributed — maintained locally) that runs `npx agentic-lib init --purge` on a schedule to keep infrastructure up to date. See [repository0/init.yml](https://github.com/xn-intenton-z2a/repository0/blob/main/.github/workflows/init.yml) for an example.
|
|
94
|
+
|
|
98
95
|
### What You Need Before Running `init`
|
|
99
96
|
|
|
100
97
|
| File | Required? | Notes |
|
|
@@ -279,16 +276,16 @@ This repository is the source for the `@xn-intenton-z2a/agentic-lib` npm package
|
|
|
279
276
|
|
|
280
277
|
```
|
|
281
278
|
src/
|
|
282
|
-
├── workflows/
|
|
279
|
+
├── workflows/ 7 GitHub Actions workflow templates
|
|
283
280
|
├── actions/ 3 composite/SDK actions (agentic-step, commit-if-changed, setup-npmrc)
|
|
284
281
|
├── agents/ 7 agent prompt files + 1 config
|
|
285
|
-
├── seeds/
|
|
286
|
-
└── scripts/
|
|
282
|
+
├── seeds/ 7 seed files (test.yml + 6 project seed files for --purge reset)
|
|
283
|
+
└── scripts/ 7 utility scripts distributed to consumers
|
|
287
284
|
```
|
|
288
285
|
|
|
289
286
|
### Testing
|
|
290
287
|
|
|
291
|
-
|
|
288
|
+
236 unit tests across 21 test files, plus system tests:
|
|
292
289
|
|
|
293
290
|
```bash
|
|
294
291
|
npm test # Run all tests (vitest)
|
package/package.json
CHANGED
|
@@ -37,7 +37,7 @@ export async function checkWipLimit(octokit, repo, label, limit) {
|
|
|
37
37
|
* @param {import('@actions/github').GitHub} octokit - GitHub API client
|
|
38
38
|
* @param {Object} repo - { owner, repo } identifying the repository
|
|
39
39
|
* @param {string|number} issueNumber - The issue number
|
|
40
|
-
* @param {string} branchPrefix - Branch naming prefix (e.g. 'agentic-lib-
|
|
40
|
+
* @param {string} branchPrefix - Branch naming prefix (e.g. 'agentic-lib-')
|
|
41
41
|
* @returns {Promise<number>} Number of branches matching the pattern
|
|
42
42
|
*/
|
|
43
43
|
export async function countBranchAttempts(octokit, repo, issueNumber, branchPrefix) {
|
|
@@ -27,6 +27,7 @@ export async function discussions(context) {
|
|
|
27
27
|
let discussionTitle = "";
|
|
28
28
|
let discussionBody = "";
|
|
29
29
|
let discussionComments = [];
|
|
30
|
+
let discussionNodeId = "";
|
|
30
31
|
|
|
31
32
|
if (urlMatch) {
|
|
32
33
|
const [, urlOwner, urlRepo, discussionNumber] = urlMatch;
|
|
@@ -34,6 +35,7 @@ export async function discussions(context) {
|
|
|
34
35
|
const query = `query {
|
|
35
36
|
repository(owner: "${urlOwner}", name: "${urlRepo}") {
|
|
36
37
|
discussion(number: ${discussionNumber}) {
|
|
38
|
+
id
|
|
37
39
|
title
|
|
38
40
|
body
|
|
39
41
|
comments(last: 10) {
|
|
@@ -48,6 +50,7 @@ export async function discussions(context) {
|
|
|
48
50
|
}`;
|
|
49
51
|
const result = await octokit.graphql(query);
|
|
50
52
|
const discussion = result.repository.discussion;
|
|
53
|
+
discussionNodeId = discussion.id || "";
|
|
51
54
|
discussionTitle = discussion.title || "";
|
|
52
55
|
discussionBody = discussion.body || "";
|
|
53
56
|
discussionComments = discussion.comments.nodes || [];
|
|
@@ -128,6 +131,28 @@ export async function discussions(context) {
|
|
|
128
131
|
|
|
129
132
|
core.info(`Discussion bot action: ${action}, arg: ${actionArg}`);
|
|
130
133
|
|
|
134
|
+
// Post reply comment back to the Discussion
|
|
135
|
+
if (discussionNodeId && replyBody) {
|
|
136
|
+
try {
|
|
137
|
+
const mutation = `mutation($discussionId: ID!, $body: String!) {
|
|
138
|
+
addDiscussionComment(input: { discussionId: $discussionId, body: $body }) {
|
|
139
|
+
comment { url }
|
|
140
|
+
}
|
|
141
|
+
}`;
|
|
142
|
+
const { addDiscussionComment } = await octokit.graphql(mutation, {
|
|
143
|
+
discussionId: discussionNodeId,
|
|
144
|
+
body: replyBody,
|
|
145
|
+
});
|
|
146
|
+
core.info(`Posted reply to discussion: ${addDiscussionComment.comment.url}`);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
core.warning(`Failed to post discussion reply: ${err.message}`);
|
|
149
|
+
}
|
|
150
|
+
} else if (!discussionNodeId) {
|
|
151
|
+
core.warning("Cannot post reply: discussion node ID not available");
|
|
152
|
+
} else if (!replyBody) {
|
|
153
|
+
core.warning("Cannot post reply: no reply content generated");
|
|
154
|
+
}
|
|
155
|
+
|
|
131
156
|
const argSuffix = actionArg ? ` (${actionArg})` : "";
|
|
132
157
|
return {
|
|
133
158
|
outcome: `discussion-${action}`,
|
|
@@ -25,7 +25,7 @@ on:
|
|
|
25
25
|
workflow_dispatch:
|
|
26
26
|
|
|
27
27
|
permissions:
|
|
28
|
-
contents:
|
|
28
|
+
contents: read
|
|
29
29
|
issues: write
|
|
30
30
|
discussions: write
|
|
31
31
|
|
|
@@ -70,9 +70,3 @@ jobs:
|
|
|
70
70
|
config: ${{ env.configPath }}
|
|
71
71
|
instructions: ".github/agentic-lib/agents/agent-discussion-bot.md"
|
|
72
72
|
discussion-url: ${{ steps.discussion-url.outputs.url }}
|
|
73
|
-
|
|
74
|
-
- name: Commit activity log changes
|
|
75
|
-
uses: ./.github/agentic-lib/actions/commit-if-changed
|
|
76
|
-
with:
|
|
77
|
-
commit-message: "agentic-step: discussions bot response"
|
|
78
|
-
push-ref: ${{ github.ref_name }}
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
github.event_name == 'workflow_dispatch' ||
|
|
37
37
|
(github.event_name == 'check_suite' &&
|
|
38
38
|
github.event.check_suite.conclusion == 'failure' &&
|
|
39
|
-
(startsWith(github.event.check_suite.head_branch, 'agentic-lib-
|
|
39
|
+
(startsWith(github.event.check_suite.head_branch, 'agentic-lib-') ||
|
|
40
40
|
startsWith(github.event.check_suite.head_branch, 'copilot/')))
|
|
41
41
|
runs-on: ubuntu-latest
|
|
42
42
|
outputs:
|
|
@@ -25,7 +25,7 @@ on:
|
|
|
25
25
|
|
|
26
26
|
env:
|
|
27
27
|
pullRequestLabel: "automerge"
|
|
28
|
-
branchPrefix: "agentic-lib-
|
|
28
|
+
branchPrefix: "agentic-lib-"
|
|
29
29
|
copilotBranchPrefix: "copilot/"
|
|
30
30
|
|
|
31
31
|
jobs:
|
|
@@ -240,7 +240,7 @@ jobs:
|
|
|
240
240
|
branchName = pullRequest.head.ref;
|
|
241
241
|
core.info(`branchName '${branchName}'`);
|
|
242
242
|
|
|
243
|
-
// Extract issue number from branch name (supports agentic-lib
|
|
243
|
+
// Extract issue number from branch name (supports agentic-lib-* and copilot/* prefixes)
|
|
244
244
|
let issueNumberMatch = '';
|
|
245
245
|
if (branchName.startsWith(branchPrefix)) {
|
|
246
246
|
issueNumberMatch = branchName.replace(branchPrefix, '');
|
|
@@ -445,100 +445,3 @@ jobs:
|
|
|
445
445
|
owner, repo, issue_number: issueNumber, name: 'in-progress',
|
|
446
446
|
});
|
|
447
447
|
}
|
|
448
|
-
|
|
449
|
-
log-intention-activity-merge-pr:
|
|
450
|
-
needs:
|
|
451
|
-
- merge-check
|
|
452
|
-
- automerge
|
|
453
|
-
if: ${{ !cancelled() && needs.merge-check.outputs.shouldSkipMerge != 'true' && needs.merge-check.outputs.pullNumber != '' }}
|
|
454
|
-
runs-on: ubuntu-latest
|
|
455
|
-
env:
|
|
456
|
-
gitUserEmail: "action@github.com"
|
|
457
|
-
gitUserName: "GitHub Actions[bot]"
|
|
458
|
-
steps:
|
|
459
|
-
- uses: actions/checkout@v4
|
|
460
|
-
with:
|
|
461
|
-
fetch-depth: 0
|
|
462
|
-
ref: main
|
|
463
|
-
|
|
464
|
-
- name: Load config
|
|
465
|
-
id: config
|
|
466
|
-
run: |
|
|
467
|
-
CONFIG="${{ vars.configPath || '.github/agentic-lib/agents/agentic-lib.yml' }}"
|
|
468
|
-
echo "intentionFilepath=$(yq -r '.intentionBot.intentionFilepath // "intentïon.md"' "$CONFIG")" >> $GITHUB_OUTPUT
|
|
469
|
-
|
|
470
|
-
- name: Get latest from remote
|
|
471
|
-
run: |
|
|
472
|
-
git config --local user.email '${{ env.gitUserEmail }}'
|
|
473
|
-
git config --local user.name '${{ env.gitUserName }}'
|
|
474
|
-
git config --local pull.ff false # never fast-forward
|
|
475
|
-
git config --local pull.rebase false # never rebase on pull
|
|
476
|
-
git fetch origin main
|
|
477
|
-
git merge origin/main --no-ff --no-edit --strategy=recursive --strategy-option=ours
|
|
478
|
-
|
|
479
|
-
- name: log-intention-activity
|
|
480
|
-
id: log-intention-activity
|
|
481
|
-
uses: actions/github-script@v7
|
|
482
|
-
env:
|
|
483
|
-
pullNumber: ${{ needs.merge-check.outputs.pullNumber }}
|
|
484
|
-
shouldSkipMerge: ${{ needs.merge-check.outputs.shouldSkipMerge }}
|
|
485
|
-
branchName: ${{ needs.merge-check.outputs.branchName }}
|
|
486
|
-
issueNumber: ${{ needs.merge-check.outputs.issueNumber }}
|
|
487
|
-
prMerged: ${{ needs.automerge.outputs.prMerged }}
|
|
488
|
-
message: ${{ needs.automerge.outputs.message }}
|
|
489
|
-
outcome: ${{ needs.automerge.result }}
|
|
490
|
-
intentionFilepath: ${{ steps.config.outputs.intentionFilepath }}
|
|
491
|
-
with:
|
|
492
|
-
script: |
|
|
493
|
-
const pullNumber = process.env.pullNumber;
|
|
494
|
-
const shouldSkipMerge = process.env.shouldSkipMerge;
|
|
495
|
-
const branchName = process.env.branchName;
|
|
496
|
-
const issueNumber = process.env.issueNumber;
|
|
497
|
-
const prMerged = process.env.prMerged;
|
|
498
|
-
const message = process.env.message;
|
|
499
|
-
const outcome = process.env.outcome;
|
|
500
|
-
const intentionFilepath = process.env.intentionFilepath;
|
|
501
|
-
|
|
502
|
-
const activity = `When attempting to merge PR #${pullNumber} for branch name "${branchName}" to resolve issue number "${issueNumber}" the decision to skip merge was "${shouldSkipMerge}":
|
|
503
|
-
|
|
504
|
-
then the PR was merged "${prMerged}"
|
|
505
|
-
|
|
506
|
-
with message: "${message}"
|
|
507
|
-
|
|
508
|
-
with outcome "${outcome}".`;
|
|
509
|
-
|
|
510
|
-
core.info(`Activity: ${activity}`);
|
|
511
|
-
core.info(`Seed discussion filepath: ${intentionFilepath}`);
|
|
512
|
-
|
|
513
|
-
const fs = require('fs');
|
|
514
|
-
const path = require('path');
|
|
515
|
-
|
|
516
|
-
// Create trace file and the parent directory of intentionFilepath if it doesn't exist
|
|
517
|
-
if (!fs.existsSync(path.dirname(intentionFilepath))) {
|
|
518
|
-
fs.mkdirSync(path.dirname(intentionFilepath), { recursive: true });
|
|
519
|
-
}
|
|
520
|
-
const isoDate = new Date().toISOString();
|
|
521
|
-
const activityLogContent = `\n## Merge PR activity at ${isoDate}
|
|
522
|
-
|
|
523
|
-
${activity}
|
|
524
|
-
|
|
525
|
-
---
|
|
526
|
-
`;
|
|
527
|
-
if (fs.existsSync(intentionFilepath)) {
|
|
528
|
-
fs.appendFileSync(intentionFilepath, activityLogContent);
|
|
529
|
-
} else {
|
|
530
|
-
fs.writeFileSync(intentionFilepath, activityLogContent);
|
|
531
|
-
}
|
|
532
|
-
core.info(`Activity logged to ${intentionFilepath}`);
|
|
533
|
-
|
|
534
|
-
- name: Commit changes
|
|
535
|
-
run: |
|
|
536
|
-
git config --local user.email '${{ env.gitUserEmail }}'
|
|
537
|
-
git config --local user.name '${{ env.gitUserName }}'
|
|
538
|
-
git config --local pull.ff false # never fast-forward
|
|
539
|
-
git config --local pull.rebase false # never rebase on pull
|
|
540
|
-
git add ${{ steps.config.outputs.intentionFilepath }}
|
|
541
|
-
git commit -m "Activity logged by ci-automerge.yml" || echo "No changes to commit"
|
|
542
|
-
git fetch origin main
|
|
543
|
-
git merge origin/main --no-ff --no-edit --strategy=recursive --strategy-option=ours
|
|
544
|
-
git push -v origin main
|