omegon 0.8.1 → 0.8.3
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.
|
@@ -194,21 +194,22 @@ export const PATTERNS: Record<string, PatternDefinition> = {
|
|
|
194
194
|
modifiersDefault: ["breaking_changes"],
|
|
195
195
|
splitStrategy: ["New versioned endpoint", "Deprecation + dual-support", "Client migration"],
|
|
196
196
|
},
|
|
197
|
-
|
|
198
|
-
name: "
|
|
199
|
-
description: "Code cleanup, renaming, or
|
|
197
|
+
refactor: {
|
|
198
|
+
name: "Refactor",
|
|
199
|
+
description: "Code cleanup, renaming, restructuring, or replacing implementations while preserving behavior",
|
|
200
200
|
keywords: [
|
|
201
201
|
"refactor", "rename", "reorganize", "cleanup", "extract", "inline", "move",
|
|
202
|
-
"restructure", "mechanical", "no functional",
|
|
202
|
+
"restructure", "mechanical", "no functional", "replace", "rewrite",
|
|
203
|
+
"swap", "substitute", "modernize",
|
|
203
204
|
],
|
|
204
|
-
requiredAny: ["refactor", "rename", "cleanup", "extract", "reorganize"],
|
|
205
|
+
requiredAny: ["refactor", "rename", "cleanup", "extract", "reorganize", "replace", "rewrite", "swap", "substitute"],
|
|
205
206
|
expectedComponents: {
|
|
206
|
-
operation: ["rename", "extract", "inline", "move", "reorganize"],
|
|
207
|
-
scope: ["function", "class", "file", "module", "component", "method"],
|
|
207
|
+
operation: ["rename", "extract", "inline", "move", "reorganize", "replace", "rewrite", "swap", "substitute"],
|
|
208
|
+
scope: ["function", "class", "file", "module", "component", "method", "implementation", "approach", "library", "framework", "pattern"],
|
|
208
209
|
},
|
|
209
210
|
systemsBase: 1,
|
|
210
211
|
modifiersDefault: [],
|
|
211
|
-
splitStrategy: ["
|
|
212
|
+
splitStrategy: ["Implement replacement / perform refactor", "Update call sites + tests", "Remove old implementation"],
|
|
212
213
|
},
|
|
213
214
|
bug_fix: {
|
|
214
215
|
name: "Bug Fix",
|
|
@@ -282,21 +283,27 @@ export const PATTERNS: Record<string, PatternDefinition> = {
|
|
|
282
283
|
modifiersDefault: ["state_coordination"],
|
|
283
284
|
splitStrategy: ["Core data model", "Rendering/UI layer", "Event handling + state management", "Application shell"],
|
|
284
285
|
},
|
|
285
|
-
|
|
286
|
-
name: "
|
|
287
|
-
description: "
|
|
286
|
+
infrastructure_tooling: {
|
|
287
|
+
name: "Infrastructure & Tooling",
|
|
288
|
+
description: "Extension development, CLI tooling, internal infrastructure, build systems, or agentic framework work",
|
|
288
289
|
keywords: [
|
|
289
|
-
"
|
|
290
|
-
"
|
|
290
|
+
"extension", "plugin", "tool", "command", "cli", "config", "configuration",
|
|
291
|
+
"pipeline", "build", "deploy", "ci", "cd", "workflow", "script", "hook",
|
|
292
|
+
"provider", "routing", "dispatch", "handler", "registry", "loader",
|
|
293
|
+
"prompt", "agent", "inference",
|
|
294
|
+
"dashboard", "diagnostic", "telemetry", "logging",
|
|
295
|
+
"skill", "template", "scaffold", "generate", "emit",
|
|
291
296
|
],
|
|
292
|
-
requiredAny: ["
|
|
297
|
+
requiredAny: ["extension", "plugin", "provider", "routing",
|
|
298
|
+
"dispatch", "registry", "agent", "skill"],
|
|
293
299
|
expectedComponents: {
|
|
294
|
-
|
|
295
|
-
|
|
300
|
+
core: ["extension", "plugin", "tool", "command", "handler", "provider", "registry"],
|
|
301
|
+
integration: ["config", "pipeline", "workflow", "routing", "dispatch", "loader"],
|
|
302
|
+
surface: ["cli", "dashboard", "status", "prompt", "template", "diagnostic"],
|
|
296
303
|
},
|
|
297
|
-
systemsBase: 1
|
|
304
|
+
systemsBase: 1,
|
|
298
305
|
modifiersDefault: [],
|
|
299
|
-
splitStrategy: ["
|
|
306
|
+
splitStrategy: ["Core implementation", "Integration + wiring", "Tests + documentation"],
|
|
300
307
|
},
|
|
301
308
|
};
|
|
302
309
|
|
|
@@ -462,11 +469,18 @@ export function detectModifiers(directive: string): string[] {
|
|
|
462
469
|
}
|
|
463
470
|
|
|
464
471
|
/**
|
|
465
|
-
* Calculate complexity:
|
|
472
|
+
* Calculate complexity: systems × (1 + 0.5 × modifiers).
|
|
473
|
+
*
|
|
474
|
+
* Previous formula was (1 + systems) which gave a floor of 2.0 even for
|
|
475
|
+
* single-system, zero-modifier directives — making the heuristic path
|
|
476
|
+
* always exceed the default threshold of 2.0. Using bare `systems`
|
|
477
|
+
* allows trivial directives (1 system, 0 modifiers) to score 1.0,
|
|
478
|
+
* so they correctly get `needs_assessment` instead of `cleave`.
|
|
479
|
+
*
|
|
466
480
|
* Capped at 100.0.
|
|
467
481
|
*/
|
|
468
482
|
export function calculateComplexity(systems: number, modifiers: string[]): number {
|
|
469
|
-
const raw =
|
|
483
|
+
const raw = systems * (1 + 0.5 * modifiers.length);
|
|
470
484
|
return Math.round(Math.min(raw, 100.0) * 10) / 10;
|
|
471
485
|
}
|
|
472
486
|
|
|
@@ -536,7 +550,7 @@ export function assessDirective(
|
|
|
536
550
|
reasoning:
|
|
537
551
|
`Pattern '${match.name}' matched with ${(match.confidence * 100).toFixed(0)}% confidence. ` +
|
|
538
552
|
`Systems: ${systemsForDisplay}, Modifiers: ${allModifiers.length}. ` +
|
|
539
|
-
`Formula:
|
|
553
|
+
`Formula: ${systemsForCalc} × (1 + 0.5 × ${allModifiers.length}) = ${complexity}. ` +
|
|
540
554
|
`Effective (validate=${validate}): ${effComplexity}`,
|
|
541
555
|
skipInterrogation: false,
|
|
542
556
|
};
|
|
@@ -545,7 +559,7 @@ export function assessDirective(
|
|
|
545
559
|
if (
|
|
546
560
|
match.confidence >= 0.90 &&
|
|
547
561
|
effComplexity <= threshold &&
|
|
548
|
-
match.name === "
|
|
562
|
+
match.name === "Refactor"
|
|
549
563
|
) {
|
|
550
564
|
result.skipInterrogation = true;
|
|
551
565
|
}
|
|
@@ -347,6 +347,50 @@ async function checkpointRelatedChanges(
|
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Maximum number of interactive preflight attempts before bailing.
|
|
352
|
+
* Prevents infinite loops when the agent repeatedly picks actions
|
|
353
|
+
* that don't resolve the dirty tree.
|
|
354
|
+
*/
|
|
355
|
+
const MAX_PREFLIGHT_ATTEMPTS = 3;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Verify the tree is clean after an action. If only volatile files remain,
|
|
359
|
+
* auto-stash them. Returns true if the tree is resolved, false if dirty
|
|
360
|
+
* files remain.
|
|
361
|
+
*/
|
|
362
|
+
async function verifyCleanAfterAction(
|
|
363
|
+
pi: ExtensionAPI,
|
|
364
|
+
repoPath: string,
|
|
365
|
+
changeName: string | null,
|
|
366
|
+
openspecContext: OpenSpecContext | null,
|
|
367
|
+
onUpdate?: AgentToolUpdateCallback<Record<string, unknown>>,
|
|
368
|
+
): Promise<{ clean: boolean; classification: WorkspaceDirtyTreeClassification | null }> {
|
|
369
|
+
const postStatus = await pi.exec("git", ["status", "--porcelain"], {
|
|
370
|
+
cwd: repoPath,
|
|
371
|
+
timeout: 5_000,
|
|
372
|
+
});
|
|
373
|
+
const postState = inspectGitState(postStatus.stdout);
|
|
374
|
+
if (postState.entries.length === 0) return { clean: true, classification: null };
|
|
375
|
+
|
|
376
|
+
const postClassification = classifyPreflightDirtyPaths(
|
|
377
|
+
postState.entries.map((e) => e.path),
|
|
378
|
+
{ changeName, openspecContext },
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
// If only volatile files remain, auto-stash and treat as clean.
|
|
382
|
+
if (postState.nonVolatile.length === 0 && postClassification.volatile.length > 0) {
|
|
383
|
+
await stashPaths(pi, repoPath, "cleave-preflight-volatile", postClassification.volatile);
|
|
384
|
+
onUpdate?.({
|
|
385
|
+
content: [{ type: "text", text: "Remaining volatile artifacts stashed automatically — tree is clean." }],
|
|
386
|
+
details: { phase: "preflight", autoResolved: "volatile_only_stash" },
|
|
387
|
+
});
|
|
388
|
+
return { clean: true, classification: null };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return { clean: false, classification: postClassification };
|
|
392
|
+
}
|
|
393
|
+
|
|
350
394
|
export async function runDirtyTreePreflight(pi: ExtensionAPI, options: DirtyTreePreflightOptions): Promise<"continue" | "skip_cleave" | "cancelled"> {
|
|
351
395
|
const status = await pi.exec("git", ["status", "--porcelain"], {
|
|
352
396
|
cwd: options.repoPath,
|
|
@@ -369,12 +413,11 @@ export async function runDirtyTreePreflight(pi: ExtensionAPI, options: DirtyTree
|
|
|
369
413
|
changeName,
|
|
370
414
|
openspecContext,
|
|
371
415
|
});
|
|
372
|
-
// Compute initial checkpoint plan for the summary display only.
|
|
373
|
-
// The plan is rebuilt from currentClassification inside the loop on each attempt (C4).
|
|
374
416
|
const initialCheckpointPlan = buildCheckpointPlan(classification, { changeName, openspecContext });
|
|
375
417
|
const summary = formatDirtyTreeSummary(classification, initialCheckpointPlan.message);
|
|
376
418
|
options.onUpdate?.({ content: [{ type: "text", text: summary }], details: { phase: "preflight" } });
|
|
377
419
|
|
|
420
|
+
// Auto-resolve: volatile-only dirty tree — stash and continue without prompting.
|
|
378
421
|
if (gitState.nonVolatile.length === 0) {
|
|
379
422
|
if (classification.volatile.length > 0) {
|
|
380
423
|
await stashPaths(pi, options.repoPath, "cleave-preflight-volatile", classification.volatile);
|
|
@@ -392,86 +435,88 @@ export async function runDirtyTreePreflight(pi: ExtensionAPI, options: DirtyTree
|
|
|
392
435
|
throw new Error(summary + "\n\nInteractive input is unavailable, so cleave cannot resolve the dirty tree automatically.");
|
|
393
436
|
}
|
|
394
437
|
|
|
395
|
-
// Mutable classification — refreshed after each
|
|
438
|
+
// Mutable classification — refreshed after each action attempt.
|
|
396
439
|
let currentClassification = classification;
|
|
440
|
+
let attempts = 0;
|
|
441
|
+
|
|
442
|
+
while (attempts < MAX_PREFLIGHT_ATTEMPTS) {
|
|
443
|
+
attempts++;
|
|
397
444
|
|
|
398
|
-
while (true) {
|
|
399
445
|
let answer: string | undefined;
|
|
400
446
|
if (hasSelect) {
|
|
401
|
-
// Preferred path: show a modal select with labelled options and descriptions.
|
|
402
447
|
const selected = await options.ui!.select!(
|
|
403
448
|
"Dirty tree detected — choose a preflight action to proceed:",
|
|
404
449
|
[...PREFLIGHT_ACTION_OPTIONS],
|
|
405
450
|
);
|
|
406
451
|
answer = parsePreflightAction(selected);
|
|
407
452
|
} else {
|
|
408
|
-
// Fallback: raw text input (headless / test environments).
|
|
409
453
|
answer = normalizePreflightInput(
|
|
410
454
|
await options.ui!.input!("Dirty tree action [checkpoint|stash-unrelated|stash-volatile|proceed-without-cleave|cancel]:"),
|
|
411
455
|
)?.toLowerCase();
|
|
412
456
|
}
|
|
457
|
+
|
|
413
458
|
try {
|
|
414
459
|
switch (answer) {
|
|
415
460
|
case "checkpoint": {
|
|
416
|
-
// Rebuild the checkpoint plan from the current (possibly refreshed) classification (C4).
|
|
417
461
|
const currentCheckpointPlan = buildCheckpointPlan(currentClassification, { changeName, openspecContext });
|
|
418
|
-
const committedFiles = new Set(currentClassification.checkpointFiles);
|
|
419
462
|
await checkpointRelatedChanges(pi, options.repoPath, currentClassification, currentCheckpointPlan.message, options.ui);
|
|
420
|
-
// Re-verify cleanliness after the checkpoint commit.
|
|
421
|
-
const postCheckpointStatus = await pi.exec("git", ["status", "--porcelain"], {
|
|
422
|
-
cwd: options.repoPath,
|
|
423
|
-
timeout: 5_000,
|
|
424
|
-
});
|
|
425
|
-
const postState = inspectGitState(postCheckpointStatus.stdout);
|
|
426
|
-
if (postState.entries.length === 0) {
|
|
427
|
-
// Tree is clean — checkpoint fully resolved the dirty tree.
|
|
428
|
-
return "continue";
|
|
429
|
-
}
|
|
430
463
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
postState.entries.map((e) => e.path),
|
|
434
|
-
{ changeName, openspecContext },
|
|
464
|
+
const { clean, classification: postClassification } = await verifyCleanAfterAction(
|
|
465
|
+
pi, options.repoPath, changeName, openspecContext, options.onUpdate,
|
|
435
466
|
);
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Remaining dirty files — emit precise diagnosis (W1: distinguish committed-but-still-dirty vs excluded-from-scope).
|
|
448
|
-
const remainingPaths = postState.entries.map((e) => e.path);
|
|
449
|
-
const diagnosisLines = [
|
|
450
|
-
"Checkpoint committed successfully, but dirty files remain — cleave cannot continue yet:",
|
|
451
|
-
...currentClassification.related.map((f) =>
|
|
452
|
-
committedFiles.has(f.path)
|
|
453
|
-
? ` • ${f.path} [was committed but remains dirty — file may have been modified after staging or only partially staged]`
|
|
454
|
-
: ` • ${f.path} [related but excluded from checkpoint scope — confidence too low to commit automatically]`
|
|
455
|
-
),
|
|
456
|
-
...currentClassification.unrelated.map((f) => ` • ${f.path} [unrelated: ${f.reason}]`),
|
|
457
|
-
...currentClassification.unknown.map((f) => ` • ${f.path} [unknown — not in change scope, was not checkpointed]`),
|
|
458
|
-
...currentClassification.volatile.map((f) => ` • ${f.path} [volatile artifact — will be auto-stashed]`),
|
|
459
|
-
"",
|
|
460
|
-
"Choose another preflight action to resolve the remaining files.",
|
|
467
|
+
if (clean) return "continue";
|
|
468
|
+
|
|
469
|
+
// Dirty files remain after checkpoint — update classification and show diagnosis.
|
|
470
|
+
currentClassification = postClassification!;
|
|
471
|
+
const remainingPaths = [
|
|
472
|
+
...currentClassification.related,
|
|
473
|
+
...currentClassification.unrelated,
|
|
474
|
+
...currentClassification.unknown,
|
|
475
|
+
...currentClassification.volatile,
|
|
461
476
|
];
|
|
462
477
|
options.onUpdate?.({
|
|
463
|
-
content: [{ type: "text", text:
|
|
464
|
-
|
|
478
|
+
content: [{ type: "text", text:
|
|
479
|
+
"Checkpoint committed, but dirty files remain:\n" +
|
|
480
|
+
remainingPaths.map((f) => ` • ${f.path} [${f.reason}]`).join("\n") +
|
|
481
|
+
"\n\nChoose another action to resolve.",
|
|
482
|
+
}],
|
|
483
|
+
details: { phase: "preflight", postCheckpointDirty: remainingPaths.map((f) => f.path) },
|
|
465
484
|
});
|
|
466
485
|
break;
|
|
467
486
|
}
|
|
468
|
-
case "stash-unrelated":
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
487
|
+
case "stash-unrelated": {
|
|
488
|
+
const toStash = [...currentClassification.unrelated, ...currentClassification.unknown];
|
|
489
|
+
if (toStash.length === 0) {
|
|
490
|
+
options.onUpdate?.({
|
|
491
|
+
content: [{ type: "text", text: "No unrelated or unknown files to stash. Choose a different action." }],
|
|
492
|
+
details: { phase: "preflight" },
|
|
493
|
+
});
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
await stashPaths(pi, options.repoPath, "cleave-preflight-unrelated", toStash);
|
|
497
|
+
const { clean, classification: postClassification } = await verifyCleanAfterAction(
|
|
498
|
+
pi, options.repoPath, changeName, openspecContext, options.onUpdate,
|
|
499
|
+
);
|
|
500
|
+
if (clean) return "continue";
|
|
501
|
+
currentClassification = postClassification!;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
case "stash-volatile": {
|
|
505
|
+
if (currentClassification.volatile.length === 0) {
|
|
506
|
+
options.onUpdate?.({
|
|
507
|
+
content: [{ type: "text", text: "No volatile files to stash. Choose a different action." }],
|
|
508
|
+
details: { phase: "preflight" },
|
|
509
|
+
});
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
473
512
|
await stashPaths(pi, options.repoPath, "cleave-preflight-volatile", currentClassification.volatile);
|
|
474
|
-
|
|
513
|
+
const { clean, classification: postClassification } = await verifyCleanAfterAction(
|
|
514
|
+
pi, options.repoPath, changeName, openspecContext, options.onUpdate,
|
|
515
|
+
);
|
|
516
|
+
if (clean) return "continue";
|
|
517
|
+
currentClassification = postClassification!;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
475
520
|
case "proceed-without-cleave":
|
|
476
521
|
return "skip_cleave";
|
|
477
522
|
case "cancel":
|
|
@@ -479,7 +524,7 @@ export async function runDirtyTreePreflight(pi: ExtensionAPI, options: DirtyTree
|
|
|
479
524
|
return "cancelled";
|
|
480
525
|
default:
|
|
481
526
|
options.onUpdate?.({
|
|
482
|
-
content: [{ type: "text", text: "Invalid
|
|
527
|
+
content: [{ type: "text", text: "Invalid action. Choose checkpoint, stash-unrelated, stash-volatile, proceed-without-cleave, or cancel." }],
|
|
483
528
|
details: { phase: "preflight" },
|
|
484
529
|
});
|
|
485
530
|
}
|
|
@@ -491,6 +536,19 @@ export async function runDirtyTreePreflight(pi: ExtensionAPI, options: DirtyTree
|
|
|
491
536
|
});
|
|
492
537
|
}
|
|
493
538
|
}
|
|
539
|
+
|
|
540
|
+
// Exhausted attempts — report remaining dirty files and bail.
|
|
541
|
+
const remaining = [
|
|
542
|
+
...currentClassification.related,
|
|
543
|
+
...currentClassification.unrelated,
|
|
544
|
+
...currentClassification.unknown,
|
|
545
|
+
...currentClassification.volatile,
|
|
546
|
+
];
|
|
547
|
+
throw new Error(
|
|
548
|
+
`Dirty tree not resolved after ${MAX_PREFLIGHT_ATTEMPTS} attempts. Remaining files:\n` +
|
|
549
|
+
remaining.map((f) => ` • ${f.path}`).join("\n") +
|
|
550
|
+
"\n\nResolve manually (git commit/stash/checkout) and retry /cleave.",
|
|
551
|
+
);
|
|
494
552
|
}
|
|
495
553
|
|
|
496
554
|
interface AssessExecutionContext {
|
|
@@ -1586,7 +1644,7 @@ export default function cleaveExtension(pi: ExtensionAPI) {
|
|
|
1586
1644
|
"Every non-trivial code change must include tests in co-located *.test.ts files. Untested code is incomplete — do not commit without tests for new functions and changed behavior.",
|
|
1587
1645
|
"Call cleave_assess before starting any multi-system or cross-cutting task to determine if decomposition is needed",
|
|
1588
1646
|
"If decision is 'execute', proceed directly. If 'cleave', use /cleave to decompose. If 'needs_assessment', proceed directly — it means no pattern matched but the task is likely simple enough for in-session execution.",
|
|
1589
|
-
"Complexity formula:
|
|
1647
|
+
"Complexity formula: systems × (1 + 0.5 × modifiers). Threshold default: 2.0.",
|
|
1590
1648
|
"The /assess command provides code assessment: `/assess cleave` (adversarial review + auto-fix), `/assess diff [ref]` (review only), `/assess spec [change]` (validate against OpenSpec scenarios), `/assess design [node-id]` (evaluate design-tree node readiness before set_status(decided)).",
|
|
1591
1649
|
"When the repo has openspec/ with active changes, suggest `/assess spec` after implementation and before `/opsx:archive`.",
|
|
1592
1650
|
"Run `/assess design <node-id>` before calling design_tree_update with set_status(decided) to verify acceptance criteria are satisfied.",
|
|
@@ -427,9 +427,13 @@ export function computeAssessmentSnapshot(repoPath: string, changeName: string):
|
|
|
427
427
|
const gitHead = safeReadGit(repoPath, ["rev-parse", "HEAD"]);
|
|
428
428
|
const dirty = detectGitDirty(repoPath, snapshotPaths);
|
|
429
429
|
|
|
430
|
+
// Fingerprint represents implementation file content — NOT git HEAD.
|
|
431
|
+
// Including gitHead would create a chicken-and-egg: committing the
|
|
432
|
+
// assessment.json (which lives in-repo) changes HEAD, which invalidates
|
|
433
|
+
// the fingerprint, making the assessment permanently stale.
|
|
434
|
+
// Git HEAD is stored separately in the snapshot for informational use.
|
|
430
435
|
const fingerprintSeed = JSON.stringify({
|
|
431
436
|
changeName,
|
|
432
|
-
gitHead,
|
|
433
437
|
dirty,
|
|
434
438
|
files,
|
|
435
439
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omegon",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Omegon — an opinionated distribution of pi (by Mario Zechner) with extensions for lifecycle management, memory, orchestration, and visualization",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omegon": "bin/omegon.mjs",
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"./extensions/cleave",
|
|
59
59
|
"./extensions/openspec",
|
|
60
60
|
"./extensions/defaults.ts",
|
|
61
|
-
"./extensions/distill.ts",
|
|
62
61
|
"./extensions/render",
|
|
63
62
|
"./extensions/local-inference",
|
|
64
63
|
"./extensions/mcp-bridge",
|
package/skills/cleave/SKILL.md
CHANGED
|
@@ -91,15 +91,21 @@ This status is injected into the agent context (not just displayed).
|
|
|
91
91
|
## Complexity Formula
|
|
92
92
|
|
|
93
93
|
```
|
|
94
|
-
complexity =
|
|
94
|
+
complexity = systems × (1 + 0.5 × modifiers)
|
|
95
95
|
effective = complexity + 1 (when validation enabled)
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
The formula uses bare `systems` (not `1 + systems`) so that single-system,
|
|
99
|
+
zero-modifier directives score 1.0 (effective 2.0) — at the default threshold
|
|
100
|
+
of 2.0, they get `needs_assessment` rather than being falsely recommended
|
|
101
|
+
for decomposition.
|
|
102
|
+
|
|
103
|
+
## Patterns (12)
|
|
99
104
|
|
|
100
105
|
Full-Stack CRUD, Authentication System, External Service Integration,
|
|
101
106
|
Database Migration, Performance Optimization, Breaking API Change,
|
|
102
|
-
|
|
107
|
+
Refactor, Bug Fix, Greenfield Project, Multi-Module Library,
|
|
108
|
+
Application Bootstrap, Infrastructure & Tooling.
|
|
103
109
|
|
|
104
110
|
## Adversarial Review Loop
|
|
105
111
|
|