@peac/cli 0.9.18 → 0.10.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.
@@ -7,6 +7,13 @@
7
7
  * - validate: Validate policy syntax and schema
8
8
  * - explain: Debug rule matching
9
9
  * - generate: Compile policy to deployment artifacts
10
+ * - list-profiles: List available policy profiles (v0.9.23+)
11
+ * - show-profile: Show profile details (v0.9.23+)
12
+ *
13
+ * Automation flags (v0.9.23+):
14
+ * - --json: Machine-readable JSON output
15
+ * - --yes: Skip confirmation prompts (auto-confirm)
16
+ * - --strict: Exit non-zero on warnings
10
17
  */
11
18
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
19
  if (k2 === undefined) k2 = k;
@@ -47,7 +54,42 @@ const commander_1 = require("commander");
47
54
  const fs = __importStar(require("fs"));
48
55
  const path = __importStar(require("path"));
49
56
  const policy_kit_1 = require("@peac/policy-kit");
50
- const policy = new commander_1.Command('policy').description('Policy file operations');
57
+ /**
58
+ * Get global options from parent command
59
+ */
60
+ function getGlobalOptions(cmd) {
61
+ const parent = cmd.parent;
62
+ if (!parent)
63
+ return {};
64
+ return parent.opts();
65
+ }
66
+ /**
67
+ * Output result - handles JSON vs human-readable format
68
+ */
69
+ function output(data, opts, humanMessage) {
70
+ if (opts.json) {
71
+ console.log(JSON.stringify(data, null, 2));
72
+ }
73
+ else if (humanMessage) {
74
+ console.log(humanMessage);
75
+ }
76
+ }
77
+ /**
78
+ * Output error - handles JSON vs human-readable format
79
+ */
80
+ function outputError(error, details, opts) {
81
+ if (opts.json) {
82
+ console.log(JSON.stringify({ success: false, error, ...details }, null, 2));
83
+ }
84
+ else {
85
+ console.error(`Error: ${error}`);
86
+ }
87
+ }
88
+ const policy = new commander_1.Command('policy')
89
+ .description('Policy file operations')
90
+ .option('--json', 'Output in machine-readable JSON format')
91
+ .option('--yes', 'Skip confirmation prompts (auto-confirm)')
92
+ .option('--strict', 'Exit non-zero on warnings');
51
93
  exports.policy = policy;
