harness-everything 0.30.4 → 0.30.6
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +38 -0
- package/README.md +17 -7
- package/bin/cli.js +5 -0
- package/ci/fable-mode-test.js +112 -51
- package/ci/mechanism-2t-workspace-identity.test.js +3 -1
- package/ci/mechanism-2w-platform-compatibility.test.js +39 -0
- package/ci/mechanism-2z-claude-plugin-manifest.test.js +12 -0
- package/ci/router-workflow-plan.test.js +92 -7
- package/docs/platform-capabilities.md +14 -1
- package/docs/troubleshooting.md +31 -1
- package/docs/workflows/fable-mode.md +10 -9
- package/evals/fable-mode/tasks/negative-tier2-no-model.yaml +3 -3
- package/evals/fable-mode/tasks/positive-haiku-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-opus-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-sonnet-mode.yaml +1 -1
- package/evals/fable-mode/tasks/positive-trigger.yaml +1 -1
- package/fable-mode/SKILL.md +18 -12
- package/fable-mode/agents/fable-orchestrator.md +7 -6
- package/fable-mode/agents/fable-verifier.md +1 -1
- package/fable-mode/agents/fable-worker-haiku.md +5 -4
- package/fable-mode/agents/fable-worker-sonnet.md +5 -4
- package/fable-mode/behavior-profile-matrix.json +36 -0
- package/fable-mode/execution-guardrails/SKILL.md +3 -6
- package/fable-mode/execution-guardrails/references/guardrail-rules.md +8 -9
- package/fable-mode/fable-haiku/SKILL.md +7 -5
- package/fable-mode/fable-haiku/references/routing-notes.md +2 -1
- package/fable-mode/fable-opus/SKILL.md +8 -6
- package/fable-mode/fable-sonnet/SKILL.md +8 -6
- package/fable-mode/model-matrix.json +7 -30
- package/fable-mode/references/model-matrix.md +35 -30
- package/fable-mode/references/profile-lookup.md +19 -0
- package/fable-mode/runtime-model-floor-matrix.json +47 -0
- package/fable-mode/scripts/model-selector.js +106 -60
- package/fable-mode/scripts/workflow-plan-consumer.js +1 -1
- package/harness-everything/SKILL.md +11 -14
- package/harness-everything/references/router-workflow-plan.md +2 -2
- package/harness-everything/schemas/router-task-shape.schema.json +3 -2
- package/harness-everything/schemas/router-workflow-plan.schema.json +6 -5
- package/harness-everything/scripts/router-contract-core.js +19 -12
- package/harness-everything/scripts/tier-router.js +100 -12
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/fable-mode/SKILL.md +18 -12
- package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +7 -6
- package/plugins/harness-everything/skills/fable-mode/agents/fable-verifier.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-haiku.md +5 -4
- package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-sonnet.md +5 -4
- package/plugins/harness-everything/skills/fable-mode/behavior-profile-matrix.json +36 -0
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +3 -6
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/references/guardrail-rules.md +8 -9
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +7 -5
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/references/routing-notes.md +2 -1
- package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +8 -6
- package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +8 -6
- package/plugins/harness-everything/skills/fable-mode/model-matrix.json +7 -30
- package/plugins/harness-everything/skills/fable-mode/references/model-matrix.md +35 -30
- package/plugins/harness-everything/skills/fable-mode/references/profile-lookup.md +19 -0
- package/plugins/harness-everything/skills/fable-mode/runtime-model-floor-matrix.json +47 -0
- package/plugins/harness-everything/skills/fable-mode/scripts/model-selector.js +106 -60
- package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +1 -1
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +11 -14
- package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +2 -2
- package/plugins/harness-everything/skills/harness-everything/schemas/router-task-shape.schema.json +3 -2
- package/plugins/harness-everything/skills/harness-everything/schemas/router-workflow-plan.schema.json +6 -5
- package/plugins/harness-everything/skills/harness-everything/scripts/router-contract-core.js +19 -12
- package/plugins/harness-everything/skills/harness-everything/scripts/tier-router.js +100 -12
- package/sbom.cdx.json +7 -7
|
@@ -46,11 +46,88 @@ function matchKeyword(prompt, keyword) {
|
|
|
46
46
|
return new RegExp(`\\b${escaped}\\b`, 'i').test(prompt);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
const FABLE_PROFILE_INVOCATION = /\bfable(?:[- ]mode)?\s+(?:on|with)\s+(haiku|sonnet|sonnect|opus)\b|\bfable-(haiku|sonnet|opus)\b/i;
|
|
50
|
+
const PROFILE_LOOKUP_FIELDS = /\b(?:requestedProfile|effectiveProfile|profileAlias|assignedRole|runtimeModel|runtimeEffort)\b/gi;
|
|
51
|
+
|
|
49
52
|
function detectFableModel(prompt) {
|
|
50
|
-
const match = prompt.match(
|
|
53
|
+
const match = prompt.match(FABLE_PROFILE_INVOCATION);
|
|
51
54
|
if (!match) return null;
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
return (match[1] || match[2]).toLowerCase();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// A profile mention is data in a lookup, not an instruction to start Fable.
|
|
59
|
+
// Validate the whole clause, not just its prefix. Unknown prose conservatively
|
|
60
|
+
// retains execution routing; format field lists are recognized separately.
|
|
61
|
+
function containsOnlyLookupTerms(text, operation) {
|
|
62
|
+
const terms = {
|
|
63
|
+
explanation: /\b(?:please|help|me|explain|resolve|define|what|is|does|mean|means|meaning|the|a|an|of|to|into|in|for|behavior|behaviour|profile|profiles|selection|json|record|alias|role|runtime|model|effort|floor|fableprofile)\b/gi,
|
|
64
|
+
output: /\b(?:return|respond|output|show|provide|only|a|an|small|compact|json|record|selection|profile|result|with|fields|containing|include|including)\b/gi,
|
|
65
|
+
};
|
|
66
|
+
const chineseTerms = {
|
|
67
|
+
explanation: /(?:請|幫我|解釋|說明|解析|的意思|意思|含義|意義|是什麼|設定檔|行為|角色)/g,
|
|
68
|
+
output: /(?:只|僅|回傳|返回|輸出|顯示|提供|包含|含|的|欄位|記錄|紀錄|結果|設定檔)/g,
|
|
69
|
+
};
|
|
70
|
+
return text.replace(PROFILE_LOOKUP_FIELDS, '').replace(terms[operation], '')
|
|
71
|
+
.replace(chineseTerms[operation], '').replace(/[\s"'`“”‘’?::?]/g, '') === '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A negation scopes only its own noun/verb list. Vocabulary-only matching would
|
|
75
|
+
// let "no delegation, do execution" pass, so English negations follow a grammar
|
|
76
|
+
// and an un-negated continuation may only extend the noun list. Chinese nouns
|
|
77
|
+
// and verbs share forms, so Chinese lists must stay inside the negated clause.
|
|
78
|
+
const negatedList = unit => `${unit}(?:\\s+or\\s+${unit})*`;
|
|
79
|
+
const NEGATED_ITEM = '(?:orchestration|delegation|stages?|staging|execution|model[- ]switch(?:ing)?)';
|
|
80
|
+
const NEGATED_ACTION = '(?:switch(?:ing)?\\s+(?:the\\s+)?models?|delegate|orchestrate|stage|execute)';
|
|
81
|
+
const ENGLISH_NEGATION = new RegExp(`^(?:(?:no|without)\\s+${negatedList(NEGATED_ITEM)}|(?:do not|don't)\\s+${negatedList(NEGATED_ACTION)})$`, 'i');
|
|
82
|
+
const ENGLISH_NEGATION_CONTINUATION = new RegExp(`^(?:or\\s+)?${negatedList(NEGATED_ITEM)}$`, 'i');
|
|
83
|
+
const CHINESE_NEGATION_TERMS = /(?:不要|不需要|無需|不|或|編排|委派|階段|執行|切換模型)/g;
|
|
84
|
+
|
|
85
|
+
function isBoundedNegation(clause, continuation) {
|
|
86
|
+
const text = clause.replace(/’/g, "'").replace(/[“”"`?::?]/g, '').replace(/\s+/g, ' ').trim();
|
|
87
|
+
if (/^(?:不要|不需要|無需|不)/.test(text)) {
|
|
88
|
+
return !continuation && text.replace(CHINESE_NEGATION_TERMS, '').replace(/\s/g, '') === '';
|
|
89
|
+
}
|
|
90
|
+
return (continuation ? ENGLISH_NEGATION_CONTINUATION : ENGLISH_NEGATION).test(text);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isFableProfileLookup(prompt, hasMacroSignal) {
|
|
94
|
+
if (!detectFableModel(prompt) || hasMacroSignal) return false;
|
|
95
|
+
if (/\b(?:direct[- ]single|iterative[- ]single|fable[- ](?:staged|parallel|multi[- ]agent[- ]workspace))\b/i.test(prompt)) return false;
|
|
96
|
+
|
|
97
|
+
const clauses = prompt
|
|
98
|
+
.split(/(?:[;,.,;。、]|\b(?:and|then|also|plus|afterwards|additionally)\b|(?:並且?|以及|接著|然後|另外))/i)
|
|
99
|
+
.map(part => part.trim())
|
|
100
|
+
.filter(Boolean);
|
|
101
|
+
if (clauses.length === 0) return false;
|
|
102
|
+
|
|
103
|
+
const [lookupClause, ...continuations] = clauses;
|
|
104
|
+
const quotedInvocation = new RegExp(`(["'\x60])(?:run|use|enter)\\s+(?:${FABLE_PROFILE_INVOCATION.source})\\1`, 'gi');
|
|
105
|
+
const normalizedLookup = lookupClause.replace(/[“”]/g, '"').replace(/[‘’]/g, "'")
|
|
106
|
+
.replace(quotedInvocation, 'fableprofile')
|
|
107
|
+
.replace(new RegExp(FABLE_PROFILE_INVOCATION.source, 'gi'), 'fableprofile');
|
|
108
|
+
const isLookupLead = /^(?:(?:please|help me)\s+|(?:請|幫我)\s*)?(?:explain|resolve|define|what (?:is|does)|解釋|說明|解析)/i.test(lookupClause)
|
|
109
|
+
&& Boolean(detectFableModel(lookupClause));
|
|
110
|
+
if (!isLookupLead || !containsOnlyLookupTerms(normalizedLookup, 'explanation')) return false;
|
|
111
|
+
|
|
112
|
+
let continuationOperation = null;
|
|
113
|
+
for (const clause of continuations) {
|
|
114
|
+
const output = /^(?:please\s+)?(?:return|respond|output|show|provide)\b|^(?:請\s*)?(?:只|僅)?(?:回傳|返回|輸出|顯示|提供)/i.test(clause);
|
|
115
|
+
const negative = /^(?:please\s+)?(?:no|without|do not|don't)\b|^(?:請\s*)?(?:不要|不需要|無需|不)/i.test(clause);
|
|
116
|
+
if (output || negative) {
|
|
117
|
+
continuationOperation = output ? 'output' : 'negative';
|
|
118
|
+
const normalizedContinuation = clause.replace(/^(?:please\s+|請\s*)/i, '');
|
|
119
|
+
const bounded = output ? containsOnlyLookupTerms(normalizedContinuation, 'output')
|
|
120
|
+
: isBoundedNegation(normalizedContinuation, false);
|
|
121
|
+
if (!bounded) return false;
|
|
122
|
+
} else if (continuationOperation === 'output') {
|
|
123
|
+
// Only named canonical fields may continue a comma/and-separated list.
|
|
124
|
+
const remainder = clause.replace(PROFILE_LOOKUP_FIELDS, '').replace(/^(?:包含|欄位)/, '').replace(/[\s"'`“”‘’]/g, '');
|
|
125
|
+
if (remainder || !new RegExp(PROFILE_LOOKUP_FIELDS.source, 'i').test(clause)) return false;
|
|
126
|
+
} else if (continuationOperation !== 'negative' || !isBoundedNegation(clause, true)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
54
131
|
}
|
|
55
132
|
|
|
56
133
|
function detectExplicitStrategy(prompt, requestedFableModel) {
|
|
@@ -250,6 +327,7 @@ function run(userPrompt, context, options = {}) {
|
|
|
250
327
|
/(?:評估|稽核|基準|壓力測試|比較).*(?:每個|所有|全部|整個|全套|技能|skill|檔案|版本)/i,
|
|
251
328
|
];
|
|
252
329
|
const hasMacroSignal = macroSignals.some(signal => signal.test(userPrompt));
|
|
330
|
+
const profileLookup = isFableProfileLookup(userPrompt, hasMacroSignal);
|
|
253
331
|
const hasTrivialEditVerb = /^(?:(?:please|help me)\s+)?(?:fix|update|correct|change)\b/i.test(userPrompt.trim());
|
|
254
332
|
const hasDocsTarget = /\b(?:readme|documentation|docs?)\b/i.test(userPrompt);
|
|
255
333
|
const hasTinyEditSignal = /\b(?:typo|spelling|wording|one line|single line)\b/i.test(userPrompt);
|
|
@@ -262,7 +340,12 @@ function run(userPrompt, context, options = {}) {
|
|
|
262
340
|
let rationale = 'No structural/testing signals matched; unclassified is not equivalent to trivial.';
|
|
263
341
|
const reasonCodes = [...loadedConfig.reasonCodes, 'no-classification-signal'];
|
|
264
342
|
|
|
265
|
-
if (
|
|
343
|
+
if (profileLookup) {
|
|
344
|
+
recommendedTier = 'Tier 1 (Trivial)';
|
|
345
|
+
rationale = 'Bounded behavior-profile lookup; select compact reference before execution.';
|
|
346
|
+
reasonCodes.splice(loadedConfig.reasonCodes.length);
|
|
347
|
+
addReason(reasonCodes, 'fable-profile-lookup');
|
|
348
|
+
} else if (memoryPersistenceRequested && !hasMacroSignal && !hasTier3Keyword && !hasTier2Keyword) {
|
|
266
349
|
recommendedTier = 'Tier 1 (Trivial)';
|
|
267
350
|
rationale = 'Explicit bounded self-evolve memory persistence request.';
|
|
268
351
|
reasonCodes.splice(loadedConfig.reasonCodes.length);
|
|
@@ -292,7 +375,7 @@ function run(userPrompt, context, options = {}) {
|
|
|
292
375
|
const hasQuestionMarks = /\?|?/.test(userPrompt);
|
|
293
376
|
const hasMultipleSentences = sentenceCount > 2;
|
|
294
377
|
|
|
295
|
-
if (!hasMacroSignal && !isTrivialDocsEdit && hasMultipleTasks && hasMultipleSentences) {
|
|
378
|
+
if (!profileLookup && !hasMacroSignal && !isTrivialDocsEdit && hasMultipleTasks && hasMultipleSentences) {
|
|
296
379
|
if (recommendedTier === 'Unclassified' || recommendedTier.startsWith('Tier 1')) {
|
|
297
380
|
recommendedTier = 'Tier 2 (Standard Task)';
|
|
298
381
|
rationale = 'Multiple tasks detected with structural complexity - upgraded to Tier 2 for TDD validation.';
|
|
@@ -320,7 +403,7 @@ function run(userPrompt, context, options = {}) {
|
|
|
320
403
|
const structuralFloor = hasMacroSignal ? 'tier3'
|
|
321
404
|
: !isTrivialDocsEdit && hasMultipleTasks && hasMultipleSentences ? 'tier2' : null;
|
|
322
405
|
const semantic = selectTier({ prompt: userPrompt, tier: recommendedTier, floor: structuralFloor,
|
|
323
|
-
explicit: Boolean(detectExplicitStrategy(userPrompt, detectFableModel(userPrompt))) }, process.env, options.systemOneScorer || undefined);
|
|
406
|
+
explicit: profileLookup || Boolean(detectExplicitStrategy(userPrompt, detectFableModel(userPrompt))) }, process.env, options.systemOneScorer || undefined);
|
|
324
407
|
if (semantic.diagnostic) console.log(`\n=> SYSTEM ONE: ${JSON.stringify(semantic.diagnostic)}`);
|
|
325
408
|
if (semantic.diagnostic?.applied) {
|
|
326
409
|
recommendedTier = semantic.tier;
|
|
@@ -334,13 +417,18 @@ function run(userPrompt, context, options = {}) {
|
|
|
334
417
|
|
|
335
418
|
const requestedFableModel = detectFableModel(promptLower);
|
|
336
419
|
if (requestedFableModel) {
|
|
337
|
-
console.log(`\n=> REQUESTED FABLE
|
|
338
|
-
console.log(`=> ROUTE: fable-mode/
|
|
339
|
-
|
|
420
|
+
console.log(`\n=> REQUESTED FABLE PROFILE: ${requestedFableModel}`);
|
|
421
|
+
console.log(`=> ROUTE: fable-mode/SKILL.md`);
|
|
422
|
+
if (profileLookup) {
|
|
423
|
+
console.log('=> FABLE OPERATION: profile-lookup');
|
|
424
|
+
console.log('=> REFERENCES: fable-mode/references/profile-lookup.md only; no stage state or delegation.');
|
|
425
|
+
} else {
|
|
426
|
+
console.log(` Profile alias: ${requestedFableModel}; resolve behavior role plus advisory host runtime floor with fable-mode/scripts/model-selector.js.`);
|
|
427
|
+
}
|
|
340
428
|
}
|
|
341
429
|
|
|
342
430
|
const allRecommendedGuides = [];
|
|
343
|
-
for (const group of routingConfig.guideGroups) {
|
|
431
|
+
for (const group of profileLookup ? [] : routingConfig.guideGroups) {
|
|
344
432
|
let matched = false;
|
|
345
433
|
if (typeof group.regex === 'string') {
|
|
346
434
|
matched = new RegExp(group.regex, 'i').test(promptLower);
|
|
@@ -366,7 +454,7 @@ function run(userPrompt, context, options = {}) {
|
|
|
366
454
|
});
|
|
367
455
|
}
|
|
368
456
|
|
|
369
|
-
emitDynamicSkills(promptLower, context, recommendedGuides);
|
|
457
|
+
if (!profileLookup) emitDynamicSkills(promptLower, context, recommendedGuides);
|
|
370
458
|
|
|
371
459
|
const externalClaimTriggers = routingConfig.factAudit.externalClaim || [];
|
|
372
460
|
const estimateTriggers = routingConfig.factAudit.estimate || [];
|
|
@@ -397,7 +485,7 @@ function run(userPrompt, context, options = {}) {
|
|
|
397
485
|
const actionGateReasonCodes = detectActionGateReasons(userPrompt);
|
|
398
486
|
const irreversibleAction = actionGateReasonCodes.includes('irreversible-action');
|
|
399
487
|
const externalSideEffect = actionGateReasonCodes.includes('external-side-effect');
|
|
400
|
-
const requestedStrategy = detectExplicitStrategy(userPrompt, requestedFableModel);
|
|
488
|
+
const requestedStrategy = profileLookup ? null : detectExplicitStrategy(userPrompt, requestedFableModel);
|
|
401
489
|
const prohibitions = detectProhibitions(userPrompt);
|
|
402
490
|
const plannerInputs = plannerInputsFromContext(context, promptLower);
|
|
403
491
|
|
package/sbom.cdx.json
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
"$schema": "https://cyclonedx.org/schema/bom-1.7.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.7",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:284476ec-2aa6-5bc2-883b-7a9196027356",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-10-
|
|
8
|
+
"timestamp": "2026-10-06T16:15:39.747Z",
|
|
9
9
|
"tools": [
|
|
10
10
|
{
|
|
11
11
|
"vendor": "Harness Everything",
|
|
12
12
|
"name": "generate-sbom.js",
|
|
13
|
-
"version": "0.30.
|
|
13
|
+
"version": "0.30.6"
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
16
|
"component": {
|
|
17
17
|
"type": "application",
|
|
18
|
-
"bom-ref": "pkg:npm/harness-everything@0.30.
|
|
18
|
+
"bom-ref": "pkg:npm/harness-everything@0.30.6",
|
|
19
19
|
"name": "harness-everything",
|
|
20
|
-
"version": "0.30.
|
|
21
|
-
"purl": "pkg:npm/harness-everything@0.30.
|
|
20
|
+
"version": "0.30.6",
|
|
21
|
+
"purl": "pkg:npm/harness-everything@0.30.6"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"components": [
|
|
@@ -1999,7 +1999,7 @@
|
|
|
1999
1999
|
]
|
|
2000
2000
|
},
|
|
2001
2001
|
{
|
|
2002
|
-
"ref": "pkg:npm/harness-everything@0.30.
|
|
2002
|
+
"ref": "pkg:npm/harness-everything@0.30.6",
|
|
2003
2003
|
"dependsOn": [
|
|
2004
2004
|
"pkg:npm/%40commitlint/cli@19.8.1",
|
|
2005
2005
|
"pkg:npm/%40commitlint/config-conventional@19.8.1",
|