promptdock 0.1.0 → 1.0.1-rc.8
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 +4 -1
- package/dist/api.js +24 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +31 -5
- package/dist/context.d.ts +11 -0
- package/dist/context.js +25 -1
- package/dist/help.js +1 -1
- package/package.json +27 -6
package/README.md
CHANGED
|
@@ -68,7 +68,10 @@ npx promptdock@latest install garry/seo-content-audit --target claude -y
|
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
- `PROMPTDOCK_TOKEN` — bearer token (overrides any stored login).
|
|
71
|
-
- `PROMPTDOCK_API_BASE` — API origin override (default `https://promptdock.ai`).
|
|
71
|
+
- `PROMPTDOCK_API_BASE` — API origin override (default `https://www.promptdock.ai`).
|
|
72
|
+
Must be the origin the API is **served** on. Pointing it at a host that redirects
|
|
73
|
+
will not work: a cross-origin redirect drops the request body and strips the
|
|
74
|
+
`Authorization` header, so the CLI refuses to follow one and tells you the target.
|
|
72
75
|
- Without `--target`/`--dir` **and** `-y`, a non-interactive install exits `1`
|
|
73
76
|
with the exact flags to add. Without a token it exits `2`.
|
|
74
77
|
- `NO_COLOR` is honored.
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { CliError, EXIT, networkError } from "./errors.js";
|
|
2
|
+
/** Origin of a Location header, for the "set PROMPTDOCK_API_BASE to …" hint. */
|
|
3
|
+
function originOf(location) {
|
|
4
|
+
try {
|
|
5
|
+
return new URL(location).origin;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return null; // relative Location — can't name an origin, fall back to the default
|
|
9
|
+
}
|
|
10
|
+
}
|
|
2
11
|
export class Api {
|
|
3
12
|
ctx;
|
|
4
13
|
baseUrl;
|
|
@@ -28,12 +37,27 @@ export class Api {
|
|
|
28
37
|
res = await this.ctx.fetch(`${this.baseUrl}${path}`, {
|
|
29
38
|
method,
|
|
30
39
|
headers: this.headers(body !== undefined),
|
|
40
|
+
// NEVER "follow" here. A cross-origin redirect silently downgrades POST to
|
|
41
|
+
// GET, drops the body, AND strips Authorization — so following one turns a
|
|
42
|
+
// misconfigured origin into a 405 or a bogus 401 with no hint of the cause.
|
|
43
|
+
// NEVER "error" either: that rejects with a TypeError, which the catch below
|
|
44
|
+
// would report as a connectivity failure — the opposite of the truth.
|
|
45
|
+
redirect: "manual",
|
|
31
46
|
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
32
47
|
});
|
|
33
48
|
}
|
|
34
49
|
catch {
|
|
35
50
|
throw networkError(this.baseUrl, this.ctx.env);
|
|
36
51
|
}
|
|
52
|
+
// Only the API client refuses redirects. Signed-URL downloads (installer.ts) use
|
|
53
|
+
// ctx.fetch directly and must keep following them — storage hands out redirects.
|
|
54
|
+
if (res.status >= 300 && res.status < 400) {
|
|
55
|
+
const to = res.headers.get("location") ?? "(no location header)";
|
|
56
|
+
throw new CliError(`${this.baseUrl} redirected to ${to} — the API must be called on its canonical origin, because a redirect drops the request body and the login token.`, EXIT.NETWORK, {
|
|
57
|
+
hint: `set PROMPTDOCK_API_BASE to the redirect target, e.g. PROMPTDOCK_API_BASE=${originOf(to) ?? "https://www.promptdock.ai"}`,
|
|
58
|
+
footer: "api",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
37
61
|
let parsed = null;
|
|
38
62
|
try {
|
|
39
63
|
parsed = await res.json();
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -5,7 +5,23 @@
|
|
|
5
5
|
import { chmodSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { CliError, EXIT } from "./errors.js";
|
|
8
|
-
|
|
8
|
+
// ⚠️ MUST be the host the API is actually SERVED on, not the brand apex.
|
|
9
|
+
// `promptdock.ai` 301-redirects to `www.promptdock.ai`, and Node's fetch follows
|
|
10
|
+
// that redirect ACROSS AN ORIGIN — which per the fetch spec (a) downgrades POST to
|
|
11
|
+
// GET and drops the body, and (b) STRIPS the `Authorization` header. Both, at any
|
|
12
|
+
// status code: a 308 preserves the method and still scrubs the bearer. So pointing
|
|
13
|
+
// this at the apex breaks every call — login POSTs answered with 405, and every
|
|
14
|
+
// authenticated GET arriving anonymous and answered 401. Keep this in lockstep with
|
|
15
|
+
// SITE_URL in lib/site-url.ts; `base-url.test.ts` fails the build if they diverge.
|
|
16
|
+
export const DEFAULT_API_BASE = "https://www.promptdock.ai";
|
|
17
|
+
/**
|
|
18
|
+
* Origins a PREVIOUS release persisted into ~/.promptdock/config.json and which are
|
|
19
|
+
* known-broken. A successful login writes `api_base`, and a stored value outranks
|
|
20
|
+
* DEFAULT_API_BASE — so without this, everyone who ever logged in with <=1.0.0 would
|
|
21
|
+
* keep hitting the apex forever, even after upgrading. Self-healing beats asking
|
|
22
|
+
* every user to log out.
|
|
23
|
+
*/
|
|
24
|
+
const LEGACY_API_BASES = new Set(["https://promptdock.ai", "http://promptdock.ai"]);
|
|
9
25
|
export function configDir(home) {
|
|
10
26
|
return join(home, ".promptdock");
|
|
11
27
|
}
|
|
@@ -56,9 +72,19 @@ export function saveConfig(home, config, platform) {
|
|
|
56
72
|
export function resolveToken(env, config) {
|
|
57
73
|
return env.PROMPTDOCK_TOKEN || (typeof config.token === "string" ? config.token : null) || null;
|
|
58
74
|
}
|
|
75
|
+
const trimBase = (s) => s.replace(/\/+$/, "");
|
|
76
|
+
// ⚠️ Login persists `api_base` ALONGSIDE the token, deliberately — do not "fix" this
|
|
77
|
+
// to skip persistence when the origin came from PROMPTDOCK_API_BASE. A token is
|
|
78
|
+
// minted by one specific database (prod and staging are separate Supabase projects),
|
|
79
|
+
// so the token and the origin are a PAIR. Storing the token without its origin means
|
|
80
|
+
// the next run sends a staging token to the default origin and 401s. The apex-pinning
|
|
81
|
+
// problem that motivated the idea is handled by LEGACY_API_BASES below instead.
|
|
59
82
|
export function resolveApiBase(env, config) {
|
|
60
|
-
|
|
61
|
-
(
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
if (env.PROMPTDOCK_API_BASE)
|
|
84
|
+
return trimBase(env.PROMPTDOCK_API_BASE);
|
|
85
|
+
const stored = typeof config.api_base === "string" ? trimBase(config.api_base) : null;
|
|
86
|
+
// Drop a base a broken release pinned here; anything else the user set is honoured.
|
|
87
|
+
if (stored && !LEGACY_API_BASES.has(stored))
|
|
88
|
+
return stored;
|
|
89
|
+
return trimBase(DEFAULT_API_BASE);
|
|
64
90
|
}
|
package/dist/context.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* argv joined for the `X-Promptdock-Cli-Args` header, with bearer tokens removed.
|
|
3
|
+
*
|
|
4
|
+
* That header rides EVERY request so the server can echo a copy-pasteable remedy in
|
|
5
|
+
* a 426. But the documented CI path is `promptdock login --token pdk_…`, so joining
|
|
6
|
+
* argv raw put the user's live secret in a custom header on every call — logged by
|
|
7
|
+
* every proxy in between, and (before the redirect fix) sent to whatever host the
|
|
8
|
+
* apex happened to redirect to. Redact the value, not the flag: the server's remedy
|
|
9
|
+
* still needs to show that `--token` was passed.
|
|
10
|
+
*/
|
|
11
|
+
export declare function redactArgs(argv: string[]): string;
|
|
1
12
|
/** I/O seam — commands never touch process.* directly (unit tests inject fakes). */
|
|
2
13
|
export type CliIo = {
|
|
3
14
|
/** stdout line */
|
package/dist/context.js
CHANGED
|
@@ -2,6 +2,30 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
|
+
/**
|
|
6
|
+
* argv joined for the `X-Promptdock-Cli-Args` header, with bearer tokens removed.
|
|
7
|
+
*
|
|
8
|
+
* That header rides EVERY request so the server can echo a copy-pasteable remedy in
|
|
9
|
+
* a 426. But the documented CI path is `promptdock login --token pdk_…`, so joining
|
|
10
|
+
* argv raw put the user's live secret in a custom header on every call — logged by
|
|
11
|
+
* every proxy in between, and (before the redirect fix) sent to whatever host the
|
|
12
|
+
* apex happened to redirect to. Redact the value, not the flag: the server's remedy
|
|
13
|
+
* still needs to show that `--token` was passed.
|
|
14
|
+
*/
|
|
15
|
+
export function redactArgs(argv) {
|
|
16
|
+
return argv
|
|
17
|
+
.map((a, i) => {
|
|
18
|
+
if (/^pdk_/.test(a))
|
|
19
|
+
return "pdk_***";
|
|
20
|
+
// `--token <value>` / `--token=<value>`
|
|
21
|
+
if (/^--token=/.test(a))
|
|
22
|
+
return "--token=***";
|
|
23
|
+
if (argv[i - 1] === "--token")
|
|
24
|
+
return "***";
|
|
25
|
+
return a;
|
|
26
|
+
})
|
|
27
|
+
.join(" ");
|
|
28
|
+
}
|
|
5
29
|
/** Read the package's own version (dist/ and src/ both sit one level under the root). */
|
|
6
30
|
export function readOwnVersion() {
|
|
7
31
|
try {
|
|
@@ -53,7 +77,7 @@ export function realContext(argv) {
|
|
|
53
77
|
platform: process.platform,
|
|
54
78
|
fetch: globalThis.fetch,
|
|
55
79
|
version: readOwnVersion(),
|
|
56
|
-
argsLine: argv
|
|
80
|
+
argsLine: redactArgs(argv),
|
|
57
81
|
now: () => Date.now(),
|
|
58
82
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
59
83
|
openUrl: (url) => openUrlBestEffort(url, process.platform),
|
package/dist/help.js
CHANGED
|
@@ -39,7 +39,7 @@ ${targets}
|
|
|
39
39
|
|
|
40
40
|
Environment
|
|
41
41
|
PROMPTDOCK_TOKEN bearer token for CI/non-interactive use (Settings → CLI sessions → Generate token)
|
|
42
|
-
PROMPTDOCK_API_BASE API origin override (default https://promptdock.ai)
|
|
42
|
+
PROMPTDOCK_API_BASE API origin override (default https://www.promptdock.ai)
|
|
43
43
|
NO_COLOR disable colored output
|
|
44
44
|
|
|
45
45
|
Exit codes
|
package/package.json
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "promptdock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "1.0.1-rc.8",
|
|
4
4
|
"description": "Install AI agent skills from PromptDock — npx promptdock@latest install <handle>/<slug>",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"promptdock",
|
|
7
|
+
"skills",
|
|
8
|
+
"ai",
|
|
9
|
+
"agents",
|
|
10
|
+
"claude",
|
|
11
|
+
"cli"
|
|
12
|
+
],
|
|
6
13
|
"homepage": "https://promptdock.ai",
|
|
7
|
-
"
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/klicklabs/promptdock.ai.git",
|
|
17
|
+
"directory": "packages/cli"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://promptdock.ai/docs/cli/errors"
|
|
21
|
+
},
|
|
8
22
|
"license": "UNLICENSED",
|
|
9
23
|
"type": "module",
|
|
10
|
-
"bin": {
|
|
11
|
-
|
|
12
|
-
|
|
24
|
+
"bin": {
|
|
25
|
+
"promptdock": "dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
13
34
|
"scripts": {
|
|
14
35
|
"build": "tsc -p tsconfig.json",
|
|
15
36
|
"test": "vitest run",
|