happyskills 1.1.0 → 1.2.1

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 (44) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/src/commands/access.js +41 -1
  4. package/src/commands/agents.js +30 -1
  5. package/src/commands/bump.js +33 -1
  6. package/src/commands/changelog.js +37 -1
  7. package/src/commands/check.js +30 -1
  8. package/src/commands/config.js +34 -1
  9. package/src/commands/convert.js +38 -1
  10. package/src/commands/delete.js +33 -1
  11. package/src/commands/diff.js +33 -1
  12. package/src/commands/disable.js +31 -1
  13. package/src/commands/enable.js +31 -1
  14. package/src/commands/feedback.js +41 -1
  15. package/src/commands/fork.js +35 -1
  16. package/src/commands/groups.js +40 -1
  17. package/src/commands/init.js +35 -1
  18. package/src/commands/install.js +35 -1
  19. package/src/commands/list.js +29 -1
  20. package/src/commands/login.js +34 -1
  21. package/src/commands/logout.js +20 -1
  22. package/src/commands/people.js +37 -1
  23. package/src/commands/postlex.js +38 -0
  24. package/src/commands/publish.js +40 -1
  25. package/src/commands/pull.js +47 -1
  26. package/src/commands/reconcile.js +36 -1
  27. package/src/commands/release.js +51 -1
  28. package/src/commands/schema.js +5 -0
  29. package/src/commands/search.js +46 -1
  30. package/src/commands/self-update.js +27 -1
  31. package/src/commands/setup.js +32 -1
  32. package/src/commands/snapshot.js +38 -1
  33. package/src/commands/status.js +26 -1
  34. package/src/commands/uninstall.js +30 -1
  35. package/src/commands/update.js +40 -1
  36. package/src/commands/validate.js +37 -1
  37. package/src/commands/versions.js +34 -1
  38. package/src/commands/visibility.js +33 -1
  39. package/src/commands/whoami.js +30 -1
  40. package/src/constants/error_codes.js +12 -1
  41. package/src/constants/next_step_actions.js +8 -0
  42. package/src/constants/next_step_by_error_code.js +5 -0
  43. package/src/integration/schema.test.js +31 -0
  44. package/src/ui/envelope.js +3 -0
