atris 3.52.0 → 3.55.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.
Files changed (131) hide show
  1. package/FOR_AGENTS.md +7 -0
  2. package/README.md +1 -1
  3. package/atris/policies/ANTISLOP.md +2 -1
  4. package/atris/skills/copy-editor/SKILL.md +2 -1
  5. package/atris/skills/design/SKILL.md +1 -1
  6. package/atris/skills/engines/SKILL.md +8 -7
  7. package/atris/skills/x-search/SKILL.md +24 -22
  8. package/atris/skills/youtube/SKILL.md +89 -40
  9. package/atris/team/_template/SOUL.md +40 -0
  10. package/atris/team/validator/MEMBER.md +1 -2
  11. package/ax +592 -91
  12. package/bin/atris +21 -0
  13. package/bin/atris.js +580 -378
  14. package/commands/api-key.js +170 -0
  15. package/commands/auth.js +453 -43
  16. package/commands/autoland.js +3 -1
  17. package/commands/autopilot-front.js +58 -11
  18. package/commands/avail.js +5 -4
  19. package/commands/balance.js +55 -0
  20. package/commands/bench.js +29 -1
  21. package/commands/brain.js +63 -12
  22. package/commands/brainstorm.js +18 -0
  23. package/commands/business.js +149 -1
  24. package/commands/chat-scan.js +17 -4
  25. package/commands/close.js +5 -1
  26. package/commands/computer.js +2 -2
  27. package/commands/doctor.js +174 -0
  28. package/commands/dream.js +7 -0
  29. package/commands/drill.js +34 -2
  30. package/commands/engine.js +47 -35
  31. package/commands/errors.js +58 -8
  32. package/commands/experiments.js +14 -0
  33. package/commands/feedback.js +61 -2
  34. package/commands/fleet-report.js +27 -7
  35. package/commands/fleet.js +98 -11
  36. package/commands/founder.js +60 -21
  37. package/commands/human-missions.js +79 -4
  38. package/commands/improve.js +54 -4
  39. package/commands/init.js +68 -92
  40. package/commands/install.js +40 -0
  41. package/commands/integrations.js +399 -30
  42. package/commands/interview.js +8 -0
  43. package/commands/land.js +48 -17
  44. package/commands/learn.js +29 -4
  45. package/commands/log.js +51 -0
  46. package/commands/member.js +68 -10
  47. package/commands/mission.js +339 -74
  48. package/commands/now.js +25 -6
  49. package/commands/orb.js +97 -2
  50. package/commands/pack.js +83 -9
  51. package/commands/playbook.js +381 -0
  52. package/commands/plugin.js +16 -0
  53. package/commands/radar.js +96 -40
  54. package/commands/recap.js +128 -21
  55. package/commands/release.js +102 -2
  56. package/commands/review.js +5 -10
  57. package/commands/revisions.js +55 -0
  58. package/commands/run-front.js +12 -4
  59. package/commands/scout.js +12 -1
  60. package/commands/search.js +123 -28
  61. package/commands/sign.js +2 -2
  62. package/commands/signup.js +12 -3
  63. package/commands/site-deploy.js +17 -4
  64. package/commands/site.js +2 -2
  65. package/commands/skill-eval.js +289 -0
  66. package/commands/skill.js +56 -6
  67. package/commands/social.js +603 -0
  68. package/commands/spaceship.js +69 -6
  69. package/commands/stream.js +8 -1
  70. package/commands/study.js +32 -19
  71. package/commands/sync.js +28 -22
  72. package/commands/task.js +418 -60
  73. package/commands/teach.js +72 -63
  74. package/commands/terminal.js +25 -9
  75. package/commands/topup.js +88 -0
  76. package/commands/truth.js +52 -6
  77. package/commands/usage.js +91 -0
  78. package/commands/verify.js +3 -2
  79. package/commands/version.js +3 -1
  80. package/commands/voice.js +5 -1
  81. package/commands/who.js +69 -11
  82. package/commands/wiki.js +7 -4
  83. package/commands/wish.js +76 -5
  84. package/commands/workflow.js +327 -145
  85. package/commands/worktree.js +1 -0
  86. package/commands/write.js +5 -0
  87. package/commands/x-search.js +340 -0
  88. package/commands/xp.js +5 -1
  89. package/commands/youtube.js +551 -33
  90. package/lib/account-bound.js +47 -0
  91. package/lib/auto-accept-certified.js +10 -2
  92. package/lib/auto-lessons.js +186 -0
  93. package/lib/autoland.js +4 -2
  94. package/lib/chat-log-scan.js +7 -4
  95. package/lib/cli-json.js +77 -0
  96. package/lib/cli-scope.js +26 -0
  97. package/lib/codex-flight.js +1 -0
  98. package/lib/conductor-artifacts.js +1 -1
  99. package/lib/context-gatherer.js +11 -0
  100. package/lib/developer-api.js +116 -0
  101. package/lib/engine-ask.js +11 -3
  102. package/lib/engine-registry.js +32 -7
  103. package/lib/feedback-triage.js +274 -0
  104. package/lib/first-minute.js +398 -0
  105. package/lib/fleet.js +115 -34
  106. package/lib/functional-owner.js +22 -0
  107. package/lib/known-commands.js +31 -5
  108. package/lib/member-scaffold.js +197 -0
  109. package/lib/mission-ledger-compact.js +127 -0
  110. package/lib/mission-root.js +4 -2
  111. package/lib/mission-runtime-loop.js +30 -2
  112. package/lib/next-moves.js +34 -34
  113. package/lib/noninteractive.js +88 -0
  114. package/lib/permission-grants.js +10 -1
  115. package/lib/policy-lessons.js +4 -1
  116. package/lib/revision-metric.js +279 -0
  117. package/lib/runner-command.js +5 -4
  118. package/lib/scratch-root.js +48 -0
  119. package/lib/skill-eval-gate.js +249 -0
  120. package/lib/task-db.js +22 -2
  121. package/lib/task-proof.js +75 -9
  122. package/lib/task-receipt.js +5 -1
  123. package/lib/verifier-quality.js +69 -0
  124. package/lib/wish-audit.js +2 -2
  125. package/lib/wish-delegate.js +10 -1
  126. package/lib/workspace-scaffold.js +270 -0
  127. package/package.json +4 -2
  128. package/scripts/det/checklist-score.js +191 -0
  129. package/scripts/det/ytsearch +31 -0
  130. package/scripts/outbound-artifact-gate.js +227 -0
  131. package/utils/update-check.js +15 -0
