@postplus/cli 0.1.7 → 0.1.9

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
@@ -1,8 +1,9 @@
1
1
  # PostPlus CLI
2
2
 
3
- `PostPlus CLI` signs you in to PostPlus Cloud and reports local account and
4
- hosted capability readiness. PostPlus skills are added from the public
5
- `postplus-skills` repository.
3
+ `PostPlus CLI` signs you in to PostPlus Cloud and reports local account,
4
+ subscription, and hosted capability readiness. An inactive or missing
5
+ subscription is reported as account state, not a status failure. PostPlus
6
+ skills are added from the public `postplus-skills` repository.
6
7
 
7
8
  ## Install
8
9
 
@@ -11,7 +12,7 @@ Requires Node.js `>=20.10.0` and npm.
11
12
  ```bash
12
13
  npm install -g @postplus/cli
13
14
  postplus auth login
14
- npx -y skills add PostPlusAI/postplus-skills --all
15
+ npx -y skills add PostPlusAI/postplus-skills --skill '*' --agent claude-code codex cursor --yes
15
16
  ```
16
17
 
17
18
  ## Commands
@@ -30,5 +31,5 @@ npx -y skills add PostPlusAI/postplus-skills --all
30
31
  installation commands. Use:
31
32
 
32
33
  ```bash
33
- npx -y skills add PostPlusAI/postplus-skills --all
34
+ npx -y skills add PostPlusAI/postplus-skills --skill '*' --agent claude-code codex cursor --yes
34
35
  ```
