@postplus/cli 0.1.27 → 0.1.28
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.
- package/build/doctor.js +194 -21
- package/build/index.js +34 -11
- package/build/skill-catalog.js +49 -12
- package/build/status.js +5 -4
- package/package.json +1 -1
package/build/doctor.js
CHANGED
|
@@ -2,6 +2,7 @@ import { resolveFreshRemoteAuth, } from './auth-session.js';
|
|
|
2
2
|
import { buildPostPlusClientCompatibilityHeaders, formatPostPlusCompatibilityError, } from './client-compatibility.js';
|
|
3
3
|
import { resolveHostedBaseUrl } from './hosted-release.js';
|
|
4
4
|
import { formatLocalDependencyReport, generateLocalDependencyReport, } from './local-dependencies.js';
|
|
5
|
+
import { loadPublicSkillCatalog, } from './skill-catalog.js';
|
|
5
6
|
import { readSubscriptionStatusField } from './subscription-status.js';
|
|
6
7
|
function createPass(id, label, detail, severity = 'required') {
|
|
7
8
|
return {
|
|
@@ -23,12 +24,16 @@ function createFail(id, label, detail, fix, input = {}) {
|
|
|
23
24
|
metadata: input.metadata,
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
|
-
export async function generateDoctorReport() {
|
|
27
|
+
export async function generateDoctorReport(options = {}) {
|
|
27
28
|
const hostedBaseUrl = await resolveHostedBaseUrl();
|
|
28
29
|
const checks = [
|
|
29
30
|
createPass('hosted_base_url', 'PostPlus Cloud', `Using ${hostedBaseUrl ?? 'https://postplus.io'}`),
|
|
30
31
|
];
|
|
31
|
-
|
|
32
|
+
const skillScope = await resolveSkillScope(options.skillId);
|
|
33
|
+
if (skillScope) {
|
|
34
|
+
checks.push(createPass('skill_catalog', 'Skill selection', `Using ${skillScope.skill.skillId} from catalog ${skillScope.catalog.releaseId}`));
|
|
35
|
+
}
|
|
36
|
+
checks.push(await checkLocalDependencies(skillScope));
|
|
32
37
|
if (!hostedBaseUrl) {
|
|
33
38
|
checks.push(createFail('remote_auth', 'Remote auth', 'PostPlus Cloud base URL could not be resolved.', 'Configure POSTPLUS_API_BASE_URL or run `postplus auth login`.'));
|
|
34
39
|
return buildDoctorReport(checks);
|
|
@@ -46,17 +51,40 @@ export async function generateDoctorReport() {
|
|
|
46
51
|
const authCheck = await checkRemoteAuth(auth);
|
|
47
52
|
checks.push(authCheck);
|
|
48
53
|
if (authCheck.status === 'pass') {
|
|
49
|
-
checks.push(await checkHostedCapabilities(auth));
|
|
54
|
+
checks.push(await checkHostedCapabilities(auth, skillScope));
|
|
55
|
+
}
|
|
56
|
+
return buildDoctorReport(checks, options.skillId);
|
|
57
|
+
}
|
|
58
|
+
async function resolveSkillScope(skillId) {
|
|
59
|
+
if (!skillId) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const catalog = await loadPublicSkillCatalog();
|
|
63
|
+
const skill = catalog.skills.find((entry) => entry.skillId === skillId);
|
|
64
|
+
if (!skill) {
|
|
65
|
+
throw new Error(`Unknown PostPlus skill: ${skillId}. Run \`postplus list\` to see released skill ids.`);
|
|
50
66
|
}
|
|
51
|
-
return
|
|
67
|
+
return { catalog, skill };
|
|
52
68
|
}
|
|
53
|
-
async function checkLocalDependencies() {
|
|
69
|
+
async function checkLocalDependencies(skillScope) {
|
|
54
70
|
try {
|
|
55
|
-
const report = await generateLocalDependencyReport(
|
|
71
|
+
const report = await generateLocalDependencyReport(skillScope
|
|
72
|
+
? {
|
|
73
|
+
loadCatalog: async () => ({
|
|
74
|
+
...skillScope.catalog,
|
|
75
|
+
skills: [skillScope.skill],
|
|
76
|
+
}),
|
|
77
|
+
}
|
|
78
|
+
: {});
|
|
56
79
|
const detail = formatLocalDependencyReport(report);
|
|
57
80
|
if (!report.ok) {
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
const skillId = skillScope?.skill.skillId;
|
|
82
|
+
return createFail('local_dependencies', skillId
|
|
83
|
+
? `Local dependencies for ${skillId}`
|
|
84
|
+
: 'Task-specific local media dependencies', detail, skillId
|
|
85
|
+
? 'Run the selected PostPlus skill in a local agent. The installed postplus-shared rules tell the agent how to bootstrap approved missing dependencies.'
|
|
86
|
+
: 'Run the affected PostPlus skill in a local agent. The installed postplus-shared rules tell the agent how to bootstrap approved missing media dependencies.', {
|
|
87
|
+
severity: skillId ? 'required' : 'task_specific',
|
|
60
88
|
metadata: {
|
|
61
89
|
bootstrapRule: 'postplus-shared',
|
|
62
90
|
missingDependencies: report.checks
|
|
@@ -69,7 +97,9 @@ async function checkLocalDependencies() {
|
|
|
69
97
|
},
|
|
70
98
|
});
|
|
71
99
|
}
|
|
72
|
-
return createPass('local_dependencies',
|
|
100
|
+
return createPass('local_dependencies', skillScope
|
|
101
|
+
? `Local dependencies for ${skillScope.skill.skillId}`
|
|
102
|
+
: 'Local dependencies', detail);
|
|
73
103
|
}
|
|
74
104
|
catch (error) {
|
|
75
105
|
return createFail('local_dependencies', 'Local dependencies', error instanceof Error
|
|
@@ -77,13 +107,14 @@ async function checkLocalDependencies() {
|
|
|
77
107
|
: 'Failed to check local dependencies.');
|
|
78
108
|
}
|
|
79
109
|
}
|
|
80
|
-
function buildDoctorReport(checks) {
|
|
110
|
+
function buildDoctorReport(checks, skillId) {
|
|
81
111
|
const requiredOk = checks.every((check) => check.severity !== 'required' || check.status === 'pass');
|
|
82
112
|
return {
|
|
83
113
|
schemaVersion: 1,
|
|
84
114
|
ok: checks.every((check) => check.status === 'pass'),
|
|
85
115
|
requiredOk,
|
|
86
116
|
checks,
|
|
117
|
+
...(skillId ? { skillId } : {}),
|
|
87
118
|
};
|
|
88
119
|
}
|
|
89
120
|
async function checkRemoteAuth(input) {
|
|
@@ -114,7 +145,7 @@ async function checkRemoteAuth(input) {
|
|
|
114
145
|
: 'Failed to validate PostPlus Cloud auth.', 'Run `postplus auth validate` after confirming network access.');
|
|
115
146
|
}
|
|
116
147
|
}
|
|
117
|
-
async function checkHostedCapabilities(input) {
|
|
148
|
+
async function checkHostedCapabilities(input, skillScope) {
|
|
118
149
|
try {
|
|
119
150
|
let response = await requestWithAuth(input, '/api/postplus-cli/hosted/readiness');
|
|
120
151
|
if (response.status === 401) {
|
|
@@ -127,17 +158,28 @@ async function checkHostedCapabilities(input) {
|
|
|
127
158
|
if (!response.ok) {
|
|
128
159
|
return createFail('hosted_capabilities', 'Hosted capabilities', readErrorMessage(payload, 'PostPlus Cloud hosted readiness check failed.'));
|
|
129
160
|
}
|
|
130
|
-
const capabilities =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
161
|
+
const capabilities = readHostedCapabilityEntries(payload.capabilities);
|
|
162
|
+
const relevantCapabilities = skillScope
|
|
163
|
+
? filterCapabilitiesForSkill(capabilities, skillScope.skill.requirements)
|
|
164
|
+
: capabilities;
|
|
165
|
+
const failedLabels = relevantCapabilities
|
|
166
|
+
.map((value) => readCapabilityFailureLabel(value, skillScope))
|
|
135
167
|
.filter((value) => value !== null);
|
|
136
|
-
if (
|
|
137
|
-
|
|
168
|
+
if (skillScope && hasHostedRequirements(skillScope.skill.requirements)) {
|
|
169
|
+
const missingRequirements = collectMissingHostedRequirementLabels(relevantCapabilities, skillScope.skill.requirements);
|
|
170
|
+
failedLabels.push(...missingRequirements);
|
|
171
|
+
}
|
|
172
|
+
if (failedLabels.length > 0 ||
|
|
173
|
+
(!skillScope && payload.ok !== true && capabilities.length === 0)) {
|
|
174
|
+
const skillId = skillScope?.skill.skillId;
|
|
175
|
+
return createFail('hosted_capabilities', skillId ? `Hosted capabilities for ${skillId}` : 'Hosted capabilities', `Not ready: ${failedLabels.join(', ') || 'unknown capability failure'}`, 'Check PostPlus Cloud provider configuration and subscription state.', {
|
|
176
|
+
severity: skillId ? 'required' : 'task_specific',
|
|
177
|
+
});
|
|
138
178
|
}
|
|
139
179
|
const subscription = readSubscriptionStatusField(payload).label;
|
|
140
|
-
return createPass('hosted_capabilities',
|
|
180
|
+
return createPass('hosted_capabilities', skillScope
|
|
181
|
+
? `Hosted capabilities for ${skillScope.skill.skillId}`
|
|
182
|
+
: 'Hosted capabilities', `Ready (${relevantCapabilities.length} capability checks passed; subscription ${subscription})`);
|
|
141
183
|
}
|
|
142
184
|
catch (error) {
|
|
143
185
|
return createFail('hosted_capabilities', 'Hosted capabilities', error instanceof Error
|
|
@@ -145,7 +187,13 @@ async function checkHostedCapabilities(input) {
|
|
|
145
187
|
: 'Failed to check hosted capability readiness.');
|
|
146
188
|
}
|
|
147
189
|
}
|
|
148
|
-
function
|
|
190
|
+
function readHostedCapabilityEntries(value) {
|
|
191
|
+
if (!Array.isArray(value)) {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
return value.filter((entry) => !!entry && typeof entry === 'object' && !Array.isArray(entry));
|
|
195
|
+
}
|
|
196
|
+
function readCapabilityFailureLabel(value, skillScope) {
|
|
149
197
|
if (!value || typeof value !== 'object') {
|
|
150
198
|
return 'invalid capability response';
|
|
151
199
|
}
|
|
@@ -163,9 +211,12 @@ function readCapabilityFailureLabel(value) {
|
|
|
163
211
|
.map(readReadinessCheckFailureLabel)
|
|
164
212
|
.filter((check) => check !== null)
|
|
165
213
|
: [];
|
|
166
|
-
|
|
214
|
+
const labelWithFailures = failedChecks.length > 0
|
|
167
215
|
? `${label} (${failedChecks.join(', ')})`
|
|
168
216
|
: label;
|
|
217
|
+
return skillScope
|
|
218
|
+
? `${labelWithFailures} for ${skillScope.skill.skillId}`
|
|
219
|
+
: labelWithFailures;
|
|
169
220
|
}
|
|
170
221
|
function readReadinessCheckFailureLabel(value) {
|
|
171
222
|
if (!value || typeof value !== 'object') {
|
|
@@ -181,6 +232,128 @@ function readReadinessCheckFailureLabel(value) {
|
|
|
181
232
|
? record.id
|
|
182
233
|
: 'unknown check';
|
|
183
234
|
}
|
|
235
|
+
function filterCapabilitiesForSkill(capabilities, requirements) {
|
|
236
|
+
if (!hasHostedRequirements(requirements)) {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
return capabilities.filter((capability) => capabilityMatchesRequirements(capability, requirements));
|
|
240
|
+
}
|
|
241
|
+
function capabilityMatchesRequirements(capability, requirements) {
|
|
242
|
+
const identifiers = collectCapabilityIdentifiers(capability);
|
|
243
|
+
const hostedCapabilities = new Set(requirements.hostedCapabilities);
|
|
244
|
+
const requirementKeys = collectHostedRequirementKeys(requirements);
|
|
245
|
+
return identifiers.some((identifier) => {
|
|
246
|
+
if (identifier === 'media-file:upload' &&
|
|
247
|
+
hostedCapabilities.has('media-file') &&
|
|
248
|
+
!requiresHostedMediaFileUpload(requirements)) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
const [prefix, suffix] = splitCapabilityIdentifier(identifier);
|
|
252
|
+
if (prefix === 'media-file' &&
|
|
253
|
+
suffix &&
|
|
254
|
+
suffix !== 'upload' &&
|
|
255
|
+
hostedCapabilities.has('media-file')) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
if (hostedCapabilities.has(identifier)) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
if (prefix &&
|
|
262
|
+
suffix &&
|
|
263
|
+
hostedCapabilities.has(prefix) &&
|
|
264
|
+
requirementKeys.has(suffix)) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
return requirementKeys.has(identifier) || requirementKeys.has(suffix);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function requiresHostedMediaFileUpload(requirements) {
|
|
271
|
+
return (requirements.hostedCapabilities.includes('media-generation') ||
|
|
272
|
+
requirements.endpointKeys.length > 0);
|
|
273
|
+
}
|
|
274
|
+
function collectCapabilityIdentifiers(capability) {
|
|
275
|
+
const identifiers = new Set();
|
|
276
|
+
for (const key of [
|
|
277
|
+
'id',
|
|
278
|
+
'key',
|
|
279
|
+
'capability',
|
|
280
|
+
'capabilityKey',
|
|
281
|
+
'collectionKey',
|
|
282
|
+
'endpointKey',
|
|
283
|
+
'modelKey',
|
|
284
|
+
'sourceKey',
|
|
285
|
+
'accountConnection',
|
|
286
|
+
]) {
|
|
287
|
+
const value = capability[key];
|
|
288
|
+
if (typeof value === 'string' && value.trim()) {
|
|
289
|
+
identifiers.add(value.trim());
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (Array.isArray(capability.checks)) {
|
|
293
|
+
for (const check of capability.checks) {
|
|
294
|
+
if (!check || typeof check !== 'object' || Array.isArray(check)) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
for (const identifier of collectCapabilityIdentifiers(check)) {
|
|
298
|
+
identifiers.add(identifier);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return [...identifiers];
|
|
303
|
+
}
|
|
304
|
+
function collectHostedRequirementKeys(requirements) {
|
|
305
|
+
return new Set([
|
|
306
|
+
...requirements.accountConnections,
|
|
307
|
+
...requirements.collectionKeys,
|
|
308
|
+
...requirements.endpointKeys,
|
|
309
|
+
...requirements.modelKeys,
|
|
310
|
+
...requirements.sourceKeys,
|
|
311
|
+
]);
|
|
312
|
+
}
|
|
313
|
+
function hasHostedRequirements(requirements) {
|
|
314
|
+
return (requirements.accountConnections.length > 0 ||
|
|
315
|
+
requirements.collectionKeys.length > 0 ||
|
|
316
|
+
requirements.endpointKeys.length > 0 ||
|
|
317
|
+
requirements.hostedCapabilities.length > 0 ||
|
|
318
|
+
requirements.modelKeys.length > 0 ||
|
|
319
|
+
requirements.sourceKeys.length > 0);
|
|
320
|
+
}
|
|
321
|
+
function collectMissingHostedRequirementLabels(capabilities, requirements) {
|
|
322
|
+
const availableIdentifiers = new Set(capabilities.flatMap(collectCapabilityIdentifiers));
|
|
323
|
+
const missing = [];
|
|
324
|
+
for (const capability of requirements.hostedCapabilities) {
|
|
325
|
+
if (![...availableIdentifiers].some((identifier) => identifierMatchesCapability(identifier, capability))) {
|
|
326
|
+
missing.push(capability);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
for (const key of collectHostedRequirementKeys(requirements)) {
|
|
330
|
+
if (![...availableIdentifiers].some((identifier) => identifierMatchesKey(identifier, key))) {
|
|
331
|
+
missing.push(key);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return missing.map((value) => `${value} readiness check missing`);
|
|
335
|
+
}
|
|
336
|
+
function identifierMatchesKey(identifier, key) {
|
|
337
|
+
if (identifier === key) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
const [, suffix] = splitCapabilityIdentifier(identifier);
|
|
341
|
+
return suffix === key;
|
|
342
|
+
}
|
|
343
|
+
function identifierMatchesCapability(identifier, capability) {
|
|
344
|
+
if (identifier === capability) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
const [prefix] = splitCapabilityIdentifier(identifier);
|
|
348
|
+
return prefix === capability;
|
|
349
|
+
}
|
|
350
|
+
function splitCapabilityIdentifier(identifier) {
|
|
351
|
+
const index = identifier.indexOf(':');
|
|
352
|
+
if (index === -1) {
|
|
353
|
+
return [null, identifier];
|
|
354
|
+
}
|
|
355
|
+
return [identifier.slice(0, index), identifier.slice(index + 1)];
|
|
356
|
+
}
|
|
184
357
|
function readErrorMessage(payload, fallback) {
|
|
185
358
|
const compatibilityError = formatPostPlusCompatibilityError(payload);
|
|
186
359
|
if (compatibilityError) {
|
package/build/index.js
CHANGED
|
@@ -37,11 +37,11 @@ Usage:
|
|
|
37
37
|
postplus auth status [--json]
|
|
38
38
|
postplus auth validate [--json]
|
|
39
39
|
postplus auth logout [--json]
|
|
40
|
-
postplus doctor [--json]
|
|
40
|
+
postplus doctor [--skill <skill-id>] [--json]
|
|
41
41
|
postplus update
|
|
42
42
|
postplus uninstall
|
|
43
43
|
postplus list [--json]
|
|
44
|
-
postplus status [--json]
|
|
44
|
+
postplus status [--skill <skill-id>] [--json]
|
|
45
45
|
postplus version
|
|
46
46
|
postplus help
|
|
47
47
|
|
|
@@ -49,15 +49,15 @@ Skills:
|
|
|
49
49
|
${POSTPLUS_SKILLS_INSTALL_COMMAND}
|
|
50
50
|
`);
|
|
51
51
|
}
|
|
52
|
-
async function runDoctor(
|
|
53
|
-
const report = await generateDoctorReport();
|
|
54
|
-
if (json) {
|
|
52
|
+
async function runDoctor(options) {
|
|
53
|
+
const report = await generateDoctorReport({ skillId: options.skillId });
|
|
54
|
+
if (options.json) {
|
|
55
55
|
writeJson(report);
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
58
|
process.stdout.write(`${formatDoctorReport(report)}\n`);
|
|
59
59
|
}
|
|
60
|
-
return report.
|
|
60
|
+
return report.requiredOk ? 0 : 1;
|
|
61
61
|
}
|
|
62
62
|
async function runAuthStatus(json) {
|
|
63
63
|
const report = await generateAuthStatusReport();
|
|
@@ -69,9 +69,9 @@ async function runAuthStatus(json) {
|
|
|
69
69
|
}
|
|
70
70
|
return report.ok ? 0 : 1;
|
|
71
71
|
}
|
|
72
|
-
async function runStatus(
|
|
73
|
-
const report = await generateStatusReport();
|
|
74
|
-
if (json) {
|
|
72
|
+
async function runStatus(options) {
|
|
73
|
+
const report = await generateStatusReport({ skillId: options.skillId });
|
|
74
|
+
if (options.json) {
|
|
75
75
|
writeJson(report);
|
|
76
76
|
}
|
|
77
77
|
else {
|
|
@@ -119,6 +119,29 @@ async function runSkillUninstallCommand() {
|
|
|
119
119
|
function writeJson(value) {
|
|
120
120
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
121
121
|
}
|
|
122
|
+
function parseDiagnosticOptions(args) {
|
|
123
|
+
const options = {
|
|
124
|
+
json: false,
|
|
125
|
+
};
|
|
126
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
127
|
+
const arg = args[index];
|
|
128
|
+
if (arg === '--json') {
|
|
129
|
+
options.json = true;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (arg === '--skill') {
|
|
133
|
+
const skillId = args[index + 1];
|
|
134
|
+
if (!skillId || skillId.startsWith('--')) {
|
|
135
|
+
throw new Error('Missing value for --skill.');
|
|
136
|
+
}
|
|
137
|
+
options.skillId = skillId;
|
|
138
|
+
index += 1;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`Unknown option for diagnostics command: ${arg}`);
|
|
142
|
+
}
|
|
143
|
+
return options;
|
|
144
|
+
}
|
|
122
145
|
async function runAuthLogout(json) {
|
|
123
146
|
const report = await clearAuthState();
|
|
124
147
|
if (json) {
|
|
@@ -199,7 +222,7 @@ async function main() {
|
|
|
199
222
|
return;
|
|
200
223
|
}
|
|
201
224
|
case 'doctor':
|
|
202
|
-
process.exitCode = await runDoctor(
|
|
225
|
+
process.exitCode = await runDoctor(parseDiagnosticOptions(rest));
|
|
203
226
|
return;
|
|
204
227
|
case 'install':
|
|
205
228
|
process.stderr.write(`PostPlus CLI does not install skills directly. Run \`${POSTPLUS_SKILLS_INSTALL_COMMAND}\`.\n`);
|
|
@@ -215,7 +238,7 @@ async function main() {
|
|
|
215
238
|
process.exitCode = await runList(json);
|
|
216
239
|
return;
|
|
217
240
|
case 'status':
|
|
218
|
-
process.exitCode = await runStatus(
|
|
241
|
+
process.exitCode = await runStatus(parseDiagnosticOptions(rest));
|
|
219
242
|
return;
|
|
220
243
|
case 'auth': {
|
|
221
244
|
const [subcommand, ...authRest] = rest;
|
package/build/skill-catalog.js
CHANGED
|
@@ -15,6 +15,15 @@ export const POSTPLUS_SKILLS_INSTALL_COMMAND = formatPostPlusSkillsInstallComman
|
|
|
15
15
|
export const POSTPLUS_SKILLS_LIST_COMMAND = formatPostPlusSkillsListCommand();
|
|
16
16
|
const POSTPLUS_SKILLS_INDEX_URL = 'https://raw.githubusercontent.com/PostPlusAI/postplus-skills/main/skills/INDEX.md';
|
|
17
17
|
const POSTPLUS_SKILLS_CATALOG_URL = 'https://raw.githubusercontent.com/PostPlusAI/postplus-skills/main/skills/catalog.json';
|
|
18
|
+
export const PUBLIC_SKILL_REQUIREMENT_KEYS = [
|
|
19
|
+
'accountConnections',
|
|
20
|
+
'collectionKeys',
|
|
21
|
+
'endpointKeys',
|
|
22
|
+
'hostedCapabilities',
|
|
23
|
+
'localDependencies',
|
|
24
|
+
'modelKeys',
|
|
25
|
+
'sourceKeys',
|
|
26
|
+
];
|
|
18
27
|
export async function loadPublicSkillCatalog(fetchFn = fetch, env = process.env) {
|
|
19
28
|
const catalogUrl = resolvePostPlusSkillsCatalogUrl(env);
|
|
20
29
|
const skillsSource = resolvePostPlusSkillsSource(env);
|
|
@@ -95,17 +104,7 @@ function parsePublicSkillCatalog(payload) {
|
|
|
95
104
|
const path = typeof skill.path === 'string' && skill.path.trim()
|
|
96
105
|
? skill.path.trim()
|
|
97
106
|
: null;
|
|
98
|
-
const requirements = skill.requirements
|
|
99
|
-
typeof skill.requirements === 'object' &&
|
|
100
|
-
!Array.isArray(skill.requirements)
|
|
101
|
-
? skill.requirements
|
|
102
|
-
: {};
|
|
103
|
-
const localDependencies = Array.isArray(requirements.localDependencies)
|
|
104
|
-
? requirements.localDependencies
|
|
105
|
-
.filter((value) => typeof value === 'string')
|
|
106
|
-
.map((value) => value.trim())
|
|
107
|
-
.filter(Boolean)
|
|
108
|
-
: [];
|
|
107
|
+
const requirements = parsePublicSkillRequirements(skill.requirements);
|
|
109
108
|
const status = typeof skill.status === 'string' ? skill.status.trim() : '';
|
|
110
109
|
if (!skillId ||
|
|
111
110
|
!path ||
|
|
@@ -113,9 +112,10 @@ function parsePublicSkillCatalog(payload) {
|
|
|
113
112
|
throw new Error('PostPlus public skill catalog has an invalid skill.');
|
|
114
113
|
}
|
|
115
114
|
return {
|
|
116
|
-
localDependencies,
|
|
115
|
+
localDependencies: requirements.localDependencies,
|
|
117
116
|
skillId,
|
|
118
117
|
path,
|
|
118
|
+
requirements,
|
|
119
119
|
};
|
|
120
120
|
});
|
|
121
121
|
if (skills.length === 0) {
|
|
@@ -127,3 +127,40 @@ function parsePublicSkillCatalog(payload) {
|
|
|
127
127
|
source,
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
+
function parsePublicSkillRequirements(value) {
|
|
131
|
+
if (value === undefined) {
|
|
132
|
+
return createEmptyRequirements();
|
|
133
|
+
}
|
|
134
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
135
|
+
throw new Error('PostPlus public skill catalog has invalid skill requirements.');
|
|
136
|
+
}
|
|
137
|
+
const record = value;
|
|
138
|
+
const requirements = createEmptyRequirements();
|
|
139
|
+
for (const key of PUBLIC_SKILL_REQUIREMENT_KEYS) {
|
|
140
|
+
const raw = record[key];
|
|
141
|
+
if (raw === undefined) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(raw)) {
|
|
145
|
+
throw new Error(`PostPlus public skill catalog has invalid ${key} requirements.`);
|
|
146
|
+
}
|
|
147
|
+
requirements[key] = raw.map((item) => {
|
|
148
|
+
if (typeof item !== 'string' || !item.trim()) {
|
|
149
|
+
throw new Error(`PostPlus public skill catalog has invalid ${key} requirements.`);
|
|
150
|
+
}
|
|
151
|
+
return item.trim();
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return requirements;
|
|
155
|
+
}
|
|
156
|
+
function createEmptyRequirements() {
|
|
157
|
+
return {
|
|
158
|
+
accountConnections: [],
|
|
159
|
+
collectionKeys: [],
|
|
160
|
+
endpointKeys: [],
|
|
161
|
+
hostedCapabilities: [],
|
|
162
|
+
localDependencies: [],
|
|
163
|
+
modelKeys: [],
|
|
164
|
+
sourceKeys: [],
|
|
165
|
+
};
|
|
166
|
+
}
|
package/build/status.js
CHANGED
|
@@ -3,17 +3,17 @@ import { writeCurrentCliVersionToLocalConfig } from './client-compatibility.js';
|
|
|
3
3
|
import { formatDoctorReport, generateDoctorReport, } from './doctor.js';
|
|
4
4
|
import { formatSkillInstallStatusReport, generateSkillInstallStatusReport, } from './skill-management.js';
|
|
5
5
|
import { formatUpdateStatusReport, generateUpdateStatusReport, } from './update-check.js';
|
|
6
|
-
export async function generateStatusReport() {
|
|
7
|
-
return generateStatusReportWithDependencies();
|
|
6
|
+
export async function generateStatusReport(options = {}) {
|
|
7
|
+
return generateStatusReportWithDependencies({}, options);
|
|
8
8
|
}
|
|
9
|
-
export async function generateStatusReportWithDependencies(dependencies = {}) {
|
|
9
|
+
export async function generateStatusReportWithDependencies(dependencies = {}, options = {}) {
|
|
10
10
|
await writeCurrentCliVersionToLocalConfig();
|
|
11
11
|
const generateAuthStatus = dependencies.generateAuthStatus ?? generateAuthStatusReport;
|
|
12
12
|
const generateDoctor = dependencies.generateDoctor ?? generateDoctorReport;
|
|
13
13
|
const generateSkillStatus = dependencies.generateSkillStatus ?? generateSkillInstallStatusReport;
|
|
14
14
|
const generateUpdateStatus = dependencies.generateUpdateStatus ?? generateUpdateStatusReport;
|
|
15
15
|
const [doctor, auth, skills, updates] = await Promise.all([
|
|
16
|
-
generateDoctor(),
|
|
16
|
+
generateDoctor({ skillId: options.skillId }),
|
|
17
17
|
generateAuthStatus(),
|
|
18
18
|
generateSkillStatus(),
|
|
19
19
|
generateUpdateStatus(),
|
|
@@ -25,6 +25,7 @@ export async function generateStatusReportWithDependencies(dependencies = {}) {
|
|
|
25
25
|
auth,
|
|
26
26
|
skills,
|
|
27
27
|
updates,
|
|
28
|
+
...(options.skillId ? { skillId: options.skillId } : {}),
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
export function formatStatusReport(report) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postplus/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "PostPlus CLI for PostPlus Cloud auth, status, and diagnostics.",
|