@every-env/spiral-cli 1.0.1 → 1.0.2
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/package.json +1 -1
- package/src/api.ts +6 -0
- package/src/auth.ts +8 -1
- package/src/cli.ts +7 -2
- package/src/config.ts +7 -0
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -16,6 +16,12 @@ import {
|
|
|
16
16
|
const BASE_URL =
|
|
17
17
|
process.env["SPIRAL_API_URL"] || "https://api.writewithspiral.com";
|
|
18
18
|
|
|
19
|
+
if (BASE_URL.startsWith("http://") && !BASE_URL.includes("localhost")) {
|
|
20
|
+
console.error(
|
|
21
|
+
"[warning] SPIRAL_API_URL uses HTTP — your API key will be sent in plaintext.",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
interface FetchOptions extends RequestInit {
|
|
20
26
|
/** Skip auth header (for public endpoints like /prime). */
|
|
21
27
|
public?: boolean;
|
package/src/auth.ts
CHANGED
|
@@ -8,7 +8,14 @@ import { AuthenticationError } from "./types.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export function getAuthToken(): string {
|
|
10
10
|
const envToken = process.env["SPIRAL_TOKEN"];
|
|
11
|
-
if (envToken)
|
|
11
|
+
if (envToken) {
|
|
12
|
+
if (!envToken.startsWith("spiral_sk_")) {
|
|
13
|
+
console.error(
|
|
14
|
+
"[warning] SPIRAL_TOKEN does not start with spiral_sk_ — it may not be redacted from error messages.",
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return envToken;
|
|
18
|
+
}
|
|
12
19
|
|
|
13
20
|
const stored = getStoredAuth();
|
|
14
21
|
if (stored?.token) return stored.token;
|
package/src/cli.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type GenerateResponse,
|
|
16
16
|
} from "./types.js";
|
|
17
17
|
|
|
18
|
-
const VERSION = "1.0.
|
|
18
|
+
const VERSION = "1.0.2";
|
|
19
19
|
|
|
20
20
|
const HELP = `
|
|
21
21
|
${theme.heading("spiral")} — write with Spiral from your terminal
|
|
@@ -328,7 +328,12 @@ main().catch((err) => {
|
|
|
328
328
|
const msg = sanitizeError(err);
|
|
329
329
|
console.error(theme.error(`Unexpected error: ${msg}`));
|
|
330
330
|
if (process.argv.includes("--debug")) {
|
|
331
|
-
|
|
331
|
+
// Sanitize the full error to avoid leaking tokens in stack traces
|
|
332
|
+
const debugOutput = err instanceof Error ? sanitizeError(err) : String(err);
|
|
333
|
+
console.error(debugOutput);
|
|
334
|
+
if (err instanceof Error && err.stack) {
|
|
335
|
+
console.error(sanitizeError(new Error(err.stack)));
|
|
336
|
+
}
|
|
332
337
|
}
|
|
333
338
|
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
334
339
|
});
|
package/src/config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { chmodSync } from "node:fs";
|
|
1
2
|
import Conf from "conf";
|
|
2
3
|
|
|
3
4
|
interface AuthCredentials {
|
|
@@ -34,6 +35,12 @@ export function storeAuth(token: string): void {
|
|
|
34
35
|
tokenPrefix: token.slice(0, 14) + "...",
|
|
35
36
|
createdAt: new Date().toISOString(),
|
|
36
37
|
});
|
|
38
|
+
// Restrict config file to owner-only (contains PAT)
|
|
39
|
+
try {
|
|
40
|
+
chmodSync(config.path, 0o600);
|
|
41
|
+
} catch {
|
|
42
|
+
// Best-effort — may fail on some platforms
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
export function clearAuth(): void {
|