pinsay-cli 0.14.1 → 0.14.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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/cli.js +98 -43
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,6 +62,10 @@ Full guides: https://pinsay.dev/docs/ · Issues: https://github.com/moamen-ui/pi
62
62
 
63
63
  ## Changelog
64
64
 
65
+ ### 0.14.2
66
+
67
+ - A saved session the server ended early (for example after your role changed) no longer fails with "Your saved key no longer works": the CLI signs in again with the saved key once and retries. Only a key the server rejects still asks you to sign in.
68
+
65
69
  ### 0.14.1
66
70
 
67
71
  - Delegation is off unless `.pinsay/config.json` has `"delegation": "auto"`: the apply prompt header says `delegation=off` and `apply --mark` with one model no longer prints the "Delegation is on…" warning.
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.14.1" : "0.0.0-dev";
395
+ BUILD_CLI_VERSION = true ? "0.14.2" : "0.0.0-dev";
396
396
  }
397
397
  });
398
398
 
@@ -1379,7 +1379,45 @@ function parseRetryAfter(value, now = Date.now()) {
1379
1379
  return void 0;
1380
1380
  return Math.max(1, Math.ceil((at - now) / 1e3));
1381
1381
  }
1382
+ function registerRenewableToken(token, renew) {
1383
+ renewers.set(token, renew);
1384
+ }
1385
+ async function currentToken(token) {
1386
+ let t = token;
1387
+ while (t && replaced.has(t)) {
1388
+ const next = await replaced.get(t).catch(() => void 0);
1389
+ if (!next || next === t)
1390
+ break;
1391
+ t = next;
1392
+ }
1393
+ return t;
1394
+ }
1395
+ function renewToken(token) {
1396
+ let next = replaced.get(token);
1397
+ if (!next) {
1398
+ const renew = renewers.get(token);
1399
+ if (!renew)
1400
+ return Promise.resolve(void 0);
1401
+ renewers.delete(token);
1402
+ next = renew();
1403
+ replaced.set(token, next);
1404
+ }
1405
+ return next;
1406
+ }
1382
1407
  async function api(server, path, options = {}) {
1408
+ const token = await currentToken(options.token);
1409
+ try {
1410
+ return await request(server, path, { ...options, token });
1411
+ } catch (err) {
1412
+ if (!(err instanceof ApiError) || err.code !== 401 || !token)
1413
+ throw err;
1414
+ const fresh = await renewToken(token);
1415
+ if (!fresh || fresh === token)
1416
+ throw err;
1417
+ return request(server, path, { ...options, token: fresh });
1418
+ }
1419
+ }
1420
+ async function request(server, path, options = {}) {
1383
1421
  const url = `${server.replace(/\/$/, "")}${path}`;
1384
1422
  const headers = { "Accept": "application/json" };
1385
1423
  if (options.token)
@@ -1412,7 +1450,7 @@ async function api(server, path, options = {}) {
1412
1450
  const body = await res.json();
1413
1451
  return body.data !== void 0 ? body.data : body;
1414
1452
  }
1415
- var ApiError, NetworkError, API_TIMEOUT_MS;
1453
+ var ApiError, NetworkError, API_TIMEOUT_MS, renewers, replaced;
1416
1454
  var init_api = __esm({
1417
1455
  "src/api.ts"() {
1418
1456
  "use strict";
@@ -1433,6 +1471,8 @@ var init_api = __esm({
1433
1471
  }
1434
1472
  };
1435
1473
  API_TIMEOUT_MS = 3e4;
1474
+ renewers = /* @__PURE__ */ new Map();
1475
+ replaced = /* @__PURE__ */ new Map();
1436
1476
  }
1437
1477
  });
1438
1478
 
@@ -2512,19 +2552,7 @@ function isJwtExpired(token) {
2512
2552
  return false;
2513
2553
  }
2514
2554
  }
