pinsay-cli 0.9.1 → 0.10.0
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 +8 -2
- package/dist/cli.js +184 -244
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ npx pinsay-cli init
|
|
|
19
19
|
|---|---|
|
|
20
20
|
| `npx pinsay-cli init` | Set up this repo (sign in, project, skills; Chrome extension by default) |
|
|
21
21
|
| `npx pinsay-cli embed` | Put the widget in your app's code |
|
|
22
|
-
| `npx pinsay-cli login` / `whoami` / `logout` | Sign in; the key is saved in this repo (
|
|
22
|
+
| `npx pinsay-cli login` / `whoami` / `logout` | Sign in; the key is saved in this repo; check (account, workspace) / clear credentials |
|
|
23
23
|
| `npx pinsay-cli remove` | Remove everything PinSay added to this repo |
|
|
24
24
|
| `npx pinsay-cli status` | Who you are, this folder's project, comments waiting |
|
|
25
25
|
| `npx pinsay-cli open` | Open this project in the dashboard |
|
|
@@ -42,7 +42,7 @@ npx pinsay-cli init
|
|
|
42
42
|
|
|
43
43
|
## API keys
|
|
44
44
|
|
|
45
|
-
Keys look like `pnsy_` + 40 hex characters. They resolve in this order: `PINSAY_API_KEY` env var → `.pinsay/credentials.env`
|
|
45
|
+
Keys look like `pnsy_` + 40 hex characters. They resolve in this order: `PINSAY_API_KEY` env var → `.pinsay/credentials.env` (mode 0600, hidden from git). `init` and `login` save the key in the repo; there is no machine-wide key since 0.10.0, and `npx pinsay-cli update` deletes one an older version saved (`~/.config/pinsay/credentials.json`).
|
|
46
46
|
|
|
47
47
|
## MCP (Claude Code / Cursor)
|
|
48
48
|
|
|
@@ -62,6 +62,12 @@ Full guides: https://pinsay.dev/docs/ · Issues: https://github.com/moamen-ui/pi
|
|
|
62
62
|
|
|
63
63
|
## Changelog
|
|
64
64
|
|
|
65
|
+
### 0.10.0
|
|
66
|
+
|
|
67
|
+
- The API key lives only in the repo: `--global` (login, init, logout, remove) is gone, and a key saved on the machine is no longer read.
|
|
68
|
+
- `update` deletes the machine-wide key file an older version saved, and says which file it removed.
|
|
69
|
+
- `whoami` shows the workspace; `status` / `apply` say "Project … not found in workspace …" instead of a generic error.
|
|
70
|
+
|
|
65
71
|
### 0.9.1
|
|
66
72
|
|
|
67
73
|
- `remove` works when the repo sits behind a linked or shortened path (Windows junctions / short paths).
|
package/dist/cli.js
CHANGED
|
@@ -392,7 +392,7 @@ var init_build_constants = __esm({
|
|
|
392
392
|
"src/build-constants.ts"() {
|
|
393
393
|
"use strict";
|
|
394
394
|
BUILD_DEFAULT_SERVER = true ? "https://app.pinsay.dev" : "https://app.pinsay.dev";
|
|
395
|
-
BUILD_CLI_VERSION = true ? "0.
|
|
395
|
+
BUILD_CLI_VERSION = true ? "0.10.0" : "0.0.0-dev";
|
|
396
396
|
}
|
|
397
397
|
});
|
|
398
398
|
|
|
@@ -1424,6 +1424,10 @@ var init_api = __esm({
|
|
|
1424
1424
|
});
|
|
1425
1425
|
|
|
1426
1426
|
// src/errors.ts
|
|
1427
|
+
function projectNotFoundMessage(project, workspace) {
|
|
1428
|
+
const where = workspace ? `workspace ${workspace}` : "this workspace";
|
|
1429
|
+
return `Project "${project}" not found in ${where}. Sign in with an account in the project's workspace (npx pinsay-cli login), or fix the key in .pinsay/config.json.`;
|
|
1430
|
+
}
|
|
1427
1431
|
function isOutage(err) {
|
|
1428
1432
|
return err instanceof NetworkError || err instanceof ApiError && err.code >= 500;
|
|
1429
1433
|
}
|
|
@@ -1435,6 +1439,8 @@ function hostOf(server) {
|
|
|
1435
1439
|
}
|
|
1436
1440
|
}
|
|
1437
1441
|
function describeError(err, server) {
|
|
1442
|
+
if (err instanceof ProjectNotFoundError)
|
|
1443
|
+
return { code: 3, message: err.message };
|
|
1438
1444
|
if (err instanceof NetworkError) {
|
|
1439
1445
|
return { code: 4, message: `Can't reach ${err.host}. Check your internet connection and try again.` };
|
|
1440
1446
|
}
|
|
@@ -1463,12 +1469,21 @@ function reportFatal(err, opts) {
|
|
|
1463
1469
|
const { code, message } = describeError(err, opts.server);
|
|
1464
1470
|
exitWithError(code, message, opts.json);
|
|
1465
1471
|
}
|
|
1466
|
-
var ISSUES_URL;
|
|
1472
|
+
var ISSUES_URL, ProjectNotFoundError;
|
|
1467
1473
|
var init_errors = __esm({
|
|
1468
1474
|
"src/errors.ts"() {
|
|
1469
1475
|
"use strict";
|
|
1470
1476
|
init_api();
|
|
1471
1477
|
ISSUES_URL = "https://github.com/moamen-ui/pinsay-cli/issues";
|
|
1478
|
+
ProjectNotFoundError = class extends Error {
|
|
1479
|
+
constructor(project, workspace) {
|
|
1480
|
+
super(projectNotFoundMessage(project, workspace));
|
|
1481
|
+
this.project = project;
|
|
1482
|
+
this.workspace = workspace;
|
|
1483
|
+
this.name = "ProjectNotFoundError";
|
|
1484
|
+
}
|
|
1485
|
+
code = "not_found";
|
|
1486
|
+
};
|
|
1472
1487
|
}
|
|
1473
1488
|
});
|
|
1474
1489
|
|
|
@@ -1476,14 +1491,12 @@ var init_errors = __esm({
|
|
|
1476
1491
|
import { promises as fs10 } from "node:fs";
|
|
1477
1492
|
import { createHash } from "node:crypto";
|
|
1478
1493
|
import { homedir } from "node:os";
|
|
1479
|
-
import {
|
|
1494
|
+
import { dirname as dirname5, join as join9 } from "node:path";
|
|
1480
1495
|
function sourceLabel(source) {
|
|
1481
1496
|
if (source === "env")
|
|
1482
1497
|
return "env var";
|
|
1483
1498
|
if (source === "repo")
|
|
1484
1499
|
return "repo credentials.env";
|
|
1485
|
-
if (source === "global")
|
|
1486
|
-
return "global store";
|
|
1487
1500
|
return "none";
|
|
1488
1501
|
}
|
|
1489
1502
|
function normalizeServerOrigin(server) {
|
|
@@ -1512,6 +1525,38 @@ function legacyGlobalCredentialsPath() {
|
|
|
1512
1525
|
return void 0;
|
|
1513
1526
|
return join9(configBase(), LEGACY_DIR_NAME, "credentials.json");
|
|
1514
1527
|
}
|
|
1528
|
+
async function findMachineKeyFiles() {
|
|
1529
|
+
const found = [];
|
|
1530
|
+
const current = globalCredentialsPath();
|
|
1531
|
+
try {
|
|
1532
|
+
await fs10.access(current);
|
|
1533
|
+
found.push(current);
|
|
1534
|
+
} catch {
|
|
1535
|
+
}
|
|
1536
|
+
const legacy = legacyGlobalCredentialsPath();
|
|
1537
|
+
if (legacy) {
|
|
1538
|
+
try {
|
|
1539
|
+
if (isCredentialStore(JSON.parse(await fs10.readFile(legacy, "utf8"))))
|
|
1540
|
+
found.push(legacy);
|
|
1541
|
+
} catch {
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return found;
|
|
1545
|
+
}
|
|
1546
|
+
async function removeMachineKeyFiles() {
|
|
1547
|
+
const removed = [];
|
|
1548
|
+
for (const file of await findMachineKeyFiles()) {
|
|
1549
|
+
try {
|
|
1550
|
+
await fs10.rm(file);
|
|
1551
|
+
} catch {
|
|
1552
|
+
continue;
|
|
1553
|
+
}
|
|
1554
|
+
removed.push(file);
|
|
1555
|
+
await fs10.rmdir(dirname5(file)).catch(() => {
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
return removed;
|
|
1559
|
+
}
|
|
1515
1560
|
function globalCacheDir() {
|
|
1516
1561
|
if (process.env.PINSAY_CONFIG_DIR)
|
|
1517
1562
|
return join9(process.env.PINSAY_CONFIG_DIR, "cache");
|
|
@@ -1531,76 +1576,6 @@ function isCredentialStore(value) {
|
|
|
1531
1576
|
(entry) => !!entry && typeof entry === "object" && typeof entry.apiKey === "string"
|
|
1532
1577
|
);
|
|
1533
1578
|
}
|
|
1534
|
-
async function readGlobalStore() {
|
|
1535
|
-
let raw;
|
|
1536
|
-
try {
|
|
1537
|
-
raw = await fs10.readFile(globalCredentialsPath(), "utf8");
|
|
1538
|
-
} catch (err) {
|
|
1539
|
-
if (err?.code === "ENOENT")
|
|
1540
|
-
return migrateLegacyStore();
|
|
1541
|
-
return {};
|
|
1542
|
-
}
|
|
1543
|
-
try {
|
|
1544
|
-
const parsed = JSON.parse(raw);
|
|
1545
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
1546
|
-
} catch {
|
|
1547
|
-
return {};
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
async function migrateLegacyStore() {
|
|
1551
|
-
const legacyFile = legacyGlobalCredentialsPath();
|
|
1552
|
-
if (!legacyFile)
|
|
1553
|
-
return {};
|
|
1554
|
-
let legacy;
|
|
1555
|
-
try {
|
|
1556
|
-
legacy = JSON.parse(await fs10.readFile(legacyFile, "utf8"));
|
|
1557
|
-
} catch {
|
|
1558
|
-
return {};
|
|
1559
|
-
}
|
|
1560
|
-
if (!isCredentialStore(legacy))
|
|
1561
|
-
return {};
|
|
1562
|
-
try {
|
|
1563
|
-
await writeGlobalStore(legacy);
|
|
1564
|
-
} catch {
|
|
1565
|
-
return legacy;
|
|
1566
|
-
}
|
|
1567
|
-
await fs10.rm(legacyFile, { force: true }).catch(() => {
|
|
1568
|
-
});
|
|
1569
|
-
await fs10.rmdir(dirname5(legacyFile)).catch(() => {
|
|
1570
|
-
});
|
|
1571
|
-
return legacy;
|
|
1572
|
-
}
|
|
1573
|
-
async function writeGlobalStore(store) {
|
|
1574
|
-
const file = globalCredentialsPath();
|
|
1575
|
-
await fs10.mkdir(dirname5(file), { recursive: true });
|
|
1576
|
-
await fs10.writeFile(file, JSON.stringify(store, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
1577
|
-
await fs10.chmod(file, 384).catch(() => {
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1580
|
-
async function getGlobalCredential(server) {
|
|
1581
|
-
const store = await readGlobalStore();
|
|
1582
|
-
const origin = normalizeServerOrigin(server);
|
|
1583
|
-
if (!store[origin] && origin === "https://app.pinsay.dev")
|
|
1584
|
-
return store["https://api.pinsay.dev"];
|
|
1585
|
-
return store[origin];
|
|
1586
|
-
}
|
|
1587
|
-
async function saveGlobalCredential(server, entry) {
|
|
1588
|
-
const store = await readGlobalStore();
|
|
1589
|
-
store[normalizeServerOrigin(server)] = { ...entry, savedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1590
|
-
await writeGlobalStore(store);
|
|
1591
|
-
}
|
|
1592
|
-
async function removeGlobalCredential(server) {
|
|
1593
|
-
const store = await readGlobalStore();
|
|
1594
|
-
const origin = normalizeServerOrigin(server);
|
|
1595
|
-
const origins = origin === "https://app.pinsay.dev" ? [origin, "https://api.pinsay.dev"] : [origin];
|
|
1596
|
-
const present = origins.filter((o) => o in store);
|
|
1597
|
-
if (present.length === 0)
|
|
1598
|
-
return false;
|
|
1599
|
-
for (const o of present)
|
|
1600
|
-
delete store[o];
|
|
1601
|
-
await writeGlobalStore(store);
|
|
1602
|
-
return true;
|
|
1603
|
-
}
|
|
1604
1579
|
async function readRepoApiKey(root) {
|
|
1605
1580
|
try {
|
|
1606
1581
|
const raw = await fs10.readFile(join9(root, ".pinsay", "credentials.env"), "utf8");
|
|
@@ -1622,18 +1597,13 @@ async function removeRepoCredentials(root) {
|
|
|
1622
1597
|
await fs10.rm(file, { force: true });
|
|
1623
1598
|
return true;
|
|
1624
1599
|
}
|
|
1625
|
-
async function resolveApiKey(root,
|
|
1600
|
+
async function resolveApiKey(root, _server) {
|
|
1626
1601
|
const envKey = process.env.PINSAY_API_KEY?.trim();
|
|
1627
1602
|
if (envKey)
|
|
1628
1603
|
return { key: envKey, source: "env" };
|
|
1629
1604
|
const repoKey = await readRepoApiKey(root);
|
|
1630
1605
|
if (repoKey)
|
|
1631
1606
|
return { key: repoKey, source: "repo" };
|
|
1632
|
-
if (server) {
|
|
1633
|
-
const globalEntry = await getGlobalCredential(server);
|
|
1634
|
-
if (globalEntry?.apiKey)
|
|
1635
|
-
return { key: globalEntry.apiKey, source: "global" };
|
|
1636
|
-
}
|
|
1637
1607
|
return { key: void 0, source: null };
|
|
1638
1608
|
}
|
|
1639
1609
|
async function removeStaleRepoTokenCache(root) {
|
|
@@ -1676,6 +1646,31 @@ var init_server = __esm({
|
|
|
1676
1646
|
}
|
|
1677
1647
|
});
|
|
1678
1648
|
|
|
1649
|
+
// src/key-scope.ts
|
|
1650
|
+
function scopeFromFlags(options) {
|
|
1651
|
+
const raw = options["scope"];
|
|
1652
|
+
if (typeof raw === "string") {
|
|
1653
|
+
const value = raw.toLowerCase();
|
|
1654
|
+
if (value === "global")
|
|
1655
|
+
return { error: GLOBAL_KEY_REMOVED };
|
|
1656
|
+
if (value !== "repo")
|
|
1657
|
+
return { error: `Invalid --scope "${raw}". Valid value: repo.` };
|
|
1658
|
+
return { explicitRepo: true };
|
|
1659
|
+
}
|
|
1660
|
+
if (options["global"] === true)
|
|
1661
|
+
return { error: GLOBAL_KEY_REMOVED };
|
|
1662
|
+
if (options["local-credentials"] === true)
|
|
1663
|
+
return { explicitRepo: true };
|
|
1664
|
+
return {};
|
|
1665
|
+
}
|
|
1666
|
+
var GLOBAL_KEY_REMOVED;
|
|
1667
|
+
var init_key_scope = __esm({
|
|
1668
|
+
"src/key-scope.ts"() {
|
|
1669
|
+
"use strict";
|
|
1670
|
+
GLOBAL_KEY_REMOVED = "--global is no longer supported: the API key is saved in this repo only (.pinsay/credentials.env). Run npx pinsay-cli update to delete a machine-wide key an older version saved.";
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1679
1674
|
// src/ui/interactive.ts
|
|
1680
1675
|
function isInteractive(options = {}) {
|
|
1681
1676
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
@@ -2658,17 +2653,27 @@ async function fetchQueue(ctx, filter) {
|
|
|
2658
2653
|
};
|
|
2659
2654
|
});
|
|
2660
2655
|
} catch (err) {
|
|
2656
|
+
if (err instanceof ApiError && err.code === 404)
|
|
2657
|
+
throw new ProjectNotFoundError(ctx.project, ctx.workspaceName);
|
|
2661
2658
|
if (err instanceof ApiError && err.code === 403) {
|
|
2662
2659
|
if (!warnedNonAdminFallback) {
|
|
2663
2660
|
console.error("Note: predefined-action prompts need an admin key");
|
|
2664
2661
|
warnedNonAdminFallback = true;
|
|
2665
2662
|
}
|
|
2666
2663
|
const summaryQuery = `view=summary${qs ? `&${qs.slice(1)}` : ""}`;
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2664
|
+
let res;
|
|
2665
|
+
try {
|
|
2666
|
+
res = await api(
|
|
2667
|
+
ctx.server,
|
|
2668
|
+
`/api/projects/${encodeURIComponent(ctx.project)}/comments?${summaryQuery}`,
|
|
2669
|
+
{ token: ctx.token }
|
|
2670
|
+
);
|
|
2671
|
+
} catch (fallbackErr) {
|
|
2672
|
+
if (fallbackErr instanceof ApiError && fallbackErr.code === 404) {
|
|
2673
|
+
throw new ProjectNotFoundError(ctx.project, ctx.workspaceName);
|
|
2674
|
+
}
|
|
2675
|
+
throw fallbackErr;
|
|
2676
|
+
}
|
|
2672
2677
|
const items = res?.items ?? [];
|
|
2673
2678
|
return items.map((item) => ({
|
|
2674
2679
|
id: item.id,
|
|
@@ -2705,6 +2710,7 @@ var init_queue = __esm({
|
|
|
2705
2710
|
"src/apply/queue.ts"() {
|
|
2706
2711
|
"use strict";
|
|
2707
2712
|
init_api();
|
|
2713
|
+
init_errors();
|
|
2708
2714
|
warnedNonAdminFallback = false;
|
|
2709
2715
|
}
|
|
2710
2716
|
});
|
|
@@ -3081,7 +3087,7 @@ async function overviewCommand(cwd2, options) {
|
|
|
3081
3087
|
for (const p of projects) {
|
|
3082
3088
|
const name = projectNames[p.key] || p.key;
|
|
3083
3089
|
const items = await fetchQueue(
|
|
3084
|
-
{ server, project: p.key, token, apiKey: key, cwd: root },
|
|
3090
|
+
{ server, project: p.key, token, apiKey: key, cwd: root, workspaceName: me?.tenantName || void 0 },
|
|
3085
3091
|
{}
|
|
3086
3092
|
);
|
|
3087
3093
|
projectsWithPending.push({
|
|
@@ -3109,8 +3115,6 @@ async function overviewCommand(cwd2, options) {
|
|
|
3109
3115
|
let sourceDesc = "key from this repo";
|
|
3110
3116
|
if (source === "env") {
|
|
3111
3117
|
sourceDesc = "key from PINSAY_API_KEY";
|
|
3112
|
-
} else if (source === "global") {
|
|
3113
|
-
sourceDesc = "key from this machine";
|
|
3114
3118
|
}
|
|
3115
3119
|
const who = email ? `${displayName} (${email})` : displayName;
|
|
3116
3120
|
console.log(` Signed in ${who} ${sym.dot} ${sourceDesc}`);
|
|
@@ -3497,7 +3501,7 @@ async function writableInsideRoot(root, abs) {
|
|
|
3497
3501
|
return false;
|
|
3498
3502
|
}
|
|
3499
3503
|
}
|
|
3500
|
-
async function collectRemovals(root
|
|
3504
|
+
async function collectRemovals(root) {
|
|
3501
3505
|
const config = await readConfig(root);
|
|
3502
3506
|
const removals = [];
|
|
3503
3507
|
if (await pathExists(join28(root, ".pinsay"))) {
|
|
@@ -3544,9 +3548,6 @@ async function collectRemovals(root, opts) {
|
|
|
3544
3548
|
}
|
|
3545
3549
|
}
|
|
3546
3550
|
}
|
|
3547
|
-
if (opts.global) {
|
|
3548
|
-
removals.push({ kind: "global-key", target: normalizeServerOrigin(opts.server) });
|
|
3549
|
-
}
|
|
3550
3551
|
const byHand = [];
|
|
3551
3552
|
for (const appDir of appDirs) {
|
|
3552
3553
|
for (const name of VITE_CONFIGS2) {
|
|
@@ -3585,13 +3586,11 @@ async function removeEmptyParents(root, abs) {
|
|
|
3585
3586
|
}
|
|
3586
3587
|
async function removeCommand(cwd2, options) {
|
|
3587
3588
|
const json = options["json"] === true;
|
|
3589
|
+
if (options["global"] === true)
|
|
3590
|
+
exitWithError(2, GLOBAL_KEY_REMOVED, json);
|
|
3588
3591
|
const interactive = isInteractive(options);
|
|
3589
|
-
const server = resolveServer();
|
|
3590
3592
|
const root = await findRepoRoot(cwd2);
|
|
3591
|
-
const { removals, byHand, tracked } = await collectRemovals(root
|
|
3592
|
-
global: options["global"] === true,
|
|
3593
|
-
server
|
|
3594
|
-
});
|
|
3593
|
+
const { removals, byHand, tracked } = await collectRemovals(root);
|
|
3595
3594
|
if (removals.length === 0) {
|
|
3596
3595
|
if (json)
|
|
3597
3596
|
console.log(JSON.stringify({ ok: true, removed: [] }));
|
|
@@ -3602,7 +3601,7 @@ async function removeCommand(cwd2, options) {
|
|
|
3602
3601
|
if (!json) {
|
|
3603
3602
|
console.log("Will remove:");
|
|
3604
3603
|
for (const r of removals) {
|
|
3605
|
-
const reason = r.kind === "exclude-block" || r.kind === "html-block" ? " (PinSay block)" : r.kind === "env-lines" ? " (VITE_PINSAY_* lines)" :
|
|
3604
|
+
const reason = r.kind === "exclude-block" || r.kind === "html-block" ? " (PinSay block)" : r.kind === "env-lines" ? " (VITE_PINSAY_* lines)" : "";
|
|
3606
3605
|
console.log(` ${r.target}${reason ? dim(reason) : ""}`);
|
|
3607
3606
|
}
|
|
3608
3607
|
if (byHand.length > 0) {
|
|
@@ -3680,8 +3679,6 @@ async function removeCommand(cwd2, options) {
|
|
|
3680
3679
|
if (!abs)
|
|
3681
3680
|
continue;
|
|
3682
3681
|
await fs25.rm(abs, { recursive: true, force: true });
|
|
3683
|
-
} else if (r.kind === "global-key") {
|
|
3684
|
-
await removeGlobalCredential(server);
|
|
3685
3682
|
}
|
|
3686
3683
|
}
|
|
3687
3684
|
if (json)
|
|
@@ -3697,8 +3694,7 @@ var init_remove = __esm({
|
|
|
3697
3694
|
"use strict";
|
|
3698
3695
|
init_git_exclude();
|
|
3699
3696
|
init_config();
|
|
3700
|
-
|
|
3701
|
-
init_server();
|
|
3697
|
+
init_key_scope();
|
|
3702
3698
|
init_errors();
|
|
3703
3699
|
init_interactive();
|
|
3704
3700
|
init_prompt();
|
|
@@ -4262,7 +4258,7 @@ async function runInitChecks(cwd2, overrides = {}, cliVersion = "0.0.0") {
|
|
|
4262
4258
|
checks.push({
|
|
4263
4259
|
id: "key",
|
|
4264
4260
|
status: "error",
|
|
4265
|
-
message: "No API key found (env
|
|
4261
|
+
message: "No API key found (env var or this repo)",
|
|
4266
4262
|
hint: "Run `npx pinsay-cli login`"
|
|
4267
4263
|
});
|
|
4268
4264
|
} else if (!serverReachable) {
|
|
@@ -5118,25 +5114,7 @@ async function detectDesignTokens(cwd2, options) {
|
|
|
5118
5114
|
|
|
5119
5115
|
// src/commands/init.ts
|
|
5120
5116
|
init_credentials();
|
|
5121
|
-
|
|
5122
|
-
// src/key-scope.ts
|
|
5123
|
-
function scopeFromFlags(options) {
|
|
5124
|
-
const raw = options["scope"];
|
|
5125
|
-
if (typeof raw === "string") {
|
|
5126
|
-
const value = raw.toLowerCase();
|
|
5127
|
-
if (value !== "global" && value !== "repo") {
|
|
5128
|
-
return { error: `Invalid --scope "${raw}". Valid values: global, repo.` };
|
|
5129
|
-
}
|
|
5130
|
-
return { scope: value };
|
|
5131
|
-
}
|
|
5132
|
-
if (options["global"] === true)
|
|
5133
|
-
return { scope: "global" };
|
|
5134
|
-
if (options["local-credentials"] === true)
|
|
5135
|
-
return { scope: "repo" };
|
|
5136
|
-
return {};
|
|
5137
|
-
}
|
|
5138
|
-
|
|
5139
|
-
// src/commands/init.ts
|
|
5117
|
+
init_key_scope();
|
|
5140
5118
|
init_server();
|
|
5141
5119
|
init_errors();
|
|
5142
5120
|
init_style();
|
|
@@ -5468,18 +5446,13 @@ function accountText(plan) {
|
|
|
5468
5446
|
if (account.keySaved === "repo") {
|
|
5469
5447
|
return `${account.displayName} \xB7 key saved in this repo (.pinsay/credentials.env, hidden from git)`;
|
|
5470
5448
|
}
|
|
5471
|
-
if (account.keySaved === "global") {
|
|
5472
|
-
return `${account.displayName} \xB7 key saved on this machine (${account.globalPath})`;
|
|
5473
|
-
}
|
|
5474
5449
|
if (account.existingSource === "env")
|
|
5475
5450
|
return `${account.displayName} \xB7 key from PINSAY_API_KEY`;
|
|
5476
|
-
if (account.existingSource === "global")
|
|
5477
|
-
return `${account.displayName} \xB7 key already saved on this machine`;
|
|
5478
5451
|
return `${account.displayName} \xB7 key already saved in this repo`;
|
|
5479
5452
|
}
|
|
5480
5453
|
if (account.kind === "pending")
|
|
5481
5454
|
return "you'll sign in in your browser";
|
|
5482
|
-
const where = account.source === "env" ? "PINSAY_API_KEY" :
|
|
5455
|
+
const where = account.source === "env" ? "PINSAY_API_KEY" : "this repo";
|
|
5483
5456
|
return `key found (${where}), not checked in a dry run`;
|
|
5484
5457
|
}
|
|
5485
5458
|
function sharedText(plan) {
|
|
@@ -5715,21 +5688,14 @@ async function decideWidget(cwd2, options, config, ctx) {
|
|
|
5715
5688
|
const w = await findExistingWidget(cwd2, config.htmlPath);
|
|
5716
5689
|
return w ? { widget: { kind: "already", file: w.file } } : { widget: { kind: "extension" } };
|
|
5717
5690
|
}
|
|
5718
|
-
function keyPlacement(session
|
|
5719
|
-
if (session.origin === "env" || session.origin === "repo"
|
|
5691
|
+
function keyPlacement(session) {
|
|
5692
|
+
if (session.origin === "env" || session.origin === "repo")
|
|
5720
5693
|
return "existing";
|
|
5721
|
-
return
|
|
5694
|
+
return "repo";
|
|
5722
5695
|
}
|
|
5723
|
-
async function saveKey(cwd2,
|
|
5724
|
-
if (keySaved === "repo")
|
|
5696
|
+
async function saveKey(cwd2, session, keySaved, project) {
|
|
5697
|
+
if (keySaved === "repo")
|
|
5725
5698
|
await writeCredentials(cwd2, session.key, project ? { project } : {});
|
|
5726
|
-
} else if (keySaved === "global") {
|
|
5727
|
-
await saveGlobalCredential(server, {
|
|
5728
|
-
apiKey: session.key,
|
|
5729
|
-
email: session.me.email,
|
|
5730
|
-
displayName: session.me.displayName
|
|
5731
|
-
});
|
|
5732
|
-
}
|
|
5733
5699
|
}
|
|
5734
5700
|
async function readStackNames(cwd2) {
|
|
5735
5701
|
const pkgStr = await fs17.readFile(join17(cwd2, "package.json"), "utf8").catch(() => "{}");
|
|
@@ -5766,7 +5732,6 @@ async function initCommand(cwd2, options = {}) {
|
|
|
5766
5732
|
const scopeResult = scopeFromFlags(options);
|
|
5767
5733
|
if (scopeResult.error)
|
|
5768
5734
|
exitWithError(2, scopeResult.error, json);
|
|
5769
|
-
const saveGlobal = scopeResult.scope === "global";
|
|
5770
5735
|
const shareResult = shareFromFlags(options);
|
|
5771
5736
|
if (shareResult.error)
|
|
5772
5737
|
exitWithError(2, shareResult.error, json);
|
|
@@ -5828,7 +5793,6 @@ async function initCommand(cwd2, options = {}) {
|
|
|
5828
5793
|
product,
|
|
5829
5794
|
pathFlag,
|
|
5830
5795
|
configIsMulti,
|
|
5831
|
-
saveGlobal,
|
|
5832
5796
|
share: shareResult.share,
|
|
5833
5797
|
wantEmbed,
|
|
5834
5798
|
notes
|
|
@@ -5852,7 +5816,7 @@ async function initCommand(cwd2, options = {}) {
|
|
|
5852
5816
|
const files2 = [
|
|
5853
5817
|
".pinsay/config.json",
|
|
5854
5818
|
".pinsay/stack.json",
|
|
5855
|
-
...account.kind === "pending"
|
|
5819
|
+
...account.kind === "pending" ? [".pinsay/credentials.env"] : [],
|
|
5856
5820
|
...widget2.kind === "embed" ? widget2.files : [],
|
|
5857
5821
|
".git/info/exclude (PinSay block)"
|
|
5858
5822
|
];
|
|
@@ -5889,7 +5853,7 @@ async function initCommand(cwd2, options = {}) {
|
|
|
5889
5853
|
});
|
|
5890
5854
|
if (!json)
|
|
5891
5855
|
console.log(`${green(sym.check)} Signed in as ${session.me.displayName}`);
|
|
5892
|
-
const keySaved = keyPlacement(session
|
|
5856
|
+
const keySaved = keyPlacement(session);
|
|
5893
5857
|
if (isJoin && configIsMulti) {
|
|
5894
5858
|
await handleMultiJoin({
|
|
5895
5859
|
cwd: cwd2,
|
|
@@ -5963,8 +5927,7 @@ async function initCommand(cwd2, options = {}) {
|
|
|
5963
5927
|
kind: "signed-in",
|
|
5964
5928
|
displayName: session.me.displayName,
|
|
5965
5929
|
keySaved,
|
|
5966
|
-
existingSource: session.origin === "env" || session.origin === "repo"
|
|
5967
|
-
globalPath: globalCredentialsPath()
|
|
5930
|
+
existingSource: session.origin === "env" || session.origin === "repo" ? session.origin : void 0
|
|
5968
5931
|
},
|
|
5969
5932
|
widget,
|
|
5970
5933
|
skills,
|
|
@@ -6031,7 +5994,7 @@ async function initCommand(cwd2, options = {}) {
|
|
|
6031
5994
|
let htmlPath;
|
|
6032
5995
|
if (keySaved !== "existing") {
|
|
6033
5996
|
progress.step("Saving your key");
|
|
6034
|
-
await saveKey(cwd2,
|
|
5997
|
+
await saveKey(cwd2, session, keySaved, project.key);
|
|
6035
5998
|
if (keySaved === "repo")
|
|
6036
5999
|
filesMod.push(".pinsay/credentials.env");
|
|
6037
6000
|
}
|
|
@@ -6257,12 +6220,11 @@ function planAccount(session, keySaved) {
|
|
|
6257
6220
|
kind: "signed-in",
|
|
6258
6221
|
displayName: session.me.displayName,
|
|
6259
6222
|
keySaved,
|
|
6260
|
-
existingSource: session.origin === "env" || session.origin === "repo"
|
|
6261
|
-
globalPath: globalCredentialsPath()
|
|
6223
|
+
existingSource: session.origin === "env" || session.origin === "repo" ? session.origin : void 0
|
|
6262
6224
|
};
|
|
6263
6225
|
}
|
|
6264
6226
|
async function multiDryRun(args) {
|
|
6265
|
-
const { cwd: cwd2, config, options, server, json, interactive, product, pathFlag, configIsMulti,
|
|
6227
|
+
const { cwd: cwd2, config, options, server, json, interactive, product, pathFlag, configIsMulti, wantEmbed } = args;
|
|
6266
6228
|
const flagTool = typeof options["tool"] === "string" ? options["tool"] : void 0;
|
|
6267
6229
|
const resolved = await resolveApiKey(cwd2, server);
|
|
6268
6230
|
const account = resolved.key && resolved.source ? { kind: "found", source: resolved.source } : { kind: "pending" };
|
|
@@ -6270,7 +6232,7 @@ async function multiDryRun(args) {
|
|
|
6270
6232
|
const tool = tools[0];
|
|
6271
6233
|
const names = pathFlag ? await readAppStackNames(cwd2, [pathFlag]) : await readAppStackNames(cwd2, listProjects(config).map((p) => p.path));
|
|
6272
6234
|
const shared2 = args.share !== void 0 ? { decided: true, share: args.share, saved: false, ...names, aiTools: tools } : typeof config.shareStack === "boolean" ? { decided: true, share: config.shareStack, saved: true, ...names, aiTools: tools } : interactive ? { decided: false, share: true, saved: false, ...names, aiTools: tools } : { decided: true, share: true, saved: false, ...names, aiTools: tools };
|
|
6273
|
-
const keyFile = account.kind === "pending"
|
|
6235
|
+
const keyFile = account.kind === "pending" ? [".pinsay/credentials.env"] : [];
|
|
6274
6236
|
let plan;
|
|
6275
6237
|
let projectLine;
|
|
6276
6238
|
if (pathFlag) {
|
|
@@ -6485,7 +6447,7 @@ async function handleMultiJoin(args) {
|
|
|
6485
6447
|
const progress = createProgress(labels.length, progressMode(isJson));
|
|
6486
6448
|
if (keySaved !== "existing") {
|
|
6487
6449
|
progress.step("Saving your key");
|
|
6488
|
-
await saveKey(cwd2,
|
|
6450
|
+
await saveKey(cwd2, session, keySaved);
|
|
6489
6451
|
}
|
|
6490
6452
|
const skillWarnings = [];
|
|
6491
6453
|
const hide = [];
|
|
@@ -6655,7 +6617,7 @@ async function handleMultiProjectSetup(args) {
|
|
|
6655
6617
|
const progress = createProgress(labels.length, progressMode(isJson));
|
|
6656
6618
|
if (keySaved !== "existing") {
|
|
6657
6619
|
progress.step("Saving your key");
|
|
6658
|
-
await saveKey(cwd2,
|
|
6620
|
+
await saveKey(cwd2, session, keySaved);
|
|
6659
6621
|
}
|
|
6660
6622
|
const skillWarnings = [];
|
|
6661
6623
|
const hide = [];
|
|
@@ -6957,6 +6919,7 @@ init_repo_paths();
|
|
|
6957
6919
|
init_server();
|
|
6958
6920
|
init_git_exclude();
|
|
6959
6921
|
init_style();
|
|
6922
|
+
init_credentials();
|
|
6960
6923
|
function sourceFor(path) {
|
|
6961
6924
|
if (path.includes("pinsay-init"))
|
|
6962
6925
|
return "/pinsay-init.md";
|
|
@@ -6980,6 +6943,17 @@ async function updateCommand(cwd2, options) {
|
|
|
6980
6943
|
const note = pinsayShNote(cwd2);
|
|
6981
6944
|
if (note)
|
|
6982
6945
|
console.log(dim(note));
|
|
6946
|
+
if (options.check) {
|
|
6947
|
+
for (const f of await findMachineKeyFiles())
|
|
6948
|
+
console.log(`machine-wide key found: ${f} (update deletes it)`);
|
|
6949
|
+
} else {
|
|
6950
|
+
const removedKeys = await removeMachineKeyFiles();
|
|
6951
|
+
for (const f of removedKeys)
|
|
6952
|
+
console.log(`removed machine-wide key ${f}`);
|
|
6953
|
+
if (removedKeys.length > 0 && !(await resolveApiKey(cwd2)).key) {
|
|
6954
|
+
console.log("This repo has no key of its own yet. Sign in for it: npx pinsay-cli login");
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6983
6957
|
const config = await readConfig(cwd2);
|
|
6984
6958
|
const server = (options.server || resolveServer()).replace(/\/$/, "");
|
|
6985
6959
|
if (!config.project && !isMultiProject(config)) {
|
|
@@ -8018,7 +7992,7 @@ init_projection();
|
|
|
8018
7992
|
init_server();
|
|
8019
7993
|
async function exitIfWorkspaceFrozen(server, token) {
|
|
8020
7994
|
if (!token)
|
|
8021
|
-
return;
|
|
7995
|
+
return void 0;
|
|
8022
7996
|
try {
|
|
8023
7997
|
const me = await api(server, "/api/auth/me", { token });
|
|
8024
7998
|
if (me?.workspaceDeletionScheduledFor) {
|
|
@@ -8032,7 +8006,9 @@ async function exitIfWorkspaceFrozen(server, token) {
|
|
|
8032
8006
|
);
|
|
8033
8007
|
process.exit(2);
|
|
8034
8008
|
}
|
|
8009
|
+
return me?.tenantName || void 0;
|
|
8035
8010
|
} catch {
|
|
8011
|
+
return void 0;
|
|
8036
8012
|
}
|
|
8037
8013
|
}
|
|
8038
8014
|
async function checkMetaAndNotify(server, config, root, parsed) {
|
|
@@ -8114,13 +8090,14 @@ async function applyCommand(cwd2, parsed, positionals = []) {
|
|
|
8114
8090
|
);
|
|
8115
8091
|
process.exit(3);
|
|
8116
8092
|
}
|
|
8117
|
-
await exitIfWorkspaceFrozen(server, token);
|
|
8093
|
+
const workspaceName = await exitIfWorkspaceFrozen(server, token);
|
|
8118
8094
|
const clientCtx = {
|
|
8119
8095
|
server,
|
|
8120
8096
|
project,
|
|
8121
8097
|
token,
|
|
8122
8098
|
apiKey,
|
|
8123
|
-
cwd: root
|
|
8099
|
+
cwd: root,
|
|
8100
|
+
workspaceName
|
|
8124
8101
|
};
|
|
8125
8102
|
if (parsed["mark"] !== void 0) {
|
|
8126
8103
|
const markVal2 = parsed["mark"];
|
|
@@ -8246,7 +8223,7 @@ async function applyAllProjects(root, cwd2, config, server, parsed) {
|
|
|
8246
8223
|
);
|
|
8247
8224
|
process.exit(3);
|
|
8248
8225
|
}
|
|
8249
|
-
await exitIfWorkspaceFrozen(server, token);
|
|
8226
|
+
const workspaceName = await exitIfWorkspaceFrozen(server, token);
|
|
8250
8227
|
const projects = listProjects(config);
|
|
8251
8228
|
const plan = parsed["plan"] === true;
|
|
8252
8229
|
const status = typeof parsed["status"] === "string" ? parsed["status"] : void 0;
|
|
@@ -8254,7 +8231,7 @@ async function applyAllProjects(root, cwd2, config, server, parsed) {
|
|
|
8254
8231
|
if (parsed["json"] === true && !plan) {
|
|
8255
8232
|
const all = [];
|
|
8256
8233
|
for (const p of projects) {
|
|
8257
|
-
const clientCtx = { server, project: p.key, token, apiKey, cwd: root };
|
|
8234
|
+
const clientCtx = { server, project: p.key, token, apiKey, cwd: root, workspaceName };
|
|
8258
8235
|
const items = await fetchQueue(clientCtx, { status, environment });
|
|
8259
8236
|
all.push({ project: p.key, path: p.path, items: items.map((item) => toAiCommentView(item)) });
|
|
8260
8237
|
}
|
|
@@ -8263,7 +8240,7 @@ async function applyAllProjects(root, cwd2, config, server, parsed) {
|
|
|
8263
8240
|
}
|
|
8264
8241
|
const sections = [];
|
|
8265
8242
|
for (const p of projects) {
|
|
8266
|
-
const clientCtx = { server, project: p.key, token, apiKey, cwd: root };
|
|
8243
|
+
const clientCtx = { server, project: p.key, token, apiKey, cwd: root, workspaceName };
|
|
8267
8244
|
const result = await runApply({ plan, status, environment }, clientCtx);
|
|
8268
8245
|
sections.push(`# Project: ${p.key} (${p.path})
|
|
8269
8246
|
|
|
@@ -14690,8 +14667,8 @@ init_git_exclude();
|
|
|
14690
14667
|
import { existsSync as existsSync7 } from "node:fs";
|
|
14691
14668
|
import { join as join26 } from "node:path";
|
|
14692
14669
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
14693
|
-
init_credentials();
|
|
14694
14670
|
init_prompt();
|
|
14671
|
+
init_key_scope();
|
|
14695
14672
|
init_server();
|
|
14696
14673
|
init_device_login();
|
|
14697
14674
|
init_errors();
|
|
@@ -14710,11 +14687,13 @@ async function loginCommand(cwd2, options = {}) {
|
|
|
14710
14687
|
if (flags.error)
|
|
14711
14688
|
exitWithError(2, flags.error, json);
|
|
14712
14689
|
const root = await findRepoRoot(cwd2);
|
|
14690
|
+
const inRepo = existsSync7(join26(root, ".pinsay")) || inGitRepo(root);
|
|
14691
|
+
if (!inRepo && !flags.explicitRepo) {
|
|
14692
|
+
exitWithError(2, "Run this inside your project's repo: the key is saved there (.pinsay/credentials.env).", json);
|
|
14693
|
+
}
|
|
14713
14694
|
const server = resolveServer();
|
|
14714
14695
|
const branding = await getBranding(server);
|
|
14715
14696
|
const product = branding.productName;
|
|
14716
|
-
const inRepo = existsSync7(join26(root, ".pinsay")) || inGitRepo(root);
|
|
14717
|
-
const scope = flags.scope ?? (inRepo ? "repo" : "global");
|
|
14718
14697
|
let flagKey = typeof options["key"] === "string" ? options["key"].trim() : "";
|
|
14719
14698
|
if (options["key"] === true) {
|
|
14720
14699
|
if (!process.stdin.isTTY)
|
|
@@ -14723,24 +14702,6 @@ async function loginCommand(cwd2, options = {}) {
|
|
|
14723
14702
|
if (!flagKey)
|
|
14724
14703
|
exitWithError(2, noKeyMessage(product), json);
|
|
14725
14704
|
}
|
|
14726
|
-
if (scope === "global" && !flagKey) {
|
|
14727
|
-
const repoKey = await readRepoApiKey(root);
|
|
14728
|
-
if (repoKey) {
|
|
14729
|
-
try {
|
|
14730
|
-
const { me } = await exchangeKey(server, repoKey);
|
|
14731
|
-
await saveGlobalCredential(server, { apiKey: repoKey, email: me.email, displayName: me.displayName });
|
|
14732
|
-
await removeRepoCredentials(root);
|
|
14733
|
-
done(
|
|
14734
|
-
json,
|
|
14735
|
-
{ server, scope: "global", moved: true, displayName: me.displayName, email: me.email },
|
|
14736
|
-
`${green(sym.check)} Moved your key to this machine's store (${globalCredentialsPath()}). Every repo on this machine can use it now.`
|
|
14737
|
-
);
|
|
14738
|
-
} catch (err) {
|
|
14739
|
-
if (!(err instanceof InvalidKeyError))
|
|
14740
|
-
throw err;
|
|
14741
|
-
}
|
|
14742
|
-
}
|
|
14743
|
-
}
|
|
14744
14705
|
let key;
|
|
14745
14706
|
let displayName;
|
|
14746
14707
|
let email;
|
|
@@ -14768,23 +14729,15 @@ async function loginCommand(cwd2, options = {}) {
|
|
|
14768
14729
|
}
|
|
14769
14730
|
closePrompts();
|
|
14770
14731
|
const who = displayName ? `${displayName}${email ? ` (${email})` : ""}` : email ?? "you";
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
console.error(line);
|
|
14777
|
-
done(
|
|
14778
|
-
json,
|
|
14779
|
-
{ server, scope: "repo", moved: false, displayName, email },
|
|
14780
|
-
`${green(sym.check)} Signed in as ${who}. Key saved in this repo (.pinsay/credentials.env, hidden from git).`
|
|
14781
|
-
);
|
|
14782
|
-
}
|
|
14783
|
-
await saveGlobalCredential(server, { apiKey: key, email, displayName });
|
|
14732
|
+
await writeCredentials(root, key);
|
|
14733
|
+
const hideWarnings = formatHideWarnings(await hidePinsayFiles(root));
|
|
14734
|
+
if (!json)
|
|
14735
|
+
for (const line of hideWarnings)
|
|
14736
|
+
console.error(line);
|
|
14784
14737
|
done(
|
|
14785
14738
|
json,
|
|
14786
|
-
{ server, scope: "
|
|
14787
|
-
|
|
14739
|
+
{ server, scope: "repo", moved: false, displayName, email },
|
|
14740
|
+
`${green(sym.check)} Signed in as ${who}. Key saved in this repo (.pinsay/credentials.env, hidden from git).`
|
|
14788
14741
|
);
|
|
14789
14742
|
}
|
|
14790
14743
|
function done(json, payload, message) {
|
|
@@ -14798,35 +14751,33 @@ function done(json, payload, message) {
|
|
|
14798
14751
|
// src/commands/logout.ts
|
|
14799
14752
|
init_config();
|
|
14800
14753
|
init_credentials();
|
|
14754
|
+
init_key_scope();
|
|
14801
14755
|
init_server();
|
|
14756
|
+
init_errors();
|
|
14802
14757
|
init_style();
|
|
14803
14758
|
var ENV_KEY_MESSAGE = "Your key comes from the PINSAY_API_KEY variable. Unset it to sign out.";
|
|
14804
14759
|
async function logoutCommand(cwd2, options = {}) {
|
|
14805
14760
|
const json = options["json"] === true;
|
|
14761
|
+
const flags = scopeFromFlags(options);
|
|
14762
|
+
if (flags.error)
|
|
14763
|
+
exitWithError(2, flags.error, json);
|
|
14806
14764
|
const server = resolveServer();
|
|
14807
14765
|
const origin = normalizeServerOrigin(server);
|
|
14808
14766
|
const root = await findRepoRoot(cwd2);
|
|
14809
|
-
const finish = (source,
|
|
14767
|
+
const finish = (source, removed, message) => {
|
|
14810
14768
|
if (json)
|
|
14811
|
-
console.log(JSON.stringify({ ok: true, server: origin, source, removed
|
|
14769
|
+
console.log(JSON.stringify({ ok: true, server: origin, source, removed }));
|
|
14812
14770
|
else
|
|
14813
14771
|
console.log(message);
|
|
14814
14772
|
process.exit(0);
|
|
14815
14773
|
};
|
|
14816
|
-
|
|
14817
|
-
if (!isGlobal && process.env.PINSAY_API_KEY?.trim()) {
|
|
14774
|
+
if (process.env.PINSAY_API_KEY?.trim())
|
|
14818
14775
|
finish("env", false, ENV_KEY_MESSAGE);
|
|
14776
|
+
if (await readRepoApiKey(root)) {
|
|
14777
|
+
const removed = await removeRepoCredentials(root);
|
|
14778
|
+
finish("repo", removed, `${green(sym.check)} Signed out: removed this repo's key (.pinsay/credentials.env).`);
|
|
14819
14779
|
}
|
|
14820
|
-
|
|
14821
|
-
const removed2 = await removeRepoCredentials(root);
|
|
14822
|
-
finish("repo", removed2, `${green(sym.check)} Signed out: removed this repo's key (.pinsay/credentials.env).`);
|
|
14823
|
-
}
|
|
14824
|
-
const removed = await removeGlobalCredential(server);
|
|
14825
|
-
finish(
|
|
14826
|
-
"global",
|
|
14827
|
-
removed,
|
|
14828
|
-
removed ? `${green(sym.check)} Removed the saved key for ${origin} from this machine.` : `No saved key for ${origin} on this machine.`
|
|
14829
|
-
);
|
|
14780
|
+
finish("repo", false, "No key saved in this repo.");
|
|
14830
14781
|
}
|
|
14831
14782
|
|
|
14832
14783
|
// src/commands/whoami.ts
|
|
@@ -14843,33 +14794,31 @@ async function whoamiCommand(cwd2, options = {}) {
|
|
|
14843
14794
|
if (isJson) {
|
|
14844
14795
|
console.log(JSON.stringify({ ok: false, server, source: null }));
|
|
14845
14796
|
} else {
|
|
14846
|
-
console.error(`No API key found for ${server} (checked
|
|
14797
|
+
console.error(`No API key found for ${server} (checked PINSAY_API_KEY and this repo's .pinsay/credentials.env).`);
|
|
14847
14798
|
console.error("Run `npx pinsay-cli login` to sign in.");
|
|
14848
14799
|
}
|
|
14849
14800
|
process.exit(3);
|
|
14850
14801
|
}
|
|
14851
14802
|
let displayName;
|
|
14852
14803
|
let email;
|
|
14804
|
+
let workspace;
|
|
14853
14805
|
try {
|
|
14854
14806
|
const login = await api(server, "/api/auth/login-with-key", { method: "POST", body: { apiKey: key } });
|
|
14855
14807
|
if (login?.status === "ok" && login.token) {
|
|
14856
|
-
const me =
|
|
14857
|
-
displayName = me?.displayName;
|
|
14858
|
-
email = me?.email;
|
|
14808
|
+
const me = await api(server, "/api/auth/me", { token: login.token });
|
|
14809
|
+
displayName = me?.displayName || void 0;
|
|
14810
|
+
email = me?.email || void 0;
|
|
14811
|
+
workspace = me?.tenantName || void 0;
|
|
14859
14812
|
}
|
|
14860
14813
|
} catch {
|
|
14861
14814
|
}
|
|
14862
|
-
if (source === "global" && (!displayName || !email)) {
|
|
14863
|
-
const cached = await getGlobalCredential(server);
|
|
14864
|
-
displayName = displayName ?? cached?.displayName;
|
|
14865
|
-
email = email ?? cached?.email;
|
|
14866
|
-
}
|
|
14867
14815
|
if (isJson) {
|
|
14868
|
-
console.log(JSON.stringify({ ok: true, server, displayName, email, source }));
|
|
14816
|
+
console.log(JSON.stringify({ ok: true, server, displayName, email, workspace: workspace ?? null, source }));
|
|
14869
14817
|
process.exit(0);
|
|
14870
14818
|
}
|
|
14871
14819
|
const who = displayName ? `${displayName}${email ? ` (${email})` : ""}` : email ?? "unknown user";
|
|
14872
|
-
|
|
14820
|
+
const where = workspace ? ` \u2014 workspace: ${workspace}` : "";
|
|
14821
|
+
console.log(`${server} \u2014 ${who}${where} \u2014 key source: ${sourceLabel(source)}`);
|
|
14873
14822
|
process.exit(0);
|
|
14874
14823
|
}
|
|
14875
14824
|
|
|
@@ -14905,6 +14854,7 @@ function parseArgs(args) {
|
|
|
14905
14854
|
// 0.9.0
|
|
14906
14855
|
"embed",
|
|
14907
14856
|
"global",
|
|
14857
|
+
// rejected since 0.10.0 (key-scope.ts); kept so it never takes the next argument
|
|
14908
14858
|
"share-stack",
|
|
14909
14859
|
"no-share-stack",
|
|
14910
14860
|
"no-color",
|
|
@@ -14942,7 +14892,7 @@ var HELP = `Usage: npx pinsay-cli <command> [options]
|
|
|
14942
14892
|
Set up
|
|
14943
14893
|
init Set up this repo (sign in, project, skills)
|
|
14944
14894
|
embed Put the widget in your app's code
|
|
14945
|
-
login Sign in; the key is saved in this repo
|
|
14895
|
+
login Sign in; the key is saved in this repo
|
|
14946
14896
|
logout Remove the key this repo uses
|
|
14947
14897
|
remove Remove everything PinSay added to this repo
|
|
14948
14898
|
Daily
|
|
@@ -14954,10 +14904,10 @@ Daily
|
|
|
14954
14904
|
reply Reply to a comment
|
|
14955
14905
|
Tools
|
|
14956
14906
|
doctor Check this install and fix what it can
|
|
14957
|
-
update Refresh the AI skills
|
|
14907
|
+
update Refresh the AI skills; delete an old machine-wide key
|
|
14958
14908
|
map Rebuild the source map without a build
|
|
14959
14909
|
mcp Start the MCP server for AI tools
|
|
14960
|
-
whoami Show the signed-in account and
|
|
14910
|
+
whoami Show the signed-in account, workspace and key source
|
|
14961
14911
|
|
|
14962
14912
|
Run npx pinsay-cli <command> --help for examples.
|
|
14963
14913
|
Flags: --no-color No colours or styling (also NO_COLOR=1)
|
|
@@ -14988,7 +14938,6 @@ var HELP_TEXTS = {
|
|
|
14988
14938
|
["--dry-run", "Show the plan; write and send nothing"],
|
|
14989
14939
|
["--path <app>", "The app folder, in a repo with several apps"],
|
|
14990
14940
|
["--key <key>", "Sign in with this key instead of the browser"],
|
|
14991
|
-
["--global", "Save the key on this machine (repo is the default)"],
|
|
14992
14941
|
["--no-browser", "Print the sign-in link; don't open a browser"],
|
|
14993
14942
|
["--tool <tool>", "AI tool for the skills (asked when omitted)"],
|
|
14994
14943
|
["--skills-dir <path>", "Where the skills are installed"],
|
|
@@ -15001,7 +14950,7 @@ var HELP_TEXTS = {
|
|
|
15001
14950
|
["--no-share-stack", "Share nothing about this app's stack"],
|
|
15002
14951
|
["--delivery <embed|extension>", "How reviewers open the widget", true],
|
|
15003
14952
|
["--no-inject", "Skip injection (use --embed or --html)", true],
|
|
15004
|
-
["--scope
|
|
14953
|
+
["--scope repo", "Old spelling; the key is always saved in this repo", true],
|
|
15005
14954
|
["--local-credentials", "Alias of --scope repo", true],
|
|
15006
14955
|
["--no-color", "No colours or styling (also NO_COLOR=1)"]
|
|
15007
14956
|
],
|
|
@@ -15040,45 +14989,39 @@ var HELP_TEXTS = {
|
|
|
15040
14989
|
]
|
|
15041
14990
|
},
|
|
15042
14991
|
login: {
|
|
15043
|
-
purpose: "Sign in; the key is saved in this repo
|
|
14992
|
+
purpose: "Sign in; the key is saved in this repo",
|
|
15044
14993
|
usage: "npx pinsay-cli login [options]",
|
|
15045
14994
|
common: [
|
|
15046
14995
|
["--key <key>", "Validate a pasted key; skip the browser"],
|
|
15047
|
-
["--global", "Save the key on this machine, not this repo"],
|
|
15048
14996
|
["--no-browser", "Print the sign-in link; don't open a browser"],
|
|
15049
14997
|
["--json", "Machine-readable output"]
|
|
15050
14998
|
],
|
|
15051
14999
|
all: [
|
|
15052
15000
|
["--key <key>", "Validate a pasted key; skip the browser"],
|
|
15053
|
-
["--global", "Save the key on this machine, not this repo"],
|
|
15054
15001
|
["--no-browser", "Print the sign-in link; don't open a browser"],
|
|
15055
15002
|
["--json", "Machine-readable output"],
|
|
15056
|
-
["--scope
|
|
15003
|
+
["--scope repo", "Old spelling; the key is always saved in this repo", true],
|
|
15057
15004
|
["--local-credentials", "Alias of --scope repo", true],
|
|
15058
15005
|
["--no-color", "No colours or styling (also NO_COLOR=1)"]
|
|
15059
15006
|
],
|
|
15060
15007
|
examples: [
|
|
15061
15008
|
["npx pinsay-cli login", "Open the browser; save the key in this repo"],
|
|
15062
|
-
["npx pinsay-cli login --global", "Save the key on this machine"],
|
|
15063
15009
|
["npx pinsay-cli login --key <key>", "Save a pasted key; no browser"]
|
|
15064
15010
|
]
|
|
15065
15011
|
},
|
|
15066
15012
|
logout: {
|
|
15067
|
-
purpose: "Remove
|
|
15013
|
+
purpose: "Remove this repo's key",
|
|
15068
15014
|
usage: "npx pinsay-cli logout [options]",
|
|
15069
15015
|
common: [
|
|
15070
|
-
["--global", "Remove this machine's saved key instead"],
|
|
15071
15016
|
["--json", "Emit { ok, server, source, removed } as JSON"]
|
|
15072
15017
|
],
|
|
15073
15018
|
all: [
|
|
15074
|
-
["--global", "Remove this machine's saved key instead"],
|
|
15075
15019
|
["--json", "Emit { ok, server, source, removed } as JSON"],
|
|
15076
|
-
["--scope <global|repo>", "Old spelling; only global changes anything", true],
|
|
15077
15020
|
["--no-color", "No colours or styling (also NO_COLOR=1)"]
|
|
15078
15021
|
],
|
|
15079
15022
|
examples: [
|
|
15080
15023
|
["npx pinsay-cli logout", "Remove this repo's key"],
|
|
15081
|
-
["npx pinsay-cli
|
|
15024
|
+
["npx pinsay-cli update", "Also delete an old machine-wide key"]
|
|
15082
15025
|
]
|
|
15083
15026
|
},
|
|
15084
15027
|
remove: {
|
|
@@ -15087,20 +15030,17 @@ var HELP_TEXTS = {
|
|
|
15087
15030
|
common: [
|
|
15088
15031
|
["--dry-run", "Show what would be removed; delete nothing"],
|
|
15089
15032
|
["-y, --yes", "Remove without asking"],
|
|
15090
|
-
["--global", "Also remove this machine's saved key"],
|
|
15091
15033
|
["--json", "Machine-readable output"]
|
|
15092
15034
|
],
|
|
15093
15035
|
all: [
|
|
15094
15036
|
["--dry-run", "Show what would be removed; delete nothing"],
|
|
15095
15037
|
["-y, --yes", "Remove without asking"],
|
|
15096
|
-
["--global", "Also remove this machine's saved key"],
|
|
15097
15038
|
["--json", "Machine-readable output"],
|
|
15098
15039
|
["--no-color", "No colours or styling (also NO_COLOR=1)"]
|
|
15099
15040
|
],
|
|
15100
15041
|
examples: [
|
|
15101
15042
|
["npx pinsay-cli remove --dry-run", "Show what would be removed"],
|
|
15102
|
-
["npx pinsay-cli remove --yes", "Remove without asking"]
|
|
15103
|
-
["npx pinsay-cli remove --global", "Also remove this machine's key"]
|
|
15043
|
+
["npx pinsay-cli remove --yes", "Remove without asking"]
|
|
15104
15044
|
]
|
|
15105
15045
|
},
|
|
15106
15046
|
status: {
|
|
@@ -15266,7 +15206,7 @@ var HELP_TEXTS = {
|
|
|
15266
15206
|
]
|
|
15267
15207
|
},
|
|
15268
15208
|
update: {
|
|
15269
|
-
purpose: "Refresh the AI skills",
|
|
15209
|
+
purpose: "Refresh the AI skills; delete an old machine-wide key",
|
|
15270
15210
|
usage: "npx pinsay-cli update [options]",
|
|
15271
15211
|
common: [
|
|
15272
15212
|
["--check", "Report what is out of date; write nothing"]
|
|
@@ -15315,13 +15255,13 @@ var HELP_TEXTS = {
|
|
|
15315
15255
|
]
|
|
15316
15256
|
},
|
|
15317
15257
|
whoami: {
|
|
15318
|
-
purpose: "Show the signed-in account and
|
|
15258
|
+
purpose: "Show the signed-in account, workspace and key source",
|
|
15319
15259
|
usage: "npx pinsay-cli whoami [options]",
|
|
15320
15260
|
common: [
|
|
15321
|
-
["--json", "Emit { ok, server, displayName, email, source } as JSON"]
|
|
15261
|
+
["--json", "Emit { ok, server, displayName, email, workspace, source } as JSON"]
|
|
15322
15262
|
],
|
|
15323
15263
|
all: [
|
|
15324
|
-
["--json", "Emit { ok, server, displayName, email, source } as JSON"],
|
|
15264
|
+
["--json", "Emit { ok, server, displayName, email, workspace, source } as JSON"],
|
|
15325
15265
|
["--no-color", "No colours or styling (also NO_COLOR=1)"]
|
|
15326
15266
|
],
|
|
15327
15267
|
examples: [
|
package/package.json
CHANGED