@alavida/agentpack 0.1.1 → 0.1.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.
Files changed (57) hide show
  1. package/README.md +16 -2
  2. package/bin/intent.js +20 -0
  3. package/package.json +11 -5
  4. package/skills/agentpack-cli/SKILL.md +16 -1
  5. package/skills/agentpack-cli/references/skill-lifecycle.md +21 -1
  6. package/skills/authoring-skillgraphs-from-knowledge/SKILL.md +148 -0
  7. package/skills/authoring-skillgraphs-from-knowledge/references/authored-metadata.md +6 -0
  8. package/skills/developing-and-testing-skills/SKILL.md +109 -0
  9. package/skills/developing-and-testing-skills/references/local-workbench.md +7 -0
  10. package/skills/getting-started-skillgraphs/SKILL.md +115 -0
  11. package/skills/getting-started-skillgraphs/references/command-routing.md +7 -0
  12. package/skills/identifying-skill-opportunities/SKILL.md +119 -0
  13. package/skills/identifying-skill-opportunities/references/capability-boundaries.md +6 -0
  14. package/skills/maintaining-skillgraph-freshness/SKILL.md +110 -0
  15. package/skills/repairing-broken-skill-or-plugin-state/SKILL.md +112 -0
  16. package/skills/repairing-broken-skill-or-plugin-state/references/diagnostic-flows.md +6 -0
  17. package/skills/shipping-production-plugins-and-packages/SKILL.md +123 -0
  18. package/skills/shipping-production-plugins-and-packages/references/plugin-delivery.md +6 -0
  19. package/src/application/plugins/build-plugin.js +5 -0
  20. package/src/application/plugins/inspect-plugin-bundle.js +5 -0
  21. package/src/application/plugins/validate-plugin-bundle.js +5 -0
  22. package/src/application/skills/build-skill-workbench-model.js +194 -0
  23. package/src/application/skills/inspect-skill.js +5 -0
  24. package/src/application/skills/list-stale-skills.js +9 -0
  25. package/src/application/skills/run-skill-workbench-action.js +23 -0
  26. package/src/application/skills/start-skill-dev-workbench.js +192 -0
  27. package/src/application/skills/validate-skills.js +5 -0
  28. package/src/cli.js +1 -1
  29. package/src/commands/plugin.js +7 -4
  30. package/src/commands/skills.js +14 -9
  31. package/src/dashboard/App.jsx +343 -0
  32. package/src/dashboard/components/Breadcrumbs.jsx +45 -0
  33. package/src/dashboard/components/ControlStrip.jsx +153 -0
  34. package/src/dashboard/components/InspectorPanel.jsx +203 -0
  35. package/src/dashboard/components/SkillGraph.jsx +567 -0
  36. package/src/dashboard/components/Tooltip.jsx +111 -0
  37. package/src/dashboard/dist/dashboard.js +26692 -0
  38. package/src/dashboard/index.html +81 -0
  39. package/src/dashboard/lib/api.js +19 -0
  40. package/src/dashboard/lib/router.js +15 -0
  41. package/src/dashboard/main.jsx +4 -0
  42. package/src/domain/plugins/load-plugin-definition.js +163 -0
  43. package/src/domain/plugins/plugin-diagnostic-error.js +18 -0
  44. package/src/domain/plugins/plugin-requirements.js +15 -0
  45. package/src/domain/skills/skill-graph.js +137 -0
  46. package/src/domain/skills/skill-model.js +187 -0
  47. package/src/domain/skills/skill-provenance.js +69 -0
  48. package/src/infrastructure/fs/build-state-repository.js +16 -0
  49. package/src/infrastructure/fs/install-state-repository.js +16 -0
  50. package/src/infrastructure/runtime/materialize-skills.js +117 -0
  51. package/src/infrastructure/runtime/open-browser.js +20 -0
  52. package/src/infrastructure/runtime/skill-dev-workbench-server.js +96 -0
  53. package/src/infrastructure/runtime/watch-skill-workbench.js +68 -0
  54. package/src/infrastructure/runtime/watch-tree.js +44 -0
  55. package/src/lib/plugins.js +46 -117
  56. package/src/lib/skills.js +141 -459
  57. package/src/utils/errors.js +33 -1
