@aopslabs/aops 0.2.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 (171) hide show
  1. package/LICENSE +19 -0
  2. package/NOTICE +7 -0
  3. package/README.md +203 -0
  4. package/assets/agent-assets/core/SKILL.md +49 -0
  5. package/assets/agent-assets/core/references/agentspace/SKILL.md +78 -0
  6. package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +108 -0
  7. package/assets/agent-assets/core/references/chatv3/SKILL.md +48 -0
  8. package/assets/agent-assets/core/references/collaborative-work/SKILL.md +85 -0
  9. package/assets/agent-assets/core/references/discuss/SKILL.md +66 -0
  10. package/assets/agent-assets/core/references/docman/SKILL.md +69 -0
  11. package/assets/agent-assets/core/references/hosted-chat/SKILL.md +64 -0
  12. package/assets/agent-assets/core/references/mission/SKILL.md +54 -0
  13. package/assets/agent-assets/core/references/projectman/SKILL.md +86 -0
  14. package/assets/agent-assets/core/references/sys/SKILL.md +36 -0
  15. package/assets/agent-assets/core/references/view/SKILL.md +58 -0
  16. package/assets/agent-assets/core/references/working-disciplines/SKILL.md +69 -0
  17. package/assets/agent-assets/core/user-guides/agent-assets.md +81 -0
  18. package/assets/agent-assets/core/user-guides/agentspace.md +1098 -0
  19. package/assets/agent-assets/core/user-guides/aops-cli.md +1107 -0
  20. package/assets/agent-assets/core/user-guides/aops-system.md +63 -0
  21. package/assets/agent-assets/core/user-guides/chatv3.md +113 -0
  22. package/assets/agent-assets/core/user-guides/docman.md +162 -0
  23. package/assets/agent-assets/core/user-guides/projectman.md +212 -0
  24. package/assets/agent-assets/core/user-guides/sys.md +94 -0
  25. package/assets/agent-assets/core/user-guides/working-disciplines.md +588 -0
  26. package/assets/agent-assets/gateway/aops/SKILL.md +14 -0
  27. package/assets/r6-remote-session-baseline.json +19 -0
  28. package/assets/skills/aops-install/SKILL.md +231 -0
  29. package/assets/skills/aops-install/agents/openai.yaml +4 -0
  30. package/dist/commands/activity.js +352 -0
  31. package/dist/commands/agent-profile.js +653 -0
  32. package/dist/commands/agent.js +710 -0
  33. package/dist/commands/agents-md.js +125 -0
  34. package/dist/commands/api.js +84 -0
  35. package/dist/commands/archive.js +873 -0
  36. package/dist/commands/artifact.js +535 -0
  37. package/dist/commands/assets.js +1414 -0
  38. package/dist/commands/auth/device-login.js +1 -0
  39. package/dist/commands/auth/legacy-export.js +177 -0
  40. package/dist/commands/auth/login.js +426 -0
  41. package/dist/commands/chat.js +1363 -0
  42. package/dist/commands/chatv3.js +1684 -0
  43. package/dist/commands/checkpoint.js +549 -0
  44. package/dist/commands/commercial-artifact.js +475 -0
  45. package/dist/commands/commercial-license.js +594 -0
  46. package/dist/commands/community-auth.js +62 -0
  47. package/dist/commands/community-cockpit.js +185 -0
  48. package/dist/commands/community-console.js +109 -0
  49. package/dist/commands/community-doctor.js +335 -0
  50. package/dist/commands/community-server.js +2062 -0
  51. package/dist/commands/community-setup.js +284 -0
  52. package/dist/commands/discuss.js +1448 -0
  53. package/dist/commands/doc.js +5219 -0
  54. package/dist/commands/experience.js +922 -0
  55. package/dist/commands/host.js +1127 -0
  56. package/dist/commands/init.js +118 -0
  57. package/dist/commands/memory.js +3129 -0
  58. package/dist/commands/mission.js +562 -0
  59. package/dist/commands/official-catalog.js +134 -0
  60. package/dist/commands/plan.js +84 -0
  61. package/dist/commands/playbook.js +415 -0
  62. package/dist/commands/pm/context.js +6 -0
  63. package/dist/commands/pm/index.js +701 -0
  64. package/dist/commands/pm/projectman.js +6266 -0
  65. package/dist/commands/project.js +1080 -0
  66. package/dist/commands/prompt.js +1024 -0
  67. package/dist/commands/repo-sync.js +1907 -0
  68. package/dist/commands/resource.js +527 -0
  69. package/dist/commands/skill.js +1211 -0
  70. package/dist/commands/start-disciplines.js +510 -0
  71. package/dist/commands/start.js +1343 -0
  72. package/dist/commands/target.js +309 -0
  73. package/dist/commands/version.js +42 -0
  74. package/dist/commands/view.js +1852 -0
  75. package/dist/launchers/cockpit.js +28 -0
  76. package/dist/launchers/options.js +74 -0
  77. package/dist/launchers/server.js +41 -0
  78. package/dist/lib/agent-assets/envelope.js +83 -0
  79. package/dist/lib/agent-assets/gateway.js +15 -0
  80. package/dist/lib/agent-assets/guards.js +23 -0
  81. package/dist/lib/agent-assets/hosted-discovery.js +148 -0
  82. package/dist/lib/agent-assets/hosted-package-input.js +154 -0
  83. package/dist/lib/agent-assets/legacy-pointer-migration.js +677 -0
  84. package/dist/lib/agent-assets/native-fs.js +589 -0
  85. package/dist/lib/agent-assets/package-manifest.js +324 -0
  86. package/dist/lib/agent-assets/portable-path.js +67 -0
  87. package/dist/lib/agent-assets/release-input.js +177 -0
  88. package/dist/lib/agent-assets/roots.js +45 -0
  89. package/dist/lib/agent-assets/runtime-binding-reader.js +545 -0
  90. package/dist/lib/agent-assets/runtime-targets.js +50 -0
  91. package/dist/lib/agent-assets/store-reader.js +1212 -0
  92. package/dist/lib/agent-assets/store-types.js +1 -0
  93. package/dist/lib/agent-assets/store-writer.js +1484 -0
  94. package/dist/lib/agent-assets/types.js +1 -0
  95. package/dist/lib/agent-assets/unicode-case-folding-v15-1.generated.js +1548 -0
  96. package/dist/lib/commercial-final-readiness.js +504 -0
  97. package/dist/lib/commercial-lifecycle-smoke-isolation.js +236 -0
  98. package/dist/lib/commercial-managed-postgres-docker-adapter.js +274 -0
  99. package/dist/lib/commercial-setup-readiness-adapter.js +179 -0
  100. package/dist/lib/community-client-contract.js +164 -0
  101. package/dist/lib/community-cockpit-lifecycle.js +601 -0
  102. package/dist/lib/community-command-abort.js +59 -0
  103. package/dist/lib/community-diagnostic.js +237 -0
  104. package/dist/lib/community-docker-adapter.js +498 -0
  105. package/dist/lib/community-home.js +31 -0
  106. package/dist/lib/community-instance-contract.js +148 -0
  107. package/dist/lib/community-instance-layout.js +97 -0
  108. package/dist/lib/community-lifecycle.js +1631 -0
  109. package/dist/lib/community-migration-snapshot.js +770 -0
  110. package/dist/lib/community-native-application-recovery.js +425 -0
  111. package/dist/lib/community-native-child.js +240 -0
  112. package/dist/lib/community-native-database-recovery.js +456 -0
  113. package/dist/lib/community-native-lifecycle.js +2458 -0
  114. package/dist/lib/community-native-migration.js +339 -0
  115. package/dist/lib/community-native-postgres.js +596 -0
  116. package/dist/lib/community-operation-journal.js +773 -0
  117. package/dist/lib/community-operation-lock.js +596 -0
  118. package/dist/lib/community-release-resolver.js +291 -0
  119. package/dist/lib/community-release-verifier.js +475 -0
  120. package/dist/lib/community-repo-discovery.js +252 -0
  121. package/dist/lib/community-setup-server-env.js +203 -0
  122. package/dist/lib/external-url.js +110 -0
  123. package/dist/lib/official-catalog-gateway.js +108 -0
  124. package/dist/lib/official-catalog.js +364 -0
  125. package/dist/lib/server-bootstrap.js +240 -0
  126. package/dist/lib/setup-agent-assets-bridge.js +176 -0
  127. package/dist/lib/setup-agent-assets-release.js +52 -0
  128. package/dist/lib/setup-external-postgres.js +108 -0
  129. package/dist/lib/setup-init-orchestrator.js +990 -0
  130. package/dist/lib/setup-install-guide.js +52 -0
  131. package/dist/lib/setup-installer-release.js +47 -0
  132. package/dist/lib/setup-local-postgres.js +329 -0
  133. package/dist/lib/setup-official-catalog-bridge.js +148 -0
  134. package/dist/lib/setup-readiness.js +888 -0
  135. package/dist/lib/tui-launcher.js +59 -0
  136. package/dist/main.js +150 -0
  137. package/dist/seeds/agents-md.js +54 -0
  138. package/dist/utils/agent-gateway.js +275 -0
  139. package/dist/utils/agents-md.js +281 -0
  140. package/dist/utils/api.js +255 -0
  141. package/dist/utils/chatv3-session-store.js +185 -0
  142. package/dist/utils/command.js +67 -0
  143. package/dist/utils/community-host-runtime.js +376 -0
  144. package/dist/utils/config.js +1015 -0
  145. package/dist/utils/discussion-workspace.js +552 -0
  146. package/dist/utils/experience-workspace.js +326 -0
  147. package/dist/utils/guide-paths.js +67 -0
  148. package/dist/utils/hosted-sugar.js +56 -0
  149. package/dist/utils/hosted-workspace.js +229 -0
  150. package/dist/utils/memory-workspace.js +537 -0
  151. package/dist/utils/operator-runtime.js +199 -0
  152. package/dist/utils/password-crypto.js +39 -0
  153. package/dist/utils/playbook-workspace.js +479 -0
  154. package/dist/utils/project-context.js +255 -0
  155. package/dist/utils/prompts.js +70 -0
  156. package/dist/utils/refresh-race.js +28 -0
  157. package/dist/utils/repo-config.js +109 -0
  158. package/dist/utils/repo-first-projectman.js +194 -0
  159. package/dist/utils/repo-first-storage.js +13 -0
  160. package/dist/utils/repo-first-view.js +305 -0
  161. package/dist/utils/session-guidance.js +278 -0
  162. package/dist/utils/session-state.js +137 -0
  163. package/dist/utils/table.js +39 -0
  164. package/dist/utils/transient-fs.js +49 -0
  165. package/dist/utils/workspace-root.js +1 -0
  166. package/launchers/aops-cockpit.ps1 +15 -0
  167. package/launchers/aops-cockpit.sh +16 -0
  168. package/launchers/aops-server.ps1 +15 -0
  169. package/launchers/aops-server.sh +16 -0
  170. package/native/tui/win32-x64/aops-tui.exe +0 -0
  171. package/package.json +81 -0
