harborai 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 (94) hide show
  1. package/README.md +17 -0
  2. package/dist/api.d.ts +62 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +943 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/binary-install.d.ts +34 -0
  7. package/dist/binary-install.d.ts.map +1 -0
  8. package/dist/binary-install.js +181 -0
  9. package/dist/binary-install.js.map +1 -0
  10. package/dist/capabilities.d.ts +5 -0
  11. package/dist/capabilities.d.ts.map +1 -0
  12. package/dist/capabilities.js +315 -0
  13. package/dist/capabilities.js.map +1 -0
  14. package/dist/constants.d.ts +5 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/constants.js +10 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/dev.d.ts +14 -0
  19. package/dist/dev.d.ts.map +1 -0
  20. package/dist/dev.js +203 -0
  21. package/dist/dev.js.map +1 -0
  22. package/dist/foreground.d.ts +13 -0
  23. package/dist/foreground.d.ts.map +1 -0
  24. package/dist/foreground.js +54 -0
  25. package/dist/foreground.js.map +1 -0
  26. package/dist/import-openapi.d.ts +12 -0
  27. package/dist/import-openapi.d.ts.map +1 -0
  28. package/dist/import-openapi.js +488 -0
  29. package/dist/import-openapi.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +1174 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/local-config.d.ts +13 -0
  35. package/dist/local-config.d.ts.map +1 -0
  36. package/dist/local-config.js +147 -0
  37. package/dist/local-config.js.map +1 -0
  38. package/dist/local-daemon-entry.d.ts +2 -0
  39. package/dist/local-daemon-entry.d.ts.map +1 -0
  40. package/dist/local-daemon-entry.js +545 -0
  41. package/dist/local-daemon-entry.js.map +1 -0
  42. package/dist/local-daemon.d.ts +58 -0
  43. package/dist/local-daemon.d.ts.map +1 -0
  44. package/dist/local-daemon.js +386 -0
  45. package/dist/local-daemon.js.map +1 -0
  46. package/dist/mcp/api-client.d.ts +17 -0
  47. package/dist/mcp/api-client.d.ts.map +1 -0
  48. package/dist/mcp/api-client.js +73 -0
  49. package/dist/mcp/api-client.js.map +1 -0
  50. package/dist/mcp/index.d.ts +4 -0
  51. package/dist/mcp/index.d.ts.map +1 -0
  52. package/dist/mcp/index.js +18 -0
  53. package/dist/mcp/index.js.map +1 -0
  54. package/dist/mcp/install.d.ts +30 -0
  55. package/dist/mcp/install.d.ts.map +1 -0
  56. package/dist/mcp/install.js +153 -0
  57. package/dist/mcp/install.js.map +1 -0
  58. package/dist/mcp/schema.d.ts +4 -0
  59. package/dist/mcp/schema.d.ts.map +1 -0
  60. package/dist/mcp/schema.js +104 -0
  61. package/dist/mcp/schema.js.map +1 -0
  62. package/dist/mcp/server.d.ts +4 -0
  63. package/dist/mcp/server.d.ts.map +1 -0
  64. package/dist/mcp/server.js +47 -0
  65. package/dist/mcp/server.js.map +1 -0
  66. package/dist/mcp/tools.d.ts +13 -0
  67. package/dist/mcp/tools.d.ts.map +1 -0
  68. package/dist/mcp/tools.js +147 -0
  69. package/dist/mcp/tools.js.map +1 -0
  70. package/dist/output-download.d.ts +8 -0
  71. package/dist/output-download.d.ts.map +1 -0
  72. package/dist/output-download.js +210 -0
  73. package/dist/output-download.js.map +1 -0
  74. package/dist/output.d.ts +155 -0
  75. package/dist/output.d.ts.map +1 -0
  76. package/dist/output.js +1123 -0
  77. package/dist/output.js.map +1 -0
  78. package/dist/passthrough.d.ts +15 -0
  79. package/dist/passthrough.d.ts.map +1 -0
  80. package/dist/passthrough.js +69 -0
  81. package/dist/passthrough.js.map +1 -0
  82. package/dist/runtime-attribution.d.ts +5 -0
  83. package/dist/runtime-attribution.d.ts.map +1 -0
  84. package/dist/runtime-attribution.js +86 -0
  85. package/dist/runtime-attribution.js.map +1 -0
  86. package/dist/state.d.ts +56 -0
  87. package/dist/state.d.ts.map +1 -0
  88. package/dist/state.js +374 -0
  89. package/dist/state.js.map +1 -0
  90. package/dist/types.d.ts +321 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +2 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +35 -0