@@ -0,0 +1,9 @@
1
+ import { inspectStaleSkill, listStaleSkills } from '../../lib/skills.js';
2
+
3
+ export function listStaleSkillsUseCase(options) {
4
+ return listStaleSkills(options);
5
+ }
6
+
7
+ export function inspectStaleSkillUseCase(target, options) {
8
+ return inspectStaleSkill(target, options);
9
+ }
@@ -0,0 +1,23 @@
1
+ import { inspectSkillDependencies } from '../../lib/skills.js';
2
+ import { inspectStaleSkillUseCase } from './list-stale-skills.js';
3
+ import { validateSkillsUseCase } from './validate-skills.js';
4
+
5
+ export function runSkillWorkbenchAction(action, context) {
6
+ if (action === 'check-stale') {
7
+ return inspectStaleSkillUseCase(context.packageName, { cwd: context.cwd });
8
+ }
9
+
10
+ if (action === 'show-dependencies') {
11
+ return inspectSkillDependencies(context.packageName, { cwd: context.cwd });
12
+ }
13
+
14
+ if (action === 'validate-skill') {
15
+ return validateSkillsUseCase(context.target, { cwd: context.cwd });
16
+ }
17
+
18
+ if (action === 'refresh') {
19
+ return { refreshed: true };
20
+ }
21
+
22
+ throw new Error(`Unsupported workbench action: ${action}`);
23
+ }
@@ -0,0 +1,192 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { parseSkillFrontmatterFile, readPackageMetadata, normalizeDisplayPath } from '../../domain/skills/skill-model.js';
4
+ import { readBuildState, compareRecordedSources } from '../../domain/skills/skill-provenance.js';
5
+ import { buildSkillGraph, buildSkillStatusMap } from '../../domain/skills/skill-graph.js';
6
+ import { buildTransitiveSkillWorkbenchModel } from './build-skill-workbench-model.js';
7
+ import { startSkillDevWorkbenchServer } from '../../infrastructure/runtime/skill-dev-workbench-server.js';
8
+ import { openBrowser } from '../../infrastructure/runtime/open-browser.js';
9
+ import { watchSkillWorkbench } from '../../infrastructure/runtime/watch-skill-workbench.js';
10
+ import { runSkillWorkbenchAction } from './run-skill-workbench-action.js';
11
+
12
+ function listPackagedSkillDirs(repoRoot) {
13
+ const stack = [repoRoot];
14
+ const results = [];
15
+
16
+ while (stack.length > 0) {
17
+ const current = stack.pop();
18
+ let entries = [];
19
+ try {
20
+ entries = readdirSync(current, { withFileTypes: true });
21
+ } catch {
22
+ continue;
23
+ }
24
+
25
+ let hasSkillFile = false;
26
+ let hasPackageFile = false;
27
+
28
+ for (const entry of entries) {
29
+ if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === '.agentpack') continue;
30
+ const fullPath = join(current, entry.name);
31
+
32
+ if (entry.isDirectory()) {
33
+ stack.push(fullPath);
34
+ continue;
35
+ }
36
+
37
+ if (entry.name === 'SKILL.md') hasSkillFile = true;
38
+ if (entry.name === 'package.json') hasPackageFile = true;
39
+ }
40
+
41
+ if (hasSkillFile && hasPackageFile) {
42
+ results.push(current);
43
+ }
44
+ }
45
+
46
+ return results.sort();
47
+ }
48
+
49
+ function findPackageDirByName(repoRoot, packageName) {
50
+ const stack = [repoRoot];
51
+
52
+ while (stack.length > 0) {
53
+ const current = stack.pop();
54
+ let entries = [];
55
+ try {
56
+ entries = readdirSync(current, { withFileTypes: true });
57
+ } catch {
58
+ continue;
59
+ }
60
+
61
+ for (const entry of entries) {
62
+ if (entry.name === '.git' || entry.name === 'node_modules') continue;
63
+ const fullPath = join(current, entry.name);
64
+
65
+ if (entry.isDirectory()) {
66
+ stack.push(fullPath);
67
+ continue;
68
+ }
69
+
70
+ if (entry.name !== 'package.json') continue;
71
+
72
+ try {
73
+ const pkg = JSON.parse(readFileSync(fullPath, 'utf-8'));
74
+ if (pkg.name === packageName) return dirname(fullPath);
75
+ } catch {
76
+ // skip
77
+ }
78
+ }
79
+ }
80
+
81
+ const nodeModulesPath = join(repoRoot, 'node_modules', ...packageName.split('/'));
82
+ if (existsSync(join(nodeModulesPath, 'SKILL.md'))) return nodeModulesPath;
83
+
84
+ return null;
85
+ }
86
+
87
+ function buildModelForSkill(repoRoot, targetPackageName) {
88
+ const packageDirs = listPackagedSkillDirs(repoRoot);
89
+ const skillGraph = buildSkillGraph(repoRoot, packageDirs, {
90
+ parseSkillFrontmatterFile,
91
+ readPackageMetadata,
92
+ findPackageDirByName: (root, name) => findPackageDirByName(root, name),
93
+ normalizeDisplayPath,
94
+ });
95
+
96
+ const buildState = readBuildState(repoRoot);
97
+ const staleSkills = new Set();
98
+ const changedSources = new Set(); // track individual changed source paths
99
+
100
+ for (const [packageName, record] of Object.entries(buildState.skills || buildState)) {
101
+ if (typeof record !== 'object' || !record.sources) continue;
102
+ try {
103
+ const changes = compareRecordedSources(repoRoot, record);
104
+ if (changes.length > 0) {
105
+ staleSkills.add(packageName);
106
+ for (const change of changes) changedSources.add(change.path);
107
+ }
108
+ } catch {
109
+ // skip
110
+ }
111
+ }
112
+
113
+ const statusMap = buildSkillStatusMap(skillGraph, staleSkills);
114
+
115
+ function resolveSkillSources(packageName) {
116
+ const graphNode = skillGraph.get(packageName);
117
+ if (!graphNode) return [];
118
+
119
+ const skillFilePath = join(repoRoot, graphNode.skillFile);
120
+ try {
121
+ const metadata = parseSkillFrontmatterFile(skillFilePath);
122
+ return metadata.sources || [];
123
+ } catch {
124
+ return [];
125
+ }
126
+ }
127
+
128
+ function resolveSkillRequires(packageName) {
129
+ const graphNode = skillGraph.get(packageName);
130
+ if (!graphNode) return [];
131
+
132
+ const skillFilePath = join(repoRoot, graphNode.skillFile);
133
+ try {
134
+ const metadata = parseSkillFrontmatterFile(skillFilePath);
135
+ return metadata.requires || [];
136
+ } catch {
137
+ return [];
138
+ }
139
+ }
140
+
141
+ return buildTransitiveSkillWorkbenchModel({
142
+ repoRoot,
143
+ targetPackageName,
144
+ skillGraph,
145
+ statusMap,
146
+ changedSources,
147
+ resolveSkillSources,
148
+ resolveSkillRequires,
149
+ });
150
+ }
151
+
152
+ export async function startSkillDevWorkbench({
153
+ repoRoot,
154
+ skillDir,
155
+ open = true,
156
+ disableBrowser = false,
157
+ }) {
158
+ const packageMetadata = readPackageMetadata(skillDir);
159
+ const defaultSkill = packageMetadata.packageName;
160
+
161
+ const server = await startSkillDevWorkbenchServer({
162
+ buildModel: (skillPackageName) => buildModelForSkill(repoRoot, skillPackageName),
163
+ defaultSkill,
164
+ onAction(action) {
165
+ return runSkillWorkbenchAction(action, {
166
+ cwd: repoRoot,
167
+ target: skillDir,
168
+ packageName: defaultSkill,
169
+ });
170
+ },
171
+ });
172
+
173
+ const watcher = watchSkillWorkbench(repoRoot, skillDir, () => {
174
+ // Model is rebuilt on each request, so no cache to invalidate
175
+ });
176
+
177
+ if (open && !disableBrowser) {
178
+ openBrowser(server.url);
179
+ }
180
+
181
+ return {
182
+ url: server.url,
183
+ port: server.port,
184
+ refresh() {
185
+ // no-op: models are built on demand per request
186
+ },
187
+ close() {
188
+ watcher.close();
189
+ server.close();
190
+ },
191
+ };
192
+ }
@@ -0,0 +1,5 @@
1
+ import { validateSkills } from '../../lib/skills.js';
2
+
3
+ export function validateSkillsUseCase(target, options) {
4
+ return validateSkills(target, options);
5
+ }
package/src/cli.js CHANGED
@@ -68,7 +68,7 @@ export function run(argv) {
68
68
  if (err instanceof AgentpackError) {
69
69
  const opts = program.opts?.() || {};
70
70
  if (opts.json) {
71
- output.json({ error: err.code, message: err.message });
71
+ output.json(err.toJSON());
72
72
  } else {
73
73
  output.error(formatError(err));
74
74
  }
@@ -1,5 +1,8 @@
1
1
  import { Command } from 'commander';
2
- import { buildPlugin, inspectPluginBundle, startPluginDev, validatePluginBundle } from '../lib/plugins.js';
2
+ import { buildPluginUseCase } from '../application/plugins/build-plugin.js';
3
+ import { inspectPluginBundleUseCase } from '../application/plugins/inspect-plugin-bundle.js';
4
+ import { validatePluginBundleUseCase } from '../application/plugins/validate-plugin-bundle.js';
5
+ import { startPluginDev } from '../lib/plugins.js';
3
6
  import { output } from '../utils/output.js';
4
7
  import { EXIT_CODES } from '../utils/errors.js';
5
8
 
@@ -13,7 +16,7 @@ export function pluginCommand() {
13
16
  .argument('<target>', 'Plugin directory path')
14
17
  .action((target, opts, command) => {
15
18
  const globalOpts = command.optsWithGlobals();
16
- const result = inspectPluginBundle(target);
19
+ const result = inspectPluginBundleUseCase(target);
17
20
 
18
21
  if (globalOpts.json) {
19
22
  output.json(result);
@@ -76,7 +79,7 @@ export function pluginCommand() {
76
79
  .argument('<target>', 'Plugin directory path')
77
80
  .action((target, opts, command) => {
78
81
  const globalOpts = command.optsWithGlobals();
79
- const result = validatePluginBundle(target);
82
+ const result = validatePluginBundleUseCase(target);
80
83
 
81
84
  if (globalOpts.json) {
82
85
  output.json(result);
@@ -114,7 +117,7 @@ export function pluginCommand() {
114
117
  .argument('<target>', 'Plugin directory path')
115
118
  .action((target, opts, command) => {
116
119
  const globalOpts = command.optsWithGlobals();
117
- const result = buildPlugin(target, { clean: opts.clean });
120
+ const result = buildPluginUseCase(target, { clean: opts.clean });
118
121
 
119
122
  if (globalOpts.json) {
120
123
  output.json(result);
@@ -1,20 +1,19 @@
1
1
  import { Command } from 'commander';
2
+ import { inspectSkillUseCase } from '../application/skills/inspect-skill.js';
3
+ import { inspectStaleSkillUseCase, listStaleSkillsUseCase } from '../application/skills/list-stale-skills.js';
4
+ import { validateSkillsUseCase } from '../application/skills/validate-skills.js';
2
5
  import {
3
6
  inspectSkillDependencies,
4
7
  inspectMissingSkillDependencies,
5
8
  inspectSkillsStatus,
6
9
  inspectRegistryConfig,
7
- inspectSkill,
8
10
  inspectSkillsEnv,
9
- inspectStaleSkill,
10
11
  installSkills,
11
12
  listOutdatedSkills,
12
- listStaleSkills,
13
13
  resolveInstallTargets,
14
14
  startSkillDev,
15
15
  unlinkSkill,
16
16
  uninstallSkills,
17
- validateSkills,
18
17
  } from '../lib/skills.js';
19
18
  import { output } from '../utils/output.js';
20
19
  import { EXIT_CODES } from '../utils/errors.js';
@@ -27,11 +26,13 @@ export function skillsCommand() {
27
26
  .command('dev')
28
27
  .description('Link one local packaged skill for local Claude and agent discovery')
29
28
  .option('--no-sync', 'Skip syncing managed package dependencies from requires')
29
+ .option('--no-dashboard', 'Skip starting the local skill development workbench')
30
30
  .argument('<target>', 'Packaged skill directory or SKILL.md path')
31
- .action((target, opts, command) => {
31
+ .action(async (target, opts, command) => {
32
32
  const globalOpts = command.optsWithGlobals();
33
33
  const session = startSkillDev(target, {
34
34
  sync: opts.sync,
35
+ dashboard: opts.dashboard,
35
36
  onStart(result) {
36
37
  if (globalOpts.json) {
37
38
  output.json(result);
@@ -46,6 +47,9 @@ export function skillsCommand() {
46
47
  for (const link of result.links) {
47
48
  output.write(`Linked: ${link}`);
48
49
  }
50
+ if (result.workbench?.enabled) {
51
+ output.write(`Workbench URL: ${result.workbench.url}`);
52
+ }
49
53
  output.write('Note: if your current agent session was already running, start a fresh session to pick up newly linked skills.');
50
54
  if (result.unresolved.length > 0) {
51
55
  output.write('Unresolved Dependencies:');
@@ -73,6 +77,7 @@ export function skillsCommand() {
73
77
 
74
78
  process.once('SIGTERM', stop);
75
79
  process.once('SIGINT', stop);
80
+ await session.ready;
76
81
  });
77
82
 
78
83
  cmd
@@ -250,7 +255,7 @@ export function skillsCommand() {
250
255
  .argument('<target>', 'Skill directory, SKILL.md path, or package name')
251
256
  .action((target, opts, command) => {
252
257
  const globalOpts = command.optsWithGlobals();
253
- const result = inspectSkill(target);
258
+ const result = inspectSkillUseCase(target);
254
259
 
255
260
  if (globalOpts.json) {
256
261
  output.json(result);
@@ -291,7 +296,7 @@ export function skillsCommand() {
291
296
  const globalOpts = command.optsWithGlobals();
292
297
 
293
298
  if (target) {
294
- const result = inspectStaleSkill(target);
299
+ const result = inspectStaleSkillUseCase(target);
295
300
 
296
301
  if (globalOpts.json) {
297
302
  output.json(result);
@@ -310,7 +315,7 @@ export function skillsCommand() {
310
315
  return;
311
316
  }
312
317
 
313
- const results = listStaleSkills();
318
+ const results = listStaleSkillsUseCase();
314
319
 
315
320
  if (globalOpts.json) {
316
321
  output.json({
@@ -337,7 +342,7 @@ export function skillsCommand() {
337
342
  .argument('[target]', 'Optional packaged skill directory, SKILL.md path, or package name')
338
343
  .action((target, opts, command) => {
339
344
  const globalOpts = command.optsWithGlobals();
340
- const result = validateSkills(target);
345
+ const result = validateSkillsUseCase(target);
341
346
 
342
347
  if (globalOpts.json) {
343
348
  output.json(