2515
- async function resolveToken(server, cwd2, explicitApiKey) {
2516
- await removeStaleRepoTokenCache(cwd2);
2517
- const apiKey = explicitApiKey || await readApiKey(cwd2, server);
2518
- if (!apiKey)
2519
- return void 0;
2520
- const cacheFile = tokenCacheFile(server, apiKey);
2521
- try {
2522
- const cached = JSON.parse(await fs22.readFile(cacheFile, "utf8"));
2523
- const token = typeof cached?.token === "string" ? cached.token.trim() : "";
2524
- if (token && !isJwtExpired(token))
2525
- return token;
2526
- } catch {
2527
- }
2555
+ async function exchangeKey2(server, apiKey, cacheFile) {
2528
2556
  try {
2529
2557
  const login = await api(
2530
2558
  server,
@@ -2551,6 +2579,31 @@ async function resolveToken(server, cwd2, explicitApiKey) {
2551
2579
  }
2552
2580
  return void 0;
2553
2581
  }
2582
+ async function resolveToken(server, cwd2, explicitApiKey) {
2583
+ await removeStaleRepoTokenCache(cwd2);
2584
+ const apiKey = explicitApiKey || await readApiKey(cwd2, server);
2585
+ if (!apiKey)
2586
+ return void 0;
2587
+ const cacheFile = tokenCacheFile(server, apiKey);
2588
+ const track = (token) => {
2589
+ registerRenewableToken(token, async () => {
2590
+ await fs22.rm(cacheFile, { force: true }).catch(() => {
2591
+ });
2592
+ const fresh2 = await exchangeKey2(server, apiKey, cacheFile);
2593
+ return fresh2 ? track(fresh2) : void 0;
2594
+ });
2595
+ return token;
2596
+ };
2597
+ try {
2598
+ const cached = JSON.parse(await fs22.readFile(cacheFile, "utf8"));
2599
+ const token = typeof cached?.token === "string" ? cached.token.trim() : "";
2600
+ if (token && !isJwtExpired(token))
2601
+ return track(token);
2602
+ } catch {
2603
+ }
2604
+ const fresh = await exchangeKey2(server, apiKey, cacheFile);
2605
+ return fresh ? track(fresh) : void 0;
2606
+ }
2554
2607
  var init_auth = __esm({
2555
2608
  "src/auth.ts"() {
2556
2609
  "use strict";
@@ -2701,8 +2754,9 @@ async function download(url, file, expectedSize, opts) {
2701
2754
  if (have && have.isFile() && (expectedSize === null ? have.size > 0 : have.size === expectedSize))
2702
2755
  return null;
2703
2756
  const headers = {};
2704
- if (opts.token)
2705
- headers["Authorization"] = `Bearer ${opts.token}`;
2757
+ const token = await currentToken(opts.token);
2758
+ if (token)
2759
+ headers["Authorization"] = `Bearer ${token}`;
2706
2760
  const doFetch = opts.fetchImpl ?? fetch;
2707
2761
  let res;
2708
2762
  try {
@@ -2871,6 +2925,7 @@ var MEDIA_DIR, MEDIA_MAX_AGE_DAYS, DOWNLOAD_TIMEOUT_MS, MAX_MEDIA_BYTES, SAFE_EX
2871
2925
  var init_media = __esm({
2872
2926
  "src/apply/media.ts"() {
2873
2927
  "use strict";
2928
+ init_api();
2874
2929
  init_git_exclude();
2875
2930
  MEDIA_DIR = join22(".pinsay", "media");
2876
2931
  MEDIA_MAX_AGE_DAYS = 7;
@@ -14345,13 +14400,13 @@ var Protocol = class {
14345
14400
  }
14346
14401
  Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
14347
14402
  }
14348
- _onrequest(request) {
14403
+ _onrequest(request2) {
14349
14404
  var _a, _b;
14350
- const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
14405
+ const handler = (_a = this._requestHandlers.get(request2.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
14351
14406
  if (handler === void 0) {
14352
14407
  (_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
14353
14408
  jsonrpc: "2.0",
14354
- id: request.id,
14409
+ id: request2.id,
14355
14410
  error: {
14356
14411
  code: ErrorCode.MethodNotFound,
14357
14412
  message: "Method not found"
@@ -14360,8 +14415,8 @@ var Protocol = class {
14360
14415
  return;
14361
14416
  }
14362
14417
  const abortController = new AbortController();
14363
- this._requestHandlerAbortControllers.set(request.id, abortController);
14364
- Promise.resolve().then(() => handler(request, { signal: abortController.signal })).then((result) => {
14418
+ this._requestHandlerAbortControllers.set(request2.id, abortController);
14419
+ Promise.resolve().then(() => handler(request2, { signal: abortController.signal })).then((result) => {
14365
14420
  var _a2;
14366
14421
  if (abortController.signal.aborted) {
14367
14422
  return;
@@ -14369,7 +14424,7 @@ var Protocol = class {
14369
14424
  return (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send({
14370
14425
  result,
14371
14426
  jsonrpc: "2.0",
14372
- id: request.id
14427
+ id: request2.id
14373
14428
  });
14374
14429
  }, (error) => {
14375
14430
  var _a2, _b2;
@@ -14378,14 +14433,14 @@ var Protocol = class {
14378
14433
  }
14379
14434
  return (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send({
14380
14435
  jsonrpc: "2.0",
14381
- id: request.id,
14436
+ id: request2.id,
14382
14437
  error: {
14383
14438
  code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
14384
14439
  message: (_b2 = error.message) !== null && _b2 !== void 0 ? _b2 : "Internal error"
14385
14440
  }
14386
14441
  });
14387
14442
  }).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
14388
- this._requestHandlerAbortControllers.delete(request.id);
14443
+ this._requestHandlerAbortControllers.delete(request2.id);
14389
14444
  });
14390
14445
  }
14391
14446
  _onprogress(notification) {
@@ -14428,7 +14483,7 @@ var Protocol = class {
14428
14483
  *
14429
14484
  * Do not use this method to emit notifications! Use notification() instead.
14430
14485
  */
14431
- request(request, resultSchema, options) {
14486
+ request(request2, resultSchema, options) {
14432
14487
  return new Promise((resolve11, reject) => {
14433
14488
  var _a, _b, _c, _d;
14434
14489
  if (!this._transport) {
@@ -14436,19 +14491,19 @@ var Protocol = class {
14436
14491
  return;
14437
14492
  }
14438
14493
  if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.enforceStrictCapabilities) === true) {
14439
- this.assertCapabilityForMethod(request.method);
14494
+ this.assertCapabilityForMethod(request2.method);
14440
14495
  }
14441
14496
  (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
14442
14497
  const messageId = this._requestMessageId++;
14443
14498
  const jsonrpcRequest = {
14444
- ...request,
14499
+ ...request2,
14445
14500
  jsonrpc: "2.0",
14446
14501
  id: messageId
14447
14502
  };
14448
14503
  if (options === null || options === void 0 ? void 0 : options.onprogress) {
14449
14504
  this._progressHandlers.set(messageId, options.onprogress);
14450
14505
  jsonrpcRequest.params = {
14451
- ...request.params,
14506
+ ...request2.params,
14452
14507
  _meta: { progressToken: messageId }
14453
14508
  };
14454
14509
  }
@@ -14526,7 +14581,7 @@ var Protocol = class {
14526
14581
  setRequestHandler(requestSchema, handler) {
14527
14582
  const method = requestSchema.shape.method.value;
14528
14583
  this.assertRequestHandlerCapability(method);
14529
- this._requestHandlers.set(method, (request, extra) => Promise.resolve(handler(requestSchema.parse(request), extra)));
14584
+ this._requestHandlers.set(method, (request2, extra) => Promise.resolve(handler(requestSchema.parse(request2), extra)));
14530
14585
  }
14531
14586
  /**
14532
14587
  * Removes the request handler for the given method.
@@ -14579,7 +14634,7 @@ var Server = class extends Protocol {
14579
14634
  this._serverInfo = _serverInfo;
14580
14635
  this._capabilities = (_a = options === null || options === void 0 ? void 0 : options.capabilities) !== null && _a !== void 0 ? _a : {};
14581
14636
  this._instructions = options === null || options === void 0 ? void 0 : options.instructions;
14582
- this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
14637
+ this.setRequestHandler(InitializeRequestSchema, (request2) => this._oninitialize(request2));
14583
14638
  this.setNotificationHandler(InitializedNotificationSchema, () => {
14584
14639
  var _a2;
14585
14640
  return (_a2 = this.oninitialized) === null || _a2 === void 0 ? void 0 : _a2.call(this);
@@ -14678,10 +14733,10 @@ var Server = class extends Protocol {
14678
14733
  break;
14679
14734
  }
14680
14735
  }
14681
- async _oninitialize(request) {
14682
- const requestedVersion = request.params.protocolVersion;
14683
- this._clientCapabilities = request.params.capabilities;
14684
- this._clientVersion = request.params.clientInfo;
14736
+ async _oninitialize(request2) {
14737
+ const requestedVersion = request2.params.protocolVersion;
14738
+ this._clientCapabilities = request2.params.capabilities;
14739
+ this._clientVersion = request2.params.clientInfo;
14685
14740
  return {
14686
14741
  protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : LATEST_PROTOCOL_VERSION,
14687
14742
  capabilities: this.getCapabilities(),
@@ -15905,9 +15960,9 @@ function createMcpServer(ctx) {
15905
15960
  tools: [...ALL_TOOLS]
15906
15961
  };
15907
15962
  });
15908
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
15909
- const name = request.params.name;
15910
- const args = request.params.arguments || {};
15963
+ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
15964
+ const name = request2.params.name;
15965
+ const args = request2.params.arguments || {};
15911
15966
  try {
15912
15967
  const result = await executeTool(name, args, ctx);
15913
15968
  return {
@@ -15958,8 +16013,8 @@ function createMcpServer(ctx) {
15958
16013
  ]
15959
16014
  };
15960
16015
  });
15961
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
15962
- const uri = request.params.uri;
16016
+ server.setRequestHandler(ReadResourceRequestSchema, async (request2) => {
16017
+ const uri = request2.params.uri;
15963
16018
  if (uri !== "pinsay://project") {
15964
16019
  throw new Error(`Unknown resource URI: ${uri}`);
15965
16020
  }
@@ -16006,12 +16061,12 @@ function createMcpServer(ctx) {
16006
16061
  ]
16007
16062
  };
16008
16063
  });
16009
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
16010
- const name = request.params.name;
16064
+ server.setRequestHandler(GetPromptRequestSchema, async (request2) => {
16065
+ const name = request2.params.name;
16011
16066
  if (name !== "pinsay_apply_instructions") {
16012
16067
  throw new Error(`Unknown prompt: ${name}`);
16013
16068
  }
16014
- const env = request.params.arguments?.environment;
16069
+ const env = request2.params.arguments?.environment;
16015
16070
  const clientCtx = {
16016
16071
  server: ctx.server,
16017
16072
  project: ctx.project,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinsay-cli",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Click-to-comment feedback for your web app: install the widget, then turn pending comments into AI apply prompts.",
5
5
  "type": "module",
6
6
  "license": "MIT",