package/dist/output.js ADDED
@@ -0,0 +1,1123 @@
1
+ import { ApiError } from './api.js';
2
+ const toPlainValue = (value) => {
3
+ if (value === null || value === undefined) {
4
+ return '';
5
+ }
6
+ if (typeof value === 'string') {
7
+ return /\s/.test(value) ? JSON.stringify(value) : value;
8
+ }
9
+ return String(value);
10
+ };
11
+ export const getOutputMode = (options) => {
12
+ if (options.json) {
13
+ return 'json';
14
+ }
15
+ if (options.plain) {
16
+ return 'plain';
17
+ }
18
+ return 'human';
19
+ };
20
+ export class CliInputError extends Error {
21
+ code = 'invalid_input';
22
+ invocation;
23
+ note;
24
+ constructor(message, invocation, note) {
25
+ super(message);
26
+ this.invocation = invocation;
27
+ this.note = note;
28
+ }
29
+ }
30
+ const writeJson = (payload) => {
31
+ console.log(JSON.stringify(payload, null, 2));
32
+ };
33
+ const writePlain = (lines) => {
34
+ console.log(lines.join('\n'));
35
+ };
36
+ const writeHuman = (text) => {
37
+ console.log(text.trimEnd());
38
+ };
39
+ const yesNoUnknown = (value) => {
40
+ if (value === true) {
41
+ return 'yes';
42
+ }
43
+ if (value === false) {
44
+ return 'no';
45
+ }
46
+ return 'unknown';
47
+ };
48
+ const writeJsonError = (payload) => {
49
+ console.error(JSON.stringify(payload, null, 2));
50
+ };
51
+ const writePlainError = (lines) => {
52
+ console.error(lines.join('\n'));
53
+ };
54
+ const writeHumanError = (text) => {
55
+ console.error(text.trimEnd());
56
+ };
57
+ const linesFromRecord = (entries) => entries
58
+ .filter(([, value]) => value !== undefined)
59
+ .map(([key, value]) => `${key}=${toPlainValue(value)}`);
60
+ const requiredLabel = (required) => (required ? 'required' : 'optional');
61
+ const schemaType = (value) => {
62
+ if (typeof value === 'string') {
63
+ return value;
64
+ }
65
+ if (Array.isArray(value)) {
66
+ const first = value.find((entry) => typeof entry === 'string' && entry !== 'null');
67
+ return first ?? 'unknown';
68
+ }
69
+ return 'unknown';
70
+ };
71
+ const summarizeRuntimeInjection = (runtimeInjection) => {
72
+ if (!runtimeInjection) {
73
+ return null;
74
+ }
75
+ const requirements = runtimeInjection.requirements.map((requirement) => ({
76
+ name: requirement.name,
77
+ kind: requirement.kind,
78
+ required: Boolean(requirement.required),
79
+ service: requirement.service,
80
+ lookup: requirement.lookup,
81
+ input_path: requirement.input_path,
82
+ fallback_order: requirement.fallback_order ?? [],
83
+ }));
84
+ const export_keys = Object.keys(runtimeInjection.exports ?? {});
85
+ const audit_context_keys = runtimeInjection.audit?.context_keys ?? [];
86
+ if (requirements.length === 0 && export_keys.length === 0 && audit_context_keys.length === 0) {
87
+ return null;
88
+ }
89
+ return {
90
+ requirements,
91
+ export_keys,
92
+ audit_context_keys,
93
+ };
94
+ };
95
+ const describeRuntimeInjectionRequirement = (requirement) => {
96
+ const details = [requirement.required ? 'required' : 'optional'];
97
+ if (requirement.service) {
98
+ details.push(`service=${requirement.service}`);
99
+ }
100
+ if (requirement.lookup) {
101
+ details.push(`lookup=${requirement.lookup}`);
102
+ }
103
+ if (requirement.input_path) {
104
+ details.push(`input_path=${requirement.input_path}`);
105
+ }
106
+ if (requirement.fallback_order.length > 0) {
107
+ details.push(`fallback=${requirement.fallback_order.join('>')}`);
108
+ }
109
+ return details.join(' ');
110
+ };
111
+ const readConfigRecord = (snapshot, key) => {
112
+ const config = snapshot.binding?.config;
113
+ if (!config || typeof config !== 'object') {
114
+ return null;
115
+ }
116
+ const value = config[key];
117
+ return value && typeof value === 'object' ? value : null;
118
+ };
119
+ const defaultCapabilityState = (summary, snapshot) => {
120
+ if (summary?.state) {
121
+ return summary.state;
122
+ }
123
+ if (summary?.granted === true) {
124
+ return 'ready';
125
+ }
126
+ return snapshot.policy?.grant_required ? 'approval_required' : 'published';
127
+ };
128
+ const formatSchemaDetail = (label, value) => value === undefined ? null : `${label}=${Array.isArray(value) ? value.join('|') : String(value)}`;
129
+ export const renderLearn = (mode, snapshot, summary) => {
130
+ const args = snapshot.surface?.cli?.args ?? [];
131
+ const inputProperties = snapshot.contract?.input_schema?.properties ?? {};
132
+ const state = defaultCapabilityState(summary, snapshot);
133
+ const secrets = snapshot.secrets?.required_refs ?? [];
134
+ const missingSecretRefs = summary?.missing_secret_refs ?? [];
135
+ const runtimeInjection = summarizeRuntimeInjection(snapshot.runtime_injection);
136
+ const commandPrefixes = readConfigRecord(snapshot, 'command_prefix_allowlist');
137
+ const allowedPrefixes = Array.isArray(commandPrefixes?.prefixes)
138
+ ? commandPrefixes.prefixes.filter((entry) => typeof entry === 'string' && entry.length > 0)
139
+ : [];
140
+ const cliPassthrough = readConfigRecord(snapshot, 'cli_passthrough');
141
+ const passthroughNotes = Array.isArray(cliPassthrough?.notes)
142
+ ? cliPassthrough.notes.filter((entry) => typeof entry === 'string' && entry.length > 0)
143
+ : [];
144
+ const preflight = readConfigRecord(snapshot, 'preflight');
145
+ const install = preflight?.install && typeof preflight.install === 'object' ? preflight.install : null;
146
+ const installMacos = install?.macos && typeof install.macos === 'object' ? install.macos : null;
147
+ const installSteps = Array.isArray(installMacos?.steps)
148
+ ? installMacos.steps.filter((entry) => typeof entry === 'string' && entry.length > 0)
149
+ : [];
150
+ const serviceRequirements = (runtimeInjection?.requirements ?? [])
151
+ .map((requirement) => requirement.service)
152
+ .filter((service) => typeof service === 'string' && service.length > 0);
153
+ const uniqueServices = [...new Set(serviceRequirements)];
154
+ const constraintShape = snapshot.policy?.constraint_shape ?? {};
155
+ const examples = snapshot.surface?.cli?.examples ?? [];
156
+ const helpCommand = typeof snapshot.surface?.cli?.help_command === 'string' && snapshot.surface.cli.help_command.length > 0
157
+ ? snapshot.surface.cli.help_command
158
+ : `harbor ${snapshot.capability.slug} --help`;
159
+ const firstRunCommand = examples[0] ?? helpCommand;
160
+ const nextSteps = [];
161
+ if (missingSecretRefs.length > 0) {
162
+ for (const secretRef of missingSecretRefs) {
163
+ nextSteps.push(`echo $SECRET_VALUE | harbor secrets set ${secretRef} --plain`);
164
+ }
165
+ }
166
+ for (const service of uniqueServices) {
167
+ nextSteps.push(`harbor services inspect ${service} --plain`);
168
+ }
169
+ if (snapshot.policy?.grant_required && summary?.granted !== true) {
170
+ nextSteps.push(helpCommand);
171
+ nextSteps.push(`${firstRunCommand} # first run may trigger a grant or approval request`);
172
+ }
173
+ else {
174
+ nextSteps.push(firstRunCommand);
175
+ }
176
+ if (nextSteps.length === 0) {
177
+ nextSteps.push(helpCommand);
178
+ }
179
+ const payload = {
180
+ capability: snapshot.capability.slug,
181
+ title: snapshot.capability.title ?? snapshot.capability.slug,
182
+ summary: snapshot.surface?.cli?.summary ?? snapshot.capability.description ?? '',
183
+ state,
184
+ granted: summary?.granted ?? null,
185
+ execution_mode: snapshot.contract?.execution_mode ?? null,
186
+ adapter_type: snapshot.binding?.adapter_type ?? null,
187
+ adapter_operation: snapshot.binding?.adapter_operation ?? null,
188
+ provider_ref: snapshot.binding?.provider_ref ?? null,
189
+ service_state: summary?.service_state ?? null,
190
+ grant_required: Boolean(snapshot.policy?.grant_required),
191
+ approval_mode: snapshot.policy?.approval_mode ?? 'none',
192
+ secrets: secrets.map((secret) => ({
193
+ name: secret.name,
194
+ kind: secret.kind,
195
+ purpose: secret.purpose,
196
+ missing: missingSecretRefs.includes(secret.name),
197
+ })),
198
+ input: args.map((arg) => {
199
+ const schema = inputProperties[arg.name];
200
+ return {
201
+ name: arg.name,
202
+ type: arg.type ?? schemaType(schema?.type),
203
+ required: Boolean(arg.required),
204
+ positional: Boolean(arg.positional),
205
+ description: arg.description ?? schema?.description ?? '',
206
+ default: schema?.default,
207
+ enum: Array.isArray(schema?.enum) ? schema.enum : undefined,
208
+ minimum: schema?.minimum,
209
+ maximum: schema?.maximum,
210
+ };
211
+ }),
212
+ restrictions: {
213
+ allow_network: constraintShape.allow_network,
214
+ allow_file_write: constraintShape.allow_file_write,
215
+ max_timeout_sec: constraintShape.max_timeout_sec,
216
+ allowed_command_prefixes: allowedPrefixes,
217
+ },
218
+ install: install
219
+ ? {
220
+ display_name: typeof install.display_name === 'string' ? install.display_name : null,
221
+ docs_url: typeof install.docs_url === 'string' ? install.docs_url : null,
222
+ steps: installSteps,
223
+ binary_missing_hint: typeof preflight?.binary_missing_hint === 'string' ? preflight.binary_missing_hint : null,
224
+ }
225
+ : null,
226
+ runtime_injection: runtimeInjection,
227
+ passthrough_notes: passthroughNotes,
228
+ examples,
229
+ next_steps: nextSteps,
230
+ };
231
+ if (mode === 'json') {
232
+ writeJson(payload);
233
+ return;
234
+ }
235
+ if (mode === 'plain') {
236
+ writePlain([
237
+ ...linesFromRecord([
238
+ ['capability', payload.capability],
239
+ ['title', payload.title],
240
+ ['summary', payload.summary],
241
+ ['state', payload.state],
242
+ ['granted', payload.granted],
243
+ ['execution_mode', payload.execution_mode],
244
+ ['adapter_type', payload.adapter_type],
245
+ ['adapter_operation', payload.adapter_operation],
246
+ ['provider_ref', payload.provider_ref],
247
+ ['service_state', payload.service_state],
248
+ ['grant_required', payload.grant_required ? 'yes' : 'no'],
249
+ ['approval_mode', payload.approval_mode],
250
+ ['allow_network', payload.restrictions.allow_network],
251
+ ['allow_file_write', payload.restrictions.allow_file_write],
252
+ ['max_timeout_sec', payload.restrictions.max_timeout_sec],
253
+ ]),
254
+ ...payload.input.map((arg) => {
255
+ const details = [
256
+ `${arg.type}:${requiredLabel(arg.required)}`,
257
+ formatSchemaDetail('default', arg.default),
258
+ formatSchemaDetail('enum', arg.enum),
259
+ formatSchemaDetail('minimum', arg.minimum),
260
+ formatSchemaDetail('maximum', arg.maximum),
261
+ ].filter((entry) => Boolean(entry));
262
+ return `input.${arg.name}=${details.join(' ')}`;
263
+ }),
264
+ ...payload.secrets.map((secret) => `secret.${secret.name}=${secret.kind}:${secret.purpose}${secret.missing ? ':missing' : ''}`),
265
+ ...payload.restrictions.allowed_command_prefixes.map((prefix) => `allowed_command_prefix=${prefix}`),
266
+ ...(payload.install?.binary_missing_hint ? [`install.binary_missing_hint=${payload.install.binary_missing_hint}`] : []),
267
+ ...(payload.install?.docs_url ? [`install.docs_url=${payload.install.docs_url}`] : []),
268
+ ...(payload.install?.steps ?? []).map((step) => `install.step=${step}`),
269
+ ...(payload.runtime_injection?.requirements ?? []).map((requirement) => `runtime_injection.${requirement.name}=${requirement.kind}:${describeRuntimeInjectionRequirement(requirement)}`),
270
+ ...payload.passthrough_notes.map((note) => `note=${note}`),
271
+ ...payload.examples.map((example) => `example=${example}`),
272
+ ...payload.next_steps.map((step, index) => `next_step.${index + 1}=${step}`),
273
+ ]);
274
+ return;
275
+ }
276
+ const inputLines = payload.input.length === 0
277
+ ? ' none'
278
+ : payload.input.map((arg) => {
279
+ const details = [
280
+ requiredLabel(arg.required),
281
+ formatSchemaDetail('default', arg.default),
282
+ formatSchemaDetail('enum', arg.enum),
283
+ formatSchemaDetail('minimum', arg.minimum),
284
+ formatSchemaDetail('maximum', arg.maximum),
285
+ ].filter((entry) => Boolean(entry)).join(' ');
286
+ return ` ${arg.name.padEnd(16)} ${String(arg.type).padEnd(10)} ${details}${arg.description ? ` ${arg.description}` : ''}`.trimEnd();
287
+ }).join('\n');
288
+ const secretLines = payload.secrets.length === 0
289
+ ? ' none'
290
+ : payload.secrets.map((secret) => ` ${secret.name.padEnd(20)} ${secret.kind.padEnd(20)} ${secret.purpose}${secret.missing ? ' (missing)' : ''}`).join('\n');
291
+ const restrictionLines = [
292
+ ` network: ${yesNoUnknown(payload.restrictions.allow_network)}`,
293
+ ` file_write: ${yesNoUnknown(payload.restrictions.allow_file_write)}`,
294
+ payload.restrictions.max_timeout_sec !== undefined ? ` max_timeout_sec: ${payload.restrictions.max_timeout_sec}` : null,
295
+ payload.restrictions.allowed_command_prefixes.length > 0 ? ` allowed_prefixes: ${payload.restrictions.allowed_command_prefixes.join(', ')}` : null,
296
+ ].filter((line) => Boolean(line)).join('\n');
297
+ const installLines = payload.install
298
+ ? [
299
+ payload.install.display_name ? ` package: ${payload.install.display_name}` : null,
300
+ payload.install.binary_missing_hint ? ` hint: ${payload.install.binary_missing_hint}` : null,
301
+ payload.install.docs_url ? ` docs: ${payload.install.docs_url}` : null,
302
+ ...(payload.install.steps.map((step) => ` step: ${step}`)),
303
+ ].filter((line) => Boolean(line)).join('\n')
304
+ : ' none';
305
+ const runtimeInjectionLines = payload.runtime_injection
306
+ ? [
307
+ payload.runtime_injection.requirements.length === 0
308
+ ? ' requirements: none'
309
+ : payload.runtime_injection.requirements.map((requirement) => ` ${requirement.name.padEnd(18)} ${requirement.kind.padEnd(20)} ${describeRuntimeInjectionRequirement(requirement)}`).join('\n'),
310
+ payload.runtime_injection.export_keys.length === 0
311
+ ? ' exports: none'
312
+ : ` exports: ${payload.runtime_injection.export_keys.join(', ')}`,
313
+ ].join('\n')
314
+ : ' none';
315
+ const exampleLines = payload.examples.length === 0 ? ' none' : payload.examples.map((example) => ` ${example}`).join('\n');
316
+ const noteLines = payload.passthrough_notes.length === 0 ? ' none' : payload.passthrough_notes.map((note) => ` - ${note}`).join('\n');
317
+ const nextStepLines = payload.next_steps.map((step) => ` ${step}`).join('\n');
318
+ writeHuman(`${payload.capability}\n\n${payload.summary}\n\nState:\n readiness: ${payload.state}\n grant_required: ${payload.grant_required ? 'yes' : 'no'}\n approval_mode: ${payload.approval_mode}\n service_state: ${payload.service_state ?? 'n/a'}\n execution_mode: ${payload.execution_mode ?? 'unknown'}\n adapter: ${payload.adapter_type ?? 'unknown'}${payload.adapter_operation ? ` (${payload.adapter_operation})` : ''}\n\nInput:\n${inputLines}\n\nSecrets:\n${secretLines}\n\nRestrictions:\n${restrictionLines}\n\nInstall:\n${installLines}\n\nRuntime injection:\n${runtimeInjectionLines}\n\nNotes:\n${noteLines}\n\nExamples:\n${exampleLines}\n\nNext:\n${nextStepLines}`);
319
+ };
320
+ export const renderClaim = (mode, payload) => {
321
+ if (mode === 'json') {
322
+ writeJson(payload);
323
+ return;
324
+ }
325
+ if (mode === 'plain') {
326
+ writePlain(linesFromRecord([
327
+ ['status', payload.result],
328
+ ['agent_id', payload.agent_id],
329
+ ['profile', payload.profile],
330
+ ['owner', payload.owner],
331
+ ['approval_id', payload.approval_id],
332
+ ['approval_url', payload.approval_url],
333
+ ]));
334
+ return;
335
+ }
336
+ if (payload.result === 'approval_required') {
337
+ writeHuman(`status: ${payload.result}\napproval_id: ${payload.approval_id ?? 'unknown'}\napproval_url: ${payload.approval_url ?? 'unknown'}\n\nnext:\n open https://dash.tryharbor.ai/login\n open ${payload.approval_url ?? 'https://dash.tryharbor.ai/approvals'}\n harbor auth claim --plain`);
338
+ return;
339
+ }
340
+ writeHuman(`status: ${payload.result}\nagent_id: ${payload.agent_id ?? 'unknown'}\nprofile: ${payload.profile}\nowner: ${payload.owner ?? 'unknown'}\n\nnext:\n harbor ls --plain\n harbor learn <capability> --plain\n harbor secrets ls --plain`);
341
+ };
342
+ export const renderWhoAmI = (mode, payload) => {
343
+ if (mode === 'json') {
344
+ writeJson(payload);
345
+ return;
346
+ }
347
+ if (mode === 'plain') {
348
+ writePlain(linesFromRecord([
349
+ ['profile', payload.profile],
350
+ ['owner_scope_id', payload.owner_scope_id],
351
+ ['owner', payload.owner],
352
+ ['agent_id', payload.agent_id],
353
+ ['agent_name', payload.agent_display_name],
354
+ ]));
355
+ return;
356
+ }
357
+ writeHuman(`profile: ${payload.profile}\nowner: ${payload.owner ?? 'unknown'}\nagent_id: ${payload.agent_id ?? 'unknown'}\nagent_name: ${payload.agent_display_name ?? 'unknown'}`);
358
+ };
359
+ export const renderProfileCurrent = (mode, payload) => {
360
+ if (mode === 'json') {
361
+ writeJson(payload);
362
+ return;
363
+ }
364
+ if (mode === 'plain') {
365
+ writePlain(linesFromRecord([
366
+ ['profile', payload.profile],
367
+ ['active_profile', payload.active_profile],
368
+ ['api_url', payload.api_url],
369
+ ['owner', payload.owner],
370
+ ['agent_id', payload.agent_id],
371
+ ]));
372
+ return;
373
+ }
374
+ writeHuman(`profile: ${payload.profile}\nactive_profile: ${payload.active_profile}\napi_url: ${payload.api_url ?? 'unset'}\nowner: ${payload.owner ?? 'unknown'}\nagent_id: ${payload.agent_id ?? 'unknown'}`);
375
+ };
376
+ export const renderProfileList = (mode, profiles) => {
377
+ if (mode === 'json') {
378
+ writeJson({ profiles });
379
+ return;
380
+ }
381
+ if (mode === 'plain') {
382
+ writePlain(profiles.map((profile) => linesFromRecord([
383
+ ['profile', profile.profile_slug],
384
+ ['active', profile.active ? 'yes' : 'no'],
385
+ ['selected', profile.selected ? 'yes' : 'no'],
386
+ ['api_url', profile.api_url],
387
+ ['owner', profile.owner],
388
+ ['agent_id', profile.agent_id],
389
+ ]).join(' ')));
390
+ return;
391
+ }
392
+ if (profiles.length === 0) {
393
+ writeHuman('No Harbor profiles.');
394
+ return;
395
+ }
396
+ const rows = profiles
397
+ .map((profile) => [
398
+ profile.profile_slug.padEnd(18),
399
+ (profile.active ? 'active' : '').padEnd(8),
400
+ (profile.selected ? 'selected' : '').padEnd(10),
401
+ (profile.api_url ?? 'unset').padEnd(28),
402
+ profile.agent_id ?? 'unknown',
403
+ ].join(' ').trimEnd())
404
+ .join('\n');
405
+ writeHuman(`PROFILE ACTIVE SELECTED API URL AGENT ID\n${rows}`);
406
+ };
407
+ export const renderMcpInstall = (mode, payload) => {
408
+ if (mode === 'json') {
409
+ writeJson(payload);
410
+ return;
411
+ }
412
+ if (mode === 'plain') {
413
+ writePlain(payload.installs.map((install) => linesFromRecord([
414
+ ['profile', payload.profile],
415
+ ['dry_run', payload.dry_run ? 'yes' : 'no'],
416
+ ['client', install.client],
417
+ ['status', install.action],
418
+ ['path', install.path],
419
+ ]).join(' ')));
420
+ return;
421
+ }
422
+ const launch = [payload.launch.command, ...payload.launch.args.map((arg) => (/\s/.test(arg) ? JSON.stringify(arg) : arg))].join(' ');
423
+ const installs = payload.installs
424
+ .map((install) => `${install.label.padEnd(16)} ${install.action.padEnd(9)} ${install.path}`)
425
+ .join('\n');
426
+ const restartNote = payload.dry_run
427
+ ? 'Dry run only. No files were changed.'
428
+ : 'Restart each client to pick up the updated MCP config.';
429
+ writeHuman(`profile: ${payload.profile}\ndry_run: ${payload.dry_run ? 'yes' : 'no'}\nlaunch: ${launch}\n\nCLIENT STATUS CONFIG PATH\n${installs}\n\n${restartNote}`);
430
+ };
431
+ export const renderUpdate = (mode, payload) => {
432
+ if (mode === 'json') {
433
+ writeJson(payload);
434
+ return;
435
+ }
436
+ if (mode === 'plain') {
437
+ writePlain(linesFromRecord([
438
+ ['status', payload.status],
439
+ ['previous_version', payload.previous_version],
440
+ ['current_version', payload.current_version],
441
+ ['latest_version', payload.latest_version],
442
+ ['channel', payload.channel],
443
+ ['message', payload.message],
444
+ ]));
445
+ return;
446
+ }
447
+ writeHuman(payload.message);
448
+ };
449
+ export const renderDevUp = (mode, payload) => {
450
+ if (mode === 'json') {
451
+ writeJson(payload);
452
+ return;
453
+ }
454
+ if (mode === 'plain') {
455
+ writePlain(linesFromRecord([
456
+ ['status', payload.status],
457
+ ['profile', payload.profile],
458
+ ['api_url', payload.api_url],
459
+ ['auth_url', payload.auth_url],
460
+ ]));
461
+ return;
462
+ }
463
+ writeHuman(`status: ${payload.status}\nprofile: ${payload.profile}\napi_url: ${payload.api_url ?? 'unset'}\nauth_url: ${payload.auth_url ?? 'unset'}`);
464
+ };
465
+ export const renderDevDown = (mode, payload) => {
466
+ if (mode === 'json') {
467
+ writeJson(payload);
468
+ return;
469
+ }
470
+ if (mode === 'plain') {
471
+ writePlain(linesFromRecord([
472
+ ['status', payload.status],
473
+ ['profile', payload.profile],
474
+ ]));
475
+ return;
476
+ }
477
+ writeHuman(`status: ${payload.status}\nprofile: ${payload.profile}`);
478
+ };
479
+ export const renderLocalDaemonStatus = (mode, payload) => {
480
+ if (mode === 'json') {
481
+ writeJson(payload);
482
+ return;
483
+ }
484
+ if (mode === 'plain') {
485
+ writePlain(linesFromRecord([
486
+ ['profile', payload.profile],
487
+ ['ready_state', payload.ready_state],
488
+ ['api_url', payload.api_url],
489
+ ['auth_url', payload.auth_url],
490
+ ['daemon_package_version', payload.daemon_package_version],
491
+ ['daemon_protocol', payload.selected_daemon_protocol],
492
+ ['state_schema_version', payload.state_schema_version],
493
+ ['api_manifest_revision', payload.api_manifest_revision],
494
+ ['last_ready_at', payload.last_ready_at],
495
+ ['api_pid', payload.managed_children.api.pid],
496
+ ['api_running', payload.managed_children.api.running ? 'yes' : 'no'],
497
+ ['runner_pid', payload.managed_children.runner.pid],
498
+ ['runner_running', payload.managed_children.runner.running ? 'yes' : 'no'],
499
+ ['socket', payload.paths.socket],
500
+ ['state', payload.paths.state],
501
+ ['daemon_log', payload.paths.daemon_log],
502
+ ['api_log', payload.paths.api_log],
503
+ ['runner_log', payload.paths.runner_log],
504
+ ]));
505
+ return;
506
+ }
507
+ writeHuman(`profile: ${payload.profile}\nready_state: ${payload.ready_state}\napi_url: ${payload.api_url}\nauth_url: ${payload.auth_url}\ndaemon_package_version: ${payload.daemon_package_version}\ndaemon_protocol: ${payload.selected_daemon_protocol}\nstate_schema_version: ${payload.state_schema_version}\napi_manifest_revision: ${payload.api_manifest_revision ?? 'unknown'}\nlast_ready_at: ${payload.last_ready_at ?? 'unknown'}\napi: ${payload.managed_children.api.running ? 'running' : 'stopped'} (pid ${payload.managed_children.api.pid ?? 'unknown'})\nrunner: ${payload.managed_children.runner.running ? 'running' : 'stopped'} (pid ${payload.managed_children.runner.pid ?? 'unknown'})\nsocket: ${payload.paths.socket}\nstate: ${payload.paths.state}\ndaemon_log: ${payload.paths.daemon_log}\napi_log: ${payload.paths.api_log}\nrunner_log: ${payload.paths.runner_log}`);
508
+ };
509
+ export const renderLocalDaemonLog = (mode, payload) => {
510
+ if (mode === 'json') {
511
+ writeJson(payload);
512
+ return;
513
+ }
514
+ if (mode === 'plain') {
515
+ writePlain([
516
+ ...linesFromRecord([
517
+ ['component', payload.component],
518
+ ['path', payload.path],
519
+ ]),
520
+ ...payload.lines,
521
+ ]);
522
+ return;
523
+ }
524
+ writeHuman(`component: ${payload.component}\npath: ${payload.path}${payload.lines.length > 0 ? `\n\n${payload.lines.join('\n')}` : '\n\n(no log lines)'}`);
525
+ };
526
+ export const renderLs = (mode, capabilities) => {
527
+ if (mode === 'json') {
528
+ writeJson({ capabilities });
529
+ return;
530
+ }
531
+ if (mode === 'plain') {
532
+ writePlain(capabilities.map((capability) => `capability=${capability.slug} state=${toPlainValue(capability.state)}${capability.summary ? ` summary=${toPlainValue(capability.summary)}` : ''}`));
533
+ return;
534
+ }
535
+ const rows = capabilities.length === 0
536
+ ? 'No published capabilities.'
537
+ : capabilities
538
+ .map((capability) => `${capability.slug.padEnd(20)} ${capability.state.padEnd(17)} ${capability.summary}`.trimEnd())
539
+ .join('\n');
540
+ writeHuman(rows);
541
+ };
542
+ export const renderInspect = (mode, snapshot) => {
543
+ const args = snapshot.surface?.cli?.args ?? [];
544
+ const runtimeInjection = summarizeRuntimeInjection(snapshot.runtime_injection);
545
+ const payload = {
546
+ capability: snapshot.capability.slug,
547
+ summary: snapshot.surface?.cli?.summary ?? snapshot.capability.description ?? '',
548
+ input: args.map((arg) => ({
549
+ name: arg.name,
550
+ type: arg.type ?? schemaType(snapshot.contract?.input_schema?.properties?.[arg.name]?.type),
551
+ required: Boolean(arg.required),
552
+ positional: Boolean(arg.positional),
553
+ description: arg.description ?? snapshot.contract?.input_schema?.properties?.[arg.name]?.description ?? '',
554
+ })),
555
+ secret_requirements: (snapshot.secrets?.required_refs ?? []).map((secret) => ({
556
+ name: secret.name,
557
+ kind: secret.kind,
558
+ purpose: secret.purpose,
559
+ })),
560
+ runtime_injection: runtimeInjection,
561
+ execution_mode: snapshot.contract?.execution_mode ?? null,
562
+ adapter: snapshot.capability.category ?? snapshot.capability.slug.split('.')[0],
563
+ grant_required: Boolean(snapshot.policy?.grant_required),
564
+ approval_mode: snapshot.policy?.approval_mode ?? 'none',
565
+ };
566
+ if (mode === 'json') {
567
+ writeJson(payload);
568
+ return;
569
+ }
570
+ if (mode === 'plain') {
571
+ writePlain([
572
+ ...linesFromRecord([
573
+ ['capability', payload.capability],
574
+ ['summary', payload.summary],
575
+ ['execution_mode', payload.execution_mode],
576
+ ['adapter', payload.adapter],
577
+ ['grant_required', payload.grant_required ? 'yes' : 'no'],
578
+ ['approval_mode', payload.approval_mode],
579
+ ]),
580
+ ...payload.input.map((arg) => `input.${arg.name}=${arg.type}:${requiredLabel(arg.required)}`),
581
+ ...payload.secret_requirements.map((secret) => `secret_requirement.${secret.name}=${secret.kind}:${secret.purpose}`),
582
+ ...(payload.runtime_injection?.requirements ?? []).map((requirement) => `runtime_injection.${requirement.name}=${requirement.kind}:${describeRuntimeInjectionRequirement(requirement)}`),
583
+ ...(payload.runtime_injection?.export_keys ?? []).map((key) => `runtime_injection.export=${key}`),
584
+ ...(payload.runtime_injection?.audit_context_keys ?? []).map((key) => `runtime_injection.audit_context_key=${key}`),
585
+ ]);
586
+ return;
587
+ }
588
+ const inputLines = payload.input.length === 0
589
+ ? ' none'
590
+ : payload.input.map((arg) => ` ${arg.name.padEnd(14)} ${String(arg.type).padEnd(8)} ${requiredLabel(arg.required)}`).join('\n');
591
+ const secretLines = payload.secret_requirements.length === 0
592
+ ? ' none'
593
+ : payload.secret_requirements.map((secret) => ` ${secret.name.padEnd(18)} ${String(secret.kind).padEnd(14)} ${secret.purpose}`).join('\n');
594
+ const runtimeInjectionLines = payload.runtime_injection
595
+ ? [
596
+ payload.runtime_injection.requirements.length === 0
597
+ ? ' requirements: none'
598
+ : payload.runtime_injection.requirements.map((requirement) => ` ${requirement.name.padEnd(18)} ${requirement.kind.padEnd(20)} ${describeRuntimeInjectionRequirement(requirement)}`).join('\n'),
599
+ payload.runtime_injection.export_keys.length === 0
600
+ ? ' exports: none'
601
+ : ` exports: ${payload.runtime_injection.export_keys.join(', ')}`,
602
+ payload.runtime_injection.audit_context_keys.length === 0
603
+ ? ' audit_context: none'
604
+ : ` audit_context: ${payload.runtime_injection.audit_context_keys.join(', ')}`,
605
+ ].join('\n')
606
+ : ' none';
607
+ writeHuman(`${payload.capability}\n\n${payload.summary}\n\nInput:\n${inputLines}\n\nSecret requirements:\n${secretLines}\n\nRuntime injection:\n${runtimeInjectionLines}\n\nExecution: ${payload.execution_mode ?? 'unknown'}\nAdapter: ${payload.adapter}\nGrant: ${payload.grant_required ? 'required' : 'not required'}\nApproval: ${payload.approval_mode}`);
608
+ };
609
+ export const renderComposioLinkSession = (mode, payload) => {
610
+ if (mode === 'json') {
611
+ writeJson(payload);
612
+ return;
613
+ }
614
+ if (mode === 'plain') {
615
+ writePlain(linesFromRecord([
616
+ ['link_session_id', payload.link_session_id],
617
+ ['status', payload.status],
618
+ ['agent_id', payload.agent_id],
619
+ ['toolkit_slug', payload.toolkit_slug],
620
+ ['auth_config_id', payload.auth_config_id],
621
+ ['connected_account_id', payload.connected_account_id],
622
+ ['redirect_url', payload.redirect_url],
623
+ ['expires_at', payload.expires_at],
624
+ ['completed_at', payload.completed_at],
625
+ ]));
626
+ return;
627
+ }
628
+ writeHuman([
629
+ `link_session_id: ${payload.link_session_id}`,
630
+ `status: ${payload.status}`,
631
+ `agent_id: ${payload.agent_id ?? 'unknown-agent'}`,
632
+ `toolkit: ${payload.toolkit_slug ?? 'unknown'}`,
633
+ `auth_config_id: ${payload.auth_config_id ?? 'unknown'}`,
634
+ `connected_account_id: ${payload.connected_account_id ?? 'pending'}`,
635
+ `redirect_url: ${payload.redirect_url ?? 'n/a'}`,
636
+ ].join('\n'));
637
+ };
638
+ export const renderComposioService = (mode, payload) => {
639
+ if (mode === 'json') {
640
+ writeJson(payload);
641
+ return;
642
+ }
643
+ if (mode === 'plain') {
644
+ const bindingLines = payload.bindings.map((binding) => [
645
+ 'binding',
646
+ binding.binding_id,
647
+ binding.agent_id,
648
+ binding.toolkit_slug,
649
+ binding.auth_config_id,
650
+ binding.connected_account_id,
651
+ binding.status,
652
+ ].join('='));
653
+ const linkLines = payload.link_sessions.map((session) => [
654
+ 'link_session',
655
+ session.link_session_id,
656
+ session.status,
657
+ session.agent_id ?? '',
658
+ session.toolkit_slug ?? '',
659
+ session.auth_config_id ?? '',
660
+ session.connected_account_id ?? '',
661
+ ].join('='));
662
+ writePlain([
663
+ ...linesFromRecord([
664
+ ['principal_id', payload.principal?.principal_id],
665
+ ['owner_scope_id', payload.principal?.owner_scope_id],
666
+ ['composio_user_id', payload.principal?.composio_user_id],
667
+ ['principal_status', payload.principal?.status],
668
+ ['active_bindings', payload.summary.active_bindings],
669
+ ['pending_link_sessions', payload.summary.pending_link_sessions],
670
+ ]),
671
+ ...bindingLines,
672
+ ...linkLines,
673
+ ]);
674
+ return;
675
+ }
676
+ const principal = payload.principal
677
+ ? [
678
+ `principal_id: ${payload.principal.principal_id}`,
679
+ `owner_scope_id: ${payload.principal.owner_scope_id}`,
680
+ `composio_user_id: ${payload.principal.composio_user_id}`,
681
+ `status: ${payload.principal.status}`,
682
+ ].join('\n')
683
+ : 'principal: not linked';
684
+ const bindings = payload.bindings.length === 0
685
+ ? ' none'
686
+ : payload.bindings.map((binding) => ` ${binding.agent_id} -> ${binding.toolkit_slug} (${binding.auth_config_id}) => ${binding.connected_account_id} [${binding.status}]`).join('\n');
687
+ const links = payload.link_sessions.length === 0
688
+ ? ' none'
689
+ : payload.link_sessions.map((session) => ` ${session.link_session_id} ${session.status} ${session.agent_id ?? 'unknown-agent'} ${session.toolkit_slug ?? 'unknown'} ${session.connected_account_id ?? 'pending'}`).join('\n');
690
+ writeHuman(`${principal}\n\nSummary:\n active_bindings=${payload.summary.active_bindings}\n pending_link_sessions=${payload.summary.pending_link_sessions}\n\nBindings:\n${bindings}\n\nLink sessions:\n${links}`);
691
+ };
692
+ export const renderProfileCleanup = (mode, payload) => {
693
+ if (mode === 'json') {
694
+ writeJson(payload);
695
+ return;
696
+ }
697
+ if (mode === 'plain') {
698
+ writePlain(linesFromRecord([
699
+ ['profile', payload.profile],
700
+ ['deleted', payload.deleted ? 'true' : 'false'],
701
+ ['cleared_session', payload.cleared_session ? 'true' : 'false'],
702
+ ['active_profile', payload.active_profile],
703
+ ]));
704
+ return;
705
+ }
706
+ writeHuman([
707
+ `profile: ${payload.profile}`,
708
+ `deleted: ${payload.deleted ? 'yes' : 'no'}`,
709
+ `cleared_session: ${payload.cleared_session ? 'yes' : 'no'}`,
710
+ `active_profile: ${payload.active_profile}`,
711
+ ].join('\n'));
712
+ };
713
+ export const renderComposioBinding = (mode, payload) => {
714
+ if (mode === 'json') {
715
+ writeJson(payload);
716
+ return;
717
+ }
718
+ if (mode === 'plain') {
719
+ writePlain(linesFromRecord([
720
+ ['binding_id', payload.binding_id],
721
+ ['status', payload.status],
722
+ ['agent_id', payload.agent_id],
723
+ ['toolkit_slug', payload.toolkit_slug],
724
+ ['auth_config_id', payload.auth_config_id],
725
+ ['connected_account_id', payload.connected_account_id],
726
+ ]));
727
+ return;
728
+ }
729
+ writeHuman([
730
+ `binding_id: ${payload.binding_id}`,
731
+ `status: ${payload.status}`,
732
+ `agent_id: ${payload.agent_id}`,
733
+ `toolkit: ${payload.toolkit_slug}`,
734
+ `auth_config_id: ${payload.auth_config_id}`,
735
+ `connected_account_id: ${payload.connected_account_id}`,
736
+ ].join('\n'));
737
+ };
738
+ export const renderStorageUpload = (mode, payload) => {
739
+ if (mode === 'json') {
740
+ writeJson(payload);
741
+ return;
742
+ }
743
+ if (mode === 'plain') {
744
+ writePlain(linesFromRecord([
745
+ ['object_key', payload.object_key],
746
+ ['relative_key', payload.relative_key],
747
+ ['size', payload.size],
748
+ ['content_type', payload.content_type],
749
+ ]));
750
+ return;
751
+ }
752
+ writeHuman([
753
+ `object_key: ${payload.object_key}`,
754
+ `relative_key: ${payload.relative_key}`,
755
+ `size: ${payload.size}`,
756
+ `content_type: ${payload.content_type ?? 'unknown'}`,
757
+ ].join('\n'));
758
+ };
759
+ export const renderStorageList = (mode, payload) => {
760
+ if (mode === 'json') {
761
+ writeJson(payload);
762
+ return;
763
+ }
764
+ if (mode === 'plain') {
765
+ writePlain(payload.objects.map((object) => [
766
+ `relative_key=${toPlainValue(object.relative_key)}`,
767
+ `size=${toPlainValue(object.size)}`,
768
+ `content_type=${toPlainValue(object.content_type)}`,
769
+ `uploaded_at=${toPlainValue(object.uploaded_at)}`,
770
+ `etag=${toPlainValue(object.etag)}`,
771
+ ].join(' ')));
772
+ return;
773
+ }
774
+ if (payload.objects.length === 0) {
775
+ writeHuman('No stored objects.');
776
+ return;
777
+ }
778
+ const rows = payload.objects
779
+ .map((object) => [
780
+ object.relative_key.padEnd(28),
781
+ String(object.size).padStart(8),
782
+ (object.content_type ?? 'unknown').padEnd(24),
783
+ (object.uploaded_at ?? 'unknown'),
784
+ ].join(' ').trimEnd())
785
+ .join('\n');
786
+ writeHuman(`RELATIVE KEY SIZE CONTENT TYPE UPLOADED AT\n${rows}`);
787
+ };
788
+ export const renderStorageDownload = (mode, payload) => {
789
+ if (mode === 'json') {
790
+ writeJson(payload);
791
+ return;
792
+ }
793
+ if (mode === 'plain') {
794
+ writePlain(linesFromRecord([
795
+ ['key', payload.key],
796
+ ['output', payload.output],
797
+ ['size', payload.size],
798
+ ['content_type', payload.content_type],
799
+ ]));
800
+ return;
801
+ }
802
+ writeHuman([
803
+ `key: ${payload.key}`,
804
+ `output: ${payload.output}`,
805
+ `size: ${payload.size}`,
806
+ `content_type: ${payload.content_type ?? 'unknown'}`,
807
+ ].join('\n'));
808
+ };
809
+ export const renderStorageDelete = (mode, payload) => {
810
+ if (mode === 'json') {
811
+ writeJson(payload);
812
+ return;
813
+ }
814
+ if (mode === 'plain') {
815
+ writePlain(linesFromRecord([
816
+ ['ok', payload.ok ? 'true' : 'false'],
817
+ ['object_key', payload.object_key],
818
+ ]));
819
+ return;
820
+ }
821
+ writeHuman(`status: ${payload.ok ? 'deleted' : 'not_deleted'}\nobject_key: ${payload.object_key}`);
822
+ };
823
+ export const renderStoragePresign = (mode, payload) => {
824
+ if (mode === 'json') {
825
+ writeJson(payload);
826
+ return;
827
+ }
828
+ if (mode === 'plain') {
829
+ writePlain(linesFromRecord([
830
+ ['operation', payload.operation],
831
+ ['object_key', payload.object_key],
832
+ ['method', payload.method],
833
+ ['url', payload.url],
834
+ ['expires_at', payload.expires_at],
835
+ ['content_type', payload.content_type],
836
+ ]));
837
+ return;
838
+ }
839
+ writeHuman([
840
+ `operation: ${payload.operation}`,
841
+ `object_key: ${payload.object_key}`,
842
+ `method: ${payload.method}`,
843
+ `url: ${payload.url}`,
844
+ `expires_at: ${payload.expires_at}`,
845
+ `content_type: ${payload.content_type ?? 'unknown'}`,
846
+ ].join('\n'));
847
+ };
848
+ export const renderSecretReferenceList = (mode, secretReferences) => {
849
+ if (mode === 'json') {
850
+ writeJson({ secret_references: secretReferences });
851
+ return;
852
+ }
853
+ if (mode === 'plain') {
854
+ writePlain(secretReferences.map((secretReference) => [
855
+ `name=${toPlainValue(secretReference.name)}`,
856
+ `kind=${toPlainValue(secretReference.kind)}`,
857
+ `managed_by=${toPlainValue(secretReference.managed_by)}`,
858
+ `status=${toPlainValue(secretReference.status)}`,
859
+ `updated_at=${toPlainValue(secretReference.updated_at)}`,
860
+ `stored_material_present=${toPlainValue(yesNoUnknown(secretReference.stored_material_present))}`,
861
+ ].join(' ')));
862
+ return;
863
+ }
864
+ if (secretReferences.length === 0) {
865
+ writeHuman('No secret references.');
866
+ return;
867
+ }
868
+ const rows = secretReferences
869
+ .map((secretReference) => [
870
+ secretReference.name.padEnd(28),
871
+ secretReference.kind.padEnd(20),
872
+ secretReference.managed_by.padEnd(14),
873
+ secretReference.status.padEnd(10),
874
+ yesNoUnknown(secretReference.stored_material_present).padEnd(8),
875
+ secretReference.updated_at,
876
+ ].join(' ').trimEnd())
877
+ .join('\n');
878
+ writeHuman(`NAME KIND MANAGED BY STATUS MATERIAL UPDATED AT\n${rows}`);
879
+ };
880
+ export const renderSecretReference = (mode, secretReference) => {
881
+ if (mode === 'json') {
882
+ writeJson(secretReference);
883
+ return;
884
+ }
885
+ const backendLocator = JSON.stringify(secretReference.backend_locator);
886
+ if (mode === 'plain') {
887
+ writePlain(linesFromRecord([
888
+ ['name', secretReference.name],
889
+ ['display_name', secretReference.display_name],
890
+ ['kind', secretReference.kind],
891
+ ['resolver_kind', secretReference.resolver_kind],
892
+ ['status', secretReference.status],
893
+ ['managed_by', secretReference.managed_by],
894
+ ['stored_material_present', yesNoUnknown(secretReference.stored_material_present)],
895
+ ['rotated_at', secretReference.rotated_at],
896
+ ['created_at', secretReference.created_at],
897
+ ['updated_at', secretReference.updated_at],
898
+ ['backend_locator', backendLocator],
899
+ ]));
900
+ return;
901
+ }
902
+ writeHuman([
903
+ `name: ${secretReference.name}`,
904
+ `display_name: ${secretReference.display_name}`,
905
+ `kind: ${secretReference.kind}`,
906
+ `resolver_kind: ${secretReference.resolver_kind}`,
907
+ `status: ${secretReference.status}`,
908
+ `managed_by: ${secretReference.managed_by}`,
909
+ `stored_material_present: ${yesNoUnknown(secretReference.stored_material_present)}`,
910
+ `rotated_at: ${secretReference.rotated_at ?? 'never'}`,
911
+ `created_at: ${secretReference.created_at}`,
912
+ `updated_at: ${secretReference.updated_at}`,
913
+ `backend_locator: ${backendLocator}`,
914
+ ].join('\n'));
915
+ };
916
+ export const renderSecretReferenceDeleted = (mode, payload) => {
917
+ if (mode === 'json') {
918
+ writeJson(payload);
919
+ return;
920
+ }
921
+ if (mode === 'plain') {
922
+ writePlain(linesFromRecord([
923
+ ['name', payload.name],
924
+ ['ok', payload.ok ? 'true' : 'false'],
925
+ ]));
926
+ return;
927
+ }
928
+ writeHuman(`name: ${payload.name}\nstatus: ${payload.ok ? 'deleted' : 'not_deleted'}`);
929
+ };
930
+ export const renderApprove = (mode, payload) => {
931
+ if (mode === 'json') {
932
+ writeJson(payload);
933
+ return;
934
+ }
935
+ if (mode === 'plain') {
936
+ writePlain(linesFromRecord([
937
+ ['approval_id', payload.approval_id],
938
+ ['status', payload.status],
939
+ ]));
940
+ return;
941
+ }
942
+ writeHuman(`approval_id: ${payload.approval_id}\nstatus: ${payload.status}`);
943
+ };
944
+ export const renderSetup = (mode, payload) => {
945
+ if (mode === 'json') {
946
+ writeJson(payload);
947
+ return;
948
+ }
949
+ if (mode === 'plain') {
950
+ writePlain(linesFromRecord([
951
+ ['profile', payload.profile],
952
+ ['api_url', payload.api_url],
953
+ ['status', payload.status],
954
+ ['owner', payload.owner],
955
+ ['agent_id', payload.agent_id],
956
+ ['agent_name', payload.agent_name],
957
+ ['approval_url', payload.approval_url],
958
+ ['health', payload.health],
959
+ ['capabilities', payload.capabilities],
960
+ ['pending_approvals', payload.pending_approvals],
961
+ ['recent_executions', payload.recent_executions],
962
+ ['starter_capability', payload.starter_capability],
963
+ ]));
964
+ return;
965
+ }
966
+ if (payload.status === 'approval_required') {
967
+ writeHuman(`profile: ${payload.profile}\napi_url: ${payload.api_url}\nstatus: ${payload.status}\nagent_name: ${payload.agent_name ?? 'unknown'}\napproval_url: ${payload.approval_url ?? 'unknown'}\n\nnext:\n open https://dash.tryharbor.ai/login\n open ${payload.approval_url ?? 'https://dash.tryharbor.ai/approvals'}\n rerun harbor setup or harbor auth claim`);
968
+ return;
969
+ }
970
+ writeHuman(`profile: ${payload.profile}\napi_url: ${payload.api_url}\nstatus: ${payload.status}\nowner: ${payload.owner ?? 'unknown'}\nagent_id: ${payload.agent_id ?? 'unknown'}\nagent_name: ${payload.agent_name ?? 'unknown'}\nhealth: ${payload.health ?? 'unknown'}\ncapabilities: ${payload.capabilities ?? 'unknown'}\npending_approvals: ${payload.pending_approvals ?? 'unknown'}\nrecent_executions: ${payload.recent_executions ?? 'unknown'}\n\nnext:\n harbor ls --plain\n ${payload.starter_capability ? `harbor learn ${payload.starter_capability} --plain` : 'harbor learn <capability> --plain'}\n ${payload.starter_capability ? `harbor ${payload.starter_capability} --help` : 'harbor <capability> --help'}\n harbor secrets ls --plain\n echo \$SECRET_VALUE | harbor secrets set SECRET_NAME --plain\n harbor mcp install --dry-run`);
971
+ };
972
+ export const renderStatus = (mode, payload) => {
973
+ const authStatus = payload.whoami
974
+ ? 'authenticated'
975
+ : payload.pending_claim_approval_id
976
+ ? 'pending_claim_approval'
977
+ : 'anonymous';
978
+ const jsonPayload = {
979
+ profile: payload.profile,
980
+ auth_status: authStatus,
981
+ agent_id: payload.whoami?.agent_id ?? null,
982
+ owner: payload.whoami?.owner ?? null,
983
+ pending_claim_approval_id: payload.pending_claim_approval_id ?? null,
984
+ health: payload.health.status,
985
+ capabilities: payload.capabilityCount,
986
+ pending_approvals: payload.health.pending_approvals,
987
+ recent_executions: payload.health.recent_executions,
988
+ };
989
+ if (mode === 'json') {
990
+ writeJson(jsonPayload);
991
+ return;
992
+ }
993
+ if (mode === 'plain') {
994
+ writePlain(linesFromRecord([
995
+ ['profile', payload.profile],
996
+ ['auth_status', authStatus],
997
+ ['agent_id', payload.whoami?.agent_id],
998
+ ['owner', payload.whoami?.owner],
999
+ ['pending_claim_approval_id', payload.pending_claim_approval_id],
1000
+ ['health', payload.health.status],
1001
+ ['capabilities', payload.capabilityCount],
1002
+ ['pending_approvals', payload.health.pending_approvals ?? ''],
1003
+ ['recent_executions', payload.health.recent_executions ?? ''],
1004
+ ]));
1005
+ return;
1006
+ }
1007
+ writeHuman(`profile: ${payload.profile}\nauth_status: ${authStatus}\nagent_id: ${payload.whoami?.agent_id ?? 'unknown'}\nowner: ${payload.whoami?.owner ?? 'unknown'}\npending_claim_approval: ${payload.pending_claim_approval_id ?? 'none'}\napi: ${payload.health.reachable ? 'reachable' : 'unreachable'}\ncapabilities: ${payload.capabilityCount}\npending_approvals: ${payload.health.pending_approvals ?? 'unknown'}\nrecent_executions: ${payload.health.recent_executions ?? 'unknown'}\nhealth: ${payload.health.status}`);
1008
+ };
1009
+ export const renderExecutionStart = (mode, payload) => {
1010
+ if (mode === 'json') {
1011
+ writeJson(payload);
1012
+ return;
1013
+ }
1014
+ if (mode === 'plain') {
1015
+ writePlain(linesFromRecord([
1016
+ ['status', payload.status],
1017
+ ['execution_id', payload.execution_id],
1018
+ ['capability', payload.capability],
1019
+ ['state', payload.state],
1020
+ ['approval_id', payload.approval_id],
1021
+ ['approval_url', payload.approval_url],
1022
+ ['reason', payload.reason],
1023
+ ]));
1024
+ return;
1025
+ }
1026
+ if (payload.status === 'approval_required') {
1027
+ const approvalHint = payload.approval_id
1028
+ ? `\n\nThe owner must approve this request before it can proceed:\n harbor approve ${payload.approval_id} --yes\n\nThen retry with the approved escalation:\n harbor ${payload.capability ?? '<capability>'} ... --approval-id ${payload.approval_id}`
1029
+ : '';
1030
+ writeHuman(`status: ${payload.status}\napproval_id: ${payload.approval_id ?? 'unknown'}\ncapability: ${payload.capability ?? 'unknown'}\nreason: ${payload.reason ?? 'grant required'}${approvalHint}`);
1031
+ return;
1032
+ }
1033
+ writeHuman(`status: ${payload.status}\nexecution_id: ${payload.execution_id ?? 'unknown'}\ncapability: ${payload.capability ?? 'unknown'}\nstate: ${payload.state ?? 'queued'}`);
1034
+ };
1035
+ export const renderError = (mode, error) => {
1036
+ if (error instanceof CliInputError) {
1037
+ const payload = {
1038
+ code: error.code,
1039
+ message: error.message,
1040
+ invocation: error.invocation,
1041
+ note: error.note,
1042
+ };
1043
+ if (mode === 'json') {
1044
+ writeJsonError(payload);
1045
+ return;
1046
+ }
1047
+ if (mode === 'plain') {
1048
+ writePlainError(linesFromRecord([
1049
+ ['error', error.code],
1050
+ ['message', error.message],
1051
+ ['invocation', error.invocation],
1052
+ ['note', error.note],
1053
+ ]));
1054
+ return;
1055
+ }
1056
+ writeHumanError(`Error: ${error.message}\n ${error.invocation}${error.note ? `\n ${error.note}` : ''}`);
1057
+ return;
1058
+ }
1059
+ if (error instanceof ApiError) {
1060
+ const payload = {
1061
+ code: error.code,
1062
+ message: error.message,
1063
+ status: error.status,
1064
+ };
1065
+ if (mode === 'json') {
1066
+ writeJsonError(payload);
1067
+ return;
1068
+ }
1069
+ if (mode === 'plain') {
1070
+ writePlainError(linesFromRecord([
1071
+ ['error', error.code],
1072
+ ['message', error.message],
1073
+ ['status', error.status],
1074
+ ]));
1075
+ return;
1076
+ }
1077
+ writeHumanError(`Error: ${error.message}`);
1078
+ return;
1079
+ }
1080
+ if (error instanceof Error) {
1081
+ const code = typeof error.code === 'string'
1082
+ ? error.code
1083
+ : null;
1084
+ const status = typeof error.status === 'number'
1085
+ ? error.status
1086
+ : null;
1087
+ if (code) {
1088
+ if (mode === 'json') {
1089
+ writeJsonError({ code, message: error.message, ...(status !== null ? { status } : {}) });
1090
+ return;
1091
+ }
1092
+ if (mode === 'plain') {
1093
+ writePlainError(linesFromRecord([
1094
+ ['error', code],
1095
+ ['message', error.message],
1096
+ ['status', status ?? ''],
1097
+ ]));
1098
+ return;
1099
+ }
1100
+ writeHumanError(`Error: ${error.message}`);
1101
+ return;
1102
+ }
1103
+ }
1104
+ const message = error instanceof Error ? error.message : String(error);
1105
+ if (mode === 'json') {
1106
+ writeJsonError({ code: 'unexpected_error', message });
1107
+ return;
1108
+ }
1109
+ if (mode === 'plain') {
1110
+ writePlainError(linesFromRecord([
1111
+ ['error', 'unexpected_error'],
1112
+ ['message', message],
1113
+ ]));
1114
+ return;
1115
+ }
1116
+ writeHumanError(`Error: ${message}`);
1117
+ };
1118
+ export const withOwner = (claim, whoami, profile) => ({
1119
+ ...claim,
1120
+ owner: claim.owner ?? whoami?.owner ?? null,
1121
+ profile: whoami?.profile_slug ?? claim.profile_slug ?? profile.profile_slug,
1122
+ });
1123
+ //# sourceMappingURL=output.js.map