commandmate 0.10.4 → 0.11.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.
Files changed (146) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +145 -145
  3. package/.next/app-path-routes-manifest.json +26 -26
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +12 -12
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/app/update/route.js +1 -1
  9. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/update-check/route.js +1 -1
  11. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  107. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  108. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  110. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  111. package/.next/server/app/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  114. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  115. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  116. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/worktrees/[id]/page.js +7 -7
  118. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  119. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  120. package/.next/server/app-paths-manifest.json +26 -26
  121. package/.next/server/chunks/2119.js +1 -1
  122. package/.next/server/chunks/2445.js +1 -1
  123. package/.next/server/chunks/5959.js +1 -1
  124. package/.next/server/chunks/9067.js +1 -1
  125. package/.next/server/middleware-manifest.json +5 -5
  126. package/.next/server/pages/500.html +1 -1
  127. package/.next/server/server-reference-manifest.json +1 -1
  128. package/.next/static/chunks/{7347-a013a163a75030ec.js → 7347-7ee39e14be89e508.js} +1 -1
  129. package/.next/static/chunks/app/worktrees/[id]/page-1c311aaa0950db1e.js +1 -0
  130. package/.next/trace +10 -10
  131. package/dist/cli/commands/update.d.ts.map +1 -1
  132. package/dist/cli/commands/update.js +178 -1
  133. package/dist/cli/program.d.ts.map +1 -1
  134. package/dist/cli/program.js +6 -0
  135. package/dist/cli/types/index.d.ts +7 -0
  136. package/dist/cli/types/index.d.ts.map +1 -1
  137. package/dist/cli/utils/npx-runner.d.ts +88 -0
  138. package/dist/cli/utils/npx-runner.d.ts.map +1 -0
  139. package/dist/cli/utils/npx-runner.js +165 -0
  140. package/dist/lib/app-update/update-lock.d.ts +39 -0
  141. package/dist/lib/app-update/update-lock.d.ts.map +1 -0
  142. package/dist/lib/app-update/update-lock.js +116 -0
  143. package/package.json +1 -1
  144. package/.next/static/chunks/app/worktrees/[id]/page-932a52f8d11971f7.js +0 -1
  145. /package/.next/static/{uBCIYS1Hth7V4unroKqGu → 8yp8SRJ9h3Uj75SpHLYpl}/_buildManifest.js +0 -0
  146. /package/.next/static/{uBCIYS1Hth7V4unroKqGu → 8yp8SRJ9h3Uj75SpHLYpl}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAkBzE;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgP9E"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAuBzE;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwP9E"}
@@ -28,11 +28,16 @@ const install_context_1 = require("../utils/install-context");
28
28
  const env_setup_1 = require("../utils/env-setup");
29
29
  const daemon_factory_1 = require("../utils/daemon-factory");
30
30
  const npm_runner_1 = require("../utils/npm-runner");
31
+ const npx_runner_1 = require("../utils/npx-runner");
31
32
  const semver_1 = require("../utils/semver");
32
33
  const health_check_1 = require("../utils/health-check");
33
34
  const worktree_servers_1 = require("../utils/worktree-servers");
34
35
  const prompt_1 = require("../utils/prompt");
35
36
  const api_client_1 = require("../utils/api-client");
37
+ // Relative import (not '@/'): the CLI build has no path alias / tsc-alias step.
38
+ // Only the abort paths of the npx relaunch touch this — success leaves the lock
39
+ // to expire, exactly like the global flow (Issue #1395 §5.2).
40
+ const update_lock_1 = require("../../lib/app-update/update-lock");
36
41
  const logger = new logger_1.CLILogger();
37
42
  /** npm package name (kept as a literal: never build it from a dynamic path) */
38
43
  const PACKAGE_NAME = 'commandmate';
@@ -43,7 +48,7 @@ const PACKAGE_NAME = 'commandmate';
43
48
  */