package/build/doctor.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { resolveHostedBaseUrl } from './hosted-release.js';
2
+ import { resolveAccessTokenState } from './local-state.js';
2
3
  function createPass(id, label, detail) {
3
4
  return {
4
5
  id,
@@ -7,16 +8,130 @@ function createPass(id, label, detail) {
7
8
  detail,
8
9
  };
9
10
  }
11
+ function createFail(id, label, detail, fix) {
12
+ return {
13
+ id,
14
+ label,
15
+ status: 'fail',
16
+ detail,
17
+ fix,
18
+ };
19
+ }
10
20
  export async function generateDoctorReport() {
11
21
  const hostedBaseUrl = await resolveHostedBaseUrl();
12
22
  const checks = [
13
23
  createPass('hosted_base_url', 'PostPlus Cloud', `Using ${hostedBaseUrl ?? 'https://postplus.io'}`),
14
24
  ];
25
+ const accessToken = await resolveAccessTokenState();
26
+ if (!hostedBaseUrl) {
27
+ 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`.'));
28
+ return buildDoctorReport(checks);
29
+ }
30
+ if (!accessToken.present || !accessToken.value) {
31
+ checks.push(createFail('remote_auth', 'Remote auth', 'No PostPlus CLI session is configured.', 'Run `postplus auth login`.'));
32
+ return buildDoctorReport(checks);
33
+ }
34
+ const authCheck = await checkRemoteAuth({
35
+ accessToken: accessToken.value,
36
+ hostedBaseUrl,
37
+ });
38
+ checks.push(authCheck);
39
+ if (authCheck.status === 'pass') {
40
+ checks.push(await checkHostedCapabilities({
41
+ accessToken: accessToken.value,
42
+ hostedBaseUrl,
43
+ }));
44
+ }
45
+ return buildDoctorReport(checks);
46
+ }
47
+ function buildDoctorReport(checks) {
15
48
  return {
16
49
  ok: checks.every((check) => check.status === 'pass'),
17
50
  checks,
18
51
  };
19
52
  }
53
+ async function checkRemoteAuth(input) {
54
+ try {
55
+ const response = await fetch(`${input.hostedBaseUrl}/api/postplus-cli/auth/whoami`, {
56
+ headers: {
57
+ accept: 'application/json',
58
+ authorization: `Bearer ${input.accessToken}`,
59
+ },
60
+ signal: AbortSignal.timeout(15000),
61
+ });
62
+ const payload = (await response.json());
63
+ if (!response.ok) {
64
+ return createFail('remote_auth', 'Remote auth', readErrorMessage(payload, 'PostPlus Cloud rejected the CLI session.'), 'Run `postplus auth login`.');
65
+ }
66
+ const accountId = typeof payload.accountId === 'string' ? payload.accountId : 'unknown';
67
+ const user = typeof payload.userEmail === 'string'
68
+ ? payload.userEmail
69
+ : typeof payload.userId === 'string'
70
+ ? payload.userId
71
+ : 'unknown';
72
+ const subscription = typeof payload.subscriptionStatus === 'string'
73
+ ? payload.subscriptionStatus
74
+ : 'unknown';
75
+ return createPass('remote_auth', 'Remote auth', `Account ${accountId}; user ${user}; subscription ${subscription}`);
76
+ }
77
+ catch (error) {
78
+ return createFail('remote_auth', 'Remote auth', error instanceof Error
79
+ ? error.message
80
+ : 'Failed to validate PostPlus Cloud auth.', 'Run `postplus auth validate` after confirming network access.');
81
+ }
82
+ }
83
+ async function checkHostedCapabilities(input) {
84
+ try {
85
+ const response = await fetch(`${input.hostedBaseUrl}/api/postplus-cli/hosted/readiness`, {
86
+ headers: {
87
+ accept: 'application/json',
88
+ authorization: `Bearer ${input.accessToken}`,
89
+ },
90
+ signal: AbortSignal.timeout(15000),
91
+ });
92
+ const payload = (await response.json());
93
+ if (!response.ok) {
94
+ return createFail('hosted_capabilities', 'Hosted capabilities', readErrorMessage(payload, 'PostPlus Cloud hosted readiness check failed.'));
95
+ }
96
+ const capabilities = Array.isArray(payload.capabilities)
97
+ ? payload.capabilities
98
+ : [];
99
+ const failedLabels = capabilities
100
+ .map(readCapabilityFailureLabel)
101
+ .filter((value) => value !== null);
102
+ if (payload.ok !== true || failedLabels.length > 0) {
103
+ return createFail('hosted_capabilities', 'Hosted capabilities', `Not ready: ${failedLabels.join(', ') || 'unknown capability failure'}`, 'Check PostPlus Cloud provider configuration and subscription state.');
104
+ }
105
+ const subscription = typeof payload.subscriptionStatus === 'string'
106
+ ? payload.subscriptionStatus
107
+ : 'unknown';
108
+ return createPass('hosted_capabilities', 'Hosted capabilities', `Ready (${capabilities.length} capability checks passed; subscription ${subscription})`);
109
+ }
110
+ catch (error) {
111
+ return createFail('hosted_capabilities', 'Hosted capabilities', error instanceof Error
112
+ ? error.message
113
+ : 'Failed to check hosted capability readiness.');
114
+ }
115
+ }
116
+ function readCapabilityFailureLabel(value) {
117
+ if (!value || typeof value !== 'object') {
118
+ return 'invalid capability response';
119
+ }
120
+ const record = value;
121
+ if (record.ok === true || record.required === false) {
122
+ return null;
123
+ }
124
+ return typeof record.label === 'string'
125
+ ? record.label
126
+ : typeof record.id === 'string'
127
+ ? record.id
128
+ : 'unknown capability';
129
+ }
130
+ function readErrorMessage(payload, fallback) {
131
+ return typeof payload.error === 'string' && payload.error.trim().length > 0
132
+ ? payload.error
133
+ : fallback;
134
+ }
20
135
  export function formatDoctorReport(report) {
21
136
  const lines = ['PostPlus CLI doctor', ''];
22
137
  for (const check of report.checks) {
@@ -1,5 +1,5 @@
1
1
  export const POSTPLUS_SKILLS_REPO = 'PostPlusAI/postplus-skills';
2
- export const POSTPLUS_SKILLS_INSTALL_COMMAND = 'npx -y skills add PostPlusAI/postplus-skills --all';
2
+ export const POSTPLUS_SKILLS_INSTALL_COMMAND = "npx -y skills add PostPlusAI/postplus-skills --skill '*' --agent claude-code codex cursor --yes";
3
3
  export const POSTPLUS_SKILLS_LIST_COMMAND = 'npx -y skills add PostPlusAI/postplus-skills --list';
4
4
  const POSTPLUS_SKILLS_INDEX_URL = 'https://raw.githubusercontent.com/PostPlusAI/postplus-skills/main/skills/INDEX.md';
5
5
  export async function loadPublicSkillCatalog() {
@@ -13,21 +13,27 @@ export async function loadPublicSkillCatalog() {
13
13
  throw new Error(`Failed to load PostPlus skill catalog (${response.status}): ${response.statusText}`);
14
14
  }
15
15
  const indexText = await response.text();
16
+ const skills = parseSkillIndex(indexText);
17
+ if (skills.length === 0) {
18
+ throw new Error('PostPlus public skill catalog is invalid: no released skills were found.');
19
+ }
16
20
  return {
17
21
  source: POSTPLUS_SKILLS_REPO,
18
22
  indexUrl: POSTPLUS_SKILLS_INDEX_URL,
19
23
  installCommand: POSTPLUS_SKILLS_INSTALL_COMMAND,
20
24
  listCommand: POSTPLUS_SKILLS_LIST_COMMAND,
21
- skills: parseSkillIndex(indexText),
25
+ skills,
22
26
  };
23
27
  }
24
28
  function parseSkillIndex(indexText) {
25
29
  const skills = [];
26
30
  let inReleasedSkills = false;
31
+ let sawReleasedSkillsSection = false;
27
32
  let currentSkill = null;
28
33
  for (const line of indexText.split('\n')) {
29
34
  if (line.trim() === '## Released Skills') {
30
35
  inReleasedSkills = true;
36
+ sawReleasedSkillsSection = true;
31
37
  continue;
32
38
  }
33
39
  if (!inReleasedSkills) {
@@ -52,5 +58,8 @@ function parseSkillIndex(indexText) {
52
58
  }
53
59
  }
54
60
  }
61
+ if (!sawReleasedSkillsSection) {
62
+ throw new Error('PostPlus public skill catalog is invalid: missing ## Released Skills section.');
63
+ }
55
64
  return skills;
56
65
  }
package/package.json CHANGED
@@ -1,12 +1,21 @@
1
1
  {
2
2
  "name": "@postplus/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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.",
7
7
  "license": "Apache-2.0",
8
8
  "files": [
9
- "build/**",
9
+ "build/auth-lifecycle.js",
10
+ "build/auth-login.js",
11
+ "build/auth-validate.js",
12
+ "build/auth.js",
13
+ "build/doctor.js",
14
+ "build/hosted-release.js",
15
+ "build/index.js",
16
+ "build/local-state.js",
17
+ "build/skill-catalog.js",
18
+ "build/status.js",
10
19
  "LICENSE",
11
20
  "NOTICE",
12
21
  "README.md"
@@ -22,7 +31,7 @@
22
31
  "postplus": "./build/index.js"
23
32
  },
24
33
  "scripts": {
25
- "build": "tsc",
34
+ "build": "node ./scripts/clean-build.mjs && tsc",
26
35
  "clean": "rm -rf .turbo node_modules build",
27
36
  "release:package": "node ./scripts/package-release.mjs",
28
37
  "start": "tsx src/index.ts",