liteagents 2.5.2 → 2.6.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 +76 -15
- package/README.md +58 -30
- package/docs/INSTALLATION_DEMO.md +1 -1
- package/docs/INSTALLATION_LOCATIONS.md +5 -5
- package/docs/INSTALLER_GUIDE.md +5 -5
- package/docs/KNOWLEDGE_BASE.md +5 -5
- package/docs/MIGRATION.md +1 -1
- package/docs/PASS_QUICK_START.md +1 -1
- package/docs/PRIVACY.md +1 -1
- package/docs/PUBLISHING.md +7 -7
- package/docs/RELEASE_NOTES_1.2.0.md +2 -2
- package/docs/SILENT_MODE_GUIDE.md +1 -1
- package/installer/cli.js +1 -1
- package/installer/installation-engine.js +82 -21
- package/installer/package-manager.js +34 -3
- package/package.json +7 -6
- package/packages/ampcode/AGENT.md +1 -0
- package/packages/ampcode/commands/friction/friction.js +19 -4
- package/packages/ampcode/commands/live-canvas/DESIGN_PRINCIPLES.md +2140 -0
- package/packages/ampcode/commands/live-canvas/README.md +273 -0
- package/packages/ampcode/commands/live-canvas/templates/.claude/settings.local.json +8 -0
- package/packages/ampcode/commands/live-canvas/templates/demo/post-variants.html +205 -0
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +1299 -0
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/format-utils.ts +283 -0
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/index.ts +62 -0
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/selector-utils.ts +423 -0
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/types.ts +118 -0
- package/packages/ampcode/commands/live-canvas/templates/overlay-vanilla.js +477 -0
- package/packages/ampcode/commands/live-canvas.md +1104 -0
- package/packages/claude/CLAUDE.md +1 -0
- package/packages/claude/commands/friction/friction.js +19 -4
- package/packages/claude/plugins/live-canvas-marketplace/.claude-plugin/marketplace.json +14 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/.claude-plugin/plugin.json +18 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/README.md +89 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package-lock.json +1142 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package.json +17 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/schema.json +37 -0
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/server.js +179 -0
- package/packages/claude/plugins/live-canvas-marketplace/setup.sh +61 -0
- package/packages/claude/skills/live-canvas/DESIGN_PRINCIPLES.md +2140 -0
- package/packages/claude/skills/live-canvas/INTEGRATION_NOTES.md +210 -0
- package/packages/claude/skills/live-canvas/README.md +273 -0
- package/packages/claude/skills/live-canvas/SKILL.md +1119 -0
- package/packages/claude/skills/live-canvas/templates/.claude/settings.local.json +8 -0
- package/packages/claude/skills/live-canvas/templates/demo/post-variants.html +205 -0
- package/packages/claude/skills/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +1299 -0
- package/packages/claude/skills/live-canvas/templates/feedback-react/format-utils.ts +283 -0
- package/packages/claude/skills/live-canvas/templates/feedback-react/index.ts +62 -0
- package/packages/claude/skills/live-canvas/templates/feedback-react/selector-utils.ts +423 -0
- package/packages/claude/skills/live-canvas/templates/feedback-react/types.ts +118 -0
- package/packages/claude/skills/live-canvas/templates/overlay-vanilla.js +477 -0
- package/packages/claude/variants.json +2 -1
- package/packages/droid/AGENTS.md +1 -0
- package/packages/droid/commands/friction/friction.js +19 -4
- package/packages/droid/commands/live-canvas/DESIGN_PRINCIPLES.md +2140 -0
- package/packages/droid/commands/live-canvas/README.md +273 -0
- package/packages/droid/commands/live-canvas/templates/.claude/settings.local.json +8 -0
- package/packages/droid/commands/live-canvas/templates/demo/post-variants.html +205 -0
- package/packages/droid/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +1299 -0
- package/packages/droid/commands/live-canvas/templates/feedback-react/format-utils.ts +283 -0
- package/packages/droid/commands/live-canvas/templates/feedback-react/index.ts +62 -0
- package/packages/droid/commands/live-canvas/templates/feedback-react/selector-utils.ts +423 -0
- package/packages/droid/commands/live-canvas/templates/feedback-react/types.ts +118 -0
- package/packages/droid/commands/live-canvas/templates/overlay-vanilla.js +477 -0
- package/packages/droid/commands/live-canvas.md +1104 -0
- package/packages/opencode/AGENTS.md +1 -0
- package/packages/opencode/command/friction/friction.js +19 -4
- package/packages/opencode/command/live-canvas/DESIGN_PRINCIPLES.md +2140 -0
- package/packages/opencode/command/live-canvas/README.md +273 -0
- package/packages/opencode/command/live-canvas/templates/.claude/settings.local.json +8 -0
- package/packages/opencode/command/live-canvas/templates/demo/post-variants.html +205 -0
- package/packages/opencode/command/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +1299 -0
- package/packages/opencode/command/live-canvas/templates/feedback-react/format-utils.ts +283 -0
- package/packages/opencode/command/live-canvas/templates/feedback-react/index.ts +62 -0
- package/packages/opencode/command/live-canvas/templates/feedback-react/selector-utils.ts +423 -0
- package/packages/opencode/command/live-canvas/templates/feedback-react/types.ts +118 -0
- package/packages/opencode/command/live-canvas/templates/overlay-vanilla.js +477 -0
- package/packages/opencode/command/live-canvas.md +1104 -0
- package/packages/opencode/opencode.jsonc +4 -0
- package/packages/subagentic-manual.md +18 -15
|
@@ -194,18 +194,23 @@ class InstallationEngine {
|
|
|
194
194
|
}
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
-
// Helper function to recursively collect all files in a directory
|
|
198
|
-
|
|
197
|
+
// Helper function to recursively collect all files in a directory.
|
|
198
|
+
// Skips node_modules directories (callers may set skipNodeModules=true for plugins).
|
|
199
|
+
const collectDirectoryFiles = async (dirPath, relativePath = '', skipNodeModules = false) => {
|
|
199
200
|
const items = await fs.promises.readdir(dirPath);
|
|
200
201
|
const filesInDir = [];
|
|
201
202
|
|
|
202
203
|
for (const item of items) {
|
|
204
|
+
if (skipNodeModules && item === 'node_modules') {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
203
208
|
const itemPath = path.join(dirPath, item);
|
|
204
209
|
const itemRelativePath = path.join(relativePath, item);
|
|
205
210
|
const stat = await fs.promises.stat(itemPath);
|
|
206
211
|
|
|
207
212
|
if (stat.isDirectory()) {
|
|
208
|
-
const subFiles = await collectDirectoryFiles(itemPath, itemRelativePath);
|
|
213
|
+
const subFiles = await collectDirectoryFiles(itemPath, itemRelativePath, skipNodeModules);
|
|
209
214
|
filesInDir.push(...subFiles);
|
|
210
215
|
} else {
|
|
211
216
|
filesInDir.push({
|
|
@@ -310,6 +315,23 @@ class InstallationEngine {
|
|
|
310
315
|
totalBytes += size;
|
|
311
316
|
}
|
|
312
317
|
|
|
318
|
+
// Collect all plugin files (plugins are directories like skills; skip node_modules)
|
|
319
|
+
for (const pluginPath of (packageContents.plugins || [])) {
|
|
320
|
+
const baseRelativePath = path.relative(sourceBase, pluginPath);
|
|
321
|
+
const pluginFiles = await collectDirectoryFiles(pluginPath, baseRelativePath, true);
|
|
322
|
+
|
|
323
|
+
for (const file of pluginFiles) {
|
|
324
|
+
filesToCopy.push({
|
|
325
|
+
sourcePath: file.sourcePath,
|
|
326
|
+
relativePath: file.relativePath,
|
|
327
|
+
size: file.size,
|
|
328
|
+
type: 'plugin'
|
|
329
|
+
});
|
|
330
|
+
totalFiles++;
|
|
331
|
+
totalBytes += file.size;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
313
335
|
// Now copy all files with progress tracking
|
|
314
336
|
let filesCompleted = 0;
|
|
315
337
|
let bytesTransferred = 0;
|
|
@@ -364,6 +386,11 @@ class InstallationEngine {
|
|
|
364
386
|
const items = await fs.promises.readdir(source);
|
|
365
387
|
|
|
366
388
|
for (const item of items) {
|
|
389
|
+
// Skip node_modules - callers (plugins, backups) should never ship bundled deps
|
|
390
|
+
if (item === 'node_modules') {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
367
394
|
const sourcePath = path.join(source, item);
|
|
368
395
|
const targetPath = path.join(target, item);
|
|
369
396
|
|
|
@@ -433,19 +460,22 @@ class InstallationEngine {
|
|
|
433
460
|
agents: contents.agents.length,
|
|
434
461
|
skills: contents.skills.length,
|
|
435
462
|
resources: contents.resources.length,
|
|
436
|
-
hooks: contents.hooks.length
|
|
463
|
+
hooks: contents.hooks.length,
|
|
464
|
+
plugins: (contents.plugins || []).length
|
|
437
465
|
},
|
|
438
466
|
installedFiles: {
|
|
439
467
|
agents: contents.agents.map(extractAgentName),
|
|
440
468
|
skills: contents.skills.map(extractSkillName),
|
|
441
469
|
resources: contents.resources.map(p => path.basename(p)),
|
|
442
|
-
hooks: contents.hooks.map(p => path.basename(p))
|
|
470
|
+
hooks: contents.hooks.map(p => path.basename(p)),
|
|
471
|
+
plugins: (contents.plugins || []).map(extractSkillName)
|
|
443
472
|
},
|
|
444
473
|
paths: {
|
|
445
474
|
agents: path.join(targetPath, 'agents'),
|
|
446
475
|
skills: path.join(targetPath, 'skills'),
|
|
447
476
|
resources: path.join(targetPath, 'resources'),
|
|
448
|
-
hooks: path.join(targetPath, 'hooks')
|
|
477
|
+
hooks: path.join(targetPath, 'hooks'),
|
|
478
|
+
plugins: path.join(targetPath, 'plugins')
|
|
449
479
|
},
|
|
450
480
|
files: {
|
|
451
481
|
total: contents.totalFiles,
|
|
@@ -538,7 +568,7 @@ class InstallationEngine {
|
|
|
538
568
|
|
|
539
569
|
// Remove files listed in manifest
|
|
540
570
|
if (manifest.installedFiles) {
|
|
541
|
-
for (const category of ['agents', 'skills', 'resources', 'hooks']) {
|
|
571
|
+
for (const category of ['agents', 'skills', 'resources', 'hooks', 'plugins']) {
|
|
542
572
|
if (manifest.installedFiles[category] && manifest.paths && manifest.paths[category]) {
|
|
543
573
|
const categoryPath = manifest.paths[category];
|
|
544
574
|
|
|
@@ -548,8 +578,8 @@ class InstallationEngine {
|
|
|
548
578
|
if (category === 'agents') {
|
|
549
579
|
// Agents have .md extension
|
|
550
580
|
itemPath = path.join(categoryPath, `${item}.md`);
|
|
551
|
-
} else if (category === 'skills') {
|
|
552
|
-
// Skills are directories
|
|
581
|
+
} else if (category === 'skills' || category === 'plugins') {
|
|
582
|
+
// Skills and plugins are directories
|
|
553
583
|
itemPath = path.join(categoryPath, item);
|
|
554
584
|
} else {
|
|
555
585
|
// Resources and hooks have their full names
|
|
@@ -650,7 +680,7 @@ class InstallationEngine {
|
|
|
650
680
|
* @param {string} targetPath - Base installation path
|
|
651
681
|
*/
|
|
652
682
|
async cleanupEmptyDirectories(targetPath) {
|
|
653
|
-
const categories = ['agents', 'skills', 'resources', 'hooks'];
|
|
683
|
+
const categories = ['agents', 'skills', 'resources', 'hooks', 'plugins'];
|
|
654
684
|
|
|
655
685
|
for (const category of categories) {
|
|
656
686
|
const categoryPath = path.join(targetPath, category);
|
|
@@ -762,7 +792,8 @@ class InstallationEngine {
|
|
|
762
792
|
agents: { expected: 0, found: 0, missing: [] },
|
|
763
793
|
skills: { expected: 0, found: 0, missing: [] },
|
|
764
794
|
resources: { expected: 0, found: 0, missing: [] },
|
|
765
|
-
hooks: { expected: 0, found: 0, missing: [] }
|
|
795
|
+
hooks: { expected: 0, found: 0, missing: [] },
|
|
796
|
+
plugins: { expected: 0, found: 0, missing: [] }
|
|
766
797
|
},
|
|
767
798
|
timestamp: new Date().toISOString()
|
|
768
799
|
};
|
|
@@ -785,8 +816,16 @@ class InstallationEngine {
|
|
|
785
816
|
const manifest = JSON.parse(await fs.promises.readFile(manifestPath, 'utf8'));
|
|
786
817
|
result.manifest = manifest;
|
|
787
818
|
|
|
788
|
-
// Verify all required directories exist
|
|
819
|
+
// Verify all required directories exist (skip categories with 0 expected items)
|
|
789
820
|
for (const [component, componentPath] of Object.entries(manifest.paths || {})) {
|
|
821
|
+
const expectedCount = (manifest.installedFiles && Array.isArray(manifest.installedFiles[component]))
|
|
822
|
+
? manifest.installedFiles[component].length
|
|
823
|
+
: 0;
|
|
824
|
+
|
|
825
|
+
if (expectedCount === 0) {
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
|
|
790
829
|
if (!fs.existsSync(componentPath)) {
|
|
791
830
|
result.valid = false;
|
|
792
831
|
result.issues.push({
|
|
@@ -799,7 +838,7 @@ class InstallationEngine {
|
|
|
799
838
|
}
|
|
800
839
|
|
|
801
840
|
// Verify installed files for each component category
|
|
802
|
-
for (const category of ['agents', 'skills', 'resources', 'hooks']) {
|
|
841
|
+
for (const category of ['agents', 'skills', 'resources', 'hooks', 'plugins']) {
|
|
803
842
|
if (manifest.installedFiles && manifest.installedFiles[category]) {
|
|
804
843
|
const expectedFiles = manifest.installedFiles[category];
|
|
805
844
|
result.components[category].expected = expectedFiles.length;
|
|
@@ -812,7 +851,7 @@ class InstallationEngine {
|
|
|
812
851
|
// Construct full path based on category
|
|
813
852
|
if (category === 'agents') {
|
|
814
853
|
itemPath = path.join(categoryPath, `${item}.md`);
|
|
815
|
-
} else if (category === 'skills') {
|
|
854
|
+
} else if (category === 'skills' || category === 'plugins') {
|
|
816
855
|
itemPath = path.join(categoryPath, item);
|
|
817
856
|
} else {
|
|
818
857
|
itemPath = path.join(categoryPath, item);
|
|
@@ -847,7 +886,7 @@ class InstallationEngine {
|
|
|
847
886
|
|
|
848
887
|
// Verify file counts match
|
|
849
888
|
if (manifest.components) {
|
|
850
|
-
for (const category of ['agents', 'skills', 'resources', 'hooks']) {
|
|
889
|
+
for (const category of ['agents', 'skills', 'resources', 'hooks', 'plugins']) {
|
|
851
890
|
if (manifest.components[category] !== undefined) {
|
|
852
891
|
const expectedCount = manifest.components[category];
|
|
853
892
|
const foundCount = result.components[category].found;
|
|
@@ -967,7 +1006,7 @@ class InstallationEngine {
|
|
|
967
1006
|
|
|
968
1007
|
// Collect all files from manifest
|
|
969
1008
|
if (manifest.installedFiles) {
|
|
970
|
-
for (const category of ['agents', 'skills', 'resources', 'hooks']) {
|
|
1009
|
+
for (const category of ['agents', 'skills', 'resources', 'hooks', 'plugins']) {
|
|
971
1010
|
if (manifest.installedFiles[category] && manifest.paths && manifest.paths[category]) {
|
|
972
1011
|
const categoryPath = manifest.paths[category];
|
|
973
1012
|
|
|
@@ -977,8 +1016,8 @@ class InstallationEngine {
|
|
|
977
1016
|
if (category === 'agents') {
|
|
978
1017
|
// Agents have .md extension
|
|
979
1018
|
itemPath = path.join(categoryPath, `${item}.md`);
|
|
980
|
-
} else if (category === 'skills') {
|
|
981
|
-
// Skills are directories - need to count all files inside
|
|
1019
|
+
} else if (category === 'skills' || category === 'plugins') {
|
|
1020
|
+
// Skills and plugins are directories - need to count all files inside
|
|
982
1021
|
itemPath = path.join(categoryPath, item);
|
|
983
1022
|
} else {
|
|
984
1023
|
// Resources and hooks have their full names
|
|
@@ -989,7 +1028,7 @@ class InstallationEngine {
|
|
|
989
1028
|
path: itemPath,
|
|
990
1029
|
category: category,
|
|
991
1030
|
name: item,
|
|
992
|
-
isDirectory: category === 'skills'
|
|
1031
|
+
isDirectory: category === 'skills' || category === 'plugins'
|
|
993
1032
|
});
|
|
994
1033
|
}
|
|
995
1034
|
}
|
|
@@ -1443,6 +1482,26 @@ class InstallationEngine {
|
|
|
1443
1482
|
}
|
|
1444
1483
|
}
|
|
1445
1484
|
|
|
1485
|
+
// Compare plugins (directories, like skills)
|
|
1486
|
+
const currentPluginsList = currentContents.plugins || [];
|
|
1487
|
+
const newPluginsList = newContents.plugins || [];
|
|
1488
|
+
const currentPlugins = new Set(currentPluginsList.map(p => path.basename(p)));
|
|
1489
|
+
const newPlugins = new Set(newPluginsList.map(p => path.basename(p)));
|
|
1490
|
+
|
|
1491
|
+
for (const plugin of newPluginsList) {
|
|
1492
|
+
const basename = path.basename(plugin);
|
|
1493
|
+
if (!currentPlugins.has(basename)) {
|
|
1494
|
+
toAdd.push({ type: 'plugin', source: plugin, name: basename });
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
for (const plugin of currentPluginsList) {
|
|
1499
|
+
const basename = path.basename(plugin);
|
|
1500
|
+
if (!newPlugins.has(basename)) {
|
|
1501
|
+
toRemove.push({ type: 'plugin', name: basename, category: 'plugins' });
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1446
1505
|
return { toAdd, toRemove };
|
|
1447
1506
|
}
|
|
1448
1507
|
|
|
@@ -1456,7 +1515,8 @@ class InstallationEngine {
|
|
|
1456
1515
|
agents: new Set(manifest.installedFiles.agents),
|
|
1457
1516
|
skills: new Set(manifest.installedFiles.skills),
|
|
1458
1517
|
resources: new Set(manifest.installedFiles.resources),
|
|
1459
|
-
hooks: new Set(manifest.installedFiles.hooks)
|
|
1518
|
+
hooks: new Set(manifest.installedFiles.hooks),
|
|
1519
|
+
plugins: new Set(manifest.installedFiles.plugins || [])
|
|
1460
1520
|
};
|
|
1461
1521
|
|
|
1462
1522
|
for (const file of filesToRemove) {
|
|
@@ -1503,7 +1563,8 @@ class InstallationEngine {
|
|
|
1503
1563
|
const sourcePath = file.source;
|
|
1504
1564
|
const targetCategory = file.type === 'agent' ? 'agents' :
|
|
1505
1565
|
file.type === 'skill' ? 'skills' :
|
|
1506
|
-
file.type === 'resource' ? 'resources' :
|
|
1566
|
+
file.type === 'resource' ? 'resources' :
|
|
1567
|
+
file.type === 'plugin' ? 'plugins' : 'hooks';
|
|
1507
1568
|
|
|
1508
1569
|
const targetDir = path.join(targetPath, targetCategory);
|
|
1509
1570
|
|
|
@@ -137,7 +137,8 @@ class PackageManager {
|
|
|
137
137
|
skills: [],
|
|
138
138
|
commands: [],
|
|
139
139
|
resources: [],
|
|
140
|
-
hooks: []
|
|
140
|
+
hooks: [],
|
|
141
|
+
plugins: []
|
|
141
142
|
};
|
|
142
143
|
|
|
143
144
|
// Helper function to process each content category
|
|
@@ -182,6 +183,7 @@ class PackageManager {
|
|
|
182
183
|
selected.commands = selectItems('commands', variantConfig.commands, availableContent.commands || [], true);
|
|
183
184
|
selected.resources = selectItems('resources', variantConfig.resources, availableContent.resources || []);
|
|
184
185
|
selected.hooks = selectItems('hooks', variantConfig.hooks, availableContent.hooks || []);
|
|
186
|
+
selected.plugins = selectItems('plugins', variantConfig.plugins, availableContent.plugins || []);
|
|
185
187
|
|
|
186
188
|
return selected;
|
|
187
189
|
}
|
|
@@ -227,6 +229,7 @@ class PackageManager {
|
|
|
227
229
|
commands: [],
|
|
228
230
|
resources: [],
|
|
229
231
|
hooks: [],
|
|
232
|
+
plugins: [],
|
|
230
233
|
totalFiles: 0,
|
|
231
234
|
totalSize: 0
|
|
232
235
|
};
|
|
@@ -295,12 +298,24 @@ class PackageManager {
|
|
|
295
298
|
}
|
|
296
299
|
}
|
|
297
300
|
|
|
301
|
+
// Build directory paths for selected plugins (plugins are directories, like skills)
|
|
302
|
+
const pluginsDir = path.join(packageDir, 'plugins');
|
|
303
|
+
if (fs.existsSync(pluginsDir)) {
|
|
304
|
+
for (const plugin of (selectedContent.plugins || [])) {
|
|
305
|
+
const pluginPath = path.join(pluginsDir, plugin);
|
|
306
|
+
if (fs.existsSync(pluginPath)) {
|
|
307
|
+
contents.plugins.push(pluginPath);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
298
312
|
// Calculate total files
|
|
299
313
|
contents.totalFiles = contents.agents.length +
|
|
300
314
|
contents.skills.length +
|
|
301
315
|
contents.commands.length +
|
|
302
316
|
contents.resources.length +
|
|
303
|
-
contents.hooks.length
|
|
317
|
+
contents.hooks.length +
|
|
318
|
+
contents.plugins.length;
|
|
304
319
|
|
|
305
320
|
return contents;
|
|
306
321
|
}
|
|
@@ -349,6 +364,7 @@ class PackageManager {
|
|
|
349
364
|
const commandsResult = await getItemsInDir(path.join(packageDir, commandsDir), true);
|
|
350
365
|
const resourcesResult = await getItemsInDir(path.join(packageDir, 'resources'));
|
|
351
366
|
const hooksResult = await getItemsInDir(path.join(packageDir, 'hooks'));
|
|
367
|
+
const pluginsResult = await getItemsInDir(path.join(packageDir, 'plugins'));
|
|
352
368
|
|
|
353
369
|
return {
|
|
354
370
|
agents: agentsResult.items,
|
|
@@ -357,7 +373,8 @@ class PackageManager {
|
|
|
357
373
|
commands: commandsResult.items,
|
|
358
374
|
commandsDir: commandsDir,
|
|
359
375
|
resources: resourcesResult.items,
|
|
360
|
-
hooks: hooksResult.items
|
|
376
|
+
hooks: hooksResult.items,
|
|
377
|
+
plugins: pluginsResult.items
|
|
361
378
|
};
|
|
362
379
|
}
|
|
363
380
|
|
|
@@ -399,6 +416,7 @@ class PackageManager {
|
|
|
399
416
|
let totalSize = 0;
|
|
400
417
|
|
|
401
418
|
// Helper function to calculate size of a file or directory recursively
|
|
419
|
+
// Skips node_modules directories (plugins may have local installs)
|
|
402
420
|
const calculatePathSize = async (itemPath) => {
|
|
403
421
|
try {
|
|
404
422
|
const stat = await fs.promises.stat(itemPath);
|
|
@@ -406,6 +424,11 @@ class PackageManager {
|
|
|
406
424
|
if (stat.isFile()) {
|
|
407
425
|
return stat.size;
|
|
408
426
|
} else if (stat.isDirectory()) {
|
|
427
|
+
// Skip node_modules to avoid bundling local dependencies
|
|
428
|
+
if (path.basename(itemPath) === 'node_modules') {
|
|
429
|
+
return 0;
|
|
430
|
+
}
|
|
431
|
+
|
|
409
432
|
// Recursively calculate directory size
|
|
410
433
|
let dirSize = 0;
|
|
411
434
|
const items = await fs.promises.readdir(itemPath);
|
|
@@ -445,6 +468,11 @@ class PackageManager {
|
|
|
445
468
|
totalSize += await calculatePathSize(hookPath);
|
|
446
469
|
}
|
|
447
470
|
|
|
471
|
+
// Calculate size for all selected plugins (directories, excluding node_modules)
|
|
472
|
+
for (const pluginPath of (contents.plugins || [])) {
|
|
473
|
+
totalSize += await calculatePathSize(pluginPath);
|
|
474
|
+
}
|
|
475
|
+
|
|
448
476
|
return {
|
|
449
477
|
size: totalSize,
|
|
450
478
|
formattedSize: this.formatBytes(totalSize)
|
|
@@ -601,6 +629,9 @@ class PackageManager {
|
|
|
601
629
|
const commandsDirName = availableContent.commandsDir || 'commands';
|
|
602
630
|
await checkContentExists('commands', selectedContent.commands || [], commandsDirName, true);
|
|
603
631
|
|
|
632
|
+
// Validate plugins (directories, like skills)
|
|
633
|
+
await checkContentExists('plugins', selectedContent.plugins || [], 'plugins', false);
|
|
634
|
+
|
|
604
635
|
} catch (error) {
|
|
605
636
|
return {
|
|
606
637
|
valid: false,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "liteagents",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "AI development toolkit with 11 specialized agents and
|
|
3
|
+
"version": "2.6.0",
|
|
4
|
+
"description": "AI development toolkit with 11 specialized agents and 23 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": {
|
|
7
7
|
"liteagents": "./installer/cli.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"clean:git": "git clean -fdx tests/tmp/",
|
|
17
17
|
"validate": "node ./scripts/validate-package.js",
|
|
18
18
|
"validate-packages": "node scripts/validate-all-packages.js",
|
|
19
|
+
"prepack": "rm -rf packages/*/plugins/*/plugins/*/node_modules",
|
|
19
20
|
"prepublishOnly": "npm run clean && npm run validate",
|
|
20
21
|
"postinstall": "node postinstall.js"
|
|
21
22
|
},
|
|
@@ -44,16 +45,16 @@
|
|
|
44
45
|
"cli",
|
|
45
46
|
"variant-system"
|
|
46
47
|
],
|
|
47
|
-
"author": "
|
|
48
|
+
"author": "hamr0 <avoidaccess@msn.com>",
|
|
48
49
|
"license": "MIT",
|
|
49
50
|
"repository": {
|
|
50
51
|
"type": "git",
|
|
51
|
-
"url": "https://github.com/
|
|
52
|
+
"url": "https://github.com/hamr0/liteagents.git"
|
|
52
53
|
},
|
|
53
54
|
"bugs": {
|
|
54
|
-
"url": "https://github.com/
|
|
55
|
+
"url": "https://github.com/hamr0/liteagents/issues"
|
|
55
56
|
},
|
|
56
|
-
"homepage": "https://github.com/
|
|
57
|
+
"homepage": "https://github.com/hamr0/liteagents#readme",
|
|
57
58
|
"publishConfig": {
|
|
58
59
|
"registry": "https://registry.npmjs.org",
|
|
59
60
|
"access": "public"
|
|
@@ -45,6 +45,7 @@ These subagents are available when using Ampcode CLI.
|
|
|
45
45
|
| explain | Explain code for someone new to the codebase | /explain <code-section> |
|
|
46
46
|
| friction | Analyze session logs for failure patterns and behavioral signals | /friction <sessions-path> |
|
|
47
47
|
| git-commit | Analyze changes and create intelligent git commits | /git-commit |
|
|
48
|
+
| live-canvas | Design UI variations and collect click-to-annotate feedback from the browser (batch mode only on Amp) | /live-canvas |
|
|
48
49
|
| optimize | Analyze and optimize performance issues | /optimize <target-area> |
|
|
49
50
|
| refactor | Refactor code while maintaining behavior and tests | /refactor <code-section> |
|
|
50
51
|
| remember | Consolidate stashes + friction into project memory | /remember |
|
|
@@ -1940,12 +1940,21 @@ function clusterCandidates(allCandidates) {
|
|
|
1940
1940
|
const clusters = Object.values(clusterMap).map(cl => {
|
|
1941
1941
|
const weight = signalWeights[cl.anchor_signal] || 1;
|
|
1942
1942
|
const peaks = cl.peaks.sort((a, b) => a - b);
|
|
1943
|
+
// Session IDs follow "project/dateStr-shortId", so the first segment is
|
|
1944
|
+
// the project. Preserve both the ID list and the deduped project set so
|
|
1945
|
+
// downstream renderers can surface which repos produced the cluster.
|
|
1946
|
+
const sessionIds = Object.keys(cl.sessions);
|
|
1947
|
+
const projects = [...new Set(
|
|
1948
|
+
sessionIds.map(s => s.includes('/') ? s.split('/')[0] : 'unknown')
|
|
1949
|
+
)].sort();
|
|
1943
1950
|
return {
|
|
1944
1951
|
anchor_signal: cl.anchor_signal,
|
|
1945
1952
|
tool_pattern: cl.tool_pattern,
|
|
1946
1953
|
count: cl.count,
|
|
1947
1954
|
score: cl.count * weight,
|
|
1948
|
-
sessions:
|
|
1955
|
+
sessions: sessionIds.length,
|
|
1956
|
+
session_ids: sessionIds,
|
|
1957
|
+
projects: projects,
|
|
1949
1958
|
median_peak: peaks[Math.floor(peaks.length / 2)],
|
|
1950
1959
|
max_peak: peaks[peaks.length - 1],
|
|
1951
1960
|
contexts: cl.contexts,
|
|
@@ -2048,10 +2057,13 @@ function extractMain(sessionsDir) {
|
|
|
2048
2057
|
|
|
2049
2058
|
// Summary table
|
|
2050
2059
|
reviewLines.push('## Cluster Summary\n\n');
|
|
2051
|
-
reviewLines.push('| # | Signal | Tool Pattern | Count | Sessions | Score | Median Peak |\n');
|
|
2052
|
-
reviewLines.push('
|
|
2060
|
+
reviewLines.push('| # | Signal | Tool Pattern | Count | Sessions | Projects | Score | Median Peak |\n');
|
|
2061
|
+
reviewLines.push('|---|--------|-------------|-------|----------|----------|-------|-------------|\n');
|
|
2053
2062
|
reviewClusters.forEach((cl, idx) => {
|
|
2054
|
-
|
|
2063
|
+
const projs = cl.projects || [];
|
|
2064
|
+
const projectsShort = projs.slice(0, 3).join(', ') +
|
|
2065
|
+
(projs.length > 3 ? `, +${projs.length - 3}` : '');
|
|
2066
|
+
reviewLines.push(`| ${idx + 1} | ${cl.anchor_signal} | ${cl.tool_pattern} | ${cl.count} | ${cl.sessions} | ${projectsShort || '-'} | ${cl.score} | ${cl.median_peak} |\n`);
|
|
2055
2067
|
});
|
|
2056
2068
|
reviewLines.push('\n---\n\n');
|
|
2057
2069
|
|
|
@@ -2059,6 +2071,9 @@ function extractMain(sessionsDir) {
|
|
|
2059
2071
|
reviewClusters.forEach((cl, idx) => {
|
|
2060
2072
|
reviewLines.push(`## Cluster ${idx + 1}: ${cl.anchor_signal} | ${cl.tool_pattern}\n\n`);
|
|
2061
2073
|
reviewLines.push(`**Occurrences:** ${cl.count} across ${cl.sessions} sessions | **Score:** ${cl.score} | **Median peak:** ${cl.median_peak} | **Max peak:** ${cl.max_peak}\n\n`);
|
|
2074
|
+
if (cl.projects && cl.projects.length > 0) {
|
|
2075
|
+
reviewLines.push(`**Projects:** ${cl.projects.join(', ')}\n\n`);
|
|
2076
|
+
}
|
|
2062
2077
|
|
|
2063
2078
|
if (cl.contexts.length > 0) {
|
|
2064
2079
|
reviewLines.push('### User Context (what the user said)\n\n');
|