@@ -93,4 +93,33 @@ const run = (args) => catch_errors('Uninstall failed', async () => {
93
93
  }
94
94
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
95
95
 
96
- module.exports = { run }
96
+ const schema = {
97
+ name: 'uninstall',
98
+ audience: 'consumer',
99
+ purpose: 'Remove one or more skills and prune their orphaned dependencies.',
100
+ mutation: true,
101
+ interactive_in_text_mode: false,
102
+ input: {
103
+ positional: [ { name: 'skills', required: true, type: 'string[]', pattern: '<owner>/<name>' } ],
104
+ flags: [
105
+ { name: 'global', alias: 'g', type: 'boolean', default: false, description: 'Remove from global scope' },
106
+ { name: 'agents', type: 'string', default: undefined, description: 'Target specific agents (comma-separated)' },
107
+ { name: 'yes', alias: 'y', type: 'boolean', default: false, description: 'Skip confirmation prompts' },
108
+ { name: 'json', type: 'boolean', default: false, description: 'Output as JSON' },
109
+ ],
110
+ },
111
+ output: {
112
+ data_shape: {
113
+ results: 'array<{ skill: string, status: string, removed: string[], orphans_pruned: string[] } | { skill: string, status: "failed", error: { code: string, message: string } }>',
114
+ },
115
+ },
116
+ errors: [
117
+ { code: 'USAGE_ERROR', next_step: { kind: 'routing', action: 'discover_schema' } },
118
+ ],
119
+ examples: [
120
+ 'happyskills uninstall acme/deploy-aws',
121
+ 'happyskills uninstall acme/deploy-aws acme/monitor acme/logging',
122
+ ],
123
+ }
124
+
125
+ module.exports = { run, schema }
@@ -333,4 +333,43 @@ const run = (args) => catch_errors('Update failed', async () => {
333
333
  }
334
334
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
335
335
 
336
- module.exports = { run }
336
+ const schema = {
337
+ name: 'update',
338
+ audience: 'consumer',
339
+ purpose: 'Bring installed skills up to date by batch-checking the registry and re-installing only outdated skills.',
340
+ mutation: true,
341
+ interactive_in_text_mode: true,
342
+ input: {
343
+ positional: [{ name: 'skill', required: false, type: 'string', pattern: '<owner>/<name>' }],
344
+ flags: [
345
+ { name: 'all', type: 'boolean', default: false },
346
+ { name: 'force', type: 'boolean', default: false },
347
+ { name: 'global', type: 'boolean', default: false },
348
+ { name: 'yes', type: 'boolean', default: false },
349
+ { name: 'agents', type: 'string', default: null },
350
+ { name: 'json', type: 'boolean', default: false }
351
+ ]
352
+ },
353
+ output: {
354
+ data_shape: {
355
+ results: 'array<{ skill: string, installed: string, latest: string, status: string }>',
356
+ outdated_count: 'number',
357
+ up_to_date_count: 'number',
358
+ drift_count: 'number',
359
+ updated: 'array<{ skill: string, from: string, to: string }>',
360
+ skipped: 'array<{ skill: string, reason: string, suggestion: string }>',
361
+ already_up_to_date: 'array<{ skill: string, version: string }>',
362
+ symlink_repairs: 'array',
363
+ errors: 'array<{ skill: string, message: string }>'
364
+ }
365
+ },
366
+ errors: [
367
+ { code: 'USAGE_ERROR', next_step: { kind: 'routing', action: 'discover_schema' } }
368
+ ],
369
+ examples: [
370
+ 'happyskills update acme/deploy-aws',
371
+ 'happyskills up --all -y --json'
372
+ ]
373
+ }
374
+
375
+ module.exports = { run, schema }
@@ -232,4 +232,40 @@ const run = (args) => catch_errors('Validate failed', async () => {
232
232
  process.exit(has_errors ? EXIT_CODES.ERROR : EXIT_CODES.SUCCESS)
233
233
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
234
234
 
235
- module.exports = { run }
235
+ const schema = {
236
+ name: 'validate',
237
+ audience: 'author',
238
+ purpose: 'Validate a local skill against all agentskills.io spec rules (structure, cross-file, file sizes, changelog, dependencies).',
239
+ mutation: true,
240
+ interactive_in_text_mode: false,
241
+ input: {
242
+ positional: [
243
+ { name: 'skill-name', required: true, type: 'string', pattern: '<skill-name>' },
244
+ ],
245
+ flags: [
246
+ { name: 'global', short: 'g', type: 'boolean', default: false },
247
+ { name: 'json', type: 'boolean', default: false },
248
+ ],
249
+ },
250
+ output: {
251
+ data_shape: {
252
+ skill: 'string',
253
+ valid: 'boolean',
254
+ errors: 'array',
255
+ warnings: 'array',
256
+ checks_passed: 'number',
257
+ checks_failed: 'number',
258
+ checks_warned: 'number',
259
+ },
260
+ },
261
+ errors: [
262
+ { code: 'USAGE_ERROR', next_step: { kind: 'routing', action: 'discover_schema' } },
263
+ { code: 'VALIDATION_FAILED', next_step: { kind: 'recovery', action: 'fix_validation_errors' } },
264
+ ],
265
+ examples: [
266
+ 'happyskills validate my-skill',
267
+ 'happyskills v my-skill --json',
268
+ ],
269
+ }
270
+
271
+ module.exports = { run, schema }
@@ -89,4 +89,37 @@ const run = (args) => catch_errors('Versions failed', async () => {
89
89
  print_table(['VERSION', 'PUBLISHED', 'COMMIT', 'MESSAGE'], rows)
90
90
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
91
91
 
92
- module.exports = { run, extract_version, sort_refs }
92
+ const schema = {
93
+ name: 'versions',
94
+ audience: 'consumer',
95
+ purpose: 'List all published versions of a skill from the registry, newest first.',
96
+ mutation: false,
97
+ interactive_in_text_mode: false,
98
+ input: {
99
+ positional: [
100
+ { name: 'skill', required: true, type: 'string', pattern: '<owner>/<name>' },
101
+ ],
102
+ flags: [
103
+ { name: 'limit', type: 'number', default: null },
104
+ { name: 'json', type: 'boolean', default: false },
105
+ ],
106
+ },
107
+ output: {
108
+ data_shape: {
109
+ skill: 'string',
110
+ count: 'number',
111
+ versions: 'array<{ version: string, ref: string, commit: string, message: string, published_at: string|null }>',
112
+ },
113
+ },
114
+ errors: [
115
+ { code: 'USAGE_ERROR', next_step: { kind: 'routing', action: 'discover_schema' } },
116
+ { code: 'NOT_FOUND' },
117
+ { code: 'NETWORK_ERROR', next_step: { kind: 'recovery', action: 'retry' } },
118
+ ],
119
+ examples: [
120
+ 'happyskills versions acme/deploy-aws',
121
+ 'happyskills versions acme/deploy-aws --limit 20 --json',
122
+ ],
123
+ }
124
+
125
+ module.exports = { run, extract_version, sort_refs, schema }
@@ -76,4 +76,36 @@ const run = (args) => catch_errors('Visibility failed', async () => {
76
76
  }
77
77
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
78
78
 
79
- module.exports = { run }
79
+ const schema = {
80
+ name: 'visibility',
81
+ audience: 'author',
82
+ purpose: 'Check or set a skill\'s visibility (public, private, workspace) in the registry.',
83
+ mutation: true,
84
+ interactive_in_text_mode: false,
85
+ input: {
86
+ positional: [
87
+ { name: 'skill', required: true, type: 'string', pattern: '<owner>/<name>' },
88
+ { name: 'visibility', required: false, type: 'string', pattern: 'public|private|workspace' },
89
+ ],
90
+ flags: [
91
+ { name: 'json', type: 'boolean', default: false },
92
+ ],
93
+ },
94
+ output: {
95
+ data_shape: {
96
+ skill: 'string',
97
+ visibility: 'string',
98
+ },
99
+ },
100
+ errors: [
101
+ { code: 'USAGE_ERROR', next_step: { kind: 'routing', action: 'discover_schema' } },
102
+ { code: 'AUTH_REQUIRED', next_step: { kind: 'recovery', action: 'login' } },
103
+ { code: 'NOT_FOUND' },
104
+ ],
105
+ examples: [
106
+ 'happyskills visibility acme/deploy-aws',
107
+ 'happyskills visibility acme/deploy-aws public',
108
+ ],
109
+ }
110
+
111
+ module.exports = { run, schema }
@@ -67,4 +67,33 @@ const run = (args) => catch_errors('Whoami failed', async () => {
67
67
  }
68
68
  }).then(([errors]) => { if (errors) { exit_with_error(errors); return } })
69
69
 
70
- module.exports = { run }
70
+ const schema = {
71
+ name: 'whoami',
72
+ audience: 'account',
73
+ purpose: 'Show the currently authenticated user and their workspaces.',
74
+ mutation: false,
75
+ interactive_in_text_mode: false,
76
+ input: {
77
+ positional: [],
78
+ flags: [
79
+ { name: 'json', type: 'boolean', default: false }
80
+ ]
81
+ },
82
+ output: {
83
+ data_shape: {
84
+ username: 'string',
85
+ email: 'string',
86
+ workspaces: 'array'
87
+ }
88
+ },
89
+ errors: [
90
+ { code: 'AUTH_REQUIRED', next_step: { kind: 'recovery', action: 'login' } },
91
+ { code: 'NETWORK_ERROR', next_step: { kind: 'recovery', action: 'retry' } }
92
+ ],
93
+ examples: [
94
+ 'happyskills whoami',
95
+ 'happyskills whoami --json'
96
+ ]
97
+ }
98
+
99
+ module.exports = { run, schema }
@@ -14,6 +14,7 @@
14
14
  // Auth & permission ────────────────────────────────────────────────────────
15
15
  const AUTH_REQUIRED = 'AUTH_REQUIRED'
16
16
  const INVALID_CREDENTIALS = 'INVALID_CREDENTIALS'
17
+ const AUTH_FAILED = 'AUTH_FAILED'
17
18
  const EXPIRED_TOKEN = 'EXPIRED_TOKEN'
18
19
  const INTERACTIVE_REQUIRED = 'INTERACTIVE_REQUIRED'
19
20
  const FORBIDDEN = 'FORBIDDEN'
@@ -109,6 +110,13 @@ const WRITE_FAILED = 'WRITE_FAILED'
109
110
  const PUBLISH_FAILED = 'PUBLISH_FAILED'
110
111
  const RANKING_SCHEMA_MISMATCH = 'RANKING_SCHEMA_MISMATCH'
111
112
 
113
+ // pull --rebase pipeline (client-side, spec 260523-02) ──────────────────────
114
+ const COMPARE_FAILED = 'COMPARE_FAILED'
115
+ const CLONE_BASE_FAILED = 'CLONE_BASE_FAILED'
116
+ const CLONE_REMOTE_FAILED = 'CLONE_REMOTE_FAILED'
117
+ const READ_LOCAL_FAILED = 'READ_LOCAL_FAILED'
118
+ const SWAP_FAILED = 'SWAP_FAILED'
119
+
112
120
  // Internal ─────────────────────────────────────────────────────────────────
113
121
  const INTERNAL_ERROR = 'INTERNAL_ERROR'
114
122
  const PERSIST_FAILED = 'PERSIST_FAILED'
@@ -147,7 +155,8 @@ const NOT_COMMUNITY_LISTED = 'NOT_COMMUNITY_LISTED'
147
155
  const UNKNOWN_CODE = 'UNKNOWN_CODE'
148
156
 
149
157
  const ERROR_CODES = Object.freeze({
150
- AUTH_REQUIRED, INVALID_CREDENTIALS, EXPIRED_TOKEN, INTERACTIVE_REQUIRED,
158
+ AUTH_REQUIRED, INVALID_CREDENTIALS, AUTH_FAILED, EXPIRED_TOKEN,
159
+ INTERACTIVE_REQUIRED,
151
160
  FORBIDDEN, INSUFFICIENT_ACCESS, LAST_OWNER, ORG_RESTRICTED,
152
161
  NETWORK_ERROR, RATE_LIMITED, DB_UNAVAILABLE, GITHUB_UNAVAILABLE,
153
162
  EMBEDDING_UNAVAILABLE, REGISTRY_UNAVAILABLE,
@@ -172,6 +181,8 @@ const ERROR_CODES = Object.freeze({
172
181
  AUTHORIZATION_PENDING,
173
182
  COMMAND_NOT_FOUND, MIN_CLI_VERSION, SNAPSHOT_FAILED, WRITE_FAILED,
174
183
  PUBLISH_FAILED, RANKING_SCHEMA_MISMATCH,
184
+ COMPARE_FAILED, CLONE_BASE_FAILED, CLONE_REMOTE_FAILED, READ_LOCAL_FAILED,
185
+ SWAP_FAILED,
175
186
  INTERNAL_ERROR, PERSIST_FAILED, VERIFICATION_FAILED,
176
187
  NO_COGNITO_USER, COGNITO_SYNC_FAILED, COGNITO_UNLINK_FAILED,
177
188
  ALREADY_HAS_PASSWORD, EMAIL_ALIAS_CONFLICT, ALREADY_APPROVED,
@@ -31,6 +31,8 @@ const PROVIDE_CHANGELOG = 'provide_changelog'
31
31
  const SELF_UPDATE = 'self_update'
32
32
  const SHOW_FORMAT = 'show_format'
33
33
  const RETRY_RANK = 'retry_rank'
34
+ const RETRY_OR_ABANDON = 'retry_or_abandon'
35
+ const REVIEW_PUBLISH_ERROR = 'review_publish_error'
34
36
 
35
37
  // kind: clarification
36
38
  const CLARIFY_QUERY = 'clarify_query'
@@ -45,6 +47,7 @@ const SPECIFY_WORKSPACE = 'specify_workspace'
45
47
  const SPECIFY_BUMP_TYPE = 'specify_bump_type'
46
48
  const RESOLVE_BUMP_DISAGREEMENT = 'resolve_bump_disagreement'
47
49
  const PICK_VERSION = 'pick_version'
50
+ const RESOLVE_UNKNOWN_DRIFT = 'resolve_unknown_drift'
48
51
 
49
52
  // kind: confirmation
50
53
  const CONFIRM_DISCARD_OR_SNAPSHOT_FIRST = 'confirm_discard_or_snapshot_first'
@@ -72,6 +75,8 @@ const ACTION_KIND = Object.freeze({
72
75
  [SELF_UPDATE]: RECOVERY,
73
76
  [SHOW_FORMAT]: RECOVERY,
74
77
  [RETRY_RANK]: RECOVERY,
78
+ [RETRY_OR_ABANDON]: RECOVERY,
79
+ [REVIEW_PUBLISH_ERROR]: RECOVERY,
75
80
 
76
81
  [CLARIFY_QUERY]: CLARIFICATION,
77
82
 
@@ -84,6 +89,7 @@ const ACTION_KIND = Object.freeze({
84
89
  [SPECIFY_BUMP_TYPE]: DECISION,
85
90
  [RESOLVE_BUMP_DISAGREEMENT]: DECISION,
86
91
  [PICK_VERSION]: DECISION,
92
+ [RESOLVE_UNKNOWN_DRIFT]: DECISION,
87
93
 
88
94
  [CONFIRM_DISCARD_OR_SNAPSHOT_FIRST]: CONFIRMATION,
89
95
  [CONFIRM_CASCADE]: CONFIRMATION,
@@ -101,10 +107,12 @@ const ACTION_KIND = Object.freeze({
101
107
  const NEXT_STEP_ACTIONS = Object.freeze({
102
108
  LOGIN, RETRY, RECONCILE_FIRST, PULL_REBASE_FIRST, FIX_VALIDATION_ERRORS,
103
109
  PROVIDE_CHANGELOG, SELF_UPDATE, SHOW_FORMAT, RETRY_RANK,
110
+ RETRY_OR_ABANDON, REVIEW_PUBLISH_ERROR,
104
111
  CLARIFY_QUERY,
105
112
  RESOLVE_REGRESSION, RESOLVE_MISSING_SKILL_JSON, RESOLVE_MISSING_DIR,
106
113
  RESOLVE_CONFLICTS, RESOLVE_PATCH_REJECTIONS, SPECIFY_WORKSPACE,
107
114
  SPECIFY_BUMP_TYPE, RESOLVE_BUMP_DISAGREEMENT, PICK_VERSION,
115
+ RESOLVE_UNKNOWN_DRIFT,
108
116
  CONFIRM_DISCARD_OR_SNAPSHOT_FIRST, CONFIRM_CASCADE, CONFIRM_DESTRUCTIVE,
109
117
  PASS_YES_FLAG,
110
118
  RANK_DIGESTS_INLINE, PRESENT_TO_USER, ATTACH_SCREENSHOT,
@@ -59,6 +59,11 @@ const NEXT_STEP_BY_ERROR_CODE = Object.freeze({
59
59
  'Sign in to HappySkills, then re-run the command.',
60
60
  { commands: ['npx happyskills login --browser --json'] }
61
61
  ),
62
+ AUTH_FAILED: () => recovery(
63
+ LOGIN,
64
+ 'The sign-in attempt did not complete. Start the login flow again, then re-run the command.',
65
+ { commands: ['npx happyskills login --browser --json'] }
66
+ ),
62
67
  EXPIRED_TOKEN: () => recovery(
63
68
  LOGIN,
64
69
  'Your session has expired. Sign in again, then re-run the command.',
@@ -94,6 +94,37 @@ describe('happyskills schema --json', () => {
94
94
  }
95
95
  })
96
96
 
97
+ it('no command returns the stub purpose (anti-stub guard — spec 260602-01)', () => {
98
+ const { stdout } = run(['schema', '--json'])
99
+ const env = parse_envelope(stdout, 'schema --json anti-stub')
100
+ const stubbed = env.data.commands.filter(c => /no curated purpose/i.test(c.purpose))
101
+ assert.deepStrictEqual(
102
+ stubbed.map(c => c.name),
103
+ [],
104
+ `these commands still return the stub purpose and need a curated schema export: ${stubbed.map(c => c.name).join(', ')}`
105
+ )
106
+ })
107
+
108
+ it('every command carries a non-empty examples array of strings', () => {
109
+ const { stdout } = run(['schema', '--json'])
110
+ const env = parse_envelope(stdout, 'schema --json examples')
111
+ for (const cmd of env.data.commands) {
112
+ assert.ok(Array.isArray(cmd.examples) && cmd.examples.length > 0, `command.examples must be a non-empty array for ${cmd.name}`)
113
+ for (const ex of cmd.examples) {
114
+ assert.ok(typeof ex === 'string' && ex.length > 0, `command.examples[] entries must be non-empty strings for ${cmd.name}`)
115
+ }
116
+ }
117
+ })
118
+
119
+ it('every command.input exposes positional and flags arrays', () => {
120
+ const { stdout } = run(['schema', '--json'])
121
+ const env = parse_envelope(stdout, 'schema --json input shape')
122
+ for (const cmd of env.data.commands) {
123
+ assert.ok(Array.isArray(cmd.input.positional), `command.input.positional must be an array for ${cmd.name}`)
124
+ assert.ok(Array.isArray(cmd.input.flags), `command.input.flags must be an array for ${cmd.name}`)
125
+ }
126
+ })
127
+
97
128
  it('every command.errors[].code is in the closed enum, and the kind/action pair is valid', () => {
98
129
  const { stdout } = run(['schema', '--json'])
99
130
  const env = parse_envelope(stdout, 'schema --json error refs')
@@ -34,6 +34,9 @@ const DEFAULT_INSTRUCTIONS = {
34
34
  retry: 'Transient failure. Retry shortly.',
35
35
  reconcile_first: 'Drift must be resolved before this operation. Run reconcile, follow its next_step, then retry.',
36
36
  pull_rebase_first: 'The local skill has diverged from the registry. Pull with --rebase, resolve any rejected patches, then retry.',
37
+ retry_or_abandon: 'The rebase step failed before any change landed. Retry the pull, or abandon and restore the snapshot.',
38
+ resolve_unknown_drift: 'Unrecognized drift subtype — surface the details to the principal for a manual decision.',
39
+ review_publish_error: 'The publish step failed. Inspect the wrapped publish error in context, resolve it, then retry.',
37
40
  fix_validation_errors: 'Fix the listed validation errors and re-run.',
38
41
  provide_changelog: 'CHANGELOG.md is missing the target version entry. Add it and re-run.',
39
42
  self_update: 'Upgrade the happyskills CLI and re-run.',