@postplus/cli 0.1.28 → 0.1.30

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/README.md CHANGED
@@ -24,7 +24,7 @@ PostPlus has three public surfaces that work together:
24
24
 
25
25
  - `https://postplus.io/`: the hosted product surface for account access, subscription state, and cloud-backed capabilities.
26
26
  - `https://github.com/PostPlusAI/postplus-skills`: the public skill repository that installs local marketing workflows into agent tools.
27
- - `https://github.com/PostPlusAI/postplus-cli`: the local command-line tool that signs you in, checks local readiness, and connects released skills to PostPlus account state.
27
+ - `https://github.com/PostPlusAI/postplus-cli`: the local command-line tool that signs you in, checks local readiness, confirms high-credit hosted requests, and connects released skills to PostPlus account state.
28
28
 
29
29
  ## Install
30
30
 
@@ -34,6 +34,7 @@ Requires Node.js and npm.
34
34
  npm install -g @postplus/cli@latest
35
35
  postplus auth login
36
36
  npx -y skills add PostPlusAI/postplus-skills --global --full-depth --skill '*' --agent claude-code codex cursor github-copilot windsurf trae trae-cn --yes
37
+ postplus skills verify
37
38
  ```
38
39
 
39
40
  Useful checks:
package/build/doctor.js CHANGED
@@ -166,6 +166,11 @@ async function checkHostedCapabilities(input, skillScope) {
166
166
  .map((value) => readCapabilityFailureLabel(value, skillScope))
167
167
  .filter((value) => value !== null);
168
168
  if (skillScope && hasHostedRequirements(skillScope.skill.requirements)) {
169
+ const subscription = readSubscriptionStatusField(payload).label;
170
+ if (requiresSocialPublishingPlan(skillScope.skill.requirements) &&
171
+ subscription === 'none') {
172
+ failedLabels.push(`PostPlus Plus or Pro plan required; current subscription ${subscription}`);
173
+ }
169
174
  const missingRequirements = collectMissingHostedRequirementLabels(relevantCapabilities, skillScope.skill.requirements);
170
175
  failedLabels.push(...missingRequirements);
171
176
  }
@@ -261,7 +266,7 @@ function capabilityMatchesRequirements(capability, requirements) {
261
266
  if (prefix &&
262
267
  suffix &&
263
268
  hostedCapabilities.has(prefix) &&
264
- requirementKeys.has(suffix)) {
269
+ (isWholeFamilyHostedCapability(prefix) || requirementKeys.has(suffix))) {
265
270
  return true;
266
271
  }
267
272
  return requirementKeys.has(identifier) || requirementKeys.has(suffix);
@@ -310,6 +315,12 @@ function collectHostedRequirementKeys(requirements) {
310
315
  ...requirements.sourceKeys,
311
316
  ]);
312
317
  }
318
+ function isWholeFamilyHostedCapability(prefix) {
319
+ return prefix === 'social-publishing';
320
+ }
321
+ function requiresSocialPublishingPlan(requirements) {
322
+ return requirements.hostedCapabilities.includes('social-publishing');
323
+ }
313
324
  function hasHostedRequirements(requirements) {
314
325
  return (requirements.accountConnections.length > 0 ||
315
326
  requirements.collectionKeys.length > 0 ||
@@ -337,6 +348,10 @@ function identifierMatchesKey(identifier, key) {
337
348
  if (identifier === key) {
338
349
  return true;
339
350
  }
351
+ if (key === 'social-publishing-workspace' &&
352
+ identifierMatchesCapability(identifier, 'social-publishing')) {
353
+ return true;
354
+ }
340
355
  const [, suffix] = splitCapabilityIdentifier(identifier);
341
356
  return suffix === key;
342
357
  }
package/build/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { readFile } from 'node:fs/promises';
2
3
  import { formatAuthRefreshReport, refreshRemoteAuth, revokeRemoteAuthAndReport, } from './auth-lifecycle.js';
3
4
  import { loginWithCloudHandoff } from './auth-login.js';
4
5
  import { formatAuthValidateReport, validateRemoteAuth, } from './auth-validate.js';
@@ -6,8 +7,9 @@ import { clearAuthState, formatAuthStatusReport, generateAuthStatusReport, } fro
6
7
  import { readCurrentCliVersion } from './client-compatibility.js';
7
8
  import { formatDoctorReport, generateDoctorReport } from './doctor.js';
8
9
  import { assertConfigFilePermissions } from './local-state.js';
10
+ import { readLargeCreditQuoteConfirmationChallenge, resolveLargeCreditQuoteConfirmation, } from './quote-confirmation.js';
9
11
  import { POSTPLUS_SKILLS_INSTALL_COMMAND, loadPublicSkillCatalog, } from './skill-catalog.js';
10
- import { runPostPlusSkillUninstall, runPostPlusSkillUpdate, } from './skill-management.js';
12
+ import { formatSkillBaselineVerifyReport, runPostPlusSkillUninstall, runPostPlusSkillUpdate, runPostPlusSkillVerify, } from './skill-management.js';
11
13
  import { formatStatusReport, generateStatusReport } from './status.js';
12
14
  import { refreshUpdateCheckCache, runCliSelfUpdateIfOutdated, } from './update-check.js';
13
15
  function printAuthHelp() {
@@ -38,6 +40,8 @@ Usage:
38
40
  postplus auth validate [--json]
39
41
  postplus auth logout [--json]
40
42
  postplus doctor [--skill <skill-id>] [--json]
43
+ postplus quote confirm --json --challenge-file <path>
44
+ postplus skills verify [--json]
41
45
  postplus update
42
46
  postplus uninstall
43
47
  postplus list [--json]
@@ -47,6 +51,9 @@ Usage:
47
51
 
48
52
  Skills:
49
53
  ${POSTPLUS_SKILLS_INSTALL_COMMAND}
54
+
55
+ After first install, run:
56
+ postplus skills verify
50
57
  `);
