@sabaiway/agent-workflow-kit 11.1.0 → 12.0.0
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/CHANGELOG.md +83 -0
- package/README.md +2 -2
- package/SKILL.md +1 -1
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/agents/review-lens.md +1 -0
- package/references/modes/procedures.md +4 -1
- package/references/modes/recipes.md +1 -1
- package/references/modes/recommendations.md +1 -1
- package/references/modes/set-recipe.md +2 -1
- package/references/modes/status.md +1 -1
- package/references/scripts/spec-schema.mjs +54 -30
- package/references/scripts/spec-schema.test.mjs +65 -0
- package/references/templates/orchestration.json +1 -1
- package/tools/carriers.mjs +1 -0
- package/tools/feedback-record-cli.mjs +300 -0
- package/tools/feedback-record.mjs +243 -0
- package/tools/inject-methodology.mjs +2 -0
- package/tools/orchestration-readme.mjs +12 -2
- package/tools/procedures.mjs +45 -9
- package/tools/script-priors.mjs +2 -0
package/tools/procedures.mjs
CHANGED
|
@@ -22,6 +22,8 @@ import { homedir } from 'node:os';
|
|
|
22
22
|
import { join, dirname } from 'node:path';
|
|
23
23
|
import { fileURLToPath } from 'node:url';
|
|
24
24
|
import { detectBackends, wrapperCmdFor, wrapperContractFor } from './detect-backends.mjs';
|
|
25
|
+
import { surveyVehicle as surveyReviewVehicle } from './cheap-agents-read.mjs';
|
|
26
|
+
import { isReadyMember, skippedLine } from './review-roster-resolve.mjs';
|
|
25
27
|
// The host-level bridge-settings registry (manifest-as-source) + its allowed-value labels. READ-ONLY
|
|
26
28
|
// core only — never the writer — so this read-only advisor never imports the atomic-write core.
|
|
27
29
|
import { loadRegistry, allowedLabel } from './bridge-settings-read.mjs';
|
|
@@ -150,7 +152,7 @@ export const extractSection = (text, activity) => {
|
|
|
150
152
|
|
|
151
153
|
// ── resolution + rendering ─────────────────────────────────────────────────────────
|
|
152
154
|
|
|
153
|
-
const resolveAllSlots = ({ activity, config, detection, overrides }) => {
|
|
155
|
+
const resolveAllSlots = ({ activity, config, detection, overrides, surveyLens }) => {
|
|
154
156
|
// The host-level settings knobs (manifest-as-source), best-effort: a corrupt bundle degrades to none
|
|
155
157
|
// and the advisor never crashes. Attached per wrapper cmd via each knob's `appliesTo`. Fact-only —
|
|
156
158
|
// model/effort are not knobs, so no model claim can ride here.
|
|
@@ -163,7 +165,7 @@ const resolveAllSlots = ({ activity, config, detection, overrides }) => {
|
|
|
163
165
|
})();
|
|
164
166
|
const knobsFor = (cmd) => [...registry.values()].filter((k) => (k.appliesTo ?? []).includes(cmd));
|
|
165
167
|
return Object.entries(ACTIVITIES[activity].slots).map(([slot, slotType]) => {
|
|
166
|
-
const resolved = resolveActivityRecipe({ config: config ?? {}, readiness: detection, activity, slot, override: overrides[slot] });
|
|
168
|
+
const resolved = resolveActivityRecipe({ config: config ?? {}, readiness: detection, activity, slot, override: overrides[slot], surveyLens });
|
|
167
169
|
if (isSwitchSlot(slotType)) return { slot, slotType, ...resolved, backends: [], contracts: [], vehicles: [] };
|
|
168
170
|
// The concrete wrapper set this slot's EFFECTIVE recipe dispatches (empty for solo). Reuse
|
|
169
171
|
// planRecipe's drift-guarded dispatch for WHICH backends, then resolve each (backend, role) to its
|
|
@@ -177,7 +179,7 @@ const resolveAllSlots = ({ activity, config, detection, overrides }) => {
|
|
|
177
179
|
// pairs, BEFORE they are flattened to wrapper names (the name array cannot reconstruct the role).
|
|
178
180
|
// Every slot with a non-empty dispatch gets contracts — including execute=delegated; the contract
|
|
179
181
|
// is NEVER gated by REVIEW_RECIPES (that set gates only the review-loop economics block).
|
|
180
|
-
const contracts = bridged
|
|
182
|
+
const contracts = activity === 'feedback-triage' ? [] : bridged
|
|
181
183
|
.map((d) => ({ backend: d.backend, role: d.role, cmd: wrapperCmdFor(d.backend, d.role), contract: wrapperContractFor(d.backend, d.role) }))
|
|
182
184
|
.filter((c) => c.cmd && c.contract)
|
|
183
185
|
// `retired` rides along: without it this surface advertised a RETIRED key as an ordinary
|
|
@@ -230,7 +232,8 @@ const backendSetLabel = (backends) =>
|
|
|
230
232
|
// review slot can resolve or request reviewed|council (execute floors at solo|delegated), so the gate
|
|
231
233
|
// reads the recipe, the requested recipe and the roster.
|
|
232
234
|
const REVIEW_RECIPES = new Set(['reviewed', 'council']);
|
|
233
|
-
const CONSULT_LINE = ' • Before every fold of a finding raised by a review member (a bridge backend or a placed lens): ASK that member whether the proposed fold solves it and adds no new problem; WAIT for its answer, READ it, then edit only as accepted or corrected — agy: agy-review --continue --decided @f --focus "Finding: <finding>. Proposed fold: <exact fold>. Does this proposed fold solve the finding and add no new problem?
|
|
235
|
+
const CONSULT_LINE = ' • Before every fold of a finding raised by a review member (a bridge backend or a placed lens): ASK that member whether the proposed fold solves it and adds no new problem; WAIT for its answer, READ it, then edit only as accepted or corrected — agy: agy-review --continue --decided @f --focus "Finding: <finding>. Proposed fold: <exact fold>. Does this proposed fold solve the finding and add no new problem? If this finding is the second case against the same check, reply with the replacement invariant, not an added case. ' +
|
|
236
|
+
'Reply accept, or correct with exact replacement text."; codex: fresh codex-review plan <consult-brief> with the same payload written before the working tree changes; a placed lens: re-dispatch the same lens vehicle with the same payload. A self-review finding, or any finding when no review member ran, is folded directly — the exemption is the finding\'s ORIGIN, never the recipe word on the slot line.';
|
|
234
237
|
const ARMED_CONSULT_LINE = ' • ARMED pre-fold sequence for a bridge-raised finding: the round is open → dispatch that bridge\'s consult with a nonce → WAIT and READ → fold accepted or corrected → flow-writer consult-attestation <planId> --backend <id> --nonce <n> --proposed-fix-digest <the-sha256-of-the-fold-text> → then edit. A lens-raised finding re-dispatches the lens without a nonce, WAIT and READ, then edit as accepted or corrected — it mints no manifest and no attestation — only its per-round participation rides its internal-attestation.';
|
|
235
238
|
// activity-aware (AD-046): the triage classification vocabulary rides EVERY review-backed activity;
|
|
236
239
|
// the LEDGER pointer renders ONLY for plan-execution — the ledger is plan-execution-scoped (AD-045),
|
|
@@ -271,8 +274,40 @@ const reviewLoopAdvice = (slots, activity, flowArmed = false, plans = []) =>
|
|
|
271
274
|
export const GROUNDING_TOOL = join(dirname(fileURLToPath(import.meta.url)), 'grounding.mjs');
|
|
272
275
|
export const REVIEW_ROUNDS_TOOL = join(dirname(fileURLToPath(import.meta.url)), 'review-rounds-cli.mjs');
|
|
273
276
|
export const REPO_SEARCH_TOOL = join(dirname(fileURLToPath(import.meta.url)), 'repo-search.mjs');
|
|
277
|
+
export const FEEDBACK_RECORD_TOOL = join(dirname(fileURLToPath(import.meta.url)), 'feedback-record-cli.mjs');
|
|
278
|
+
const FEEDBACK_TRIAGE = 'feedback-triage';
|
|
274
279
|
const GROUNDING_FACTS_OUT = '/tmp/review-facts.md';
|
|
275
280
|
const MINTS_RECEIPT = Object.freeze({ mintsReceipt: true });
|
|
281
|
+
const FEEDBACK_BRIDGE_LINES = Object.freeze({
|
|
282
|
+
'codex-review': 'codex-review plan <record>',
|
|
283
|
+
'agy-review': 'agy-review plan <record> --facts @<facts>',
|
|
284
|
+
});
|
|
285
|
+
const FEEDBACK_LENS_LINE = 'the Agent tool, read-only, in the background — the brief carries <record> plus <facts>';
|
|
286
|
+
const mintsReceipts = (review) => review.roster == null
|
|
287
|
+
? (review.backends ?? []).length > 0 || REVIEW_RECIPES.has(review.degradedFrom)
|
|
288
|
+
: review.roster.some((row) => row.kind === 'bridge');
|
|
289
|
+
|
|
290
|
+
const renderFeedbackTriageAdvice = (activity, slots) => {
|
|
291
|
+
if (activity !== FEEDBACK_TRIAGE) return [];
|
|
292
|
+
const review = slots.find((slot) => slot.slot === 'review');
|
|
293
|
+
const members = review.roster == null
|
|
294
|
+
? review.backends.map((name) => ` then: ${FEEDBACK_BRIDGE_LINES[name]}`)
|
|
295
|
+
: review.roster.map((row) => !isReadyMember(row)
|
|
296
|
+
? ` then: ${row.member} — ${skippedLine(row)}`
|
|
297
|
+
: row.kind === 'bridge'
|
|
298
|
+
? ` then: ${FEEDBACK_BRIDGE_LINES[row.member]}`
|
|
299
|
+
: ` then: ${row.member} — ${FEEDBACK_LENS_LINE}`);
|
|
300
|
+
return [
|
|
301
|
+
` run: node ${renderToolPath(FEEDBACK_RECORD_TOOL)} --check <record> --excerpts <facts>`,
|
|
302
|
+
...members,
|
|
303
|
+
...(mintsReceipts(review)
|
|
304
|
+
? [
|
|
305
|
+
` then: node ${renderToolPath(REVIEW_ROUNDS_TOOL)} --artifact <record> --activity feedback-triage`,
|
|
306
|
+
ROUND_RENDER_FACT_LINE,
|
|
307
|
+
]
|
|
308
|
+
: [ROUND_RENDER_NO_BRIDGE_LINE]),
|
|
309
|
+
];
|
|
310
|
+
};
|
|
276
311
|
|
|
277
312
|
// The round table judges what review-rounds-cli resolves from the config (S27), never this render's
|
|
278
313
|
// override or degradation, so the advisor states that fact beneath the command instead of predicting
|
|
@@ -285,10 +320,7 @@ const roundRenderAdvice = (slots, plans) => {
|
|
|
285
320
|
const review = slots.find((s) => s.slot === 'review');
|
|
286
321
|
if (review === undefined) return [];
|
|
287
322
|
const roster = review.roster ?? null;
|
|
288
|
-
|
|
289
|
-
? (review.backends ?? []).length > 0 || REVIEW_RECIPES.has(review.degradedFrom)
|
|
290
|
-
: roster.some((row) => row.kind === 'bridge');
|
|
291
|
-
if (!shouldRenderCommand) return [ROUND_RENDER_NO_BRIDGE_LINE];
|
|
323
|
+
if (!mintsReceipts(review)) return [ROUND_RENDER_NO_BRIDGE_LINE];
|
|
292
324
|
const lensMembers = (roster ?? []).filter((row) => row.kind === 'lens').map((row) => row.member);
|
|
293
325
|
const operand = populatedPlan(plans, MINTS_RECEIPT);
|
|
294
326
|
return [
|
|
@@ -345,6 +377,7 @@ const slotSkewWarning = (section, activity) => {
|
|
|
345
377
|
return [`the installed engine's canon lists slots (${listed.join(', ')}) for ${activity} while this kit's registry names (${registry.join(', ')}) — the resolved lines follow the registry; the engine and this kit are out of step — /agent-workflow-kit status names which member is behind: upgrade that one. Tell the user.`];
|
|
346
378
|
};
|
|
347
379
|
const groundingPreStepAdvice = (activity, slots, plans) => {
|
|
380
|
+
if (activity === FEEDBACK_TRIAGE) return [];
|
|
348
381
|
if (!slots.some((s) => (s.backends ?? []).includes('agy-review'))) return [];
|
|
349
382
|
const operand = populatedPlan(plans);
|
|
350
383
|
const planArg = operand === null ? '--plan <path>' : `--plan ${operand}`;
|
|
@@ -621,6 +654,7 @@ const formatHuman = ({ activity, section, slots, warnings, plans, autonomy, flow
|
|
|
621
654
|
? ` ${parallelLine({ value: s.recipe, carrier })} — ${SOURCE_LABEL[s.source]}`
|
|
622
655
|
: ` ${s.slot}: ${s.recipe} — ${SOURCE_LABEL[s.source]}${arrow}${backendSetLabel(s.backends)}`);
|
|
623
656
|
if (s.reason) lines.push(` ↳ ${s.reason}`);
|
|
657
|
+
if (s.slot === 'review') lines.push(...renderFeedbackTriageAdvice(activity, slots));
|
|
624
658
|
// The form replaces the one-line vehicle mention: a carrier never told how to carry is a name,
|
|
625
659
|
// not an instruction. Indented like the driving contracts beside it.
|
|
626
660
|
for (const v of s.vehicles ?? []) {
|
|
@@ -664,6 +698,7 @@ const buildJson = ({ activity, section, slots, configSource, warnings, plans, au
|
|
|
664
698
|
readersSweep,
|
|
665
699
|
// ADDITIVE (AD-038): the populated grounding pre-step, structured (empty when agy is not dispatched).
|
|
666
700
|
groundingPreStep: groundingPreStepAdvice(activity, slots, plans),
|
|
701
|
+
feedbackTriage: renderFeedbackTriageAdvice(activity, slots),
|
|
667
702
|
// ADDITIVE (cost-tiered execution): the unconditional cost-lane advisory, structured.
|
|
668
703
|
costLanes: costLanesAdvice(),
|
|
669
704
|
// ADDITIVE (the fold channel): the finding-scope block, structured (empty outside plan-execution).
|
|
@@ -737,7 +772,8 @@ export const main = (argv, ctx = {}) => {
|
|
|
737
772
|
`backend detection failed (${(err && err.message) || err}) — treating every bridge as not ready; recipes needing a bridge degrade to solo (the executor vehicle is unaffected).`,
|
|
738
773
|
),
|
|
739
774
|
});
|
|
740
|
-
const
|
|
775
|
+
const surveyLens = ctx.surveyLens ?? ((spec) => surveyReviewVehicle(cwd, spec, ctx));
|
|
776
|
+
const slots = resolveAllSlots({ activity, config, detection, overrides, surveyLens });
|
|
741
777
|
const warnings = [...detectWarnings, ...collectWarnings(slots), ...slotSkewWarning(section, activity)];
|
|
742
778
|
const plans = plansInFlight(cwd);
|
|
743
779
|
// The autonomy facts (AD-044 Plan 4): resolved levels + red-lines from the policy file. A
|
package/tools/script-priors.mjs
CHANGED
|
@@ -34,6 +34,8 @@ export const SCRIPT_PRIORS = Object.freeze([
|
|
|
34
34
|
prior('spec-schema.mjs', '4.7.0', '4.7.0', '40b5b038d5ec5ed53c327c6d269d22fe5fa2bed99ae711fbf84306ad047be452'),
|
|
35
35
|
prior('spec-schema.test.mjs', '4.7.0', '4.7.0', 'fde896419924223e54cfcabfdb1ef5807df5386fac700ed7c1463b6e7f81501b'),
|
|
36
36
|
prior('check-docs-size.mjs', '4.6.0', '6.0.0', '22d020c3668cdbfb4cbc1f67a8a85b2baa2d0c4956808a50626d37409e81ab38'),
|
|
37
|
+
prior('spec-schema.mjs', '5.0.0', '7.2.1', '6a7d1e836c158baab5a412a1ad76d34891934dc28c88486c264a4b5d46f5892a'),
|
|
38
|
+
prior('spec-schema.test.mjs', '5.0.0', '7.2.1', '698564d7283281be1826019d214df475bb876687915de086818d8f5ece0e0336'),
|
|
37
39
|
]);
|
|
38
40
|
|
|
39
41
|
export const digestOf = (bytes) => createHash('sha256').update(bytes).digest('hex');
|