liteagents 2.11.1 → 2.12.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 +10 -0
- package/installer/package-manager.js +11 -2
- package/package.json +1 -1
- package/packages/ampcode/commands/friction/friction.js +7 -1
- package/packages/claude/commands/friction/friction.js +7 -1
- package/packages/droid/commands/friction/friction.js +7 -1
- package/packages/opencode/command/friction/friction.js +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
+
## [2.12.0] - 2026-07-07
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Friction cluster ranking now breaks ties by intensity.** Antigen/episode clusters were ordered by tier then recurrence, with equal-recurrence ties left to incidental feed order — so a mild reaction could outrank a far more intense one that recurred equally. Added a final tiebreak on median peak friction (a value already computed), so the more intense reaction ranks first. Ranking-only: it reorders within what recurrence already gated and never promotes across the severity × recurrence 2×2 (a loud one-off stays an episode). Applied identically across all four packages.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **`validate-packages` failed 0/4 valid on every package.** `validatePackage` demanded a `<name>.md` for each selected command, but a command can legitimately ship as a helper subdirectory with no doc — `commands/friction/friction.js`, run by `/remember` after `/friction` was collapsed into it. The installer already bundles such subdirs; validation now matches that instead of requiring a resurrected `friction.md`. No user-facing command is re-added.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
20
30
|
## [2.11.1] - 2026-07-03
|
|
21
31
|
|
|
22
32
|
### Changed
|
|
@@ -583,7 +583,7 @@ class PackageManager {
|
|
|
583
583
|
const selectedContent = await this.selectVariantContent(toolId, variant, availableContent);
|
|
584
584
|
|
|
585
585
|
// Helper function to check if file/directory exists
|
|
586
|
-
const checkContentExists = async (category, items, dirName, addExtension = false) => {
|
|
586
|
+
const checkContentExists = async (category, items, dirName, addExtension = false, allowBundleDir = false) => {
|
|
587
587
|
const categoryDir = path.join(packageDir, dirName);
|
|
588
588
|
|
|
589
589
|
// If directory doesn't exist but items are expected, that's an issue
|
|
@@ -611,6 +611,15 @@ class PackageManager {
|
|
|
611
611
|
}
|
|
612
612
|
|
|
613
613
|
if (!fs.existsSync(itemPath)) {
|
|
614
|
+
// A command may ship as a bundled helper subdirectory (no .md doc),
|
|
615
|
+
// e.g. friction/friction.js run by /remember. The installer bundles
|
|
616
|
+
// such subdirs; accept them here so validation matches install.
|
|
617
|
+
if (allowBundleDir) {
|
|
618
|
+
const bundleDir = path.join(categoryDir, item);
|
|
619
|
+
if (fs.existsSync(bundleDir) && fs.statSync(bundleDir).isDirectory()) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
614
623
|
const displayPath = addExtension ? `${item}.md` : item;
|
|
615
624
|
issues.push(`${category.slice(0, -1)} '${displayPath}' not found in ${dirName}/ (required by ${variant} variant)`);
|
|
616
625
|
missingFiles++;
|
|
@@ -627,7 +636,7 @@ class PackageManager {
|
|
|
627
636
|
|
|
628
637
|
// Validate commands (use dynamic directory name)
|
|
629
638
|
const commandsDirName = availableContent.commandsDir || 'commands';
|
|
630
|
-
await checkContentExists('commands', selectedContent.commands || [], commandsDirName, true);
|
|
639
|
+
await checkContentExists('commands', selectedContent.commands || [], commandsDirName, true, true);
|
|
631
640
|
|
|
632
641
|
// Validate plugins (directories, like skills)
|
|
633
642
|
await checkContentExists('plugins', selectedContent.plugins || [], 'plugins', false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "liteagents",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "AI development toolkit with 11 specialized agents and 17 commands including live-canvas UI design with click-to-annotate feedback. Simple one-question installer for Claude, Opencode, Ampcode, and Droid.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -2179,8 +2179,14 @@ function clusterCandidates(allCandidates) {
|
|
|
2179
2179
|
});
|
|
2180
2180
|
|
|
2181
2181
|
// Drop the noise tier (one-off + mild); rank by recurrence then severity.
|
|
2182
|
+
// Final tiebreak on median peak friction — graded intensity discriminates
|
|
2183
|
+
// among clusters that tie on tier and recurrence. Ranking only: it reorders
|
|
2184
|
+
// within what recurrence already gated, never promotes across the 2x2.
|
|
2182
2185
|
const kept = out.filter(c => c.suggested_artifact !== 'drop');
|
|
2183
|
-
kept.sort((a, b) =>
|
|
2186
|
+
kept.sort((a, b) =>
|
|
2187
|
+
b.score - a.score
|
|
2188
|
+
|| b.sessions - a.sessions
|
|
2189
|
+
|| (b.median_peak || 0) - (a.median_peak || 0));
|
|
2184
2190
|
return kept;
|
|
2185
2191
|
}
|
|
2186
2192
|
|
|
@@ -2179,8 +2179,14 @@ function clusterCandidates(allCandidates) {
|
|
|
2179
2179
|
});
|
|
2180
2180
|
|
|
2181
2181
|
// Drop the noise tier (one-off + mild); rank by recurrence then severity.
|
|
2182
|
+
// Final tiebreak on median peak friction — graded intensity discriminates
|
|
2183
|
+
// among clusters that tie on tier and recurrence. Ranking only: it reorders
|
|
2184
|
+
// within what recurrence already gated, never promotes across the 2x2.
|
|
2182
2185
|
const kept = out.filter(c => c.suggested_artifact !== 'drop');
|
|
2183
|
-
kept.sort((a, b) =>
|
|
2186
|
+
kept.sort((a, b) =>
|
|
2187
|
+
b.score - a.score
|
|
2188
|
+
|| b.sessions - a.sessions
|
|
2189
|
+
|| (b.median_peak || 0) - (a.median_peak || 0));
|
|
2184
2190
|
return kept;
|
|
2185
2191
|
}
|
|
2186
2192
|
|
|
@@ -2179,8 +2179,14 @@ function clusterCandidates(allCandidates) {
|
|
|
2179
2179
|
});
|
|
2180
2180
|
|
|
2181
2181
|
// Drop the noise tier (one-off + mild); rank by recurrence then severity.
|
|
2182
|
+
// Final tiebreak on median peak friction — graded intensity discriminates
|
|
2183
|
+
// among clusters that tie on tier and recurrence. Ranking only: it reorders
|
|
2184
|
+
// within what recurrence already gated, never promotes across the 2x2.
|
|
2182
2185
|
const kept = out.filter(c => c.suggested_artifact !== 'drop');
|
|
2183
|
-
kept.sort((a, b) =>
|
|
2186
|
+
kept.sort((a, b) =>
|
|
2187
|
+
b.score - a.score
|
|
2188
|
+
|| b.sessions - a.sessions
|
|
2189
|
+
|| (b.median_peak || 0) - (a.median_peak || 0));
|
|
2184
2190
|
return kept;
|
|
2185
2191
|
}
|
|
2186
2192
|
|
|
@@ -2179,8 +2179,14 @@ function clusterCandidates(allCandidates) {
|
|
|
2179
2179
|
});
|
|
2180
2180
|
|
|
2181
2181
|
// Drop the noise tier (one-off + mild); rank by recurrence then severity.
|
|
2182
|
+
// Final tiebreak on median peak friction — graded intensity discriminates
|
|
2183
|
+
// among clusters that tie on tier and recurrence. Ranking only: it reorders
|
|
2184
|
+
// within what recurrence already gated, never promotes across the 2x2.
|
|
2182
2185
|
const kept = out.filter(c => c.suggested_artifact !== 'drop');
|
|
2183
|
-
kept.sort((a, b) =>
|
|
2186
|
+
kept.sort((a, b) =>
|
|
2187
|
+
b.score - a.score
|
|
2188
|
+
|| b.sessions - a.sessions
|
|
2189
|
+
|| (b.median_peak || 0) - (a.median_peak || 0));
|
|
2184
2190
|
return kept;
|
|
2185
2191
|
}
|
|
2186
2192
|
|