52
94
  /**
53
95
  * peac policy init
@@ -58,31 +100,68 @@ policy
58
100
  .command('init')
59
101
  .description('Create a new PEAC policy file')
60
102
  .option('-f, --format <format>', 'Output format (yaml or json)', 'yaml')
61
- .option('-o, --output <file>', 'Output file path', 'peac-policy.yaml')
103
+ .option('-o, --output <file>', 'Output file path')
62
104
  .option('--force', 'Overwrite existing file')
63
- .action((options) => {
105
+ .option('--profile <id>', 'Use a pre-built profile as template')
106
+ .action((options, cmd) => {
107
+ const globalOpts = getGlobalOptions(cmd);
64
108
  try {
65
109
  const format = options.format?.toLowerCase() || 'yaml';
66
110
  const outputPath = options.output || (format === 'json' ? 'peac-policy.json' : 'peac-policy.yaml');
67
- // Check if file exists and --force not set
68
- if (fs.existsSync(outputPath) && !options.force) {
69
- console.error(`Error: File already exists: ${outputPath}`);
70
- console.error('Use --force to overwrite.');
111
+ // Check if file exists and --force/--yes not set
112
+ if (fs.existsSync(outputPath) && !options.force && !globalOpts.yes) {
113
+ outputError(`File already exists: ${outputPath}`, { path: outputPath, hint: 'Use --force or --yes to overwrite' }, globalOpts);
71
114
  process.exit(1);
72
115
  }
73
- const example = (0, policy_kit_1.createExamplePolicy)();
74
- const content = format === 'json' ? (0, policy_kit_1.serializePolicyJson)(example) : (0, policy_kit_1.serializePolicyYaml)(example);
116
+ let content;
117
+ let policyName;
118
+ if (options.profile) {
119
+ // Use profile as template
120
+ try {
121
+ const profile = (0, policy_kit_1.loadProfile)(options.profile);
122
+ const policyDoc = profile.policy;
123
+ content =
124
+ format === 'json' ? (0, policy_kit_1.serializePolicyJson)(policyDoc) : (0, policy_kit_1.serializePolicyYaml)(policyDoc);
125
+ policyName = profile.name;
126
+ }
127
+ catch (err) {
128
+ if (err instanceof policy_kit_1.ProfileError) {
129
+ outputError(err.message, { code: err.code, profile: options.profile }, globalOpts);
130
+ process.exit(1);
131
+ }
132
+ throw err;
133
+ }
134
+ }
135
+ else {
136
+ const example = (0, policy_kit_1.createExamplePolicy)();
137
+ content = format === 'json' ? (0, policy_kit_1.serializePolicyJson)(example) : (0, policy_kit_1.serializePolicyYaml)(example);
138
+ policyName = 'Example Policy';
139
+ }
75
140
  fs.writeFileSync(outputPath, content, 'utf-8');
76
- console.log(`Created policy file: ${outputPath}`);
77
- console.log('');
78
- console.log('Next steps:');
79
- console.log(' 1. Edit the policy file to define your access rules');
80
- console.log(' 2. Validate with: peac policy validate ' + outputPath);
81
- console.log(' 3. Generate artifacts with: peac policy generate ' + outputPath);
141
+ if (globalOpts.json) {
142
+ output({
143
+ success: true,
144
+ file: outputPath,
145
+ format,
146
+ profile: options.profile || null,
147
+ policyName,
148
+ }, globalOpts);
149
+ }
150
+ else {
151
+ console.log(`Created policy file: ${outputPath}`);
152
+ if (options.profile) {
153
+ console.log(`Based on profile: ${options.profile}`);
154
+ }
155
+ console.log('');
156
+ console.log('Next steps:');
157
+ console.log(' 1. Edit the policy file to define your access rules');
158
+ console.log(' 2. Validate with: peac policy validate ' + outputPath);
159
+ console.log(' 3. Generate artifacts with: peac policy generate ' + outputPath);
160
+ }
82
161
  process.exit(0);
83
162
  }
84
163
  catch (err) {
85
- console.error('Error:', err instanceof Error ? err.message : String(err));
164
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
86
165
  process.exit(1);
87
166
  }
88
167
  });
@@ -94,68 +173,123 @@ policy
94
173
  .description('Validate a PEAC policy file (YAML or JSON)')
95
174
  .argument('<file>', 'Path to policy file')
96
175
  .option('-v, --verbose', 'Show detailed validation output')
97
- .action((file, options) => {
176
+ .action((file, options, cmd) => {
177
+ const globalOpts = getGlobalOptions(cmd);
178
+ const warnings = [];
98
179
  try {
99
- console.log(`Validating policy file: ${file}\n`);
100
180
  const policyDoc = (0, policy_kit_1.loadPolicy)(file);
101
- console.log('Policy is valid!\n');
102
- console.log('Policy Information:');
103
- console.log(` Version: ${policyDoc.version}`);
104
- if (policyDoc.name) {
105
- console.log(` Name: ${policyDoc.name}`);
106
- }
107
- console.log(` Default: ${policyDoc.defaults.decision}`);
108
- console.log(` Rules: ${policyDoc.rules.length}`);
109
- if (options.verbose && policyDoc.rules.length > 0) {
110
- console.log('\nRules:');
111
- for (const rule of policyDoc.rules) {
112
- console.log(` - ${rule.name}: ${rule.decision}`);
113
- if (rule.subject) {
114
- const parts = [];
115
- if (rule.subject.type) {
116
- const types = Array.isArray(rule.subject.type)
117
- ? rule.subject.type.join('|')
118
- : rule.subject.type;
119
- parts.push(`type=${types}`);
120
- }
121
- if (rule.subject.labels) {
122
- parts.push(`labels=[${rule.subject.labels.join(',')}]`);
181
+ // Collect any warnings (e.g., deprecated features)
182
+ // Currently no warnings defined, but this is the pattern for future use
183
+ const result = {
184
+ success: true,
185
+ file,
186
+ valid: true,
187
+ warnings,
188
+ policy: {
189
+ version: policyDoc.version,
190
+ name: policyDoc.name || null,
191
+ defaultDecision: policyDoc.defaults.decision,
192
+ ruleCount: policyDoc.rules.length,
193
+ rules: options.verbose
194
+ ? policyDoc.rules.map((r) => ({
195
+ name: r.name,
196
+ decision: r.decision,
197
+ subject: r.subject || null,
198
+ purpose: r.purpose || null,
199
+ licensingMode: r.licensing_mode || null,
200
+ }))
201
+ : undefined,
202
+ },
203
+ };
204
+ if (globalOpts.json) {
205
+ output(result, globalOpts);
206
+ }
207
+ else {
208
+ console.log(`Validating policy file: ${file}\n`);
209
+ console.log('Policy is valid!\n');
210
+ console.log('Policy Information:');
211
+ console.log(` Version: ${policyDoc.version}`);
212
+ if (policyDoc.name) {
213
+ console.log(` Name: ${policyDoc.name}`);
214
+ }
215
+ console.log(` Default: ${policyDoc.defaults.decision}`);
216
+ console.log(` Rules: ${policyDoc.rules.length}`);
217
+ if (options.verbose && policyDoc.rules.length > 0) {
218
+ console.log('\nRules:');
219
+ for (const rule of policyDoc.rules) {
220
+ console.log(` - ${rule.name}: ${rule.decision}`);
221
+ if (rule.subject) {
222
+ const parts = [];
223
+ if (rule.subject.type) {
224
+ const types = Array.isArray(rule.subject.type)
225
+ ? rule.subject.type.join('|')
226
+ : rule.subject.type;
227
+ parts.push(`type=${types}`);
228
+ }
229
+ if (rule.subject.labels) {
230
+ parts.push(`labels=[${rule.subject.labels.join(',')}]`);
231
+ }
232
+ if (rule.subject.id) {
233
+ parts.push(`id=${rule.subject.id}`);
234
+ }
235
+ if (parts.length > 0) {
236
+ console.log(` subject: ${parts.join(', ')}`);
237
+ }
123
238
  }
124
- if (rule.subject.id) {
125
- parts.push(`id=${rule.subject.id}`);
239
+ if (rule.purpose) {
240
+ const purposes = Array.isArray(rule.purpose) ? rule.purpose.join('|') : rule.purpose;
241
+ console.log(` purpose: ${purposes}`);
126
242
  }
127
- if (parts.length > 0) {
128
- console.log(` subject: ${parts.join(', ')}`);
243
+ if (rule.licensing_mode) {
244
+ const modes = Array.isArray(rule.licensing_mode)
245
+ ? rule.licensing_mode.join('|')
246
+ : rule.licensing_mode;
247
+ console.log(` licensing_mode: ${modes}`);
129
248
  }
130
249
  }
131
- if (rule.purpose) {
132
- const purposes = Array.isArray(rule.purpose) ? rule.purpose.join('|') : rule.purpose;
133
- console.log(` purpose: ${purposes}`);
134
- }
135
- if (rule.licensing_mode) {
136
- const modes = Array.isArray(rule.licensing_mode)
137
- ? rule.licensing_mode.join('|')
138
- : rule.licensing_mode;
139
- console.log(` licensing_mode: ${modes}`);
250
+ }
251
+ if (warnings.length > 0) {
252
+ console.log('\nWarnings:');
253
+ for (const warning of warnings) {
254
+ console.log(` - ${warning}`);
140
255
  }
141
256
  }
142
257
  }
258
+ // Exit with non-zero if --strict and there are warnings
259
+ if (globalOpts.strict && warnings.length > 0) {
260
+ process.exit(1);
261
+ }
143
262
  process.exit(0);
144
263
  }
145
264
  catch (err) {
146
265
  if (err instanceof policy_kit_1.PolicyValidationError) {
147
- console.error('Policy validation failed:\n');
148
- for (const issue of err.issues) {
149
- console.error(` - ${issue.path.join('.')}: ${issue.message}`);
266
+ const issues = err.issues.map((i) => ({
267
+ path: i.path.join('.'),
268
+ message: i.message,
269
+ }));
270
+ if (globalOpts.json) {
271
+ output({
272
+ success: false,
273
+ file,
274
+ valid: false,
275
+ error: 'Validation failed',
276
+ issues,
277
+ }, globalOpts);
278
+ }
279
+ else {
280
+ console.error('Policy validation failed:\n');
281
+ for (const issue of err.issues) {
282
+ console.error(` - ${issue.path.join('.')}: ${issue.message}`);
283
+ }
150
284
  }
151
285
  process.exit(1);
152
286
  }
153
287
  else if (err instanceof policy_kit_1.PolicyLoadError) {
154
- console.error(`Failed to load policy: ${err.message}`);
288
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
155
289
  process.exit(1);
156
290
  }
157
291
  else {
158
- console.error('Error:', err instanceof Error ? err.message : String(err));
292
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
159
293
  process.exit(1);
160
294
  }
161
295
  }
@@ -173,7 +307,7 @@ policy
173
307
  .command('generate')
174
308
  .description('Generate deployment artifacts from a policy file')
175
309
  .argument('<file>', 'Path to policy file')
176
- .option('-o, --out <dir>', 'Output directory', 'dist')
310
+ .option('-o, --out <dir>', 'Output directory (use "-" for stdout)', 'dist')
177
311
  .option('--well-known', 'Output peac.txt to .well-known/ subdirectory')
178
312
  .option('--dry-run', 'Show what would be generated without writing files')
179
313
  .option('--peac-version <version>', 'PEAC protocol version (default: 0.9)')
@@ -184,9 +318,13 @@ policy
184
318
  .option('--rate-limit <limit>', 'Rate limit string (e.g., "100/hour", "unlimited")')
185
319
  .option('--negotiate <url>', 'Negotiate endpoint URL')
186
320
  .option('--no-comments', 'Omit comments from generated files')
187
- .action((file, options) => {
321
+ .action((file, options, cmd) => {
322
+ const globalOpts = getGlobalOptions(cmd);
323
+ const isStdout = options.out === '-';
188
324
  try {
189
- console.log(`Loading policy: ${file}\n`);
325
+ if (!globalOpts.json && !isStdout) {
326
+ console.log(`Loading policy: ${file}\n`);
327
+ }
190
328
  const policyDoc = (0, policy_kit_1.loadPolicy)(file);
191
329
  const compileOptions = {
192
330
  peacVersion: options.peacVersion,
@@ -198,6 +336,32 @@ policy
198
336
  negotiateUrl: options.negotiate,
199
337
  includeComments: options.comments !== false,
200
338
  };
339
+ // Generate content
340
+ const peacTxt = (0, policy_kit_1.compilePeacTxt)(policyDoc, compileOptions);
341
+ const robotsTxt = (0, policy_kit_1.compileRobotsSnippet)(policyDoc, compileOptions);
342
+ const aiprefTemplates = (0, policy_kit_1.compileAiprefTemplates)(policyDoc, compileOptions);
343
+ const markdown = (0, policy_kit_1.renderPolicyMarkdown)(policyDoc, compileOptions);
344
+ // Stdout mode: output all content as JSON
345
+ if (isStdout || globalOpts.json) {
346
+ const result = {
347
+ success: true,
348
+ source: file,
349
+ artifacts: {
350
+ 'peac.txt': peacTxt,
351
+ 'robots-ai-snippet.txt': robotsTxt,
352
+ 'aipref-headers.json': aiprefTemplates,
353
+ 'ai-policy.md': markdown,
354
+ },
355
+ };
356
+ if (isStdout && !globalOpts.json) {
357
+ // Plain stdout: just output peac.txt
358
+ console.log(peacTxt);
359
+ }
360
+ else {
361
+ output(result, { json: true });
362
+ }
363
+ process.exit(0);
364
+ }
201
365
  // Determine output paths
202
366
  const outDir = options.out;
203
367
  let peacTxtPath;
@@ -210,11 +374,6 @@ policy
210
374
  const robotsPath = path.join(outDir, 'robots-ai-snippet.txt');
211
375
  const aiprefPath = path.join(outDir, 'aipref-headers.json');
212
376
  const mdPath = path.join(outDir, 'ai-policy.md');
213
- // Generate content
214
- const peacTxt = (0, policy_kit_1.compilePeacTxt)(policyDoc, compileOptions);
215
- const robotsTxt = (0, policy_kit_1.compileRobotsSnippet)(policyDoc, compileOptions);
216
- const aiprefTemplates = (0, policy_kit_1.compileAiprefTemplates)(policyDoc, compileOptions);
217
- const markdown = (0, policy_kit_1.renderPolicyMarkdown)(policyDoc, compileOptions);
218
377
  if (options.dryRun) {
219
378
  // Dry run: show what would be generated
220
379
  console.log('Dry run - files that would be generated:\n');
@@ -262,11 +421,11 @@ policy
262
421
  }
263
422
  catch (err) {
264
423
  if (err instanceof policy_kit_1.PolicyLoadError) {
265
- console.error(`Failed to load policy: ${err.message}`);
424
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
266
425
  process.exit(1);
267
426
  }
268
427
  else {
269
- console.error('Error:', err instanceof Error ? err.message : String(err));
428
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
270
429
  process.exit(1);
271
430
  }
272
431
  }
@@ -286,7 +445,8 @@ policy
286
445
  .option('-p, --purpose <purpose>', 'Access purpose (crawl, index, train, inference, ai_input, ai_index, search)')
287
446
  .option('-m, --licensing-mode <mode>', 'Licensing mode (subscription, pay_per_crawl, pay_per_inference)')
288
447
  .option('--all-matches', 'Show all matching rules, not just the first')
289
- .action((file, options) => {
448
+ .action((file, options, cmd) => {
449
+ const globalOpts = getGlobalOptions(cmd);
290
450
  try {
291
451
  const policyDoc = (0, policy_kit_1.loadPolicy)(file);
292
452
  // Build evaluation context from options
@@ -309,56 +469,244 @@ policy
309
469
  if (options.licensingMode) {
310
470
  context.licensing_mode = options.licensingMode;
311
471
  }
312
- console.log('Evaluation Context:');
313
- if (context.subject) {
314
- console.log(` Subject: ${JSON.stringify(context.subject)}`);
315
- }
316
- else {
317
- console.log(' Subject: (any)');
318
- }
319
- console.log(` Purpose: ${context.purpose || '(any)'}`);
320
- console.log(` Licensing Mode: ${context.licensing_mode || '(any)'}`);
321
- console.log();
322
472
  if (options.allMatches) {
323
473
  const matches = (0, policy_kit_1.explainMatches)(policyDoc, context);
324
- console.log(`Matching Rules (${matches.length}):`);
325
- for (const match of matches) {
326
- if (match === '[default]') {
327
- console.log(` - [default] -> ${policyDoc.defaults.decision}`);
474
+ if (globalOpts.json) {
475
+ output({
476
+ success: true,
477
+ context,
478
+ matches: matches.map((m) => {
479
+ if (m === '[default]') {
480
+ return {
481
+ rule: '[default]',
482
+ decision: policyDoc.defaults.decision,
483
+ };
484
+ }
485
+ const rule = policyDoc.rules.find((r) => r.name === m);
486
+ return rule
487
+ ? { rule: rule.name, decision: rule.decision }
488
+ : { rule: m, decision: null };
489
+ }),
490
+ }, globalOpts);
491
+ }
492
+ else {
493
+ console.log('Evaluation Context:');
494
+ if (context.subject) {
495
+ console.log(` Subject: ${JSON.stringify(context.subject)}`);
328
496
  }
329
497
  else {
330
- const rule = policyDoc.rules.find((r) => r.name === match);
331
- if (rule) {
332
- console.log(` - ${rule.name} -> ${rule.decision}`);
498
+ console.log(' Subject: (any)');
499
+ }
500
+ console.log(` Purpose: ${context.purpose || '(any)'}`);
501
+ console.log(` Licensing Mode: ${context.licensing_mode || '(any)'}`);
502
+ console.log();
503
+ console.log(`Matching Rules (${matches.length}):`);
504
+ for (const match of matches) {
505
+ if (match === '[default]') {
506
+ console.log(` - [default] -> ${policyDoc.defaults.decision}`);
507
+ }
508
+ else {
509
+ const rule = policyDoc.rules.find((r) => r.name === match);
510
+ if (rule) {
511
+ console.log(` - ${rule.name} -> ${rule.decision}`);
512
+ }
333
513
  }
334
514
  }
335
515
  }
336
516
  }
337
517
  else {
338
518
  const result = (0, policy_kit_1.evaluate)(policyDoc, context);
339
- console.log('Result:');
340
- console.log(` Decision: ${result.decision}`);
341
- if (result.matched_rule) {
342
- console.log(` Matched Rule: ${result.matched_rule}`);
519
+ if (globalOpts.json) {
520
+ output({
521
+ success: true,
522
+ context,
523
+ result: {
524
+ decision: result.decision,
525
+ matchedRule: result.matched_rule || '[default]',
526
+ reason: result.reason || null,
527
+ },
528
+ }, globalOpts);
343
529
  }
344
530
  else {
345
- console.log(' Matched Rule: (default)');
346
- }
347
- if (result.reason) {
348
- console.log(` Reason: ${result.reason}`);
531
+ console.log('Evaluation Context:');
532
+ if (context.subject) {
533
+ console.log(` Subject: ${JSON.stringify(context.subject)}`);
534
+ }
535
+ else {
536
+ console.log(' Subject: (any)');
537
+ }
538
+ console.log(` Purpose: ${context.purpose || '(any)'}`);
539
+ console.log(` Licensing Mode: ${context.licensing_mode || '(any)'}`);
540
+ console.log();
541
+ console.log('Result:');
542
+ console.log(` Decision: ${result.decision}`);
543
+ if (result.matched_rule) {
544
+ console.log(` Matched Rule: ${result.matched_rule}`);
545
+ }
546
+ else {
547
+ console.log(' Matched Rule: (default)');
548
+ }
549
+ if (result.reason) {
550
+ console.log(` Reason: ${result.reason}`);
551
+ }
349
552
  }
350
553
  }
351
554
  process.exit(0);
352
555
  }
353
556
  catch (err) {
354
557
  if (err instanceof policy_kit_1.PolicyLoadError) {
355
- console.error(`Failed to load policy: ${err.message}`);
558
+ outputError(`Failed to load policy: ${err.message}`, { file }, globalOpts);
356
559
  process.exit(1);
357
560
  }
358
561
  else {
359
- console.error('Error:', err instanceof Error ? err.message : String(err));
562
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
563
+ process.exit(1);
564
+ }
565
+ }
566
+ });
567
+ /**
568
+ * peac policy list-profiles
569
+ *
570
+ * List available pre-built policy profiles (v0.9.23+)
571
+ */
572
+ policy
573
+ .command('list-profiles')
574
+ .description('List available pre-built policy profiles')
575
+ .action((options, cmd) => {
576
+ const globalOpts = getGlobalOptions(cmd);
577
+ try {
578
+ const profileIds = (0, policy_kit_1.listProfiles)();
579
+ const profiles = profileIds.map((id) => (0, policy_kit_1.getProfileSummary)(id));
580
+ if (globalOpts.json) {
581
+ output({
582
+ success: true,
583
+ profiles: profiles.map((p) => ({
584
+ id: p.id,
585
+ name: p.name,
586
+ description: p.description,
587
+ defaultDecision: p.defaultDecision,
588
+ ruleCount: p.ruleCount,
589
+ requiresReceipt: p.requiresReceipt,
590
+ requiredParams: p.requiredParams,
591
+ optionalParams: p.optionalParams,
592
+ })),
593
+ }, globalOpts);
594
+ }
595
+ else {
596
+ console.log('Available Policy Profiles:\n');
597
+ for (const profile of profiles) {
598
+ console.log(` ${profile.id}`);
599
+ console.log(` Name: ${profile.name}`);
600
+ console.log(` Default: ${profile.defaultDecision}`);
601
+ console.log(` Rules: ${profile.ruleCount}`);
602
+ if (profile.requiresReceipt) {
603
+ console.log(' Requires receipt: yes');
604
+ }
605
+ if (profile.requiredParams.length > 0) {
606
+ console.log(` Required params: ${profile.requiredParams.join(', ')}`);
607
+ }
608
+ console.log();
609
+ }
610
+ console.log('Use "peac policy show-profile <id>" for full details');
611
+ console.log('Use "peac policy init --profile <id>" to create a policy from a profile');
612
+ }
613
+ process.exit(0);
614
+ }
615
+ catch (err) {
616
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
617
+ process.exit(1);
618
+ }
619
+ });
620
+ /**
621
+ * peac policy show-profile <id>
622
+ *
623
+ * Show details of a specific profile (v0.9.23+)
624
+ */
625
+ policy
626
+ .command('show-profile')
627
+ .description('Show details of a specific policy profile')
628
+ .argument('<id>', 'Profile ID')
629
+ .action((id, options, cmd) => {
630
+ const globalOpts = getGlobalOptions(cmd);
631
+ try {
632
+ const profile = (0, policy_kit_1.loadProfile)(id);
633
+ const summary = (0, policy_kit_1.getProfileSummary)(id);
634
+ if (globalOpts.json) {
635
+ output({
636
+ success: true,
637
+ profile: {
638
+ id: profile.id,
639
+ name: profile.name,
640
+ description: profile.description,
641
+ policy: profile.policy,
642
+ parameters: profile.parameters,
643
+ defaults: profile.defaults,
644
+ },
645
+ }, globalOpts);
646
+ }
647
+ else {
648
+ console.log(`Profile: ${profile.name}`);
649
+ console.log(`ID: ${profile.id}`);
650
+ console.log();
651
+ console.log('Description:');
652
+ console.log(profile.description
653
+ .split('\n')
654
+ .map((l) => ` ${l}`)
655
+ .join('\n'));
656
+ console.log();
657
+ console.log('Policy:');
658
+ console.log(` Version: ${profile.policy.version}`);
659
+ console.log(` Default decision: ${profile.policy.defaults.decision}`);
660
+ console.log(` Rules: ${profile.policy.rules?.length || 0}`);
661
+ if (profile.policy.rules && profile.policy.rules.length > 0) {
662
+ console.log();
663
+ console.log('Rules:');
664
+ for (const rule of profile.policy.rules) {
665
+ console.log(` - ${rule.name}: ${rule.decision}`);
666
+ if (rule.purpose) {
667
+ const purposes = Array.isArray(rule.purpose) ? rule.purpose.join(', ') : rule.purpose;
668
+ console.log(` purpose: ${purposes}`);
669
+ }
670
+ if (rule.reason) {
671
+ console.log(` reason: ${rule.reason}`);
672
+ }
673
+ }
674
+ }
675
+ if (Object.keys(profile.parameters || {}).length > 0) {
676
+ console.log();
677
+ console.log('Parameters:');
678
+ for (const [key, param] of Object.entries(profile.parameters || {})) {
679
+ const required = param.required ? ' (required)' : '';
680
+ console.log(` ${key}${required}`);
681
+ console.log(` ${param.description}`);
682
+ if (param.default) {
683
+ console.log(` Default: ${param.default}`);
684
+ }
685
+ if (param.example) {
686
+ console.log(` Example: ${param.example}`);
687
+ }
688
+ }
689
+ }
690
+ if (profile.defaults) {
691
+ console.log();
692
+ console.log('Defaults:');
693
+ if (profile.defaults.requirements?.receipt) {
694
+ console.log(' Receipt required: yes');
695
+ }
696
+ if (profile.defaults.rate_limit) {
697
+ console.log(` Rate limit: ${profile.defaults.rate_limit.limit}/${profile.defaults.rate_limit.window_seconds}s`);
698
+ }
699
+ }
700
+ }
701
+ process.exit(0);
702
+ }
703
+ catch (err) {
704
+ if (err instanceof policy_kit_1.ProfileError) {
705
+ outputError(err.message, { code: err.code, profile: id }, globalOpts);
360
706
  process.exit(1);
361
707
  }
708
+ outputError(err instanceof Error ? err.message : String(err), {}, globalOpts);
709
+ process.exit(1);
362
710
  }
363
711
  });
364
712
  //# sourceMappingURL=policy.js.map