@@ -0,0 +1,710 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import { Command } from 'commander';
3
+ import { banner, logError, logInfo, logSuccess } from '@aopslabs/xf-cli-ui';
4
+ import { applyCommonOptions, compactPayload, normalizeNonEmpty } from '../utils/command.js';
5
+ import { buildAgentContextHeaders, invokeHostedToolWithApiState, parseJsonInput, requireApiState, unwrapHostedToolResult, } from '../utils/agent-gateway.js';
6
+ import { promptInput } from '../utils/prompts.js';
7
+ function augmentAgentInvokeErrorMessage(toolId, message) {
8
+ const normalized = String(message ?? '').toLowerCase();
9
+ if (normalized.includes('apply_required')) {
10
+ return `${message}\nRetry with --apply because ${toolId} is a guarded write tool.`;
11
+ }
12
+ if (normalized.includes('confirmation_required')) {
13
+ return `${message}\nRetry with --confirm after verifying the destructive action is intended.`;
14
+ }
15
+ return message;
16
+ }
17
+ function asRecord(value) {
18
+ return value && typeof value === 'object' && !Array.isArray(value)
19
+ ? value
20
+ : null;
21
+ }
22
+ function asStringArray(value) {
23
+ return Array.isArray(value)
24
+ ? value.map((entry) => normalizeNonEmpty(entry)).filter((entry) => Boolean(entry))
25
+ : [];
26
+ }
27
+ function parsePositiveInteger(value) {
28
+ const parsed = Number.parseInt(value, 10);
29
+ if (!Number.isFinite(parsed) || parsed <= 0) {
30
+ throw new Error('Expected a positive integer.');
31
+ }
32
+ return parsed;
33
+ }
34
+ function extractTagValue(tags, prefix) {
35
+ const match = tags.find((tag) => tag.toLowerCase().startsWith(prefix));
36
+ if (!match)
37
+ return undefined;
38
+ return normalizeNonEmpty(match.slice(prefix.length));
39
+ }
40
+ function compactTool(tool, options = {}) {
41
+ const tags = asStringArray(tool.tags);
42
+ const policy = asRecord(tool.policy);
43
+ const safety = asRecord(policy?.safety);
44
+ const links = asRecord(tool.links);
45
+ const examples = asStringArray(tool.examples);
46
+ const toolId = normalizeNonEmpty(tool.toolId) ??
47
+ normalizeNonEmpty(tool.id) ??
48
+ normalizeNonEmpty(tool.operationId) ??
49
+ '(unknown-tool)';
50
+ const title = normalizeNonEmpty(tool.title);
51
+ const summary = normalizeNonEmpty(tool.summary);
52
+ const guard = compactPayload({
53
+ apply: safety?.applyRequired,
54
+ confirm: safety?.confirmationRequired,
55
+ destructive: safety?.destructive,
56
+ });
57
+ return compactPayload({
58
+ id: toolId,
59
+ domain: normalizeNonEmpty(tool.domain),
60
+ op: normalizeNonEmpty(tool.operationId),
61
+ title,
62
+ summary: summary && summary !== title ? summary : undefined,
63
+ resource: extractTagValue(tags, 'resource:'),
64
+ kind: extractTagValue(tags, 'kind:'),
65
+ action: extractTagValue(tags, 'action:'),
66
+ effect: normalizeNonEmpty(tool.sideEffect),
67
+ schema: normalizeNonEmpty(tool.inputSchemaRef),
68
+ guard: Object.keys(guard).length > 0 ? guard : undefined,
69
+ source: normalizeNonEmpty(tool.defaultSourceId),
70
+ detail: normalizeNonEmpty(links?.detail),
71
+ invoke: normalizeNonEmpty(links?.invoke),
72
+ example: options.examples ? examples[0] : undefined,
73
+ });
74
+ }
75
+ function toolMatchesQuery(tool, query) {
76
+ const tags = asStringArray(tool.tags);
77
+ const haystack = [
78
+ tool.toolId,
79
+ tool.id,
80
+ tool.domain,
81
+ tool.operationId,
82
+ tool.title,
83
+ tool.summary,
84
+ tool.description,
85
+ tool.inputSchemaRef,
86
+ tool.outputSchemaRef,
87
+ tool.sideEffect,
88
+ tool.defaultSourceId,
89
+ ...tags,
90
+ ]
91
+ .map((value) => normalizeNonEmpty(value)?.toLowerCase())
92
+ .filter((value) => Boolean(value))
93
+ .join('\n');
94
+ return haystack.includes(query);
95
+ }
96
+ function summarizeRecommendedTool(value) {
97
+ const tool = asRecord(value);
98
+ if (!tool)
99
+ return undefined;
100
+ return compactPayload({
101
+ toolId: normalizeNonEmpty(tool.toolId),
102
+ title: normalizeNonEmpty(tool.title),
103
+ summary: normalizeNonEmpty(tool.summary),
104
+ reason: normalizeNonEmpty(tool.reason),
105
+ operationKind: normalizeNonEmpty(tool.operationKind),
106
+ resource: normalizeNonEmpty(tool.resource),
107
+ safety: normalizeNonEmpty(tool.safety),
108
+ });
109
+ }
110
+ function summarizeResource(value) {
111
+ const resource = asRecord(value);
112
+ if (!resource)
113
+ return undefined;
114
+ return compactPayload({
115
+ resourceId: normalizeNonEmpty(resource.resourceId),
116
+ title: normalizeNonEmpty(resource.title),
117
+ summary: normalizeNonEmpty(resource.summary),
118
+ kind: normalizeNonEmpty(resource.kind),
119
+ toolCount: resource.toolCount,
120
+ operationKinds: asStringArray(resource.operationKinds),
121
+ sampleToolIds: asStringArray(resource.sampleToolIds).slice(0, 6),
122
+ });
123
+ }
124
+ function resourceMatchesQuery(resource, query) {
125
+ const haystack = [
126
+ resource.resourceId,
127
+ resource.title,
128
+ resource.summary,
129
+ resource.kind,
130
+ ...asStringArray(resource.operationKinds),
131
+ ...asStringArray(resource.sampleToolIds),
132
+ ]
133
+ .map((value) => normalizeNonEmpty(value)?.toLowerCase())
134
+ .filter((value) => Boolean(value))
135
+ .join('\n');
136
+ return haystack.includes(query);
137
+ }
138
+ function buildAgentToolsSummary(params) {
139
+ const { payload, tools, originalToolCount, matchedToolCount, domain, q, limit, examples } = params;
140
+ const flow = asRecord(payload.flow);
141
+ const discovery = asRecord(payload.discovery);
142
+ const routes = asRecord(discovery?.routes);
143
+ const provenance = asRecord(discovery?.provenance);
144
+ const referenceDomain = asRecord(discovery?.referenceDomain) ?? asRecord(provenance?.referenceDomain);
145
+ const rawResources = Array.isArray(referenceDomain?.humanReadableResources)
146
+ ? referenceDomain.humanReadableResources
147
+ : [];
148
+ const resources = rawResources
149
+ .map((entry) => asRecord(entry))
150
+ .filter((entry) => Boolean(entry))
151
+ .filter((entry) => q ? resourceMatchesQuery(entry, q) : true)
152
+ .map((entry) => summarizeResource(entry))
153
+ .filter((entry) => Boolean(entry));
154
+ const recommendedFirstTools = (Array.isArray(referenceDomain?.recommendedFirstTools)
155
+ ? referenceDomain.recommendedFirstTools
156
+ : [])
157
+ .map((entry) => summarizeRecommendedTool(entry))
158
+ .filter((entry) => Boolean(entry))
159
+ .filter((entry) => {
160
+ if (!q)
161
+ return true;
162
+ return Object.values(entry)
163
+ .map((value) => normalizeNonEmpty(value)?.toLowerCase())
164
+ .filter((value) => Boolean(value))
165
+ .join('\n')
166
+ .includes(q);
167
+ })
168
+ .slice(0, 8);
169
+ return compactPayload({
170
+ ok: payload.ok,
171
+ catalogVersion: payload.catalogVersion,
172
+ generatedAt: payload.generatedAt,
173
+ partial: payload.partial,
174
+ domain: domain ?? normalizeNonEmpty(referenceDomain?.domain),
175
+ counts: {
176
+ total: originalToolCount,
177
+ matched: matchedToolCount,
178
+ returned: tools.length,
179
+ resources: resources.length,
180
+ },
181
+ filters: compactPayload({ domain, q, limit }),
182
+ flow: flow
183
+ ? compactPayload({
184
+ summary: normalizeNonEmpty(flow.summary),
185
+ routes: asRecord(flow.routes),
186
+ })
187
+ : undefined,
188
+ discovery: compactPayload({
189
+ toolCatalog: normalizeNonEmpty(routes?.toolCatalog),
190
+ toolDetailTemplate: normalizeNonEmpty(routes?.toolDetailTemplate),
191
+ invokeTemplate: normalizeNonEmpty(routes?.invokeTemplate),
192
+ rawDiscoveryDocument: normalizeNonEmpty(routes?.rawDiscoveryDocument),
193
+ rawOpenapi: normalizeNonEmpty(routes?.rawOpenapi),
194
+ }),
195
+ resources,
196
+ recommendedFirstTools,
197
+ tools: tools.map((tool) => compactTool(tool, { examples })),
198
+ next: {
199
+ narrow: 'aops-cli agent tools --domain <domain> --q <keyword> --summary --json',
200
+ schema: 'aops-cli agent schema --tool <toolId> --json',
201
+ invoke: "aops-cli agent invoke --tool <toolId> --input '@payload.json' --preview|--apply --json",
202
+ },
203
+ errors: Array.isArray(payload.errors) && payload.errors.length > 0 ? payload.errors : undefined,
204
+ });
205
+ }
206
+ function selectAgentTools(tools, options) {
207
+ const q = normalizeNonEmpty(options.q)?.toLowerCase();
208
+ const limit = Number.isFinite(options.limit) && options.limit && options.limit > 0
209
+ ? options.limit
210
+ : undefined;
211
+ const normalizedTools = tools
212
+ .map((entry) => asRecord(entry))
213
+ .filter((entry) => Boolean(entry));
214
+ const matchedTools = q
215
+ ? normalizedTools.filter((tool) => toolMatchesQuery(tool, q))
216
+ : normalizedTools;
217
+ const selectedTools = typeof limit === 'number' ? matchedTools.slice(0, limit) : matchedTools;
218
+ return {
219
+ selectedTools,
220
+ matchedToolCount: matchedTools.length,
221
+ q,
222
+ limit,
223
+ };
224
+ }
225
+ function schemaType(schema) {
226
+ const type = schema.type;
227
+ if (Array.isArray(type)) {
228
+ return type.map((entry) => normalizeNonEmpty(entry)).filter(Boolean).join('|') || undefined;
229
+ }
230
+ const explicitType = normalizeNonEmpty(type);
231
+ if (explicitType)
232
+ return explicitType;
233
+ if (Array.isArray(schema.enum))
234
+ return 'enum';
235
+ if (Object.prototype.hasOwnProperty.call(schema, 'const'))
236
+ return 'const';
237
+ for (const key of ['oneOf', 'anyOf', 'allOf']) {
238
+ const variants = schema[key];
239
+ if (Array.isArray(variants))
240
+ return `${key}(${variants.length})`;
241
+ }
242
+ return undefined;
243
+ }
244
+ function summarizeAdditionalProperties(value) {
245
+ if (typeof value === 'boolean')
246
+ return value;
247
+ const schema = asRecord(value);
248
+ return schema ? schemaType(schema) ?? 'schema' : undefined;
249
+ }
250
+ function schemaHasProperties(schema) {
251
+ const properties = asRecord(schema.properties);
252
+ return Boolean(properties && Object.keys(properties).length > 0);
253
+ }
254
+ function isFlexibleObjectSchema(schema) {
255
+ return !schemaHasProperties(schema) && (schema.additionalProperties === true ||
256
+ Boolean(asRecord(schema.additionalProperties)));
257
+ }
258
+ function isOpaqueInputSchema(schema) {
259
+ if (isFlexibleObjectSchema(schema))
260
+ return true;
261
+ const properties = asRecord(schema.properties);
262
+ if (!properties)
263
+ return false;
264
+ return ['data', 'input', 'patch', 'payload'].some((key) => {
265
+ const child = asRecord(properties[key]);
266
+ return child ? isFlexibleObjectSchema(child) : false;
267
+ });
268
+ }
269
+ function summarizeEnum(value) {
270
+ if (!Array.isArray(value))
271
+ return undefined;
272
+ return value.slice(0, 12).map((entry) => {
273
+ if (entry === null || ['string', 'number', 'boolean'].includes(typeof entry))
274
+ return entry;
275
+ return String(entry);
276
+ });
277
+ }
278
+ function collectSchemaFields(params) {
279
+ if (params.depth > 8)
280
+ return;
281
+ const properties = asRecord(params.schema.properties);
282
+ if (properties) {
283
+ for (const [key, rawChild] of Object.entries(properties)) {
284
+ const child = asRecord(rawChild);
285
+ if (!child)
286
+ continue;
287
+ const childPath = params.path ? `${params.path}.${key}` : key;
288
+ const childRequired = params.required.has(key);
289
+ const childRequiredSet = new Set(asStringArray(child.required));
290
+ const description = normalizeNonEmpty(child.description);
291
+ const defaultValue = Object.prototype.hasOwnProperty.call(child, 'default')
292
+ ? child.default
293
+ : undefined;
294
+ params.fields.push(compactPayload({
295
+ path: childPath,
296
+ type: schemaType(child),
297
+ required: childRequired,
298
+ format: normalizeNonEmpty(child.format),
299
+ description,
300
+ enum: summarizeEnum(child.enum),
301
+ const: Object.prototype.hasOwnProperty.call(child, 'const') ? child.const : undefined,
302
+ default: defaultValue,
303
+ additionalProperties: summarizeAdditionalProperties(child.additionalProperties),
304
+ }));
305
+ collectSchemaFields({
306
+ schema: child,
307
+ path: childPath,
308
+ required: childRequiredSet,
309
+ fields: params.fields,
310
+ depth: params.depth + 1,
311
+ });
312
+ const items = asRecord(child.items);
313
+ if (items) {
314
+ collectSchemaFields({
315
+ schema: items,
316
+ path: `${childPath}[]`,
317
+ required: new Set(asStringArray(items.required)),
318
+ fields: params.fields,
319
+ depth: params.depth + 1,
320
+ });
321
+ }
322
+ }
323
+ }
324
+ for (const key of ['oneOf', 'anyOf', 'allOf']) {
325
+ const variants = params.schema[key];
326
+ if (!Array.isArray(variants))
327
+ continue;
328
+ params.fields.push(compactPayload({
329
+ path: params.path || '$',
330
+ type: `${key}(${variants.length})`,
331
+ }));
332
+ for (const [index, rawVariant] of variants.slice(0, 4).entries()) {
333
+ const variant = asRecord(rawVariant);
334
+ if (!variant)
335
+ continue;
336
+ collectSchemaFields({
337
+ schema: variant,
338
+ path: params.path ? `${params.path}.${key}[${index}]` : `${key}[${index}]`,
339
+ required: new Set(asStringArray(variant.required)),
340
+ fields: params.fields,
341
+ depth: params.depth + 1,
342
+ });
343
+ }
344
+ }
345
+ }
346
+ function buildAgentSchemaSummary(params) {
347
+ const tool = asRecord(params.payload.tool);
348
+ const rootRequired = asStringArray(params.inputJsonSchema.required);
349
+ const fields = [];
350
+ collectSchemaFields({
351
+ schema: params.inputJsonSchema,
352
+ path: '',
353
+ required: new Set(rootRequired),
354
+ fields,
355
+ depth: 0,
356
+ });
357
+ const domain = normalizeNonEmpty(tool?.domain) ??
358
+ normalizeNonEmpty(params.toolId.split('.')[0]);
359
+ const opaque = isOpaqueInputSchema(params.inputJsonSchema);
360
+ const returnedFields = fields.slice(0, 80);
361
+ return compactPayload({
362
+ toolId: params.toolId,
363
+ title: normalizeNonEmpty(tool?.title),
364
+ operationId: normalizeNonEmpty(tool?.operationId),
365
+ domain,
366
+ schemaSummary: compactPayload({
367
+ rootType: schemaType(params.inputJsonSchema),
368
+ required: rootRequired,
369
+ additionalProperties: summarizeAdditionalProperties(params.inputJsonSchema.additionalProperties),
370
+ opaque,
371
+ fieldCount: fields.length,
372
+ returnedFieldCount: returnedFields.length,
373
+ truncated: fields.length > returnedFields.length,
374
+ fields: returnedFields,
375
+ }),
376
+ next: compactPayload({
377
+ fullSchema: `aops-cli agent schema --tool ${params.toolId} --json`,
378
+ openapi: domain ? `aops-cli agent openapi --domain ${domain} --json` : undefined,
379
+ detail: `GET /api/agent/tools/${params.toolId}`,
380
+ invoke: `aops-cli agent invoke --tool ${params.toolId} --input @payload.json --preview|--apply --json`,
381
+ fallback: opaque
382
+ ? [
383
+ 'If this summary is opaque, inspect OpenAPI for the operation requestBody schema.',
384
+ 'If OpenAPI is also opaque, inspect the domain kit/Zod source before raw invoke payload authoring.',
385
+ 'For routine sugar use, prefer the matching command --help surface.',
386
+ ]
387
+ : undefined,
388
+ }),
389
+ });
390
+ }
391
+ export async function runAgentTools(options = {}) {
392
+ const interactive = !options.yes && !options.json;
393
+ const apiState = await requireApiState(options);
394
+ if (!apiState)
395
+ return;
396
+ const domain = normalizeNonEmpty(options.domain)?.toLowerCase();
397
+ const query = domain ? `?domain=${encodeURIComponent(domain)}` : '';
398
+ const path = `/api/agent/tools${query}`;
399
+ let headers;
400
+ try {
401
+ headers = await buildAgentContextHeaders(options);
402
+ }
403
+ catch (error) {
404
+ const message = error instanceof Error ? error.message : String(error);
405
+ logError(message);
406
+ process.exitCode = 1;
407
+ return;
408
+ }
409
+ if (interactive) {
410
+ banner('AOPS Agent Tools');
411
+ logInfo(`API: ${apiState.baseUrl}`);
412
+ if (domain)
413
+ logInfo(`Domain filter: ${domain}`);
414
+ }
415
+ try {
416
+ const payload = await apiState.client.fetchJson(path, {
417
+ method: 'GET',
418
+ headers,
419
+ timeoutMs: options.timeoutMs,
420
+ });
421
+ const tools = Array.isArray(payload.tools) ? payload.tools : [];
422
+ const originalToolCount = tools.length;
423
+ const { selectedTools, matchedToolCount, q, limit } = selectAgentTools(tools, options);
424
+ if (options.json) {
425
+ if (options.summary) {
426
+ console.log(JSON.stringify(buildAgentToolsSummary({
427
+ payload,
428
+ tools: selectedTools,
429
+ originalToolCount,
430
+ matchedToolCount,
431
+ domain,
432
+ q,
433
+ limit,
434
+ examples: options.examples,
435
+ }), null, 2));
436
+ return;
437
+ }
438
+ const shouldFilter = Boolean(q) || typeof limit === 'number';
439
+ console.log(JSON.stringify(shouldFilter
440
+ ? {
441
+ ...payload,
442
+ filters: compactPayload({ domain, q, limit }),
443
+ toolCount: {
444
+ total: originalToolCount,
445
+ matched: matchedToolCount,
446
+ returned: selectedTools.length,
447
+ },
448
+ tools: selectedTools,
449
+ }
450
+ : payload, null, 2));
451
+ return;
452
+ }
453
+ const errors = Array.isArray(payload.errors) ? payload.errors : [];
454
+ const catalogVersion = typeof payload.catalogVersion === 'string' ? payload.catalogVersion : 'unknown';
455
+ const flow = (payload.flow &&
456
+ typeof payload.flow === 'object' &&
457
+ !Array.isArray(payload.flow)) ? payload.flow : null;
458
+ logSuccess(`Tools: ${selectedTools.length}${selectedTools.length === originalToolCount ? '' : `/${originalToolCount}`} (catalog: ${catalogVersion})`);
459
+ if (q)
460
+ logInfo(`Query: ${q}`);
461
+ if (typeof limit === 'number')
462
+ logInfo(`Limit: ${limit}`);
463
+ const flowSummary = flow && typeof flow.summary === 'string'
464
+ ? flow.summary
465
+ : undefined;
466
+ if (flowSummary) {
467
+ logInfo(`Flow: ${flowSummary}`);
468
+ }
469
+ for (const raw of selectedTools) {
470
+ const tool = raw;
471
+ const toolId = normalizeNonEmpty(tool.toolId) ??
472
+ normalizeNonEmpty(tool.id) ??
473
+ normalizeNonEmpty(tool.operationId) ??
474
+ '(unknown-tool)';
475
+ const title = normalizeNonEmpty(tool.title) ??
476
+ normalizeNonEmpty(tool.name) ??
477
+ normalizeNonEmpty(tool.summary) ??
478
+ normalizeNonEmpty(tool.description);
479
+ const sourceId = normalizeNonEmpty(tool.sourceId) ?? normalizeNonEmpty(tool.domain);
480
+ const suffix = [
481
+ sourceId ? `source=${sourceId}` : undefined,
482
+ title ? title : undefined,
483
+ ]
484
+ .filter(Boolean)
485
+ .join(' | ');
486
+ console.log(`- ${toolId}${suffix ? ` :: ${suffix}` : ''}`);
487
+ }
488
+ if (errors.length > 0) {
489
+ logInfo('Source errors:');
490
+ for (const err of errors) {
491
+ console.log(`- ${JSON.stringify(err)}`);
492
+ }
493
+ }
494
+ if (options.summary) {
495
+ logInfo('Next: inspect one exact input contract with `aops-cli agent schema --tool <toolId> --json`.');
496
+ }
497
+ }
498
+ catch (error) {
499
+ const message = error instanceof Error ? error.message : String(error);
500
+ logError(`Failed to fetch agent tools: ${message}`);
501
+ process.exitCode = 1;
502
+ }
503
+ }
504
+ export async function runAgentInvoke(options = {}) {
505
+ const interactive = !options.yes && !options.json;
506
+ const apiState = await requireApiState(options);
507
+ if (!apiState)
508
+ return;
509
+ let toolId = normalizeNonEmpty(options.tool)?.toLowerCase();
510
+ if (!toolId && interactive) {
511
+ toolId = normalizeNonEmpty(await promptInput({ message: 'Tool id:' }))?.toLowerCase();
512
+ }
513
+ if (!toolId) {
514
+ logError('Missing tool id. Provide --tool <id>.');
515
+ process.exitCode = 1;
516
+ return;
517
+ }
518
+ let input;
519
+ try {
520
+ input = parseJsonInput(options.input, 'input');
521
+ }
522
+ catch (error) {
523
+ const message = error instanceof Error ? error.message : String(error);
524
+ logError(message);
525
+ process.exitCode = 1;
526
+ return;
527
+ }
528
+ if (interactive) {
529
+ banner('AOPS Agent Invoke');
530
+ logInfo(`API: ${apiState.baseUrl}`);
531
+ logInfo(`Tool: ${toolId}`);
532
+ }
533
+ try {
534
+ const payload = await invokeHostedToolWithApiState(apiState, {
535
+ ...options,
536
+ toolId,
537
+ input,
538
+ });
539
+ if (options.json) {
540
+ console.log(JSON.stringify(payload, null, 2));
541
+ return;
542
+ }
543
+ logSuccess('Tool invocation completed.');
544
+ console.log(JSON.stringify(unwrapHostedToolResult(payload), null, 2));
545
+ }
546
+ catch (error) {
547
+ const message = error instanceof Error ? error.message : String(error);
548
+ logError(`Failed to invoke tool ${toolId}: ${augmentAgentInvokeErrorMessage(toolId, message)}`);
549
+ process.exitCode = 1;
550
+ }
551
+ }
552
+ export async function runAgentOpenApi(options = {}) {
553
+ const interactive = !options.yes && !options.json;
554
+ const apiState = await requireApiState(options);
555
+ if (!apiState)
556
+ return;
557
+ const domain = normalizeNonEmpty(options.domain)?.toLowerCase();
558
+ const query = domain ? `?domain=${encodeURIComponent(domain)}` : '';
559
+ const path = `/api/agent/openapi.json${query}`;
560
+ if (interactive) {
561
+ banner('AOPS Agent OpenAPI');
562
+ logInfo(`API: ${apiState.baseUrl}`);
563
+ if (domain)
564
+ logInfo(`Domain filter: ${domain}`);
565
+ }
566
+ try {
567
+ const payload = await apiState.client.fetchJson(path, {
568
+ method: 'GET',
569
+ timeoutMs: options.timeoutMs,
570
+ });
571
+ const pretty = JSON.stringify(payload, null, 2);
572
+ const outPath = normalizeNonEmpty(options.out);
573
+ if (outPath) {
574
+ writeFileSync(outPath, `${pretty}\n`, 'utf8');
575
+ if (!options.json)
576
+ logSuccess(`Wrote ${outPath}`);
577
+ }
578
+ console.log(pretty);
579
+ }
580
+ catch (error) {
581
+ const message = error instanceof Error ? error.message : String(error);
582
+ logError(`Failed to generate OpenAPI: ${message}`);
583
+ process.exitCode = 1;
584
+ }
585
+ }
586
+ export async function runAgentSchema(options = {}) {
587
+ const interactive = !options.yes && !options.json;
588
+ const apiState = await requireApiState(options);
589
+ if (!apiState)
590
+ return;
591
+ const toolId = normalizeNonEmpty(options.tool)?.toLowerCase();
592
+ if (!toolId) {
593
+ logError('Missing tool id. Provide --tool <id>.');
594
+ process.exitCode = 1;
595
+ return;
596
+ }
597
+ const path = `/api/agent/tools/${encodeURIComponent(toolId)}`;
598
+ if (interactive) {
599
+ banner('AOPS Agent Schema');
600
+ logInfo(`API: ${apiState.baseUrl}`);
601
+ logInfo(`Tool: ${toolId}`);
602
+ }
603
+ try {
604
+ const payload = await apiState.client.fetchJson(path, {
605
+ method: 'GET',
606
+ timeoutMs: options.timeoutMs,
607
+ });
608
+ const inputJsonSchema = payload?.tool?.inputJsonSchema;
609
+ const inputSchemaRecord = asRecord(inputJsonSchema);
610
+ if (!inputSchemaRecord) {
611
+ logError(`No input schema is published for ${toolId}. The tool's kit may not expose a per-operation input schema yet.`);
612
+ process.exitCode = 1;
613
+ return;
614
+ }
615
+ const result = options.summary
616
+ ? buildAgentSchemaSummary({ toolId, payload, inputJsonSchema: inputSchemaRecord })
617
+ : { toolId, inputJsonSchema };
618
+ const pretty = JSON.stringify(result, null, 2);
619
+ const outPath = normalizeNonEmpty(options.out);
620
+ if (outPath) {
621
+ writeFileSync(outPath, `${pretty}\n`, 'utf8');
622
+ if (!options.json)
623
+ logSuccess(`Wrote ${outPath}`);
624
+ }
625
+ if (options.json) {
626
+ console.log(pretty);
627
+ return;
628
+ }
629
+ logSuccess('Input schema fetched.');
630
+ console.log(pretty);
631
+ }
632
+ catch (error) {
633
+ const message = error instanceof Error ? error.message : String(error);
634
+ logError(`Failed to fetch schema for ${toolId}: ${message}`);
635
+ process.exitCode = 1;
636
+ }
637
+ }
638
+ export function makeAgentCommand() {
639
+ const cmd = new Command('agent').description('Primary operator plane for federated tool discovery and invoke');
640
+ applyCommonOptions(cmd
641
+ .command('tools')
642
+ .description('List federated tools from the canonical operator plane (/api/agent/tools)')
643
+ .option('--domain <id>', 'Filter by domain id (e.g. docman)')
644
+ .option('--q <text>', 'Client-side search over tool id, title, summary, tags, resource, and kind')
645
+ .option('--limit <n>', 'Limit returned tools after filtering', parsePositiveInteger)
646
+ .option('--summary', 'Print a compact, token-efficient catalog summary (especially useful with --json)')
647
+ .option('--examples', 'Include first invoke example in --summary output')
648
+ .option('--tenant-id <id>', 'Tenant id header (x-tenant-id)')
649
+ .option('--locale <locale>', 'Locale header (x-locale)')
650
+ .option('--fallback-locale <locale>', 'Fallback locale header (x-fallback-locale)')
651
+ .option('--scope-id <id>', 'Canonical owner scope override')
652
+ .option('--scope-resolution <mode>', 'Owner scope read mode: explicit or cascade')
653
+ .option('--project-id <id>', 'Project id used to resolve owner scope from the active AOPS context')
654
+ .option('--project-name <name>', 'Project name from repo-local .aops/aops.config.json for owner-scope resolution')
655
+ .action(async (options) => {
656
+ await runAgentTools(options);
657
+ }), { withProject: false });
658
+ applyCommonOptions(cmd
659
+ .command('invoke')
660
+ .description('Invoke a tool via the canonical operator plane (/api/agent/tools/{toolId}/invoke)')
661
+ .option('--tool <id>', 'Tool id')
662
+ .option('--source-id <id>', 'Optional source id override')
663
+ .option('--input <json>', 'JSON input payload or @file.json')
664
+ .option('--preview', 'Return a validated preflight summary without executing the tool')
665
+ .option('--apply', 'Explicitly allow guarded write operations')
666
+ .option('--confirm', 'Explicitly confirm destructive operations')
667
+ .option('--idempotency-key <key>', 'Optional guarded-write idempotency key')
668
+ .option('--tenant-id <id>', 'Tenant id header (x-tenant-id)')
669
+ .option('--locale <locale>', 'Locale header (x-locale)')
670
+ .option('--fallback-locale <locale>', 'Fallback locale header (x-fallback-locale)')
671
+ .option('--scope-id <id>', 'Canonical owner scope override')
672
+ .option('--scope-resolution <mode>', 'Owner scope read mode: explicit or cascade')
673
+ .option('--project-id <id>', 'Project id used to resolve owner scope from the active AOPS context')
674
+ .option('--project-name <name>', 'Project name from repo-local .aops/aops.config.json for owner-scope resolution')
675
+ .action(async (options) => {
676
+ await runAgentInvoke(options);
677
+ }), { withProject: false });
678
+ applyCommonOptions(cmd
679
+ .command('openapi')
680
+ .description('Generate OpenAPI from the canonical federated tool catalog')
681
+ .option('--domain <id>', 'Filter OpenAPI by domain')
682
+ .option('--out <path>', 'Write output to file')
683
+ .action(async (options) => {
684
+ await runAgentOpenApi(options);
685
+ }), { withProject: false });
686
+ applyCommonOptions(cmd
687
+ .command('schema')
688
+ .description("Print the live JSON Schema for one tool's input contract — use this before authoring --input payloads")
689
+ .option('--tool <id>', 'Tool id (e.g. docman.document.create)')
690
+ .option('--summary', 'Print a compact flattened field summary and fallback ladder')
691
+ .option('--out <path>', 'Write output to file')
692
+ .action(async (options) => {
693
+ await runAgentSchema(options);
694
+ }), { withProject: false });
695
+ cmd.addHelpText('after', `
696
+ Examples:
697
+ aops-cli agent tools --domain docman
698
+ aops-cli agent tools --domain agentspace --summary --json
699
+ aops-cli agent tools --domain agentspace --q memory --limit 20 --summary --json
700
+ aops-cli agent tools --domain agentspace --q resource.create --summary --examples --json
701
+ aops-cli agent tools --domain docman --scope-id <scope-id>
702
+ aops-cli agent invoke --tool docman.document-group.list --project-id <project-id> --input '{"query":{"limit":10}}'
703
+ aops-cli agent invoke --tool docman.document-group.create --scope-id <scope-id> --apply --input '{"data":{"groupUid":"api-guides","title":"API Guides"}}'
704
+ aops-cli agent invoke --tool inventory.unit.create --project-id <project-id> --preview --input '{"unitTypeUid":"length","unitUid":"mm"}'
705
+ aops-cli agent invoke --tool inventory.unit.create --project-id <project-id> --apply --idempotency-key inventory.unit.create:seed-1 --input '{"unitTypeUid":"length","unitUid":"mm","nameMl":{"en":"Millimeter"}}'
706
+ aops-cli agent schema --tool docman.document.create --summary --json
707
+ aops-cli agent openapi --out ./openapi.json
708
+ `);
709
+ return cmd;
710
+ }