51
58
  }
52
59
  async function runDoctor(options) {
@@ -116,6 +123,90 @@ async function runSkillUpdateCommand() {
116
123
  async function runSkillUninstallCommand() {
117
124
  return runPostPlusSkillUninstall();
118
125
  }
126
+ async function runSkillsCommand(rest) {
127
+ const [subcommand] = rest;
128
+ switch (subcommand) {
129
+ case 'verify': {
130
+ const options = rest.slice(1);
131
+ const unknownOption = options.find((option) => option !== '--json');
132
+ if (unknownOption) {
133
+ process.stderr.write(`Unknown option for skills verify: ${unknownOption}\n`);
134
+ return 1;
135
+ }
136
+ const report = await runPostPlusSkillVerify();
137
+ if (options.includes('--json')) {
138
+ writeJson(report);
139
+ }
140
+ else {
141
+ process.stdout.write(`${formatSkillBaselineVerifyReport(report)}\n`);
142
+ }
143
+ return report.ok ? 0 : 1;
144
+ }
145
+ case 'help':
146
+ case '--help':
147
+ case '-h':
148
+ case undefined:
149
+ process.stdout.write(`PostPlus CLI — skills commands
150
+
151
+ Usage:
152
+ postplus skills verify [--json] Verify installed public skills and record the managed baseline
153
+
154
+ Options:
155
+ --json Output results as JSON
156
+ `);
157
+ return 0;
158
+ default:
159
+ process.stderr.write(`Unknown skills command: ${subcommand}\n`);
160
+ return 1;
161
+ }
162
+ }
163
+ async function runQuoteCommand(rest) {
164
+ const [subcommand, ...options] = rest;
165
+ if (subcommand !== 'confirm') {
166
+ process.stderr.write(`Unknown quote command: ${subcommand ?? ''}\n`);
167
+ return 1;
168
+ }
169
+ const parsed = parseQuoteConfirmOptions(options);
170
+ if (!parsed.json) {
171
+ process.stderr.write('quote confirm requires --json.\n');
172
+ return 1;
173
+ }
174
+ if (!parsed.challengeFile) {
175
+ process.stderr.write('quote confirm requires --challenge-file.\n');
176
+ return 1;
177
+ }
178
+ const challenge = readLargeCreditQuoteConfirmationChallenge(JSON.parse(await readFile(parsed.challengeFile, 'utf8')));
179
+ if (!challenge) {
180
+ process.stderr.write('Invalid large credit quote confirmation challenge.\n');
181
+ return 1;
182
+ }
183
+ writeJson(await resolveLargeCreditQuoteConfirmation(challenge));
184
+ return 0;
185
+ }
186
+ function parseQuoteConfirmOptions(args) {
187
+ const options = {
188
+ challengeFile: null,
189
+ json: false,
190
+ };
191
+ for (let index = 0; index < args.length; index += 1) {
192
+ const arg = args[index];
193
+ if (arg === '--json') {
194
+ options.json = true;
195
+ continue;
196
+ }
197
+ if (arg === '--challenge-file') {
198
+ const challengeFile = args[index + 1];
199
+ if (!challengeFile || challengeFile.startsWith('--')) {
200
+ throw new Error('Missing value for --challenge-file.');
201
+ }
202
+ options.challengeFile = challengeFile;
203
+ index += 1;
204
+ continue;
205
+ }
206
+ throw new Error(`Unknown option for quote confirm: ${arg}`);
207
+ }
208
+ return options;
209
+ }
119
210
  function writeJson(value) {
120
211
  process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
121
212
  }
@@ -215,6 +306,9 @@ async function main() {
215
306
  if (helpTopic === 'auth') {
216
307
  printAuthHelp();
217
308
  }
309
+ else if (helpTopic === 'skills') {
310
+ await runSkillsCommand(['help']);
311
+ }
218
312
  else {
219
313
  printHelp();
220
314
  }
@@ -224,6 +318,12 @@ async function main() {
224
318
  case 'doctor':
225
319
  process.exitCode = await runDoctor(parseDiagnosticOptions(rest));
226
320
  return;
321
+ case 'quote':
322
+ process.exitCode = await runQuoteCommand(rest);
323
+ return;
324
+ case 'skills':
325
+ process.exitCode = await runSkillsCommand(rest);
326
+ return;
227
327
  case 'install':
228
328
  process.stderr.write(`PostPlus CLI does not install skills directly. Run \`${POSTPLUS_SKILLS_INSTALL_COMMAND}\`.\n`);
229
329
  process.exitCode = 1;
@@ -0,0 +1,163 @@
1
+ import readline from 'node:readline/promises';
2
+ import { readLocalConfig, updateLocalConfig } from './local-state.js';
3
+ const PRODUCT_ERROR_CODE = 'postplus_cli_quote_confirmation_required';
4
+ export function readLargeCreditQuoteConfirmationChallenge(value) {
5
+ if (!value || typeof value !== 'object') {
6
+ return null;
7
+ }
8
+ const record = value;
9
+ const challenge = record.productErrorCode === PRODUCT_ERROR_CODE
10
+ ? record.quoteConfirmation
11
+ : record.quoteConfirmation && typeof record.quoteConfirmation === 'object'
12
+ ? record.quoteConfirmation
13
+ : value;
14
+ if (!challenge || typeof challenge !== 'object') {
15
+ return null;
16
+ }
17
+ const parsed = challenge;
18
+ if (typeof parsed.accountId !== 'string' ||
19
+ typeof parsed.action !== 'string' ||
20
+ typeof parsed.estimatedMillicredits !== 'number' ||
21
+ typeof parsed.featureLabel !== 'string' ||
22
+ typeof parsed.operationId !== 'string' ||
23
+ typeof parsed.requiredTierMillicredits !== 'number' ||
24
+ typeof parsed.reservedMillicredits !== 'number' ||
25
+ typeof parsed.serviceLabel !== 'string' ||
26
+ typeof parsed.token !== 'string') {
27
+ return null;
28
+ }
29
+ return {
30
+ accountId: parsed.accountId,
31
+ action: parsed.action,
32
+ billingUnit: typeof parsed.billingUnit === 'string' ? parsed.billingUnit : undefined,
33
+ drivers: parseDrivers(parsed.drivers),
34
+ estimatedCredits: typeof parsed.estimatedCredits === 'number'
35
+ ? parsed.estimatedCredits
36
+ : undefined,
37
+ estimatedMillicredits: parsed.estimatedMillicredits,
38
+ estimatedOnly: parsed.estimatedOnly === true,
39
+ featureLabel: parsed.featureLabel,
40
+ operationId: parsed.operationId,
41
+ requiredTierCredits: typeof parsed.requiredTierCredits === 'number'
42
+ ? parsed.requiredTierCredits
43
+ : undefined,
44
+ requiredTierMillicredits: parsed.requiredTierMillicredits,
45
+ reservedCredits: typeof parsed.reservedCredits === 'number'
46
+ ? parsed.reservedCredits
47
+ : undefined,
48
+ reservedMillicredits: parsed.reservedMillicredits,
49
+ serviceLabel: parsed.serviceLabel,
50
+ token: parsed.token,
51
+ };
52
+ }
53
+ export async function resolveLargeCreditQuoteConfirmation(challenge, dependencies = {
54
+ confirm: confirmLargeCreditQuote,
55
+ }) {
56
+ const acknowledgedTierMillicredits = await readAcknowledgedTierMillicredits(challenge);
57
+ if (acknowledgedTierMillicredits < challenge.requiredTierMillicredits) {
58
+ await dependencies.confirm(challenge);
59
+ await writeAcknowledgedTierMillicredits(challenge);
60
+ }
61
+ return {
62
+ schemaVersion: 1,
63
+ token: challenge.token,
64
+ };
65
+ }
66
+ export async function confirmLargeCreditQuote(challenge) {
67
+ const terminal = readline.createInterface({
68
+ input: process.stdin,
69
+ output: process.stderr,
70
+ });
71
+ try {
72
+ const answer = await terminal.question(buildLargeCreditConfirmationPrompt(challenge));
73
+ if (answer.trim() !== 'CONFIRM') {
74
+ throw new Error('Large credit charge was not confirmed.');
75
+ }
76
+ }
77
+ finally {
78
+ terminal.close();
79
+ }
80
+ }
81
+ export function buildLargeCreditConfirmationPrompt(challenge) {
82
+ const lines = [
83
+ '',
84
+ 'PostPlus large credit warning',
85
+ `This request crosses the ${formatCredits(challenge.requiredTierMillicredits)}-credit warning tier.`,
86
+ `Estimated charge: ${formatCredits(challenge.estimatedMillicredits)} credits${challenge.estimatedOnly ? ' (estimate)' : ''}.`,
87
+ `Reserved before execution: ${formatCredits(challenge.reservedMillicredits)} credits.`,
88
+ `Capability: ${formatText(challenge.featureLabel)} / ${formatText(challenge.action)}.`,
89
+ `Service: ${formatText(challenge.serviceLabel)}.`,
90
+ ];
91
+ const drivers = Array.isArray(challenge.drivers)
92
+ ? challenge.drivers.filter((driver) => {
93
+ return (driver &&
94
+ typeof driver === 'object' &&
95
+ typeof driver.label === 'string' &&
96
+ driver.value !== undefined &&
97
+ driver.value !== null);
98
+ })
99
+ : [];
100
+ if (drivers.length > 0) {
101
+ lines.push('High-credit drivers:');
102
+ for (const driver of drivers.slice(0, 8)) {
103
+ lines.push(`- ${driver.label}: ${String(driver.value)}`);
104
+ }
105
+ }
106
+ lines.push('PostPlus will warn again only when a future request crosses a higher tier.', 'Type CONFIRM to continue: ');
107
+ return lines.join('\n');
108
+ }
109
+ async function readAcknowledgedTierMillicredits(challenge) {
110
+ const config = await readLocalConfig();
111
+ const tier = config?.largeCreditConfirmation?.acknowledgedTierMillicreditsByAccountId?.[challenge.accountId];
112
+ return typeof tier === 'number' && Number.isSafeInteger(tier) && tier > 0
113
+ ? tier
114
+ : 0;
115
+ }
116
+ async function writeAcknowledgedTierMillicredits(challenge) {
117
+ await updateLocalConfig((current) => {
118
+ const config = current ?? {};
119
+ const largeCreditConfirmation = config.largeCreditConfirmation ?? {};
120
+ const currentTiers = largeCreditConfirmation.acknowledgedTierMillicreditsByAccountId ?? {};
121
+ const previousTier = currentTiers[challenge.accountId];
122
+ return {
123
+ ...config,
124
+ largeCreditConfirmation: {
125
+ ...largeCreditConfirmation,
126
+ acknowledgedTierMillicreditsByAccountId: {
127
+ ...currentTiers,
128
+ [challenge.accountId]: Math.max(typeof previousTier === 'number' &&
129
+ Number.isSafeInteger(previousTier)
130
+ ? previousTier
131
+ : 0, challenge.requiredTierMillicredits),
132
+ },
133
+ },
134
+ };
135
+ });
136
+ }
137
+ function parseDrivers(value) {
138
+ if (!Array.isArray(value)) {
139
+ return [];
140
+ }
141
+ return value
142
+ .filter((driver) => {
143
+ return Boolean(driver) && typeof driver === 'object';
144
+ })
145
+ .filter((driver) => typeof driver.label === 'string')
146
+ .map((driver) => ({
147
+ key: typeof driver.key === 'string' ? driver.key : undefined,
148
+ label: driver.label,
149
+ value: driver.value,
150
+ }));
151
+ }
152
+ function formatText(value) {
153
+ return value.trim() ? value : 'unknown';
154
+ }
155
+ function formatCredits(millicredits) {
156
+ const credits = millicredits / 1_000;
157
+ if (!Number.isFinite(credits)) {
158
+ return 'unknown';
159
+ }
160
+ return Number.isInteger(credits)
161
+ ? String(credits)
162
+ : credits.toFixed(3).replace(/0+$/, '').replace(/\.$/, '');
163
+ }
@@ -49,8 +49,38 @@ export async function runPostPlusSkillUninstall(dependencies = {
49
49
  export async function generateSkillInstallStatusReport(dependencies = {
50
50
  runCommand,
51
51
  }) {
52
+ return (await inspectPostPlusSkillInstall(dependencies)).report;
53
+ }
54
+ export async function runPostPlusSkillVerify(dependencies = {
55
+ runCommand,
56
+ }) {
57
+ const inspection = await inspectPostPlusSkillInstall(dependencies);
58
+ const previousManagedSkillsReleaseId = inspection.report.managedSkillsReleaseId;
59
+ if (!inspection.report.ok) {
60
+ return {
61
+ ...inspection.report,
62
+ baselineUpdated: false,
63
+ previousManagedSkillsReleaseId,
64
+ verifiedSkillsReleaseId: null,
65
+ };
66
+ }
67
+ await writeManagedSkillBaseline({
68
+ releaseId: inspection.catalog.releaseId,
69
+ skillNames: inspection.requiredSkillNames,
70
+ });
71
+ await writeCurrentCliVersionToLocalConfig();
72
+ return {
73
+ ...inspection.report,
74
+ baselineUpdated: true,
75
+ managedSkillsReleaseId: inspection.catalog.releaseId,
76
+ previousManagedSkillsReleaseId,
77
+ verifiedSkillsReleaseId: inspection.catalog.releaseId,
78
+ };
79
+ }
80
+ async function inspectPostPlusSkillInstall(dependencies) {
52
81
  const catalog = await loadPublicSkillCatalog();
53
- const requiredSkills = new Set(catalog.skills.map((skill) => skill.skillId));
82
+ const requiredSkillNames = catalog.skills.map((skill) => skill.skillId);
83
+ const requiredSkills = new Set(requiredSkillNames);
54
84
  const baseline = await readManagedSkillBaseline();
55
85
  const retiredManagedSkills = baseline.skillNames.filter((skillName) => !requiredSkills.has(skillName));
56
86
  try {
@@ -64,36 +94,44 @@ export async function generateSkillInstallStatusReport(dependencies = {
64
94
  .filter((scope) => scope.trim().length > 0)),
65
95
  ].sort();
66
96
  return {
67
- ok: missingSkills.length === 0,
68
- error: null,
69
- installCommand: formatPostPlusSkillsInstallCommand(catalog.source),
70
- installedCount: installedNames.size,
71
- managedSkillsReleaseId: baseline.releaseId,
72
- missingSkills,
73
- requiredCount: requiredSkills.size,
74
- retiredManagedSkills,
75
- scopes,
76
- source: catalog.source,
77
- updateCommand: formatPostPlusSkillUpdateCommand(),
78
- uninstallCommand: formatPostPlusSkillUninstallCommand(),
97
+ catalog,
98
+ report: {
99
+ ok: missingSkills.length === 0,
100
+ error: null,
101
+ installCommand: formatPostPlusSkillsInstallCommand(catalog.source),
102
+ installedCount: installedNames.size,
103
+ managedSkillsReleaseId: baseline.releaseId,
104
+ missingSkills,
105
+ requiredCount: requiredSkills.size,
106
+ retiredManagedSkills,
107
+ scopes,
108
+ source: catalog.source,
109
+ updateCommand: formatPostPlusSkillUpdateCommand(),
110
+ uninstallCommand: formatPostPlusSkillUninstallCommand(),
111
+ },
112
+ requiredSkillNames,
79
113
  };
80
114
  }
81
115
  catch (error) {
82
116
  return {
83
- ok: false,
84
- error: error instanceof Error
85
- ? error.message
86
- : 'Failed to inspect installed PostPlus skills.',
87
- installCommand: formatPostPlusSkillsInstallCommand(catalog.source),
88
- installedCount: 0,
89
- managedSkillsReleaseId: baseline.releaseId,
90
- missingSkills: [...requiredSkills],
91
- requiredCount: requiredSkills.size,
92
- retiredManagedSkills,
93
- scopes: [],
94
- source: catalog.source,
95
- updateCommand: formatPostPlusSkillUpdateCommand(),
96
- uninstallCommand: formatPostPlusSkillUninstallCommand(),
117
+ catalog,
118
+ report: {
119
+ ok: false,
120
+ error: error instanceof Error
121
+ ? error.message
122
+ : 'Failed to inspect installed PostPlus skills.',
123
+ installCommand: formatPostPlusSkillsInstallCommand(catalog.source),
124
+ installedCount: 0,
125
+ managedSkillsReleaseId: baseline.releaseId,
126
+ missingSkills: [...requiredSkills],
127
+ requiredCount: requiredSkills.size,
128
+ retiredManagedSkills,
129
+ scopes: [],
130
+ source: catalog.source,
131
+ updateCommand: formatPostPlusSkillUpdateCommand(),
132
+ uninstallCommand: formatPostPlusSkillUninstallCommand(),
133
+ },
134
+ requiredSkillNames,
97
135
  };
98
136
  }
99
137
  }
@@ -122,6 +160,31 @@ export function formatSkillInstallStatusReport(report) {
122
160
  }
123
161
  return lines.join('\n');
124
162
  }
163
+ export function formatSkillBaselineVerifyReport(report) {
164
+ const lines = ['PostPlus skills verify', ''];
165
+ if (report.error) {
166
+ lines.push(`[FAIL] Skill installer: ${report.error}`);
167
+ }
168
+ else if (report.ok) {
169
+ lines.push(`[PASS] Installed released skills: ${report.installedCount}/${report.requiredCount}`);
170
+ }
171
+ else {
172
+ lines.push(`[FAIL] Installed released skills: ${report.installedCount}/${report.requiredCount}`);
173
+ }
174
+ lines.push(` Source: ${report.source}`);
175
+ lines.push(` Previous managed baseline: ${report.previousManagedSkillsReleaseId ?? 'none'}`);
176
+ if (report.baselineUpdated && report.verifiedSkillsReleaseId) {
177
+ lines.push(` Verified baseline: ${report.verifiedSkillsReleaseId}`);
178
+ lines.push(' Next: postplus status');
179
+ }
180
+ else {
181
+ lines.push(' Verified baseline: unchanged');
182
+ }
183
+ if (report.missingSkills.length > 0) {
184
+ lines.push(` Missing: ${formatSkillList(report.missingSkills, 8)}`, ` Fix: ${report.installCommand}`);
185
+ }
186
+ return lines.join('\n');
187
+ }
125
188
  export function buildPostPlusSkillUpdateArgs(skillNames) {
126
189
  if (skillNames.length === 0) {
127
190
  throw new Error('PostPlus public skill catalog has no released skills.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postplus/cli",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
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.",
@@ -18,6 +18,7 @@
18
18
  "build/index.js",
19
19
  "build/local-dependencies.js",
20
20
  "build/local-state.js",
21
+ "build/quote-confirmation.js",
21
22
  "build/skill-catalog.js",
22
23
  "build/skill-management.js",
23
24
  "build/status.js",