@xn-intenton-z2a/agentic-lib 7.1.22 → 7.1.23
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/bin/agentic-lib.js +36 -0
- package/package.json +1 -1
- package/src/actions/agentic-step/config-loader.js +1 -0
- package/src/actions/agentic-step/tasks/discussions.js +58 -25
- package/src/agents/agent-discussion-bot.md +42 -35
- package/src/seeds/zero-agentic-lib.toml +7 -1
- package/src/seeds/zero-package.json +1 -1
- package/src/workflows/agent-supervisor-schedule.yml +83 -0
package/bin/agentic-lib.js
CHANGED
|
@@ -786,6 +786,42 @@ function initReseed() {
|
|
|
786
786
|
|
|
787
787
|
function initPurge(seedsDir) {
|
|
788
788
|
console.log("\n--- Purge: Reset Source Files to Seed State ---");
|
|
789
|
+
|
|
790
|
+
// Read TOML to get source and tests paths (or use defaults)
|
|
791
|
+
let sourcePath = "src/lib/";
|
|
792
|
+
let testsPath = "tests/unit/";
|
|
793
|
+
const tomlTarget = resolve(target, "agentic-lib.toml");
|
|
794
|
+
if (existsSync(tomlTarget)) {
|
|
795
|
+
try {
|
|
796
|
+
const tomlContent = readFileSync(tomlTarget, "utf8");
|
|
797
|
+
const sourceMatch = tomlContent.match(/^source\s*=\s*"([^"]+)"/m);
|
|
798
|
+
const testsMatch = tomlContent.match(/^tests\s*=\s*"([^"]+)"/m);
|
|
799
|
+
if (sourceMatch) sourcePath = sourceMatch[1];
|
|
800
|
+
if (testsMatch) testsPath = testsMatch[1];
|
|
801
|
+
} catch (err) {
|
|
802
|
+
console.log(` WARN: Could not read TOML for paths, using defaults: ${err.message}`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Clear source directory completely
|
|
807
|
+
const sourceDir = resolve(target, sourcePath);
|
|
808
|
+
if (existsSync(sourceDir)) {
|
|
809
|
+
console.log(` CLEAR: ${sourcePath}`);
|
|
810
|
+
if (!dryRun) rmSync(sourceDir, { recursive: true });
|
|
811
|
+
initChanges++;
|
|
812
|
+
}
|
|
813
|
+
if (!dryRun) mkdirSync(sourceDir, { recursive: true });
|
|
814
|
+
|
|
815
|
+
// Clear tests directory completely
|
|
816
|
+
const testsDir = resolve(target, testsPath);
|
|
817
|
+
if (existsSync(testsDir)) {
|
|
818
|
+
console.log(` CLEAR: ${testsPath}`);
|
|
819
|
+
if (!dryRun) rmSync(testsDir, { recursive: true });
|
|
820
|
+
initChanges++;
|
|
821
|
+
}
|
|
822
|
+
if (!dryRun) mkdirSync(testsDir, { recursive: true });
|
|
823
|
+
|
|
824
|
+
// Copy seed files
|
|
789
825
|
const SEED_MAP = {
|
|
790
826
|
"zero-main.js": "src/lib/main.js",
|
|
791
827
|
"zero-main.test.js": "tests/unit/main.test.js",
|
package/package.json
CHANGED
|
@@ -117,6 +117,7 @@ export function loadConfig(configPath) {
|
|
|
117
117
|
|
|
118
118
|
return {
|
|
119
119
|
schedule: toml.schedule?.tier || "schedule-1",
|
|
120
|
+
supervisor: toml.schedule?.supervisor || "daily",
|
|
120
121
|
paths,
|
|
121
122
|
buildScript: execution.build || "npm run build",
|
|
122
123
|
testScript: execution.test || "npm test",
|
|
@@ -9,6 +9,8 @@ import * as core from "@actions/core";
|
|
|
9
9
|
import { existsSync } from "fs";
|
|
10
10
|
import { runCopilotTask, readOptionalFile, scanDirectory } from "../copilot.js";
|
|
11
11
|
|
|
12
|
+
const BOT_LOGINS = ["github-actions[bot]", "github-actions"];
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
15
|
* Respond to a GitHub Discussion using the Copilot SDK.
|
|
14
16
|
*
|
|
@@ -64,6 +66,16 @@ export async function discussions(context) {
|
|
|
64
66
|
core.warning(`Could not parse discussion URL: ${discussionUrl}`);
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
// Separate human comments from bot's own replies
|
|
70
|
+
const humanComments = discussionComments.filter(
|
|
71
|
+
(c) => !BOT_LOGINS.includes(c.author?.login),
|
|
72
|
+
);
|
|
73
|
+
const botReplies = discussionComments.filter(
|
|
74
|
+
(c) => BOT_LOGINS.includes(c.author?.login),
|
|
75
|
+
);
|
|
76
|
+
const latestHumanComment = humanComments.length > 0 ? humanComments[humanComments.length - 1] : null;
|
|
77
|
+
const lastBotReply = botReplies.length > 0 ? botReplies[botReplies.length - 1] : null;
|
|
78
|
+
|
|
67
79
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
68
80
|
const contributing = readOptionalFile(config.paths.contributing.path, 1000);
|
|
69
81
|
|
|
@@ -78,47 +90,68 @@ export async function discussions(context) {
|
|
|
78
90
|
|
|
79
91
|
const agentInstructions = instructions || "Respond to the GitHub Discussion as the repository bot.";
|
|
80
92
|
|
|
81
|
-
|
|
93
|
+
// Build thread-aware prompt
|
|
94
|
+
const promptParts = [
|
|
82
95
|
"## Instructions",
|
|
83
96
|
agentInstructions,
|
|
84
97
|
"",
|
|
85
|
-
"## Discussion",
|
|
98
|
+
"## Discussion Thread",
|
|
86
99
|
`URL: ${discussionUrl}`,
|
|
87
100
|
discussionTitle ? `### ${discussionTitle}` : "",
|
|
88
101
|
discussionBody || "(no body)",
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
// Show conversation history (human comments only, with timestamps)
|
|
105
|
+
if (humanComments.length > 0) {
|
|
106
|
+
promptParts.push("", "### Conversation History");
|
|
107
|
+
for (const c of humanComments) {
|
|
108
|
+
const isLatest = c === latestHumanComment;
|
|
109
|
+
const prefix = isLatest ? ">>> **[LATEST — RESPOND TO THIS]** " : "";
|
|
110
|
+
promptParts.push(`${prefix}**${c.author?.login || "unknown"}** (${c.createdAt}):\n${c.body}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Show the bot's last reply so it knows what it already said
|
|
115
|
+
if (lastBotReply) {
|
|
116
|
+
promptParts.push(
|
|
117
|
+
"",
|
|
118
|
+
"### Your Last Reply (DO NOT REPEAT THIS)",
|
|
119
|
+
lastBotReply.body.substring(0, 500),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Context section
|
|
124
|
+
promptParts.push(
|
|
91
125
|
"",
|
|
92
|
-
"## Context",
|
|
126
|
+
"## Repository Context",
|
|
93
127
|
`### Mission\n${mission}`,
|
|
94
128
|
contributing ? `### Contributing\n${contributing}` : "",
|
|
95
129
|
`### Current Features\n${featureNames.join(", ") || "none"}`,
|
|
96
130
|
recentActivity ? `### Recent Activity\n${recentActivity}` : "",
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Actions — concise, not a wall of text
|
|
134
|
+
promptParts.push(
|
|
97
135
|
"",
|
|
98
|
-
"##
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"",
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"If the user requests something that contradicts or would undermine the mission,",
|
|
113
|
-
"you MUST push back. Explain why the request conflicts with the mission and suggest",
|
|
114
|
-
"an alternative that aligns with it. Use `[ACTION:nop]` in this case.",
|
|
115
|
-
"The mission is the non-negotiable foundation of this repository.",
|
|
116
|
-
].join("\n");
|
|
136
|
+
"## Actions",
|
|
137
|
+
"Include exactly one action tag in your response. Only mention actions to the user when relevant.",
|
|
138
|
+
"`[ACTION:request-supervisor] <free text>` — Ask the supervisor to evaluate and act on a user request",
|
|
139
|
+
"`[ACTION:create-feature] <name>` — Create a new feature",
|
|
140
|
+
"`[ACTION:update-feature] <name>` — Update an existing feature",
|
|
141
|
+
"`[ACTION:delete-feature] <name>` — Delete a feature",
|
|
142
|
+
"`[ACTION:create-issue] <title>` — Create a new issue",
|
|
143
|
+
"`[ACTION:seed-repository]` — Reset to initial state",
|
|
144
|
+
"`[ACTION:nop]` — No action needed, just respond conversationally",
|
|
145
|
+
"`[ACTION:mission-complete]` — Declare mission complete",
|
|
146
|
+
"`[ACTION:stop]` — Halt automation",
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const prompt = promptParts.filter(Boolean).join("\n");
|
|
117
150
|
|
|
118
151
|
const { content, tokensUsed } = await runCopilotTask({
|
|
119
152
|
model,
|
|
120
153
|
systemMessage:
|
|
121
|
-
"You are
|
|
154
|
+
"You are this repository. Respond in first person. Be concise and engaging — never repeat what you said in your last reply. Adapt to the user's language level. Encourage experimentation and suggest interesting projects. When a user requests an action, pass it to the supervisor via [ACTION:request-supervisor]. Protect the mission: push back on requests that contradict it.",
|
|
122
155
|
prompt,
|
|
123
156
|
writablePaths: [],
|
|
124
157
|
});
|
|
@@ -1,35 +1,42 @@
|
|
|
1
|
-
You are the voice of
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
to the
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
You are the voice of this GitHub repository. You exist as this repository — refer to yourself in the first person.
|
|
2
|
+
|
|
3
|
+
## Core Behaviour
|
|
4
|
+
|
|
5
|
+
- **Be concise.** Do NOT repeat information from your previous replies. If you already explained something, don't explain it again.
|
|
6
|
+
- **Read the thread.** Pay close attention to the full conversation history. Respond specifically to the latest human message, not to the general topic.
|
|
7
|
+
- **Adapt to the user.** Match the user's language level, tone, and engagement style. If they're technical, be technical. If they're casual, be casual. If they're a beginner, be welcoming and encouraging.
|
|
8
|
+
- **Be engaging.** Suggest interesting experiments, projects, or changes the user might enjoy. Encourage them to try things and ask questions.
|
|
9
|
+
- **Don't dump capabilities.** Only mention specific actions when they're relevant to what the user is asking about. Don't list all your actions in every response.
|
|
10
|
+
|
|
11
|
+
## Mission Alignment
|
|
12
|
+
|
|
13
|
+
Your mission comes from MISSION.md. Everything you do should serve that mission.
|
|
14
|
+
- If a user requests something that contradicts the mission, push back politely and suggest an aligned alternative.
|
|
15
|
+
- Be proactive about suggesting features that advance the mission without needing to be asked.
|
|
16
|
+
|
|
17
|
+
## Supervisor Integration
|
|
18
|
+
|
|
19
|
+
You work with a supervisor system that orchestrates the repository's workflows. When a user requests an action:
|
|
20
|
+
1. Acknowledge the request
|
|
21
|
+
2. Explain that you'll pass it to the supervisor for evaluation
|
|
22
|
+
3. The supervisor will decide what workflows to run and may respond back through you
|
|
23
|
+
|
|
24
|
+
You can request the supervisor to:
|
|
25
|
+
- Start code transformations (pick up issues, generate code)
|
|
26
|
+
- Maintain features and library documentation
|
|
27
|
+
- Review and close issues
|
|
28
|
+
- Fix failing PRs
|
|
29
|
+
- Create new issues from feature ideas
|
|
30
|
+
|
|
31
|
+
When relaying supervisor responses back to the user, present them naturally as your own awareness of what's happening in the repository.
|
|
32
|
+
|
|
33
|
+
## Conversation Style
|
|
34
|
+
|
|
35
|
+
- Use previous interactions to build rapport — reference things the user mentioned before
|
|
36
|
+
- If you asked a question previously that wasn't answered, you may follow up on it if still relevant
|
|
37
|
+
- Adjust focus throughout the conversation: open up to explore ideas, narrow down to solve specific problems
|
|
38
|
+
- If another user is mentioned with "@", assume part of the message is for them and you're on "cc"
|
|
39
|
+
|
|
40
|
+
## Repository Context
|
|
41
|
+
|
|
42
|
+
Use the contextual information provided (files, commit history, feature list, recent activity) to give informed, specific answers rather than generic ones. Reference actual state when answering questions about progress.
|
|
@@ -6,16 +6,20 @@
|
|
|
6
6
|
# Place it at the root of your project.
|
|
7
7
|
|
|
8
8
|
[schedule]
|
|
9
|
-
tier = "schedule-1"
|
|
9
|
+
tier = "schedule-1" # schedule-1 through schedule-4
|
|
10
|
+
supervisor = "daily" # off | weekly | daily | hourly | continuous
|
|
10
11
|
|
|
11
12
|
[paths]
|
|
12
13
|
mission = "MISSION.md"
|
|
13
14
|
source = "src/lib/"
|
|
14
15
|
tests = "tests/unit/"
|
|
15
16
|
features = "features/"
|
|
17
|
+
library = "library/"
|
|
16
18
|
docs = "docs/"
|
|
17
19
|
readme = "README.md"
|
|
18
20
|
dependencies = "package.json"
|
|
21
|
+
contributing = "CONTRIBUTING.md"
|
|
22
|
+
library-sources = "SOURCES.md"
|
|
19
23
|
|
|
20
24
|
[execution]
|
|
21
25
|
build = "npm run build"
|
|
@@ -27,6 +31,8 @@ feature-issues = 2
|
|
|
27
31
|
maintenance-issues = 1
|
|
28
32
|
attempts-per-branch = 3
|
|
29
33
|
attempts-per-issue = 2
|
|
34
|
+
features-limit = 4
|
|
35
|
+
library-limit = 32
|
|
30
36
|
|
|
31
37
|
[bot]
|
|
32
38
|
log-file = "intentïon.md"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (C) 2025-2026 Polycode Limited
|
|
3
|
+
# .github/workflows/agent-supervisor-schedule.yml
|
|
4
|
+
#
|
|
5
|
+
# Changes the agent-supervisor's cron schedule by editing the workflow file
|
|
6
|
+
# directly and pushing to main. This is the control plane for how often
|
|
7
|
+
# the supervisor runs proactively.
|
|
8
|
+
|
|
9
|
+
name: agent-supervisor-schedule
|
|
10
|
+
run-name: "agent-supervisor-schedule → ${{ inputs.frequency }}"
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
inputs:
|
|
15
|
+
frequency:
|
|
16
|
+
description: "How often the supervisor should run"
|
|
17
|
+
required: true
|
|
18
|
+
type: choice
|
|
19
|
+
options:
|
|
20
|
+
- "off"
|
|
21
|
+
- "weekly"
|
|
22
|
+
- "daily"
|
|
23
|
+
- "hourly"
|
|
24
|
+
- "continuous"
|
|
25
|
+
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
update-schedule:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
with:
|
|
35
|
+
ref: main
|
|
36
|
+
|
|
37
|
+
- name: Update supervisor schedule
|
|
38
|
+
uses: actions/github-script@v7
|
|
39
|
+
with:
|
|
40
|
+
script: |
|
|
41
|
+
const fs = require('fs');
|
|
42
|
+
const frequency = '${{ inputs.frequency }}';
|
|
43
|
+
const workflowPath = '.github/workflows/agent-supervisor.yml';
|
|
44
|
+
|
|
45
|
+
const SCHEDULE_MAP = {
|
|
46
|
+
off: null,
|
|
47
|
+
weekly: '0 6 * * 1',
|
|
48
|
+
daily: '0 6 * * *',
|
|
49
|
+
hourly: '0 * * * *',
|
|
50
|
+
continuous: '*/10 * * * *',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
let content = fs.readFileSync(workflowPath, 'utf8');
|
|
54
|
+
const cron = SCHEDULE_MAP[frequency];
|
|
55
|
+
|
|
56
|
+
// Remove any existing schedule block (between 'on:' triggers)
|
|
57
|
+
// The schedule block looks like:
|
|
58
|
+
// schedule:
|
|
59
|
+
// - cron: "..."
|
|
60
|
+
content = content.replace(/\n schedule:\n - cron: "[^"]*"\n/g, '\n');
|
|
61
|
+
|
|
62
|
+
if (cron) {
|
|
63
|
+
// Insert schedule block after the 'on:' line
|
|
64
|
+
const scheduleBlock = `\n schedule:\n - cron: "${cron}"\n`;
|
|
65
|
+
// Insert before workflow_run or workflow_dispatch (whichever comes first after 'on:')
|
|
66
|
+
content = content.replace(
|
|
67
|
+
/\non:\n/,
|
|
68
|
+
`\non:${scheduleBlock}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fs.writeFileSync(workflowPath, content);
|
|
73
|
+
core.info(`Updated supervisor schedule to: ${frequency} (cron: ${cron || 'none'})`);
|
|
74
|
+
|
|
75
|
+
- name: Commit and push
|
|
76
|
+
run: |
|
|
77
|
+
git config user.name "github-actions[bot]"
|
|
78
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
79
|
+
FREQUENCY="${{ inputs.frequency }}"
|
|
80
|
+
git add .github/workflows/agent-supervisor.yml
|
|
81
|
+
git diff --cached --quiet && echo "No changes to commit" && exit 0
|
|
82
|
+
git commit -m "supervisor: set schedule to ${FREQUENCY}"
|
|
83
|
+
git push origin main
|