44
49
  async function updateCommand(options = {}) {
45
50
  try {
46
- // --- Step 0: npx gate (Issue #1319) -------------------------------------
51
+ // --- Step 0: npx gate (Issue #1319 / #1395) -----------------------------
47
52
  // `npx commandmate` runs from the npx cache, which isGlobalInstall() reports
48
53
  // as global (Issue #1195). Without this gate step 1 lets a throwaway process
49
54
  // rewrite the user's global install, and step 8 then fails its own check by
@@ -51,6 +56,14 @@ async function updateCommand(options = {}) {
51
56
  // The gate covers --check too: "current version" under npx is whatever npx
52
57
  // happened to cache, which says nothing about the user's install.
53
58
  if ((0, install_context_1.isNpxExecution)()) {
59
+ // Issue #1395: the GUI update route spawns this with the hidden
60
+ // --relaunch-npx flag to actually update in place (fetch a fresh npx cache
61
+ // and relaunch the daemon from it). The bare user-facing `commandmate
62
+ // update` under npx stays the #1319 no-op (§6).
63
+ if (options.relaunchNpx) {
64
+ await runNpxSelfUpdate();
65
+ return;
66
+ }
54
67
  printNpxGuidance();
55
68
  process.exit(types_1.ExitCode.SUCCESS);
56
69
  return;
@@ -244,6 +257,134 @@ async function updateCommand(options = {}) {
244
257
  process.exit(types_1.ExitCode.UNEXPECTED_ERROR);
245
258
  }
246
259
  }
260
+ /**
261
+ * npx in-place self-update orchestrator (Issue #1395, design §2.1).
262
+ *
263
+ * Runs detached from the server it replaces (the GUI route spawns it with
264
+ * `detached + unref`), so stopping the old daemon does not kill this process.
265
+ * The sequence is fail-fast: the new version is fetched and verified BEFORE the
266
+ * old daemon is stopped, so a stale/failed fetch aborts with zero downtime.
267
+ *
268
+ * Lock policy (§5.2): the route already holds the update lock. Abort paths here
269
+ * release it so a retry is not blocked for 10 minutes; a successful relaunch
270
+ * leaves it to expire, exactly like the global flow (a competing retry must not
271
+ * stop the freshly-started daemon). npx env hygiene lives inside npx-runner.
272
+ */
273
+ async function runNpxSelfUpdate() {
274
+ // .env must exist and be loaded before status/auth resolution so the health
275
+ // check URL and token resolve correctly (mirrors step 6).
276
+ const envPath = (0, env_setup_1.getEnvPath)();
277
+ if (!(0, fs_1.existsSync)(envPath)) {
278
+ logger.error('No .env configuration was found, so the server cannot be relaunched.');
279
+ logger.info('Nothing was changed.');
280
+ printNpxManualRelaunch();
281
+ (0, update_lock_1.releaseUpdateLock)();
282
+ process.exit(types_1.ExitCode.CONFIG_ERROR);
283
+ return;
284
+ }
285
+ (0, dotenv_1.config)({ path: envPath });
286
+ // Expected version = the registry's latest (honours the user's .npmrc).
287
+ const view = (0, npm_runner_1.viewLatestVersion)(PACKAGE_NAME);
288
+ if (!view.success || !view.version) {
289
+ logger.error(`Failed to query the npm registry: ${view.error ?? 'unknown error'}`);
290
+ logger.info('Nothing was changed. Check your network/npm configuration and try again.');
291
+ (0, update_lock_1.releaseUpdateLock)();
292
+ process.exit(types_1.ExitCode.UPDATE_FAILED);
293
+ return;
294
+ }
295
+ const expected = view.version;
296
+ // --- Warmup + version verify BEFORE the stop (fail-fast, zero downtime) ----
297
+ logger.info(`Fetching ${PACKAGE_NAME}@latest via npx (this may take a minute)...`);
298
+ const warm = (0, npx_runner_1.warmNpxLatest)(PACKAGE_NAME);
299
+ if (!warm.success || !warm.version) {
300
+ logger.error(`Failed to fetch the latest version via npx: ${warm.error ?? 'unknown error'}`);
301
+ printNpxStaleGuidance();
302
+ (0, update_lock_1.releaseUpdateLock)();
303
+ process.exit(types_1.ExitCode.UPDATE_FAILED);
304
+ return;
305
+ }
306
+ if (stripV(warm.version) !== stripV(expected)) {
307
+ logger.error(`npx returned v${warm.version} but the registry latest is v${expected} (a stale npx cache is likely).`);
308
+ printNpxStaleGuidance();
309
+ (0, update_lock_1.releaseUpdateLock)();
310
+ process.exit(types_1.ExitCode.UPDATE_FAILED);
311
+ return;
312
+ }
313
+ // --- Stop the current daemon (a brief outage starts here) ------------------
314
+ const daemonManager = (0, daemon_factory_1.getDaemonManagerFactory)().create();
315
+ const wasRunning = await daemonManager.isRunning();
316
+ if (wasRunning) {
317
+ logger.info('Stopping the current server...');
318
+ const stopped = await daemonManager.stop();
319
+ if (!stopped) {
320
+ logger.error('Failed to stop the server. Update aborted (nothing was changed).');
321
+ logger.info(`Run "${PACKAGE_NAME} stop --force" and try again.`);
322
+ (0, update_lock_1.releaseUpdateLock)();
323
+ process.exit(types_1.ExitCode.STOP_FAILED);
324
+ return;
325
+ }
326
+ logger.success('Server stopped');
327
+ }
328
+ // --- Relaunch from the freshly-cached version ------------------------------
329
+ logger.info(`Starting ${PACKAGE_NAME}@latest from the npx cache...`);
330
+ const relaunch = (0, npx_runner_1.spawnNpxDaemon)(PACKAGE_NAME);
331
+ if (!relaunch.success) {
332
+ logger.error(`Failed to start the new server: ${relaunch.error ?? 'unknown error'}`);
333
+ // The old server was stopped, so it is down: release the lock so the user
334
+ // can retry immediately.
335
+ printNpxManualRelaunch();
336
+ (0, update_lock_1.releaseUpdateLock)();
337
+ process.exit(types_1.ExitCode.START_FAILED);
338
+ return;
339
+ }
340
+ // (a) liveness is a precondition for the HTTP probe
341
+ if (!(await daemonManager.isRunning())) {
342
+ logger.error('The new server could not be detected after the relaunch.');
343
+ printNpxManualRelaunch();
344
+ (0, update_lock_1.releaseUpdateLock)();
345
+ process.exit(types_1.ExitCode.START_FAILED);
346
+ return;
347
+ }
348
+ // (b) base URL comes from getStatus(), never re-derived here (D-13)
349
+ const status = await daemonManager.getStatus();
350
+ const baseUrl = status?.url;
351
+ if (!baseUrl) {
352
+ logger.error('The server started but its address could not be confirmed.');
353
+ printNpxManualRelaunch();
354
+ (0, update_lock_1.releaseUpdateLock)();
355
+ process.exit(types_1.ExitCode.START_FAILED);
356
+ return;
357
+ }
358
+ // Post-start version verify (belt-and-suspenders, §4.2). A mismatch is a
359
+ // warning, not a rollback: the new daemon is up and the GUI will reload onto
360
+ // whatever it is now running.
361
+ if (status?.version && stripV(status.version) !== stripV(expected)) {
362
+ logger.warn(`The running server reports v${status.version}, but v${expected} was expected. ` +
363
+ `Verify with "${PACKAGE_NAME} status".`);
364
+ }
365
+ // (c) poll until readiness is proven
366
+ logger.info('Waiting for the server to become ready...');
367
+ const readiness = await (0, health_check_1.waitForReady)(baseUrl, { token: (0, api_client_1.resolveAuthToken)() });
368
+ if (readiness === 'ready') {
369
+ logger.success(`CommandMate v${status?.version ?? expected} is ready at ${baseUrl}`);
370
+ printNpxPostUpdateNotes();
371
+ process.exit(types_1.ExitCode.SUCCESS);
372
+ return;
373
+ }
374
+ // (d) degrade: the server answers but readiness cannot be proven (auth/IP/TLS)
375
+ if (readiness === 'degraded') {
376
+ logger.warn('サーバは応答していますが、マイグレーション完了は確認できませんでした(認証有効時はトークンが必要です)。');
377
+ logger.info(`"${PACKAGE_NAME} status" で確認してください。`);
378
+ printNpxPostUpdateNotes();
379
+ process.exit(types_1.ExitCode.SUCCESS);
380
+ return;
381
+ }
382
+ // (e) timeout: the relaunch itself succeeded and the new daemon is up, so the
383
+ // lock is left to expire (a retry must not stop the fresh server).
384
+ logger.error('The server started but did not answer in time.');
385
+ printNpxManualRelaunch();
386
+ process.exit(types_1.ExitCode.START_FAILED);
387
+ }
247
388
  /**
248
389
  * Read the version from the installed package.json.
249
390
  * @throws if package.json cannot be read or has no version
@@ -295,6 +436,42 @@ function printNpxGuidance() {
295
436
  console.log('(stop the server -> install -> restart).');
296
437
  console.log('');
297
438
  }
439
+ /**
440
+ * Guidance when npx could not fetch the expected latest (Issue #1395).
441
+ * The old server is untouched, so this only tells the user how to retry.
442
+ */
443
+ function printNpxStaleGuidance() {
444
+ console.log('');
445
+ console.log('The latest version could not be fetched cleanly (a stale npx cache is likely).');
446
+ console.log('Nothing was changed — the current server is still running.');
447
+ console.log('Try again in a moment, or clear the npx/npm cache first:');
448
+ console.log(` npm cache clean --force`);
449
+ console.log(` npx --yes --prefer-online ${PACKAGE_NAME}@latest`);
450
+ console.log('');
451
+ }
452
+ /**
453
+ * Guidance when the relaunch could not be completed/confirmed (Issue #1395).
454
+ * Under npx there is no global install to roll back to; the recovery path is to
455
+ * relaunch with npx by hand. Config/db under ~/.commandmate are preserved.
456
+ */
457
+ function printNpxManualRelaunch() {
458
+ console.log('');
459
+ console.log('Finish the update by relaunching the server manually:');
460
+ console.log(` npx ${PACKAGE_NAME}@latest`);
461
+ console.log('Your configuration and database under ~/.commandmate are preserved.');
462
+ console.log('');
463
+ }
464
+ /**
465
+ * Completion notes for the npx relaunch (Issue #1395 §7.2).
466
+ * Startup options are not fully re-derived from CLI flags after a relaunch, so
467
+ * point the user at status rather than asserting anything was lost/kept.
468
+ */
469
+ function printNpxPostUpdateNotes() {
470
+ console.log('');
471
+ console.log('Note: 再起動後は .env と引き継がれた設定で起動しています。');
472
+ console.log(` ${PACKAGE_NAME} status で稼働先(ポート等)を確認してください。`);
473
+ console.log('');
474
+ }
298
475
  /**
299
476
  * Manual upgrade steps for non-global (development checkout) installs.
300
477
  *
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0DpC;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,OAAO,CA0JtC"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA0D5C;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAkKtC"}
@@ -172,10 +172,16 @@ function buildProgram() {
172
172
  .description('Update CommandMate to the latest version')
173
173
  .option('--check', 'Only check for updates (no install, stop or restart)')
174
174
  .option('-y, --yes', 'Skip the confirmation prompt (required for non-interactive use)')
175
+ // Issue #1395: hidden — the GUI update route uses this to relaunch an
176
+ // npx-launched server from a fresh npx cache. Hidden so the user-facing
177
+ // `commandmate update` under npx stays a no-op (§6). Fixed argv, no request
178
+ // input reaches it (§5).
179
+ .addOption(new commander_1.Option('--relaunch-npx', 'Internal: relaunch an npx server from a fresh cache').hideHelp())
175
180
  .action(async (options) => {
176
181
  await (0, update_1.updateCommand)({
177
182
  check: options.check,
178
183
  yes: options.yes,
184
+ relaunchNpx: options.relaunchNpx,
179
185
  });
180
186
  });
181
187
  // Issue #264: issue/docs commands (addCommand pattern for subcommand support)
@@ -89,6 +89,13 @@ export interface UpdateOptions {
89
89
  check?: boolean;
90
90
  /** Skip the confirmation prompt (required for non-interactive execution, D-2) */
91
91
  yes?: boolean;
92
+ /**
93
+ * Hidden flag (Issue #1395): under npx, stop the current daemon and relaunch it
94
+ * from a freshly-fetched `npx commandmate@latest` cache instead of the no-op
95
+ * guidance. Set only by the GUI update route; the bare user-facing
96
+ * `commandmate update` under npx stays a no-op (§6).
97
+ */
98
+ relaunchNpx?: boolean;
92
99
  }
93
100
  /**
94
101
  * Daemon process status
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * npx Execution Wrapper
3
+ * Issue #1395: GUI one-click self-update for npx-launched servers.
4
+ *
5
+ * The npx self-update fetches a fresh npx cache and relaunches the daemon from
6
+ * it (design §2.1), rather than mutating a global install (rejected Alt C). This
7
+ * module owns the two npx spawns and the env hygiene they need:
8
+ *
9
+ * - `warmNpxLatest` — force-download the latest and read back its version, so
10
+ * staleness can be caught *before* the old daemon is stopped (design §4.2).
11
+ * - `spawnNpxDaemon` — relaunch the server from the freshly-cached version.
12
+ * - `sanitizeNpxEnv` — strip the `npm_*` env a `npm run start` parent leaks, so
13
+ * it cannot skew npx's registry/cache/prefix resolution (design §7.3).
14
+ *
15
+ * MF-SEC-1 (mirrors npm-runner): every command uses spawnSync with array args,
16
+ * never a shell string. `packageName` is always a literal constant supplied by
17
+ * the caller (update.ts PACKAGE_NAME) — never built from request input (§5).
18
+ *
19
+ * @module npx-runner
20
+ */
21
+ /**
22
+ * Upper bound for the warmup download.
23
+ *
24
+ * The warmup runs *before* the old daemon is stopped, so hitting this bound
25
+ * aborts with zero downtime (design §4.2). Kept comfortably under the banner's
26
+ * UPDATE_TIMEOUT_MS (5 min, UpdateNotificationBanner.tsx) so a stalled download
27
+ * aborts and logs before the GUI gives up (design §8.2 / §9-8).
28
+ */
29
+ export declare const NPX_WARMUP_TIMEOUT_MS: number;
30
+ /** Result of the warmup + version query */
31
+ export interface NpxWarmResult {
32
+ /** Whether the warmup succeeded and a version was read */
33
+ success: boolean;
34
+ /** Version reported by `<pkg> --version` (only when success) */
35
+ version?: string;
36
+ /** Human readable failure reason (only when !success) */
37
+ error?: string;
38
+ }
39
+ /** Result of the daemon relaunch */
40
+ export interface NpxDaemonResult {
41
+ /** Whether the relaunch exited 0 */
42
+ success: boolean;
43
+ /** Exit status of the npx process (null when it never ran) */
44
+ status: number | null;
45
+ /** Human readable failure reason (only when !success) */
46
+ error?: string;
47
+ }
48
+ /**
49
+ * Build an env for an npx spawn with the leaked `npm_*` variables removed.
50
+ *
51
+ * A server started by `npm run start` carries `npm_config_*` / `npm_lifecycle_*`
52
+ * / `npm_package_*` in its env; those flow down the inherit chain into the npx
53
+ * call and npx reads `npm_config_*` as configuration, which would silently
54
+ * redirect its registry/cache/prefix (design §7.3). Everything else — notably
55
+ * `CM_*` (config continuity) and `PATH` (needed to locate npx) — passes through.
56
+ *
57
+ * @param env - Source env (defaults to the current process env)
58
+ * @returns A fresh env object with all `npm_*` keys removed
59
+ */
60
+ export declare function sanitizeNpxEnv(env?: Record<string, string | undefined>): NodeJS.ProcessEnv;
61
+ /**
62
+ * Force-fetch the latest published version via npx and read back its version.
63
+ *
64
+ * `npx --yes <pkg>@latest --version` downloads the latest into the npx cache
65
+ * (`--yes` suppresses the install prompt) and prints the package version;
66
+ * commander's `.version()` short-circuits before any command runs, so this has
67
+ * no side effects and starts no server (design §2.1). Running it before the
68
+ * stop lets a stale/failed fetch abort with zero downtime (design §4.2).
69
+ *
70
+ * @param packageName - Package name (a literal constant, e.g. `commandmate`)
71
+ * @returns The fetched version, or a classified failure
72
+ */
73
+ export declare function warmNpxLatest(packageName: string): NpxWarmResult;
74
+ /**
75
+ * Relaunch the server as a daemon from the freshly-cached npx version.
76
+ *
77
+ * `npx --yes <pkg>@latest start --daemon` runs the just-warmed package (so no
78
+ * new download) and spawns `npm run start` from the new cache dir; the npx
79
+ * process exits once the daemon is detached. `start --daemon` is used rather
80
+ * than the bare quickstart, which bails in a non-interactive process (design
81
+ * §2.1). The call blocks until npx exits, so the exit status is the relaunch
82
+ * outcome. Output is echoed so it lands in the update log.
83
+ *
84
+ * @param packageName - Package name (a literal constant, e.g. `commandmate`)
85
+ * @returns Success, or a classified failure carrying the exit status
86
+ */
87
+ export declare function spawnNpxDaemon(packageName: string): NpxDaemonResult;
88
+ //# sourceMappingURL=npx-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npx-runner.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/npx-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QAAgB,CAAC;AAEnD,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,CAAC,UAAU,CAWnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAoChE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAyCnE"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ /**
3
+ * npx Execution Wrapper
4
+ * Issue #1395: GUI one-click self-update for npx-launched servers.
5
+ *
6
+ * The npx self-update fetches a fresh npx cache and relaunches the daemon from
7
+ * it (design §2.1), rather than mutating a global install (rejected Alt C). This
8
+ * module owns the two npx spawns and the env hygiene they need:
9
+ *
10
+ * - `warmNpxLatest` — force-download the latest and read back its version, so
11
+ * staleness can be caught *before* the old daemon is stopped (design §4.2).
12
+ * - `spawnNpxDaemon` — relaunch the server from the freshly-cached version.
13
+ * - `sanitizeNpxEnv` — strip the `npm_*` env a `npm run start` parent leaks, so
14
+ * it cannot skew npx's registry/cache/prefix resolution (design §7.3).
15
+ *
16
+ * MF-SEC-1 (mirrors npm-runner): every command uses spawnSync with array args,
17
+ * never a shell string. `packageName` is always a literal constant supplied by
18
+ * the caller (update.ts PACKAGE_NAME) — never built from request input (§5).
19
+ *
20
+ * @module npx-runner
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.NPX_WARMUP_TIMEOUT_MS = void 0;
24
+ exports.sanitizeNpxEnv = sanitizeNpxEnv;
25
+ exports.warmNpxLatest = warmNpxLatest;
26
+ exports.spawnNpxDaemon = spawnNpxDaemon;
27
+ const child_process_1 = require("child_process");
28
+ /**
29
+ * Upper bound for the warmup download.
30
+ *
31
+ * The warmup runs *before* the old daemon is stopped, so hitting this bound
32
+ * aborts with zero downtime (design §4.2). Kept comfortably under the banner's
33
+ * UPDATE_TIMEOUT_MS (5 min, UpdateNotificationBanner.tsx) so a stalled download
34
+ * aborts and logs before the GUI gives up (design §8.2 / §9-8).
35
+ */
36
+ exports.NPX_WARMUP_TIMEOUT_MS = 3 * 60 * 1000;
37
+ /**
38
+ * Build an env for an npx spawn with the leaked `npm_*` variables removed.
39
+ *
40
+ * A server started by `npm run start` carries `npm_config_*` / `npm_lifecycle_*`
41
+ * / `npm_package_*` in its env; those flow down the inherit chain into the npx
42
+ * call and npx reads `npm_config_*` as configuration, which would silently
43
+ * redirect its registry/cache/prefix (design §7.3). Everything else — notably
44
+ * `CM_*` (config continuity) and `PATH` (needed to locate npx) — passes through.
45
+ *
46
+ * @param env - Source env (defaults to the current process env)
47
+ * @returns A fresh env object with all `npm_*` keys removed
48
+ */
49
+ function sanitizeNpxEnv(env = process.env) {
50
+ // Built as a plain record: the project augments ProcessEnv with a required
51
+ // NODE_ENV, so an empty ProcessEnv literal would not typecheck.
52
+ const clean = {};
53
+ for (const [key, value] of Object.entries(env)) {
54
+ if (/^npm_/i.test(key)) {
55
+ continue;
56
+ }
57
+ clean[key] = value;
58
+ }
59
+ return clean;
60
+ }
61
+ /**
62
+ * Force-fetch the latest published version via npx and read back its version.
63
+ *
64
+ * `npx --yes <pkg>@latest --version` downloads the latest into the npx cache
65
+ * (`--yes` suppresses the install prompt) and prints the package version;
66
+ * commander's `.version()` short-circuits before any command runs, so this has
67
+ * no side effects and starts no server (design §2.1). Running it before the
68
+ * stop lets a stale/failed fetch abort with zero downtime (design §4.2).
69
+ *
70
+ * @param packageName - Package name (a literal constant, e.g. `commandmate`)
71
+ * @returns The fetched version, or a classified failure
72
+ */
73
+ function warmNpxLatest(packageName) {
74
+ const result = (0, child_process_1.spawnSync)('npx', ['--yes', `${packageName}@latest`, '--version'], {
75
+ encoding: 'utf-8',
76
+ timeout: exports.NPX_WARMUP_TIMEOUT_MS,
77
+ env: sanitizeNpxEnv(),
78
+ });
79
+ if (result.error) {
80
+ const errnoError = result.error;
81
+ if (errnoError.code === 'ENOENT') {
82
+ return {
83
+ success: false,
84
+ error: 'npx command not found. Install Node.js/npm and try again.',
85
+ };
86
+ }
87
+ return { success: false, error: errnoError.message };
88
+ }
89
+ if (result.status !== 0) {
90
+ const stderr = readStream(result.stderr);
91
+ return {
92
+ success: false,
93
+ error: stderr || `npx exited with status ${String(result.status)}`,
94
+ };
95
+ }
96
+ const version = parseVersion(readStream(result.stdout));
97
+ if (!version) {
98
+ return { success: false, error: 'npx did not report a version' };
99
+ }
100
+ return { success: true, version };
101
+ }
102
+ /**
103
+ * Relaunch the server as a daemon from the freshly-cached npx version.
104
+ *
105
+ * `npx --yes <pkg>@latest start --daemon` runs the just-warmed package (so no
106
+ * new download) and spawns `npm run start` from the new cache dir; the npx
107
+ * process exits once the daemon is detached. `start --daemon` is used rather
108
+ * than the bare quickstart, which bails in a non-interactive process (design
109
+ * §2.1). The call blocks until npx exits, so the exit status is the relaunch
110
+ * outcome. Output is echoed so it lands in the update log.
111
+ *
112
+ * @param packageName - Package name (a literal constant, e.g. `commandmate`)
113
+ * @returns Success, or a classified failure carrying the exit status
114
+ */
115
+ function spawnNpxDaemon(packageName) {
116
+ const result = (0, child_process_1.spawnSync)('npx', ['--yes', `${packageName}@latest`, 'start', '--daemon'], {
117
+ encoding: 'utf-8',
118
+ env: sanitizeNpxEnv(),
119
+ });
120
+ const stdout = readStream(result.stdout);
121
+ const stderr = readStream(result.stderr);
122
+ if (stdout) {
123
+ console.log(stdout);
124
+ }
125
+ if (stderr) {
126
+ console.error(stderr);
127
+ }
128
+ if (result.error) {
129
+ const errnoError = result.error;
130
+ if (errnoError.code === 'ENOENT') {
131
+ return {
132
+ success: false,
133
+ status: null,
134
+ error: 'npx command not found. Install Node.js/npm and try again.',
135
+ };
136
+ }
137
+ return { success: false, status: result.status, error: errnoError.message };
138
+ }
139
+ if (result.status !== 0) {
140
+ return {
141
+ success: false,
142
+ status: result.status,
143
+ error: stderr || `npx start exited with status ${String(result.status)}`,
144
+ };
145
+ }
146
+ return { success: true, status: 0 };
147
+ }
148
+ /**
149
+ * Extract the first semver-looking token from `--version` output.
150
+ * Robust against npx warning noise that may share the stream.
151
+ */
152
+ function parseVersion(output) {
153
+ const match = output.match(/\b(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\b/);
154
+ return match ? match[1] : null;
155
+ }
156
+ /**
157
+ * Read a spawnSync stream as a trimmed string.
158
+ * `encoding: 'utf-8'` yields strings, but mocks/edge cases may yield null.
159
+ */
160
+ function readStream(stream) {
161
+ if (typeof stream === 'string') {
162
+ return stream.trim();
163
+ }
164
+ return '';
165
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Update Lock
3
+ * Issue #1198: guard `POST /api/app/update` against concurrent self-updates.
4
+ *
5
+ * Design constraints:
6
+ * - Acquisition is a single O_EXCL create (mirrors PidManager.writePid), so two
7
+ * concurrent requests cannot both win.
8
+ * - A successful update restarts the server, so nothing survives to release the
9
+ * lock. Timeout expiry is therefore the primary release path, and
10
+ * releaseUpdateLock() exists only for the spawn-failed case.
11
+ *
12
+ * @module lib/app-update/update-lock
13
+ */
14
+ /** Lock file name inside the config directory */
15
+ export declare const UPDATE_LOCK_FILENAME = "update.lock";
16
+ /**
17
+ * Age after which a lock is considered abandoned.
18
+ * `commandmate update` takes tens of seconds (npm install dominates); 10 minutes
19
+ * is well clear of that while still recovering from a killed update process.
20
+ */
21
+ export declare const UPDATE_LOCK_TIMEOUT_MS: number;
22
+ /**
23
+ * Absolute path of the update lock file.
24
+ */
25
+ export declare function getUpdateLockPath(): string;
26
+ /**
27
+ * Take the update lock.
28
+ *
29
+ * @param now - Current epoch ms (injectable for tests)
30
+ * @returns true when the caller now holds the lock, false when an update is in progress
31
+ */
32
+ export declare function acquireUpdateLock(now?: number): boolean;
33
+ /**
34
+ * Drop the update lock.
35
+ * Only meaningful when the update never started (spawn failure): a started
36
+ * update replaces this process, so the lock outlives it until it expires.
37
+ */
38
+ export declare function releaseUpdateLock(): void;
39
+ //# sourceMappingURL=update-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-lock.d.ts","sourceRoot":"","sources":["../../../src/lib/app-update/update-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAiB,CAAC;AAUrD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AA0CD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAmB,GAAG,OAAO,CAoBnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC"}