@postplus/cli 0.1.37 → 0.1.38

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.
@@ -1,33 +1,6 @@
1
1
  // Generated from the PostPlus Cloud hosted catalog release gate.
2
2
  // Keep keys in sync with apps/web hosted capability and collection catalogs.
3
3
  export const RESEARCH_COLLECTION_HINTS = {
4
- 'amazon-asins': {
5
- asins: ['B0C1234567'],
6
- country: 'US',
7
- },
8
- 'amazon-bestsellers': {
9
- categoryUrl: 'https://www.amazon.com/Best-Sellers/zgbs',
10
- maxItems: 5,
11
- },
12
- 'amazon-free-products': {
13
- keyword: 'portable blender',
14
- maxItems: 5,
15
- },
16
- 'amazon-products': {
17
- country: 'US',
18
- keyword: 'portable blender',
19
- maxItems: 5,
20
- },
21
- 'amazon-reviews': {
22
- asin: 'B0C1234567',
23
- country: 'US',
24
- maxReviews: 10,
25
- },
26
- 'amazon-reviews-v2': {
27
- asin: 'B0C1234567',
28
- domainCode: 'com',
29
- maxReviews: 10,
30
- },
31
4
  'google-trends-fast': {
32
5
  queries: ['portable blender'],
33
6
  },
@@ -97,13 +70,6 @@ export const RESEARCH_COLLECTION_HINTS = {
97
70
  'youtube-video-download': {
98
71
  urls: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
99
72
  },
100
- 'x-posts': {
101
- maxItems: 5,
102
- searchTerms: ['product launch'],
103
- },
104
- 'x-profiles': {
105
- handles: ['OpenAI'],
106
- },
107
73
  };
108
74
  export const PUBLIC_CONTENT_SOURCE_HINTS = {
109
75
  'facebook-group-posts': [
package/build/index.js CHANGED
@@ -9,7 +9,7 @@ import { readCurrentCliVersion } from './client-compatibility.js';
9
9
  import { formatDoctorReport, generateDoctorReport } from './doctor.js';
10
10
  import { runHostedDomainCommand } from './hosted-domain-commands.js';
11
11
  import { assertConfigFilePermissions } from './local-state.js';
12
- import { readLargeCreditQuoteConfirmationChallenge, resolveLargeCreditQuoteConfirmation, } from './quote-confirmation.js';
12
+ import { QUOTE_AUTO_CONFIRM_UNDER_ENV, QuoteAutoConfirmCeilingExceededError, QuoteConfirmationNonInteractiveError, confirmLargeCreditQuote, readLargeCreditQuoteConfirmationChallenge, resolveLargeCreditQuoteConfirmation, } from './quote-confirmation.js';
13
13
  import { POSTPLUS_SKILLS_CURRENT_DIRECTORY_INSTALL_COMMAND, POSTPLUS_SKILLS_INSTALL_COMMAND, formatPostPlusSkillsInstallCommand, loadPublicSkillCatalog, } from './skill-catalog.js';
14
14
  import { formatSkillBaselineVerifyReport, runPostPlusSkillUninstall, runPostPlusSkillUpdate, runPostPlusSkillVerify, } from './skill-management.js';
15
15
  import { formatStatusReport, generateStatusReport } from './status.js';
@@ -51,7 +51,7 @@ Usage:
51
51
  postplus publish capability --request <hosted-capability-request.json> [--output <result.json>]
52
52
  postplus mobile schema [--json]
53
53
  postplus mobile capability --request <hosted-capability-request.json> [--output <result.json>]
54
- postplus quote confirm --json --challenge-file <path>
54
+ postplus quote confirm --json --challenge-file <path> [--auto-confirm-under <millicredits>]
55
55
  postplus skills verify [--json]
56
56
  postplus studio init|open|status Open bundled Local Studio
57
57
  postplus update [--current-directory]
@@ -208,11 +208,46 @@ async function runQuoteCommand(rest) {
208
208
  process.stderr.write('Invalid large credit quote confirmation challenge.\n');
209
209
  return 1;
210
210
  }
211
- writeJson(await resolveLargeCreditQuoteConfirmation(challenge));
211
+ const ceilingMillicredits = resolveQuoteAutoConfirmCeiling(parsed.autoConfirmUnder);
212
+ try {
213
+ writeJson(await resolveLargeCreditQuoteConfirmation(challenge, {
214
+ confirm: confirmLargeCreditQuote,
215
+ ceilingMillicredits,
216
+ }));
217
+ }
218
+ catch (error) {
219
+ if (error instanceof QuoteAutoConfirmCeilingExceededError ||
220
+ error instanceof QuoteConfirmationNonInteractiveError) {
221
+ process.stderr.write(`${error.message}\n`);
222
+ return 1;
223
+ }
224
+ throw error;
225
+ }
212
226
  return 0;
213
227
  }
228
+ /**
229
+ * Resolves the bounded auto-confirm ceiling in millicredits. Precedence:
230
+ * explicit --auto-confirm-under flag, then the
231
+ * POSTPLUS_QUOTE_AUTO_CONFIRM_UNDER_MILLICREDITS env var. Returns null when
232
+ * neither is set, leaving today's interactive behavior unchanged.
233
+ */
234
+ function resolveQuoteAutoConfirmCeiling(flagValue) {
235
+ if (flagValue !== null) {
236
+ return flagValue;
237
+ }
238
+ const envValue = process.env[QUOTE_AUTO_CONFIRM_UNDER_ENV];
239
+ if (envValue === undefined || envValue.trim() === '') {
240
+ return null;
241
+ }
242
+ const parsed = Number(envValue);
243
+ if (!Number.isFinite(parsed) || parsed < 0) {
244
+ throw new Error(`Invalid ${QUOTE_AUTO_CONFIRM_UNDER_ENV}: expected a non-negative number of millicredits.`);
245
+ }
246
+ return parsed;
247
+ }
214
248
  function parseQuoteConfirmOptions(args) {
215
249
  const options = {
250
+ autoConfirmUnder: null,
216
251
  challengeFile: null,
217
252
  json: false,
218
253
  };
@@ -231,6 +266,19 @@ function parseQuoteConfirmOptions(args) {
231
266
  index += 1;
232
267
  continue;
233
268
  }
269
+ if (arg === '--auto-confirm-under') {
270
+ const rawValue = args[index + 1];
271
+ if (!rawValue || rawValue.startsWith('--')) {
272
+ throw new Error('Missing value for --auto-confirm-under.');
273
+ }
274
+ const value = Number(rawValue);
275
+ if (!Number.isFinite(value) || value < 0) {
276
+ throw new Error('Invalid value for --auto-confirm-under: expected a non-negative number of millicredits.');
277
+ }
278
+ options.autoConfirmUnder = value;
279
+ index += 1;
280
+ continue;
281
+ }
234
282
  throw new Error(`Unknown option for quote confirm: ${arg}`);
235
283
  }
236
284
  return options;
@@ -1,6 +1,50 @@
1
1
  import readline from 'node:readline/promises';
2
2
  import { readLocalConfig, updateLocalConfig } from './local-state.js';
3
3
  const PRODUCT_ERROR_CODE = 'postplus_cli_quote_confirmation_required';
4
+ export const QUOTE_AUTO_CONFIRM_CEILING_EXCEEDED_CODE = 'postplus_cli_quote_auto_confirm_ceiling_exceeded';
5
+ export const QUOTE_AUTO_CONFIRM_UNDER_ENV = 'POSTPLUS_QUOTE_AUTO_CONFIRM_UNDER_MILLICREDITS';
6
+ /**
7
+ * Thrown when a bounded auto-confirm ceiling is configured but the challenge
8
+ * cost exceeds it. Carries the original challenge so an orchestrator or human
9
+ * can confirm explicitly instead of the CLI hanging on a readline prompt.
10
+ */
11
+ export class QuoteAutoConfirmCeilingExceededError extends Error {
12
+ code = QUOTE_AUTO_CONFIRM_CEILING_EXCEEDED_CODE;
13
+ challenge;
14
+ ceilingMillicredits;
15
+ costMillicredits;
16
+ constructor(input) {
17
+ super(`Quote cost ${input.costMillicredits} millicredits exceeds the ` +
18
+ `auto-confirm ceiling of ${input.ceilingMillicredits} millicredits. ` +
19
+ 'Confirm explicitly or raise --auto-confirm-under / ' +
20
+ `${QUOTE_AUTO_CONFIRM_UNDER_ENV}.`);
21
+ this.name = 'QuoteAutoConfirmCeilingExceededError';
22
+ this.challenge = input.challenge;
23
+ this.ceilingMillicredits = input.ceilingMillicredits;
24
+ this.costMillicredits = input.costMillicredits;
25
+ }
26
+ }
27
+ /**
28
+ * Thrown when no auto-confirm ceiling is configured and stdin is not a TTY, so
29
+ * the interactive readline prompt would hang. Fails fast with an actionable
30
+ * message instead.
31
+ */
32
+ export class QuoteConfirmationNonInteractiveError extends Error {
33
+ code = 'postplus_cli_quote_confirmation_non_interactive';
34
+ challenge;
35
+ constructor(challenge) {
36
+ super('Quote confirmation required but stdin is not a TTY and no auto-confirm ' +
37
+ 'ceiling is configured. Pass --auto-confirm-under <millicredits>, set ' +
38
+ `${QUOTE_AUTO_CONFIRM_UNDER_ENV}, or run interactively.`);
39
+ this.name = 'QuoteConfirmationNonInteractiveError';
40
+ this.challenge = challenge;
41
+ }
42
+ }
43
+ function resolveChallengeCostMillicredits(challenge) {
44
+ return typeof challenge.estimatedMillicredits === 'number'
45
+ ? challenge.estimatedMillicredits
46
+ : challenge.requiredTierMillicredits;
47
+ }
4
48
  export function readLargeCreditQuoteConfirmationChallenge(value) {
5
49
  if (!value || typeof value !== 'object') {
6
50
  return null;
@@ -55,7 +99,7 @@ export async function resolveLargeCreditQuoteConfirmation(challenge, dependencie
55
99
  }) {
56
100
  const acknowledgedTierMillicredits = await readAcknowledgedTierMillicredits(challenge);
57
101
  if (acknowledgedTierMillicredits < challenge.requiredTierMillicredits) {
58
- await dependencies.confirm(challenge);
102
+ await runQuoteConfirmation(challenge, dependencies);
59
103
  await writeAcknowledgedTierMillicredits(challenge);
60
104
  }
61
105
  return {
@@ -63,6 +107,39 @@ export async function resolveLargeCreditQuoteConfirmation(challenge, dependencie
63
107
  token: challenge.token,
64
108
  };
65
109
  }
110
+ async function runQuoteConfirmation(challenge, dependencies) {
111
+ const ceiling = dependencies.ceilingMillicredits;
112
+ if (typeof ceiling === 'number' && Number.isFinite(ceiling)) {
113
+ const cost = resolveChallengeCostMillicredits(challenge);
114
+ if (cost > ceiling) {
115
+ throw new QuoteAutoConfirmCeilingExceededError({
116
+ challenge,
117
+ ceilingMillicredits: ceiling,
118
+ costMillicredits: cost,
119
+ });
120
+ }
121
+ const log = dependencies.logNotice ?? defaultLogNotice;
122
+ const now = (dependencies.now ?? (() => new Date()))();
123
+ log(JSON.stringify({
124
+ event: 'quote_auto_confirm',
125
+ timestamp: now.toISOString(),
126
+ accountId: challenge.accountId,
127
+ operationId: challenge.operationId,
128
+ costMillicredits: cost,
129
+ ceilingMillicredits: ceiling,
130
+ requiredTierMillicredits: challenge.requiredTierMillicredits,
131
+ }));
132
+ return;
133
+ }
134
+ const isTty = dependencies.isTty ?? (() => Boolean(process.stdin.isTTY));
135
+ if (!isTty()) {
136
+ throw new QuoteConfirmationNonInteractiveError(challenge);
137
+ }
138
+ await dependencies.confirm(challenge);
139
+ }
140
+ function defaultLogNotice(line) {
141
+ process.stderr.write(`${line}\n`);
142
+ }
66
143
  export async function confirmLargeCreditQuote(challenge) {
67
144
  const terminal = readline.createInterface({
68
145
  input: process.stdin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postplus/cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
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.",