@xn-intenton-z2a/agentic-lib 7.4.32 → 7.4.34
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 +12 -10
- package/.github/workflows/agentic-lib-schedule.yml +128 -56
- package/.github/workflows/agentic-lib-test.yml +1 -1
- package/.github/workflows/agentic-lib-workflow.yml +30 -2
- package/agentic-lib.toml +22 -2
- package/bin/agentic-lib.js +166 -19
- package/package.json +1 -1
- package/src/actions/agentic-step/tasks/direct.js +19 -11
- package/src/actions/agentic-step/tasks/implementation-review.js +66 -15
- package/src/actions/agentic-step/tasks/maintain-features.js +5 -0
- package/src/actions/agentic-step/tasks/review-issue.js +13 -2
- package/src/actions/agentic-step/tasks/transform.js +18 -0
- package/src/copilot/config.js +17 -3
- package/src/copilot/telemetry.js +18 -1
- package/src/seeds/zero-MISSION.md +14 -14
- package/src/seeds/zero-README.md +106 -65
- package/src/seeds/zero-package.json +1 -1
|
@@ -19,7 +19,7 @@ on:
|
|
|
19
19
|
mode:
|
|
20
20
|
type: string
|
|
21
21
|
required: false
|
|
22
|
-
default: "
|
|
22
|
+
default: "purge"
|
|
23
23
|
dry-run:
|
|
24
24
|
type: string
|
|
25
25
|
required: false
|
|
@@ -27,7 +27,7 @@ on:
|
|
|
27
27
|
mission-seed:
|
|
28
28
|
type: string
|
|
29
29
|
required: false
|
|
30
|
-
default: "
|
|
30
|
+
default: "7-kyu-understand-fizz-buzz"
|
|
31
31
|
mission-text:
|
|
32
32
|
type: string
|
|
33
33
|
required: false
|
|
@@ -58,11 +58,11 @@ on:
|
|
|
58
58
|
description: "Init mode"
|
|
59
59
|
type: choice
|
|
60
60
|
required: false
|
|
61
|
-
default: "
|
|
61
|
+
default: "purge"
|
|
62
62
|
options:
|
|
63
|
-
- update
|
|
64
|
-
- reseed
|
|
65
63
|
- purge
|
|
64
|
+
- reseed
|
|
65
|
+
- update
|
|
66
66
|
dry-run:
|
|
67
67
|
description: "Preview changes without writing files"
|
|
68
68
|
type: boolean
|
|
@@ -72,8 +72,10 @@ on:
|
|
|
72
72
|
description: "Mission seed name (purge only)"
|
|
73
73
|
type: choice
|
|
74
74
|
required: false
|
|
75
|
-
default: "
|
|
75
|
+
default: "7-kyu-understand-fizz-buzz"
|
|
76
76
|
options:
|
|
77
|
+
- random
|
|
78
|
+
- generate
|
|
77
79
|
- 8-kyu-remember-empty
|
|
78
80
|
- 8-kyu-remember-hello-world
|
|
79
81
|
- 7-kyu-understand-fizz-buzz
|
|
@@ -158,7 +160,7 @@ jobs:
|
|
|
158
160
|
with:
|
|
159
161
|
script: |
|
|
160
162
|
core.setOutput('dry-run', context.payload.inputs?.['dry-run'] || 'false');
|
|
161
|
-
core.setOutput('mission', context.payload.inputs?.['mission-seed'] || '
|
|
163
|
+
core.setOutput('mission', context.payload.inputs?.['mission-seed'] || '7-kyu-understand-fizz-buzz');
|
|
162
164
|
core.setOutput('profile', context.payload.inputs?.['profile'] || '');
|
|
163
165
|
core.setOutput('model', context.payload.inputs?.['model'] || '');
|
|
164
166
|
core.setOutput('create-seed-issues', context.payload.inputs?.['create-seed-issues'] || 'false');
|
|
@@ -171,18 +173,18 @@ jobs:
|
|
|
171
173
|
with:
|
|
172
174
|
ref: ${{ inputs.ref }}
|
|
173
175
|
dry-run: ${{ inputs.dry-run || 'false' }}
|
|
174
|
-
skip-tests: ${{ inputs.mode
|
|
176
|
+
skip-tests: ${{ inputs.mode != 'update' }}
|
|
175
177
|
secrets: inherit
|
|
176
178
|
|
|
177
179
|
# Step 2: Reseed/purge and configure (only if mode != update)
|
|
178
180
|
# Use !cancelled() so purge runs even if update's npm test failed
|
|
179
181
|
init:
|
|
180
182
|
needs: [params, update]
|
|
181
|
-
if: "!cancelled() &&
|
|
183
|
+
if: "!cancelled() && inputs.mode != 'update'"
|
|
182
184
|
runs-on: ubuntu-latest
|
|
183
185
|
env:
|
|
184
186
|
INIT_MODE: ${{ inputs.mode }}
|
|
185
|
-
INIT_MISSION_SEED: ${{ inputs.mission-seed || '
|
|
187
|
+
INIT_MISSION_SEED: ${{ inputs.mission-seed || '7-kyu-understand-fizz-buzz' }}
|
|
186
188
|
INIT_MISSION_TEXT: ${{ inputs.mission-text }}
|
|
187
189
|
steps:
|
|
188
190
|
- uses: actions/checkout@v6
|
|
@@ -18,9 +18,10 @@ on:
|
|
|
18
18
|
required: false
|
|
19
19
|
default: ""
|
|
20
20
|
frequency:
|
|
21
|
-
description: "How often the workflow should run"
|
|
22
|
-
required:
|
|
21
|
+
description: "How often the workflow should run (empty = read from agentic-lib.toml)"
|
|
22
|
+
required: false
|
|
23
23
|
type: string
|
|
24
|
+
default: ""
|
|
24
25
|
model:
|
|
25
26
|
description: "Copilot SDK model to use"
|
|
26
27
|
required: false
|
|
@@ -39,16 +40,27 @@ on:
|
|
|
39
40
|
workflow_dispatch:
|
|
40
41
|
inputs:
|
|
41
42
|
frequency:
|
|
42
|
-
description: "How often the workflow should run (maintenance = weekly + remove mission-complete + unlimited budget)"
|
|
43
|
-
required:
|
|
43
|
+
description: "How often the workflow should run (empty = read from agentic-lib.toml, maintenance = weekly + remove mission-complete + unlimited budget)"
|
|
44
|
+
required: false
|
|
44
45
|
type: choice
|
|
46
|
+
default: ""
|
|
45
47
|
options:
|
|
48
|
+
- ""
|
|
46
49
|
- "off"
|
|
47
50
|
- "maintenance"
|
|
48
51
|
- "weekly"
|
|
49
52
|
- "daily"
|
|
50
53
|
- "hourly"
|
|
51
54
|
- "continuous"
|
|
55
|
+
focus:
|
|
56
|
+
description: "Focus mode (empty = read from agentic-lib.toml)"
|
|
57
|
+
required: false
|
|
58
|
+
type: choice
|
|
59
|
+
default: ""
|
|
60
|
+
options:
|
|
61
|
+
- ""
|
|
62
|
+
- "mission"
|
|
63
|
+
- "maintenance"
|
|
52
64
|
model:
|
|
53
65
|
description: "Copilot SDK model to use (empty = read from agentic-lib.toml)"
|
|
54
66
|
required: false
|
|
@@ -85,16 +97,36 @@ jobs:
|
|
|
85
97
|
frequency: ${{ steps.resolve.outputs.frequency }}
|
|
86
98
|
model: ${{ steps.resolve.outputs.model }}
|
|
87
99
|
profile: ${{ steps.resolve.outputs.profile }}
|
|
100
|
+
focus: ${{ steps.resolve.outputs.focus }}
|
|
88
101
|
maintenance: ${{ steps.resolve.outputs.maintenance }}
|
|
89
102
|
steps:
|
|
103
|
+
- uses: actions/checkout@v6
|
|
104
|
+
with:
|
|
105
|
+
sparse-checkout: agentic-lib.toml
|
|
106
|
+
sparse-checkout-cone-mode: false
|
|
90
107
|
- id: resolve
|
|
91
108
|
uses: actions/github-script@v8
|
|
92
109
|
with:
|
|
93
110
|
script: |
|
|
94
|
-
const
|
|
111
|
+
const fs = require('fs');
|
|
112
|
+
const tomlPath = 'agentic-lib.toml';
|
|
113
|
+
let tomlContent = '';
|
|
114
|
+
if (fs.existsSync(tomlPath)) tomlContent = fs.readFileSync(tomlPath, 'utf8');
|
|
115
|
+
const readToml = (key) => {
|
|
116
|
+
const m = tomlContent.match(new RegExp(`^\\s*${key}\\s*=\\s*"([^"]*)"`, 'm'));
|
|
117
|
+
return m ? m[1] : '';
|
|
118
|
+
};
|
|
119
|
+
let frequency = context.payload.inputs?.['frequency'] || '';
|
|
120
|
+
if (!frequency) frequency = readToml('supervisor') || 'off';
|
|
121
|
+
const model = context.payload.inputs?.['model'] || '';
|
|
122
|
+
const profile = context.payload.inputs?.['profile'] || '';
|
|
123
|
+
let focus = context.payload.inputs?.['focus'] || '';
|
|
124
|
+
if (!focus) focus = readToml('focus') || 'mission';
|
|
125
|
+
if (frequency === 'maintenance') focus = 'maintenance';
|
|
95
126
|
core.setOutput('frequency', frequency);
|
|
96
|
-
core.setOutput('model',
|
|
97
|
-
core.setOutput('profile',
|
|
127
|
+
core.setOutput('model', model);
|
|
128
|
+
core.setOutput('profile', profile);
|
|
129
|
+
core.setOutput('focus', focus);
|
|
98
130
|
core.setOutput('maintenance', frequency === 'maintenance' ? 'true' : 'false');
|
|
99
131
|
|
|
100
132
|
update-schedule:
|
|
@@ -116,8 +148,8 @@ jobs:
|
|
|
116
148
|
with:
|
|
117
149
|
script: |
|
|
118
150
|
const fs = require('fs');
|
|
119
|
-
const frequency = '${{
|
|
120
|
-
const
|
|
151
|
+
const frequency = '${{ needs.params.outputs.frequency }}';
|
|
152
|
+
const focus = '${{ needs.params.outputs.focus }}';
|
|
121
153
|
const tomlPath = 'agentic-lib.toml';
|
|
122
154
|
let model = '${{ inputs.model }}';
|
|
123
155
|
if (!model && fs.existsSync(tomlPath)) {
|
|
@@ -126,75 +158,107 @@ jobs:
|
|
|
126
158
|
if (m) model = m[1];
|
|
127
159
|
}
|
|
128
160
|
if (!model) model = 'gpt-5-mini';
|
|
129
|
-
|
|
161
|
+
let profile = '${{ inputs.profile }}';
|
|
162
|
+
if (!profile && fs.existsSync(tomlPath)) {
|
|
163
|
+
const toml = fs.readFileSync(tomlPath, 'utf8');
|
|
164
|
+
const m = toml.match(/^\s*profile\s*=\s*"([^"]*)"/m);
|
|
165
|
+
if (m) profile = m[1];
|
|
166
|
+
}
|
|
130
167
|
|
|
131
168
|
const isMaintenance = frequency === 'maintenance';
|
|
132
169
|
const effectiveFrequency = isMaintenance ? 'weekly' : frequency;
|
|
133
170
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
// Proportional schedule maps for each workflow
|
|
172
|
+
const WORKFLOW_SCHEDULE_MAP = {
|
|
173
|
+
off: '0 0 31 2 *',
|
|
174
|
+
weekly: '25 6 * * 1', // Monday 6:25am
|
|
175
|
+
daily: '25 6 * * *', // Every day 6:25am
|
|
176
|
+
hourly: '25 * * * *', // Every hour at :25
|
|
177
|
+
continuous: '5,25,45 * * * *', // Every 20 min
|
|
178
|
+
};
|
|
179
|
+
const INIT_SCHEDULE_MAP = {
|
|
180
|
+
off: '0 0 31 2 *',
|
|
181
|
+
weekly: '0 4 1 * *', // 1st of month 4:00am
|
|
182
|
+
daily: '0 4 * * 1', // Monday 4:00am
|
|
183
|
+
hourly: '0 4 * * *', // Every day 4:00am
|
|
184
|
+
continuous: '0 1,5,9,13,17,21 * * *', // Every 4 hours
|
|
185
|
+
};
|
|
186
|
+
const TEST_SCHEDULE_MAP = {
|
|
137
187
|
off: '0 0 31 2 *',
|
|
138
|
-
weekly: '
|
|
139
|
-
daily: '
|
|
140
|
-
hourly: '
|
|
141
|
-
continuous: '
|
|
188
|
+
weekly: '40 6 * * 1', // Monday 6:40am
|
|
189
|
+
daily: '40 6 * * *', // Every day 6:40am
|
|
190
|
+
hourly: '40 0,4,8,12,16,20 * * *', // Every 4 hours at :40
|
|
191
|
+
continuous: '40 * * * *', // Every hour at :40
|
|
142
192
|
};
|
|
143
193
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
194
|
+
// Helper: update cron in a workflow file
|
|
195
|
+
function updateWorkflowCron(path, cron, label) {
|
|
196
|
+
if (!fs.existsSync(path)) {
|
|
197
|
+
core.info(`${label}: file not found at ${path}, skipping`);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
let content = fs.readFileSync(path, 'utf8');
|
|
201
|
+
// Remove any duplicate schedule: blocks (keep only the first)
|
|
202
|
+
const dupScheduleRegex = /(\n schedule:\n - cron: "[^"]*"\n)(\s*schedule:\n\s*- cron: "[^"]*"\n)/;
|
|
203
|
+
if (dupScheduleRegex.test(content)) {
|
|
204
|
+
content = content.replace(dupScheduleRegex, '$1');
|
|
205
|
+
core.info(`${label}: removed duplicate schedule block`);
|
|
206
|
+
}
|
|
207
|
+
const cronRegex = /- cron: "[^"]*"/;
|
|
208
|
+
if (cronRegex.test(content)) {
|
|
209
|
+
content = content.replace(cronRegex, `- cron: "${cron}"`);
|
|
210
|
+
} else {
|
|
211
|
+
const scheduleBlock = `\n schedule:\n - cron: "${cron}"\n`;
|
|
212
|
+
content = content.replace(/\non:\n/, `\non:${scheduleBlock}`);
|
|
213
|
+
}
|
|
214
|
+
fs.writeFileSync(path, content);
|
|
215
|
+
core.info(`${label}: set cron to "${cron}"`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const workflowPath = '.github/workflows/agentic-lib-workflow.yml';
|
|
219
|
+
const initPath = '.github/workflows/agentic-lib-init.yml';
|
|
220
|
+
const testPath = '.github/workflows/agentic-lib-test.yml';
|
|
221
|
+
|
|
222
|
+
const workflowCron = WORKFLOW_SCHEDULE_MAP[effectiveFrequency];
|
|
223
|
+
const initCron = INIT_SCHEDULE_MAP[effectiveFrequency];
|
|
224
|
+
const testCron = TEST_SCHEDULE_MAP[effectiveFrequency];
|
|
147
225
|
|
|
148
226
|
// Check if the frequency is already set — skip if no-op (but never skip maintenance)
|
|
149
|
-
// Must check BOTH the config file AND the workflow file to avoid desynchronisation
|
|
150
227
|
const supervisorRegex2 = /^\s*supervisor\s*=\s*"([^"]*)"/m;
|
|
151
228
|
if (!isMaintenance && fs.existsSync(tomlPath)) {
|
|
152
229
|
const currentToml = fs.readFileSync(tomlPath, 'utf8');
|
|
153
230
|
const currentMatch = currentToml.match(supervisorRegex2);
|
|
154
231
|
const currentFreq = currentMatch ? currentMatch[1] : '';
|
|
155
|
-
|
|
232
|
+
const wfContent = fs.existsSync(workflowPath) ? fs.readFileSync(workflowPath, 'utf8') : '';
|
|
156
233
|
const cronRegex = /- cron: "([^"]*)"/;
|
|
157
|
-
const workflowCronMatch =
|
|
234
|
+
const workflowCronMatch = wfContent.match(cronRegex);
|
|
158
235
|
const currentCron = workflowCronMatch ? workflowCronMatch[1] : null;
|
|
159
|
-
const expectedCron = cron; // from SCHEDULE_MAP
|
|
160
236
|
const configMatches = currentFreq === frequency;
|
|
161
|
-
const workflowMatches = currentCron ===
|
|
237
|
+
const workflowMatches = currentCron === workflowCron;
|
|
162
238
|
if (configMatches && workflowMatches) {
|
|
163
239
|
core.info(`Schedule already set to ${frequency} — no change needed`);
|
|
164
240
|
return;
|
|
165
241
|
}
|
|
166
|
-
if (configMatches && !workflowMatches) {
|
|
167
|
-
core.info(`Config says ${frequency} but workflow cron is "${currentCron}" (expected "${expectedCron}") — updating workflow`);
|
|
168
|
-
}
|
|
169
242
|
}
|
|
170
243
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
} else {
|
|
176
|
-
// No schedule block exists — insert one after 'on:'
|
|
177
|
-
const scheduleBlock = `\n schedule:\n - cron: "${cron}"\n`;
|
|
178
|
-
content = content.replace(
|
|
179
|
-
/\non:\n/,
|
|
180
|
-
`\non:${scheduleBlock}`
|
|
181
|
-
);
|
|
182
|
-
}
|
|
244
|
+
// Update all three workflow files proportionally
|
|
245
|
+
updateWorkflowCron(workflowPath, workflowCron, 'workflow');
|
|
246
|
+
updateWorkflowCron(initPath, initCron, 'init');
|
|
247
|
+
updateWorkflowCron(testPath, testCron, 'test');
|
|
183
248
|
|
|
184
|
-
// Stamp the file with current date
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
(match) => match + dateStamp + '\n'
|
|
193
|
-
|
|
249
|
+
// Stamp the workflow file with current date
|
|
250
|
+
if (fs.existsSync(workflowPath)) {
|
|
251
|
+
let content = fs.readFileSync(workflowPath, 'utf8');
|
|
252
|
+
const dateStamp = `# Schedule updated: ${new Date().toISOString()}`;
|
|
253
|
+
const stampRegex = /^# Schedule updated: .*/m;
|
|
254
|
+
if (stampRegex.test(content)) {
|
|
255
|
+
content = content.replace(stampRegex, dateStamp);
|
|
256
|
+
} else {
|
|
257
|
+
content = content.replace(/^(# .*\n)+/m, (match) => match + dateStamp + '\n');
|
|
258
|
+
}
|
|
259
|
+
fs.writeFileSync(workflowPath, content);
|
|
194
260
|
}
|
|
195
|
-
|
|
196
|
-
fs.writeFileSync(workflowPath, content);
|
|
197
|
-
core.info(`Updated workflow schedule to: ${effectiveFrequency} (cron: ${cron || 'none'})`);
|
|
261
|
+
core.info(`Updated proportional schedules: workflow=${effectiveFrequency}, init=${effectiveFrequency}(proportional), test=${effectiveFrequency}(proportional)`);
|
|
198
262
|
|
|
199
263
|
// Maintenance mode: remove mission-complete/failed signals
|
|
200
264
|
if (isMaintenance) {
|
|
@@ -206,7 +270,7 @@ jobs:
|
|
|
206
270
|
}
|
|
207
271
|
}
|
|
208
272
|
|
|
209
|
-
// Update agentic-lib.toml with model and
|
|
273
|
+
// Update agentic-lib.toml with model, supervisor, focus, and profile settings
|
|
210
274
|
if (fs.existsSync(tomlPath)) {
|
|
211
275
|
let toml = fs.readFileSync(tomlPath, 'utf8');
|
|
212
276
|
|
|
@@ -227,6 +291,14 @@ jobs:
|
|
|
227
291
|
toml = toml.replace(scheduleSupervisorRegex, `$1supervisor = "${frequency}"`);
|
|
228
292
|
}
|
|
229
293
|
|
|
294
|
+
// Update focus
|
|
295
|
+
const focusRegex = /^(\s*focus\s*=\s*)"[^"]*"/m;
|
|
296
|
+
if (focusRegex.test(toml)) {
|
|
297
|
+
toml = toml.replace(focusRegex, `$1"${focus}"`);
|
|
298
|
+
} else if (toml.match(/^\[schedule\]/m)) {
|
|
299
|
+
toml = toml.replace(/^(\s*supervisor\s*=\s*"[^"]*".*$)/m, `$1\nfocus = "${focus}"`);
|
|
300
|
+
}
|
|
301
|
+
|
|
230
302
|
if (profile) {
|
|
231
303
|
const profileRegex = /(\[tuning\][^\[]*?)(^\s*profile\s*=\s*"[^"]*")/m;
|
|
232
304
|
if (profileRegex.test(toml)) {
|
|
@@ -244,7 +316,7 @@ jobs:
|
|
|
244
316
|
}
|
|
245
317
|
|
|
246
318
|
fs.writeFileSync(tomlPath, toml);
|
|
247
|
-
core.info(`Updated agentic-lib.toml: model=${model}, supervisor=${frequency}${profile ? ', profile=' + profile : ''}`);
|
|
319
|
+
core.info(`Updated agentic-lib.toml: model=${model}, supervisor=${frequency}, focus=${focus}${profile ? ', profile=' + profile : ''}`);
|
|
248
320
|
} else {
|
|
249
321
|
core.warning('agentic-lib.toml not found — skipping config update');
|
|
250
322
|
}
|
|
@@ -260,7 +332,7 @@ jobs:
|
|
|
260
332
|
git config user.email "${TOKEN_ID}+${TOKEN_USER}@users.noreply.github.com"
|
|
261
333
|
FREQUENCY="${{ inputs.frequency }}"
|
|
262
334
|
MODEL="${{ inputs.model }}"
|
|
263
|
-
git add .github/workflows/agentic-lib-workflow.yml agentic-lib.toml
|
|
335
|
+
git add .github/workflows/agentic-lib-workflow.yml .github/workflows/agentic-lib-init.yml .github/workflows/agentic-lib-test.yml agentic-lib.toml
|
|
264
336
|
# Stage removed mission files ONLY if maintenance mode deleted them
|
|
265
337
|
if [ "$FREQUENCY" = "maintenance" ]; then
|
|
266
338
|
git rm --ignore-unmatch MISSION_COMPLETE.md MISSION_FAILED.md 2>/dev/null || true
|
|
@@ -17,7 +17,7 @@ run-name: "agentic-lib-workflow [${{ github.ref_name }}]"
|
|
|
17
17
|
|
|
18
18
|
on:
|
|
19
19
|
#@dist schedule:
|
|
20
|
-
#@dist - cron: "0
|
|
20
|
+
#@dist - cron: "0 0 31 2 *"
|
|
21
21
|
workflow_call:
|
|
22
22
|
inputs:
|
|
23
23
|
ref:
|
|
@@ -729,11 +729,30 @@ jobs:
|
|
|
729
729
|
echo "- **Features:** ${{ steps.maintain-features.outputs.narrative }}" >> $GITHUB_STEP_SUMMARY
|
|
730
730
|
echo "- **Library:** ${{ steps.maintain-library.outputs.narrative }}" >> $GITHUB_STEP_SUMMARY
|
|
731
731
|
|
|
732
|
+
- name: Check health for commit message
|
|
733
|
+
id: health
|
|
734
|
+
if: github.repository != 'xn-intenton-z2a/agentic-lib' && needs.params.outputs.dry-run != 'true'
|
|
735
|
+
run: |
|
|
736
|
+
if npm ci --ignore-scripts 2>/dev/null; then
|
|
737
|
+
TEST_OUTPUT=$(npm test 2>&1) || true
|
|
738
|
+
PASS_COUNT=$(echo "$TEST_OUTPUT" | grep -oP '\d+ passing' | head -1 || echo "")
|
|
739
|
+
FAIL_COUNT=$(echo "$TEST_OUTPUT" | grep -oP '\d+ failing' | head -1 || echo "")
|
|
740
|
+
if [ -n "$FAIL_COUNT" ]; then
|
|
741
|
+
echo "summary=maintain(features+library): ${PASS_COUNT:-0 passing}, ${FAIL_COUNT} [unstable]" >> $GITHUB_OUTPUT
|
|
742
|
+
elif [ -n "$PASS_COUNT" ]; then
|
|
743
|
+
echo "summary=maintain(features+library): ${PASS_COUNT} [healthy]" >> $GITHUB_OUTPUT
|
|
744
|
+
else
|
|
745
|
+
echo "summary=maintain(features+library): tests completed [healthy]" >> $GITHUB_OUTPUT
|
|
746
|
+
fi
|
|
747
|
+
else
|
|
748
|
+
echo "summary=maintain(features+library): [broken: npm ci failed]" >> $GITHUB_OUTPUT
|
|
749
|
+
fi
|
|
750
|
+
|
|
732
751
|
- name: Commit and push changes
|
|
733
752
|
if: github.repository != 'xn-intenton-z2a/agentic-lib' && needs.params.outputs.dry-run != 'true'
|
|
734
753
|
uses: ./.github/agentic-lib/actions/commit-if-changed
|
|
735
754
|
with:
|
|
736
|
-
commit-message: "agentic-step: maintain features and library"
|
|
755
|
+
commit-message: "${{ steps.health.outputs.summary || 'agentic-step: maintain features and library' }}"
|
|
737
756
|
push-ref: ${{ github.ref_name }}
|
|
738
757
|
fail-on-conflict: "false"
|
|
739
758
|
|
|
@@ -1621,6 +1640,15 @@ jobs:
|
|
|
1621
1640
|
# echo "tests-passed=true" >> $GITHUB_OUTPUT
|
|
1622
1641
|
# echo "Behaviour tests passed"
|
|
1623
1642
|
|
|
1643
|
+
- name: Sync lockfile if package.json changed
|
|
1644
|
+
if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true'
|
|
1645
|
+
run: |
|
|
1646
|
+
if git diff --name-only | grep -q 'package.json'; then
|
|
1647
|
+
echo "package.json changed — syncing lockfile"
|
|
1648
|
+
npm install --package-lock-only || echo "::warning::Lockfile sync failed"
|
|
1649
|
+
git add package-lock.json 2>/dev/null || true
|
|
1650
|
+
fi
|
|
1651
|
+
|
|
1624
1652
|
- name: Commit and push
|
|
1625
1653
|
if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true' && steps.pre-commit-behaviour-test.outputs.tests-passed != 'false'
|
|
1626
1654
|
uses: ./.github/agentic-lib/actions/commit-if-changed
|
package/agentic-lib.toml
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
# During init: #@dist transforms restore standard paths for consumer repos.
|
|
7
7
|
|
|
8
8
|
[schedule]
|
|
9
|
-
supervisor = "daily" # off | weekly | daily | hourly | continuous
|
|
9
|
+
supervisor = "daily" #@dist "off" # off | weekly | daily | hourly | continuous
|
|
10
|
+
focus = "mission" # mission | maintenance
|
|
10
11
|
|
|
11
12
|
[paths]
|
|
12
13
|
mission = "test/MISSION.md" #@dist "MISSION.md"
|
|
@@ -89,6 +90,11 @@ max-test-output = 4000 # max chars of test output in prompts
|
|
|
89
90
|
max-file-listing = 30 # max files in directory listings (0 = unlimited)
|
|
90
91
|
max-library-index = 2000 # max chars for library index in prompts
|
|
91
92
|
max-fix-test-output = 8000 # max chars of failed run log in fix-code
|
|
93
|
+
review-issues-cap = 2 # max issues reviewed per batch (conservative for 10 min timeout)
|
|
94
|
+
min-resolved-issues = 1 # mission-complete: minimum closed-as-RESOLVED issues
|
|
95
|
+
min-cumulative-transforms = 1 # mission-complete: minimum transform cycles
|
|
96
|
+
max-source-todos = 2 # mission-complete: max TODO comments in src
|
|
97
|
+
acceptance-criteria-threshold = 30 # mission-complete: % acceptance criteria required
|
|
92
98
|
|
|
93
99
|
[profiles.med]
|
|
94
100
|
# Balanced — good results, middle ground.
|
|
@@ -111,6 +117,11 @@ max-test-output = 10000 # max chars of test output in prompts
|
|
|
111
117
|
max-file-listing = 100 # max files in directory listings (0 = unlimited)
|
|
112
118
|
max-library-index = 5000 # max chars for library index in prompts
|
|
113
119
|
max-fix-test-output = 15000 # max chars of failed run log in fix-code
|
|
120
|
+
review-issues-cap = 3 # max issues reviewed per batch
|
|
121
|
+
min-resolved-issues = 2 # mission-complete: minimum closed-as-RESOLVED issues
|
|
122
|
+
min-cumulative-transforms = 1 # mission-complete: minimum transform cycles
|
|
123
|
+
max-source-todos = 1 # mission-complete: max TODO comments in src
|
|
124
|
+
acceptance-criteria-threshold = 50 # mission-complete: % acceptance criteria required
|
|
114
125
|
|
|
115
126
|
[profiles.max]
|
|
116
127
|
# Thorough — maximum context for complex missions.
|
|
@@ -133,6 +144,11 @@ max-test-output = 20000 # max chars of test output in prompts
|
|
|
133
144
|
max-file-listing = 0 # max files in directory listings (0 = unlimited)
|
|
134
145
|
max-library-index = 10000 # max chars for library index in prompts
|
|
135
146
|
max-fix-test-output = 30000 # max chars of failed run log in fix-code
|
|
147
|
+
review-issues-cap = 4 # max issues reviewed per batch (may need step timeout awareness)
|
|
148
|
+
min-resolved-issues = 3 # mission-complete: minimum closed-as-RESOLVED issues
|
|
149
|
+
min-cumulative-transforms = 2 # mission-complete: minimum transform cycles
|
|
150
|
+
max-source-todos = 0 # mission-complete: max TODO comments in src
|
|
151
|
+
acceptance-criteria-threshold = 75 # mission-complete: % acceptance criteria required
|
|
136
152
|
|
|
137
153
|
[goals]
|
|
138
154
|
# W12/W13: Code coverage thresholds — stated in all code-changing prompts
|
|
@@ -144,7 +160,11 @@ min-branch-coverage = 30 # minimum % branch coverage required
|
|
|
144
160
|
# All conditions must be met simultaneously.
|
|
145
161
|
min-resolved-issues = 1 # minimum closed-as-RESOLVED issues since init
|
|
146
162
|
max-source-todos = 0 # max TODO comments allowed in ./src (0 = none)
|
|
147
|
-
|
|
163
|
+
acceptance-criteria-threshold = 50 # percentage of acceptance criteria that must be met (0-100)
|
|
164
|
+
min-cumulative-transforms = 1 # minimum transform cycles completed
|
|
165
|
+
require-no-open-issues = true # all issues must be closed
|
|
166
|
+
require-no-open-prs = true # all PRs must be merged/closed
|
|
167
|
+
require-no-critical-gaps = true # no critical implementation gaps
|
|
148
168
|
|
|
149
169
|
[bot]
|
|
150
170
|
log-prefix = "tmp/agent-log-" #@dist "agent-log-"
|