@@ -0,0 +1,289 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
6
+ const { spawnSync } = require('node:child_process');
7
+ const { getEngineAdapter } = require('../lib/bench/engines');
8
+ const {
9
+ SKILL_EVAL_SCHEMA,
10
+ appendSkillEvalReceipt,
11
+ changedSkillFiles,
12
+ } = require('../lib/skill-eval-gate');
13
+
14
+ const REVIEW_DIRECTORY_PREFIX = 'atris-review-';
15
+ const RUBRIC_KEYS = Object.freeze([
16
+ 'instruction_clarity',
17
+ 'trigger_precision',
18
+ 'procedural_completeness',
19
+ 'safety',
20
+ 'verifiability',
21
+ ]);
22
+ const JUDGE_ORDER = Object.freeze(['claude', 'codex', 'cursor']);
23
+
24
+ function readFlag(args, name) {
25
+ const prefix = `${name}=`;
26
+ const inline = args.find((arg) => String(arg).startsWith(prefix));
27
+ if (inline) return String(inline).slice(prefix.length);
28
+ const index = args.indexOf(name);
29
+ if (index !== -1 && args[index + 1] && !String(args[index + 1]).startsWith('--')) {
30
+ return String(args[index + 1]);
31
+ }
32
+ return null;
33
+ }
34
+
35
+ function parseArgs(args = []) {
36
+ const valueFlags = new Set(['--judge', '--worker-model', '--timeout']);
37
+ let skillPath = null;
38
+ for (let index = 0; index < args.length; index += 1) {
39
+ const arg = String(args[index]);
40
+ if (valueFlags.has(arg)) {
41
+ index += 1;
42
+ continue;
43
+ }
44
+ if (arg.startsWith('--')) continue;
45
+ if (!skillPath) skillPath = arg;
46
+ }
47
+ return {
48
+ skillPath,
49
+ judge: readFlag(args, '--judge') || process.env.ATRIS_SKILL_JUDGE || null,
50
+ workerModel: readFlag(args, '--worker-model') || null,
51
+ timeoutMs: Math.max(1000, Number(readFlag(args, '--timeout') || 300) * 1000),
52
+ json: args.includes('--json'),
53
+ help: args.includes('--help') || args.includes('-h') || args.includes('help'),
54
+ };
55
+ }
56
+
57
+ function workerModelFromEnvironment(env = process.env) {
58
+ if (env.ATRIS_WORKER_MODEL) return String(env.ATRIS_WORKER_MODEL).trim();
59
+ if (env.CODEX_SANDBOX || env.CODEX_THREAD_ID) return String(env.CODEX_MODEL || 'codex').trim();
60
+ if (env.CLAUDECODE || env.CLAUDE_CODE_ENTRYPOINT) {
61
+ return String(env.ATRIS_CLAUDE_MODEL || env.ANTHROPIC_MODEL || 'claude').trim();
62
+ }
63
+ if (env.CURSOR_AGENT) return 'cursor';
64
+ if (env.DEVIN_SESSION_ID) return 'devin';
65
+ if (env.ATRIS_RUNNER_MODEL) return String(env.ATRIS_RUNNER_MODEL).trim();
66
+ return 'human';
67
+ }
68
+
69
+ function identityFamily(value) {
70
+ const normalized = String(value || '').trim().toLowerCase();
71
+ if (/claude|anthropic/.test(normalized)) return 'claude';
72
+ if (/codex|openai|gpt/.test(normalized)) return 'codex';
73
+ if (/cursor/.test(normalized)) return 'cursor';
74
+ return normalized;
75
+ }
76
+
77
+ function resolveSkillPath(root, requested) {
78
+ if (!requested) throw new Error('a skill path is required');
79
+ let absolute = path.resolve(root, requested);
80
+ try {
81
+ if (fs.statSync(absolute).isDirectory()) absolute = path.join(absolute, 'SKILL.md');
82
+ } catch {
83
+ // A deleted SKILL.md can still be evaluated from the branch diff.
84
+ }
85
+ const relative = path.relative(root, absolute).replace(/\\/g, '/');
86
+ if (!relative || relative === '..' || relative.startsWith('../') || path.basename(relative) !== 'SKILL.md') {
87
+ throw new Error('the skill path must name a SKILL.md inside this workspace');
88
+ }
89
+ return { absolute, relative };
90
+ }
91
+
92
+ function gitOutput(root, args) {
93
+ const result = spawnSync('git', args, {
94
+ cwd: root,
95
+ encoding: 'utf8',
96
+ timeout: 10000,
97
+ maxBuffer: 4 * 1024 * 1024,
98
+ });
99
+ return result.status === 0 ? String(result.stdout || '') : null;
100
+ }
101
+
102
+ function previousSkillContent(root, skillPath) {
103
+ for (const ref of ['origin/master', 'origin/main', 'master', 'main', 'HEAD']) {
104
+ const content = gitOutput(root, ['show', `${ref}:${skillPath}`]);
105
+ if (content !== null) return { ref, content };
106
+ }
107
+ return { ref: null, content: '' };
108
+ }
109
+
110
+ function buildJudgePrompt(skillPath, previousRef) {
111
+ const comparison = previousRef
112
+ ? `previous-skill.md is the version from ${previousRef}. Reject regressions even when the current file is acceptable in isolation.`
113
+ : 'There is no previous version. Judge whether the new skill is ready to guide an agent safely and repeatably.';
114
+ return `You are reviewing agent instructions in current-skill.md.
115
+ ${comparison}
116
+
117
+ Score each rubric from 1 to 5:
118
+ - instruction_clarity: an agent can follow the instructions without guessing.
119
+ - trigger_precision: the skill says exactly when it should and should not run.
120
+ - procedural_completeness: the required workflow and closure behavior are present.
121
+ - safety: risky actions, permissions, and failure behavior are explicit.
122
+ - verifiability: success can be checked with concrete evidence.
123
+
124
+ Set passed to true only when every score is at least 4 and the current version has no regression from the previous version. Do not edit any files. Return exactly one JSON object and no markdown:
125
+ {"passed":true,"rubric_scores":{"instruction_clarity":4,"trigger_precision":4,"procedural_completeness":4,"safety":4,"verifiability":4},"summary":"one short factual sentence"}`;
126
+ }
127
+
128
+ function parseJudgePayload(output) {
129
+ const text = String(output || '').trim();
130
+ const candidates = [text];
131
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
132
+ if (fenced) candidates.push(fenced[1].trim());
133
+ const firstBrace = text.indexOf('{');
134
+ const lastBrace = text.lastIndexOf('}');
135
+ if (firstBrace !== -1 && lastBrace > firstBrace) candidates.push(text.slice(firstBrace, lastBrace + 1));
136
+
137
+ let payload = null;
138
+ for (const candidate of candidates) {
139
+ try {
140
+ payload = JSON.parse(candidate);
141
+ break;
142
+ } catch {
143
+ // Try the next extraction form.
144
+ }
145
+ }
146
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
147
+ throw new Error('the judge did not return one readable JSON object');
148
+ }
149
+ if (!payload.rubric_scores || typeof payload.rubric_scores !== 'object' || Array.isArray(payload.rubric_scores)) {
150
+ throw new Error('the judge did not return rubric scores');
151
+ }
152
+ const rubricScores = {};
153
+ for (const key of RUBRIC_KEYS) {
154
+ const score = Number(payload.rubric_scores[key]);
155
+ if (!Number.isFinite(score) || score < 1 || score > 5) {
156
+ throw new Error(`the judge returned an invalid ${key} score`);
157
+ }
158
+ rubricScores[key] = score;
159
+ }
160
+ const passed = payload.passed === true && Object.values(rubricScores).every((score) => score >= 4);
161
+ return {
162
+ passed,
163
+ rubric_scores: rubricScores,
164
+ summary: String(payload.summary || '').trim().slice(0, 500),
165
+ };
166
+ }
167
+
168
+ function createReviewDirectory(fileSystem = fs) {
169
+ const directory = fileSystem.mkdtempSync(path.join(os.tmpdir(), REVIEW_DIRECTORY_PREFIX));
170
+ if (/(eval|test)/i.test(path.basename(directory))) {
171
+ fileSystem.rmSync(directory, { recursive: true, force: true });
172
+ throw new Error('could not create a neutral review workspace');
173
+ }
174
+ return directory;
175
+ }
176
+
177
+ function chooseJudge(requested, workerModel, directory, engineFactory = getEngineAdapter) {
178
+ const workerFamily = identityFamily(workerModel);
179
+ const candidates = requested ? [requested] : JUDGE_ORDER;
180
+ const unavailable = [];
181
+ for (const name of candidates) {
182
+ let adapter;
183
+ try {
184
+ adapter = engineFactory(name);
185
+ } catch (error) {
186
+ unavailable.push(`${name}: ${error.message || error}`);
187
+ continue;
188
+ }
189
+ if (identityFamily(adapter.name) === workerFamily) {
190
+ unavailable.push(`${adapter.name}: matches worker model`);
191
+ continue;
192
+ }
193
+ const status = adapter.available(directory);
194
+ if (!status.available) {
195
+ unavailable.push(`${adapter.name}: ${status.reason}`);
196
+ continue;
197
+ }
198
+ return adapter;
199
+ }
200
+ const detail = unavailable.length ? ` (${unavailable.join('; ')})` : '';
201
+ throw new Error(`no independent judge engine is available${detail}`);
202
+ }
203
+
204
+ function printHelp() {
205
+ console.log('Usage: atris skill eval <skill-path> [--judge <engine>] [--worker-model <id>] [--timeout <seconds>] [--json]');
206
+ console.log('');
207
+ console.log('Runs an independent rubric review and appends its receipt to .atris/state/scorecards.jsonl.');
208
+ }
209
+
210
+ function skillEvalCommand(args = [], dependencies = {}) {
211
+ const options = parseArgs(args);
212
+ if (options.help) {
213
+ printHelp();
214
+ return 0;
215
+ }
216
+ const root = path.resolve(dependencies.root || process.cwd());
217
+ let directory = null;
218
+ try {
219
+ const skill = resolveSkillPath(root, options.skillPath);
220
+ const previous = previousSkillContent(root, skill.relative);
221
+ let current = '';
222
+ try {
223
+ current = fs.readFileSync(skill.absolute, 'utf8');
224
+ } catch {
225
+ if (!previous.ref) throw new Error(`could not read ${skill.relative}`);
226
+ }
227
+
228
+ directory = createReviewDirectory(dependencies.fs || fs);
229
+ fs.writeFileSync(path.join(directory, 'current-skill.md'), current || '[skill deleted]\n', 'utf8');
230
+ fs.writeFileSync(path.join(directory, 'previous-skill.md'), previous.content || '[no previous skill]\n', 'utf8');
231
+ const workerModel = options.workerModel || workerModelFromEnvironment(dependencies.env || process.env);
232
+ const judge = chooseJudge(
233
+ options.judge,
234
+ workerModel,
235
+ directory,
236
+ dependencies.getEngineAdapter || getEngineAdapter,
237
+ );
238
+ const result = judge.run(buildJudgePrompt(skill.relative, previous.ref), directory, options.timeoutMs);
239
+ if (!result || result.status !== 0) {
240
+ const detail = String(result && (result.stderr || result.stdout) || '').trim().slice(0, 400);
241
+ throw new Error(`the ${judge.name} judge failed${detail ? `: ${detail}` : ''}`);
242
+ }
243
+ const verdict = parseJudgePayload(result.stdout);
244
+ const changed = changedSkillFiles(root).find((entry) => entry.path === skill.relative);
245
+ const receiptAt = new Date(Math.max(
246
+ Date.now(),
247
+ Number(changed && changed.changed_at_ms || 0) + 1,
248
+ )).toISOString();
249
+ const receipt = {
250
+ schema: SKILL_EVAL_SCHEMA,
251
+ ts: receiptAt,
252
+ source: 'skill_eval',
253
+ skill_path: skill.relative,
254
+ skill_changed_at: changed ? changed.changed_at : null,
255
+ worker_model: workerModel,
256
+ judge_identity: judge.name,
257
+ passed: verdict.passed,
258
+ rubric_scores: verdict.rubric_scores,
259
+ summary: verdict.summary || null,
260
+ };
261
+ const receiptFile = appendSkillEvalReceipt(root, receipt);
262
+ const relativeReceipt = path.relative(root, receiptFile).replace(/\\/g, '/');
263
+ if (options.json) {
264
+ console.log(JSON.stringify({ ok: verdict.passed, receipt, receipt_file: relativeReceipt }));
265
+ } else if (verdict.passed) {
266
+ console.log(`skill eval passed for ${skill.relative}; receipt written to ${relativeReceipt}.`);
267
+ } else {
268
+ console.error(`skill eval failed for ${skill.relative}; the failing receipt was written to ${relativeReceipt}.`);
269
+ }
270
+ return verdict.passed ? 0 : 1;
271
+ } catch (error) {
272
+ const message = String(error && error.message ? error.message : error);
273
+ if (options.json) console.log(JSON.stringify({ ok: false, error: message }));
274
+ else console.error(`skill eval could not run: ${message}.`);
275
+ return 2;
276
+ } finally {
277
+ if (directory) {
278
+ try {
279
+ (dependencies.fs || fs).rmSync(directory, { recursive: true, force: true });
280
+ } catch {
281
+ // The result is already recorded; temporary cleanup is best effort.
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ module.exports = {
288
+ skillEvalCommand,
289
+ };
package/commands/skill.js CHANGED
@@ -440,9 +440,36 @@ function generateTags(folderName, description) {
440
440
 
441
441
  // --- Subcommand Handlers ---
442
442
 
443
- function skillList() {
443
+ function skillColor(text, code) {
444
+ if (process.env.NO_COLOR || !process.stdout.isTTY) return String(text);
445
+ return `\x1b[${code}m${text}\x1b[0m`;
446
+ }
447
+
448
+ function skillList(...flags) {
449
+ const asJson = flags.includes('--json') || process.argv.includes('--json');
444
450
  const skills = findReadableSkills();
445
451
 
452
+ if (asJson) {
453
+ const rows = skills.map((skill) => {
454
+ const checks = runAuditChecks(skill);
455
+ const passing = checks.filter(c => c.pass).length;
456
+ const total = checks.length;
457
+ return {
458
+ name: skill.folder,
459
+ version: (skill.frontmatter || {}).version || null,
460
+ checks_passing: passing,
461
+ checks_total: total,
462
+ status: getStatus(checks),
463
+ };
464
+ });
465
+ console.log(JSON.stringify({
466
+ ok: true,
467
+ count: rows.length,
468
+ skills: rows,
469
+ }, null, 2));
470
+ return;
471
+ }
472
+
446
473
  if (skills.length === 0) {
447
474
  console.log('No skills found in local or bundled Atris skill roots.');
448
475
  return;
@@ -459,9 +486,9 @@ function skillList() {
459
486
  const total = checks.length;
460
487
  const status = getStatus(checks);
461
488
  const version = (skill.frontmatter || {}).version || '-';
462
- const statusIcon = status === 'PASS' ? '\x1b[32mPASS\x1b[0m'
463
- : status === 'WARN' ? '\x1b[33mWARN\x1b[0m'
464
- : '\x1b[31mFAIL\x1b[0m';
489
+ const statusIcon = status === 'PASS' ? skillColor('PASS', '32')
490
+ : status === 'WARN' ? skillColor('WARN', '33')
491
+ : skillColor('FAIL', '31');
465
492
 
466
493
  if (status !== 'PASS') needsAttention++;
467
494
 
@@ -789,6 +816,10 @@ function skillCreate(nameArg, ...flags) {
789
816
  // --- LINK subcommand (system-level symlink for existing skills) ---
790
817
 
791
818
  function skillLink(name, ...flags) {
819
+ if (name === '--help' || name === '-h' || name === 'help' || flags.some((f) => f === '--help' || f === '-h' || f === 'help')) {
820
+ console.error('Usage: atris skill link [name|--all]');
821
+ process.exit(2);
822
+ }
792
823
  const isAll = name === '--all';
793
824
 
794
825
  const skillsDir = path.join(process.cwd(), 'atris', 'skills');
@@ -934,14 +965,32 @@ function skillDelete(name) {
934
965
  // --- Main Dispatcher ---
935
966
 
936
967
  function skillCommand(subcommand, ...args) {
968
+ if (subcommand === '--help' || subcommand === '-h' || subcommand === 'help'
969
+ || args.some((a) => a === '--help' || a === '-h' || a === 'help')) {
970
+ console.log('');
971
+ console.log('Usage: atris skill <subcommand> [name]');
972
+ console.log('');
973
+ console.log('Subcommands:');
974
+ console.log(' create <name> Scaffold a new skill with SKILL.md template');
975
+ console.log(' delete <name> Remove a skill and all its symlinks');
976
+ console.log(' link [name|--all] Symlink skills to ~/.claude/skills/ (system-level)');
977
+ console.log(' list [--json] Show all skills with compliance status');
978
+ console.log(' audit [name|--all] Validate skill against Anthropic guide');
979
+ console.log(' fix [name|--all] Auto-fix common compliance issues');
980
+ console.log(' eval <skill-path> Run an independent rubric review and write its receipt');
981
+ console.log('');
982
+ process.exit(0);
983
+ }
937
984
  switch (subcommand) {
938
985
  case 'list':
939
986
  case 'ls':
940
- return skillList();
987
+ return skillList(...args);
941
988
  case 'audit':
942
989
  return skillAudit(args[0] || '--all');
943
990
  case 'fix':
944
991
  return skillFix(args[0] || '--all');
992
+ case 'eval':
993
+ return require('./skill-eval').skillEvalCommand(args);
945
994
  case 'create':
946
995
  case 'new':
947
996
  return skillCreate(args[0], ...args.slice(1));
@@ -959,9 +1008,10 @@ function skillCommand(subcommand, ...args) {
959
1008
  console.log(' create <name> Scaffold a new skill with SKILL.md template');
960
1009
  console.log(' delete <name> Remove a skill and all its symlinks');
961
1010
  console.log(' link [name|--all] Symlink skills to ~/.claude/skills/ (system-level)');
962
- console.log(' list Show all skills with compliance status');
1011
+ console.log(' list [--json] Show all skills with compliance status');
963
1012
  console.log(' audit [name|--all] Validate skill against Anthropic guide');
964
1013
  console.log(' fix [name|--all] Auto-fix common compliance issues');
1014
+ console.log(' eval <skill-path> Run an independent rubric review and write its receipt');
965
1015
  console.log('');
966
1016
  console.log('Create flags:');
967
1017
  console.log(' --integration Use integration template (bootstrap + API)');