@ikon85/agent-workflow-kit 0.44.1 → 0.45.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/.agents/skills/audit-skills/SKILL.md +7 -4
- package/.agents/skills/code-review/SKILL.md +7 -4
- package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +7 -4
- package/.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +7 -4
- package/.agents/skills/improve-codebase-architecture/SKILL.md +7 -4
- package/.agents/skills/orchestrate-wave/SKILL.md +1 -1
- package/.agents/skills/orchestrate-wave/references/dispatch-subagents.md +9 -0
- package/.agents/skills/orchestrate-wave/references/dispatch-workflow.md +9 -0
- package/.agents/skills/research/SKILL.md +7 -4
- package/.agents/skills/to-issues/SKILL.md +25 -4
- package/.claude/skills/audit-skills/SKILL.md +7 -4
- package/.claude/skills/code-review/SKILL.md +7 -4
- package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +7 -4
- package/.claude/skills/codex-build/SKILL.md +13 -0
- package/.claude/skills/codex-review/SKILL.md +13 -0
- package/.claude/skills/grill-me-codex/SKILL.md +14 -0
- package/.claude/skills/grill-with-docs-codex/SKILL.md +14 -0
- package/.claude/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +7 -4
- package/.claude/skills/improve-codebase-architecture/SKILL.md +7 -4
- package/.claude/skills/orchestrate-wave/SKILL.md +1 -1
- package/.claude/skills/orchestrate-wave/references/dispatch-subagents.md +9 -0
- package/.claude/skills/orchestrate-wave/references/dispatch-workflow.md +9 -0
- package/.claude/skills/research/SKILL.md +7 -4
- package/.claude/skills/skill-manifest.json +34 -23
- package/.claude/skills/to-issues/SKILL.md +25 -4
- package/README.md +71 -0
- package/agent-workflow-kit.package.json +149 -45
- package/package.json +1 -1
- package/scripts/doctrine-migration/index.mjs +296 -0
- package/scripts/kit-release.mjs +41 -9
- package/src/cli.mjs +521 -80
- package/src/commands/routing-status.mjs +288 -0
- package/src/commands/update.mjs +9 -1
- package/src/consumer-migrations.json +23 -1
- package/src/lib/bundle.mjs +158 -2
- package/src/lib/consumerMigrations.mjs +55 -0
- package/src/lib/dispatchJournal.mjs +300 -0
- package/src/lib/dispatchPlan.mjs +286 -0
- package/src/lib/dispatchReceipt.mjs +226 -89
- package/src/lib/frontendWorkloads.mjs +35 -33
- package/src/lib/routeDispatcher.mjs +367 -70
- package/src/lib/routingAccessGraph.mjs +265 -20
- package/src/lib/routingAccessGraphStore.mjs +300 -0
- package/src/lib/routingAdapters/claude.mjs +104 -4
- package/src/lib/routingAdapters/codex.mjs +132 -7
- package/src/lib/routingAdapters/hostBridge.mjs +291 -0
- package/src/lib/routingCatalog.mjs +201 -24
- package/src/lib/routingDispatchLease.mjs +253 -0
- package/src/lib/routingEvidenceCache.mjs +78 -0
- package/src/lib/routingIntent.mjs +176 -10
- package/src/lib/routingIntentClassifier.mjs +137 -0
- package/src/lib/routingInventory/snapshots/claude.json +49 -0
- package/src/lib/routingInventory/snapshots/codex.json +109 -0
- package/src/lib/routingInventory.mjs +182 -0
- package/src/lib/routingPolicy.mjs +193 -6
- package/src/lib/routingProfile.mjs +1251 -123
- package/src/lib/routingProfilePolicy.mjs +156 -0
- package/src/lib/routingProfileStorage.mjs +299 -0
- package/src/lib/routingResolver.mjs +369 -86
- package/src/lib/routingSources/artificialAnalysis.mjs +19 -7
- package/src/lib/routingSources/benchlm.mjs +5 -0
- package/src/lib/routingSources/codeArena.mjs +13 -3
- package/src/lib/routingSources/deepswe.mjs +19 -5
- package/src/lib/routingSources/openhands.mjs +17 -4
- package/src/lib/routingSources/openhandsFrontend.mjs +13 -3
- package/src/lib/safeText.mjs +26 -0
- package/src/lib/updateCandidate.mjs +36 -3
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertPublishedEffort,
|
|
3
|
+
evidenceFreshness,
|
|
4
|
+
evidenceIdentity,
|
|
5
|
+
evidenceSourceClaim,
|
|
6
|
+
} from '../routingCatalog.mjs';
|
|
7
|
+
|
|
1
8
|
const SOURCE_ID = 'deepswe';
|
|
2
9
|
const OWNER = 'DataCurve';
|
|
3
10
|
const ARTIFACT_URL =
|
|
4
11
|
'https://deepswe.datacurve.ai/artifacts/v1.1/leaderboard-live.json';
|
|
12
|
+
const WORKLOAD = evidenceIdentity({ workload: 'repository-repair', axis: 'functional' });
|
|
5
13
|
|
|
6
14
|
function object(value, field) {
|
|
7
15
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
@@ -34,7 +42,9 @@ function context({ snapshotHash, observedAt, expiresAt }) {
|
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
function ingest({ payload, ...inputContext }) {
|
|
37
|
-
|
|
45
|
+
// The caller's window bounds the refresh; the observation is dated by the
|
|
46
|
+
// Kit-side freshness policy for this source, never by the owner artifact.
|
|
47
|
+
const { snapshotHash, observedAt } = context(inputContext);
|
|
38
48
|
object(payload, 'DeepSWE payload');
|
|
39
49
|
const artifact = object(payload.artifact, 'DeepSWE artifact');
|
|
40
50
|
if (artifact.owner !== OWNER || artifact.url !== ARTIFACT_URL) {
|
|
@@ -54,7 +64,10 @@ function ingest({ payload, ...inputContext }) {
|
|
|
54
64
|
object(row, `DeepSWE rows[${index}]`);
|
|
55
65
|
const providerId = string(row.provider, `DeepSWE rows[${index}].provider`);
|
|
56
66
|
const modelId = string(row.model, `DeepSWE rows[${index}].model`);
|
|
57
|
-
const effort =
|
|
67
|
+
const effort = assertPublishedEffort({
|
|
68
|
+
sourceId: SOURCE_ID,
|
|
69
|
+
effort: string(row.effort, `DeepSWE rows[${index}].effort`),
|
|
70
|
+
});
|
|
58
71
|
const id = `${SOURCE_ID}:${benchmarkVersion}:${providerId}:${modelId}:${effort}`;
|
|
59
72
|
if (observationIds.has(id)) throw new TypeError(`duplicate DeepSWE observation: ${id}`);
|
|
60
73
|
observationIds.add(id);
|
|
@@ -64,7 +77,7 @@ function ingest({ payload, ...inputContext }) {
|
|
|
64
77
|
providerId,
|
|
65
78
|
modelId,
|
|
66
79
|
effort,
|
|
67
|
-
workload:
|
|
80
|
+
workload: WORKLOAD,
|
|
68
81
|
harness: { id: harnessId, version: harnessVersion },
|
|
69
82
|
score: number(row.score, `DeepSWE rows[${index}].score`),
|
|
70
83
|
source: {
|
|
@@ -82,11 +95,11 @@ function ingest({ payload, ...inputContext }) {
|
|
|
82
95
|
`DeepSWE rows[${index}].confidence95HalfWidth`,
|
|
83
96
|
),
|
|
84
97
|
},
|
|
85
|
-
freshness: {
|
|
98
|
+
freshness: evidenceFreshness({ sourceId: SOURCE_ID, observedAt }),
|
|
86
99
|
cost: {
|
|
87
100
|
amount: number(row.averageCostUsd, `DeepSWE rows[${index}].averageCostUsd`),
|
|
88
101
|
currency: 'USD',
|
|
89
|
-
unit: '
|
|
102
|
+
unit: 'attempt',
|
|
90
103
|
},
|
|
91
104
|
});
|
|
92
105
|
});
|
|
@@ -102,5 +115,6 @@ export const deepSweSource = Object.freeze({
|
|
|
102
115
|
sourceId: SOURCE_ID,
|
|
103
116
|
owner: OWNER,
|
|
104
117
|
artifactUrl: ARTIFACT_URL,
|
|
118
|
+
claim: evidenceSourceClaim(SOURCE_ID),
|
|
105
119
|
ingest,
|
|
106
120
|
});
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertCostUnit,
|
|
3
|
+
assertPublishedEffort,
|
|
4
|
+
evidenceFreshness,
|
|
5
|
+
evidenceIdentity,
|
|
6
|
+
evidenceSourceClaim,
|
|
7
|
+
} from '../routingCatalog.mjs';
|
|
8
|
+
|
|
1
9
|
const SOURCE_ID = 'openhands-evaluation';
|
|
2
10
|
const OWNER = 'All Hands AI';
|
|
3
11
|
const ARTIFACT_URL = 'https://github.com/All-Hands-AI/OpenHands/tree/main/evaluation';
|
|
12
|
+
const WORKLOAD = evidenceIdentity({ workload: 'repository-repair', axis: 'functional' });
|
|
4
13
|
|
|
5
14
|
function object(value, field) {
|
|
6
15
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
@@ -50,7 +59,10 @@ function ingest({ payload, snapshotHash, observedAt, expiresAt }) {
|
|
|
50
59
|
object(row, `OpenHands results[${index}]`);
|
|
51
60
|
const providerId = string(row.provider, `OpenHands results[${index}].provider`);
|
|
52
61
|
const modelId = string(row.model, `OpenHands results[${index}].model`);
|
|
53
|
-
const effort =
|
|
62
|
+
const effort = assertPublishedEffort({
|
|
63
|
+
sourceId: SOURCE_ID,
|
|
64
|
+
effort: string(row.effort, `OpenHands results[${index}].effort`),
|
|
65
|
+
});
|
|
54
66
|
const id = `${SOURCE_ID}:${benchmarkVersion}:${providerId}:${modelId}:${effort}`;
|
|
55
67
|
if (observationIds.has(id)) throw new TypeError(`duplicate OpenHands observation: ${id}`);
|
|
56
68
|
observationIds.add(id);
|
|
@@ -61,7 +73,7 @@ function ingest({ payload, snapshotHash, observedAt, expiresAt }) {
|
|
|
61
73
|
providerId,
|
|
62
74
|
modelId,
|
|
63
75
|
effort,
|
|
64
|
-
workload:
|
|
76
|
+
workload: WORKLOAD,
|
|
65
77
|
harness: { id: harnessId, version: harnessVersion },
|
|
66
78
|
score: number(row.resolvedRate, `OpenHands results[${index}].resolvedRate`),
|
|
67
79
|
source: {
|
|
@@ -76,14 +88,14 @@ function ingest({ payload, snapshotHash, observedAt, expiresAt }) {
|
|
|
76
88
|
kind: 'standard-error',
|
|
77
89
|
value: number(row.standardError, `OpenHands results[${index}].standardError`),
|
|
78
90
|
},
|
|
79
|
-
freshness: {
|
|
91
|
+
freshness: evidenceFreshness({ sourceId: SOURCE_ID, observedAt }),
|
|
80
92
|
cost: {
|
|
81
93
|
amount: number(meanCost.amount, `OpenHands results[${index}].meanCost.amount`),
|
|
82
94
|
currency: string(
|
|
83
95
|
meanCost.currency,
|
|
84
96
|
`OpenHands results[${index}].meanCost.currency`,
|
|
85
97
|
),
|
|
86
|
-
unit:
|
|
98
|
+
unit: assertCostUnit(meanCost.unit, `OpenHands results[${index}].meanCost.unit`),
|
|
87
99
|
},
|
|
88
100
|
});
|
|
89
101
|
});
|
|
@@ -98,5 +110,6 @@ export const openHandsSource = Object.freeze({
|
|
|
98
110
|
sourceId: SOURCE_ID,
|
|
99
111
|
owner: OWNER,
|
|
100
112
|
artifactUrl: ARTIFACT_URL,
|
|
113
|
+
claim: evidenceSourceClaim(SOURCE_ID),
|
|
101
114
|
ingest,
|
|
102
115
|
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { frontendEvidenceWorkload } from '../frontendWorkloads.mjs';
|
|
2
|
+
import {
|
|
3
|
+
assertCostUnit,
|
|
4
|
+
assertPublishedEffort,
|
|
5
|
+
evidenceFreshness,
|
|
6
|
+
evidenceSourceClaim,
|
|
7
|
+
} from '../routingCatalog.mjs';
|
|
2
8
|
|
|
3
9
|
const OWNER_URL = 'https://www.openhands.dev/blog/openhands-index';
|
|
4
10
|
const SOURCE_ID = 'openhands-frontend';
|
|
@@ -70,7 +76,10 @@ function ingest({ payload, snapshotHash, observedAt, expiresAt }) {
|
|
|
70
76
|
object(row, `OpenHands rows[${index}]`);
|
|
71
77
|
const providerId = string(row.providerId, `OpenHands rows[${index}].providerId`);
|
|
72
78
|
const modelId = string(row.modelId, `OpenHands rows[${index}].modelId`);
|
|
73
|
-
const effort =
|
|
79
|
+
const effort = assertPublishedEffort({
|
|
80
|
+
sourceId: SOURCE_ID,
|
|
81
|
+
effort: string(row.effort, `OpenHands rows[${index}].effort`),
|
|
82
|
+
});
|
|
74
83
|
const modelIdentity = `${providerId}:${modelId}`;
|
|
75
84
|
if (!modelIds.has(modelIdentity)) {
|
|
76
85
|
models.push({ providerId, modelId });
|
|
@@ -116,11 +125,11 @@ function ingest({ payload, snapshotHash, observedAt, expiresAt }) {
|
|
|
116
125
|
status: row.status,
|
|
117
126
|
sampleSize: finite(row.sampleSize, `OpenHands rows[${index}].sampleSize`),
|
|
118
127
|
},
|
|
119
|
-
freshness: {
|
|
128
|
+
freshness: evidenceFreshness({ sourceId: SOURCE_ID, observedAt }),
|
|
120
129
|
cost: {
|
|
121
130
|
amount: finite(row.cost.amount, `OpenHands rows[${index}].cost.amount`),
|
|
122
131
|
currency: string(row.cost.currency, `OpenHands rows[${index}].cost.currency`),
|
|
123
|
-
unit:
|
|
132
|
+
unit: assertCostUnit(row.cost.unit, `OpenHands rows[${index}].cost.unit`),
|
|
124
133
|
},
|
|
125
134
|
});
|
|
126
135
|
}
|
|
@@ -131,5 +140,6 @@ export const openHandsFrontendSource = Object.freeze({
|
|
|
131
140
|
sourceId: SOURCE_ID,
|
|
132
141
|
owner: 'OpenHands',
|
|
133
142
|
artifactUrl: OWNER_URL,
|
|
143
|
+
claim: evidenceSourceClaim(SOURCE_ID),
|
|
134
144
|
ingest,
|
|
135
145
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text that reaches a terminal verbatim.
|
|
3
|
+
*
|
|
4
|
+
* Two shipped surfaces need the same guarantee and must not each grow their own
|
|
5
|
+
* copy: the update plan renders Kit-authored manifest prose, and `routing status`
|
|
6
|
+
* renders diagnostics that can carry an external error message. Either would
|
|
7
|
+
* repaint the terminal if a control sequence rode through, so both strip C0/C1
|
|
8
|
+
* control characters here.
|
|
9
|
+
*
|
|
10
|
+
* This module is a leaf on purpose: it imports nothing, so an installed consumer
|
|
11
|
+
* receives it whole without dragging the installer-side update machinery along.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Validate that a value is a string and strip C0/C1 control characters plus
|
|
16
|
+
* redundant whitespace from it. Returns null for a non-string or an input that
|
|
17
|
+
* sanitizes to nothing, so a caller can distinguish "absent" from "empty".
|
|
18
|
+
*/
|
|
19
|
+
export function sanitizeReadinessText(value) {
|
|
20
|
+
if (typeof value !== 'string') return null;
|
|
21
|
+
const cleaned = value
|
|
22
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]+/g, ' ')
|
|
23
|
+
.replace(/\s+/g, ' ')
|
|
24
|
+
.trim();
|
|
25
|
+
return cleaned || null;
|
|
26
|
+
}
|
|
@@ -11,6 +11,7 @@ import { validateConsumerFile } from './consumerPath.mjs';
|
|
|
11
11
|
import { sha256File } from './hash.mjs';
|
|
12
12
|
import { stubSentinel } from './sentinel.mjs';
|
|
13
13
|
import { STUB_TARGETS } from './bundle.mjs';
|
|
14
|
+
import { sanitizeReadinessText } from './safeText.mjs';
|
|
14
15
|
import {
|
|
15
16
|
CONSUMER_MANIFEST_NAME, CONSUMER_ORIGIN, READINESS_MANIFEST_PATH,
|
|
16
17
|
filesForInstallRole, indexByPath, readManifest, validateManifest, writeManifest,
|
|
@@ -415,7 +416,7 @@ export async function adoptReadinessCandidate({
|
|
|
415
416
|
migrations,
|
|
416
417
|
migrated: migrations.map(({ path }) => path),
|
|
417
418
|
migrationConflicts,
|
|
418
|
-
availability: readinessDiff(before, after),
|
|
419
|
+
availability: readinessDiff(before, after, nextManifest?.readiness?.capabilities),
|
|
419
420
|
incompatible,
|
|
420
421
|
};
|
|
421
422
|
}
|
|
@@ -568,11 +569,38 @@ async function readinessSnapshot(root, manifest) {
|
|
|
568
569
|
return { skills, capabilities };
|
|
569
570
|
}
|
|
570
571
|
|
|
571
|
-
|
|
572
|
+
/**
|
|
573
|
+
* Manifest prose is Kit-authored but reaches a terminal verbatim, so every
|
|
574
|
+
* catalog string is validated (must be a string) and stripped of C0/C1 control
|
|
575
|
+
* characters — an escape sequence would otherwise repaint the update plan.
|
|
576
|
+
*
|
|
577
|
+
* The implementation moved to `./safeText.mjs` when `routing status` needed the
|
|
578
|
+
* same guarantee: that command ships to consumers, this module does not, so
|
|
579
|
+
* importing it from here would have escaped the installed consumer. Imported
|
|
580
|
+
* and re-exported rather than relocated, so this module keeps using it and
|
|
581
|
+
* every existing caller keeps its import path.
|
|
582
|
+
*/
|
|
583
|
+
export { sanitizeReadinessText };
|
|
584
|
+
|
|
585
|
+
/** One unresolved capability in plain terms: what it is and what closes it. */
|
|
586
|
+
function unresolvedEntry(capability, state, catalogEntry) {
|
|
587
|
+
return {
|
|
588
|
+
capability,
|
|
589
|
+
state,
|
|
590
|
+
title: sanitizeReadinessText(catalogEntry?.title),
|
|
591
|
+
remedy: sanitizeReadinessText(catalogEntry?.remedy),
|
|
592
|
+
evidencePaths: (catalogEntry?.evidence?.paths ?? [])
|
|
593
|
+
.map(sanitizeReadinessText)
|
|
594
|
+
.filter((path) => path !== null),
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function readinessDiff(before, after, catalog = {}) {
|
|
572
599
|
const newlyAvailable = [];
|
|
573
600
|
const newlyDegraded = [];
|
|
574
601
|
const newlyBlocked = [];
|
|
575
602
|
const unresolved = new Set();
|
|
603
|
+
const unresolvedEntries = [];
|
|
576
604
|
for (const [skill, current] of Object.entries(after.skills)) {
|
|
577
605
|
const prior = before.skills[skill];
|
|
578
606
|
if (current.verdict === 'blocked' && prior?.verdict !== 'blocked') newlyBlocked.push(skill);
|
|
@@ -582,11 +610,16 @@ function readinessDiff(before, after) {
|
|
|
582
610
|
}
|
|
583
611
|
}
|
|
584
612
|
for (const [capability, result] of Object.entries(after.capabilities)) {
|
|
585
|
-
if (result.state
|
|
613
|
+
if (result.state === 'ready') continue;
|
|
614
|
+
unresolved.add(`${capability}:${result.state}`);
|
|
615
|
+
unresolvedEntries.push(unresolvedEntry(capability, result.state, catalog?.[capability]));
|
|
586
616
|
}
|
|
587
617
|
return {
|
|
588
618
|
newlyAvailable: newlyAvailable.sort(), newlyDegraded: newlyDegraded.sort(),
|
|
589
619
|
newlyBlocked: newlyBlocked.sort(), stillUnresolved: [...unresolved].sort(),
|
|
620
|
+
unresolved: unresolvedEntries.sort(
|
|
621
|
+
(a, b) => (a.capability < b.capability ? -1 : 1),
|
|
622
|
+
),
|
|
590
623
|
};
|
|
591
624
|
}
|
|
592
625
|
|