codemem 0.44.1 → 0.45.0-rc.1

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/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, DeviceIdentityError, EXTRACTION_BENCHMARK_QUALITY_WEIGHTS, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, ObserverOutputError, ObserverOutputTransportError, PROMPT_TRANSPORT_PROTOCOL_RANGE, REF_BACKFILL_JOB, RawEventIngestValidationError, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, TRUSTED_HOOK_MAPPER_OPTIONS, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, applyDistillRule, arePromptTransportProtocolRangesCompatible, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildViewerIdentityTarget, classifyPromptTransportFailure, clonePromptPackAttempt, collectOperationalStatus, compareMemoryRoleReports, connect, connectReadOnly, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, detectInstallKind, draftDistillRule, ensureDeviceIdentity, ensureSchemaBootstrapped, estimateExtractionModelCost, exportMemories, extractApplyPatchPaths, extractionReplayObserverIdentity, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, formatHostPort, getAttributionDiagnostics, getExtractionBenchmarkProfile, getExtractionModelPricing, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryArtifactReport, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getUpdateStatus, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, ingestRawEvents, initDatabase, isAutomaticRecallMeasurement, isEmbeddingDisabled, isReleaseVersionForChannel, judgeDistillReport, listMaintenanceJobs, listPerPeerScopeSyncState, listRetentionScopeIds, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, normalizePromptTransportProtocolRange, planReplicationOpsAgePrune, probeCodememViewerLiveness, probeCodememViewerLiveness as probeCodememViewerLiveness$1, probeRequiredNativeRuntime, projectMatchesFilter, promptPackArtifactFingerprint, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, recordAutomaticRecall, recordPromptPackArtifacts, recordPromptPackTerminal, recordRetrievalSurface, renderUnifiedDiff, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveDbPath, resolveHookProject, resolveProject, resolveProjectRoot, resolveRetrievalSession, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, scoreExtractionBenchmarkOutput, setPeerProjectFilter, stripJsonComments, stripTrailingCommas, syncPassPreflight, tryUpdateRetrievalDelivery, updatePeerAddresses, vacuumDatabase, viewerUrl, writeCodememConfigFile } from "@codemem/core";
2
+ import { ContextOnlyReplayError, DEDUP_KEY_BACKFILL_JOB, DEFAULT_COORDINATOR_DB_PATH, DedupKeyBackfillRunner, DeviceIdentityError, EXTRACTION_BENCHMARK_QUALITY_WEIGHTS, MUTATING_TOOL_NAMES, MemoryStore, ObserverClient, ObserverOutputError, ObserverOutputTransportError, PROMPT_TRANSPORT_PROTOCOL_RANGE, REF_BACKFILL_JOB, RawEventIngestValidationError, RawEventSweeper, RefBackfillRunner, SCOPE_BACKFILL_JOB, SESSION_CONTEXT_BACKFILL_JOB, SUMMARY_DEDUP_BACKFILL_JOB, ScopeBackfillRunner, SessionContextBackfillRunner, SummaryDedupBackfillRunner, SyncRetentionRunner, TRUSTED_HOOK_MAPPER_OPTIONS, VERSION, VectorModelMigrationRunner, aiBackfillStructuredContent, applyBootstrapSnapshot, applyDistillRule, arePromptTransportProtocolRangesCompatible, backfillMemoryDedupKeys, backfillNarrativeFromBody, backfillTagsText, backfillVectors, buildBaseUrl, buildDirectPeerAuthHeaders, buildDistillReport, buildRawEventEnvelopeFromCodexHook, buildRawEventEnvelopeFromHook, buildViewerIdentityTarget, classifyPromptTransportFailure, clonePromptPackAttempt, collectOperationalStatus, compareMemoryRoleReports, connect, connectReadOnly, coordinatorCreateGroupAction, coordinatorCreateInviteAction, coordinatorCreateScopeAction, coordinatorDisableDeviceAction, coordinatorEnrollDeviceAction, coordinatorGrantScopeMembershipAction, coordinatorImportInviteAction, coordinatorListBootstrapGrantsAction, coordinatorListDevicesAction, coordinatorListGroupsAction, coordinatorListJoinRequestsAction, coordinatorListScopeMembershipsAction, coordinatorListScopesAction, coordinatorRemoveDeviceAction, coordinatorRenameDeviceAction, coordinatorReviewJoinRequestAction, coordinatorRevokeBootstrapGrantAction, coordinatorRevokeScopeMembershipAction, coordinatorUpdateScopeAction, createBetterSqliteCoordinatorApp, deactivateLowSignalMemories, deactivateLowSignalObservations, dedupNearDuplicateMemories, detectInstallKind, draftDistillRule, ensureDeviceIdentity, ensureSchemaBootstrapped, estimateExtractionModelCost, exportMemories, extractApplyPatchPaths, extractionReplayObserverIdentity, fetchAllSnapshotPages, fingerprintPublicKey, flushRawEvents, formatHostPort, getAttributionDiagnostics, getExtractionBenchmarkProfile, getExtractionModelPricing, getInjectionEvalScenarioPack, getInjectionEvalScenarioPrompts, getMaintenanceJob, getMemoryArtifactReport, getMemoryRoleReport, getRawEventRelinkPlan, getRawEventRelinkReport, getRawEventStatus, getSemanticIndexDiagnostics, getSessionExtractionEval, getSessionExtractionEvalScenario, getUpdateStatus, getWorkspaceCodememConfigPath, hasPendingDedupKeyBackfill, hasPendingRefBackfill, hasPendingScopeBackfill, hasPendingSessionContextBackfill, hasPendingSummaryDedupBackfill, hasUnsyncedSharedMemoryChanges, importMemories, ingestRawEvents, initDatabase, isAutomaticRecallMeasurement, isEmbeddingDisabled, isExplicitUpdateInstallEligible, isReleaseVersionForChannel, judgeDistillReport, listMaintenanceJobs, listPerPeerScopeSyncState, listRetentionScopeIds, loadObserverConfig, loadPublicKey, loadSqliteVec, mdnsEnabled, normalizePromptTransportProtocolRange, planReplicationOpsAgePrune, probeCodememViewerLiveness, probeCodememViewerLiveness as probeCodememViewerLiveness$1, probeRequiredNativeRuntime, projectMatchesFilter, promptPackArtifactFingerprint, pruneReplicationOpsUntilCaughtUp, rawEventsGate, readCodememConfigFile, readCodememConfigFileAtPath, readCoordinatorSyncConfig, readImportPayload, recordAutomaticRecall, recordPromptPackArtifacts, recordPromptPackTerminal, recordRetrievalSurface, renderUnifiedDiff, replayBatchExtraction, replayBatchExtractionWithTierRouting, requestJson, resolveCodememConfigPath, resolveComparablePath, resolveDbPath, resolveHookProject, resolveProject, resolveProjectRoot, resolveRetrievalSession, retryRawEventFailures, runSyncDaemon, runSyncPass, scanSecretsRetroactive, schema, scoreExtractionBenchmarkOutput, setPeerProjectFilter, stripJsonComments, stripTrailingCommas, syncPassPreflight, tryUpdateRetrievalDelivery, updatePeerAddresses, vacuumDatabase, viewerUrl, writeCodememConfigFile } from "@codemem/core";
3
3
  import { Command, Option } from "commander";
4
4
  import omelette from "omelette";
5
5
  import { randomInt, randomUUID } from "node:crypto";
6
- import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
6
+ import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
7
7
  import { homedir, networkInterfaces } from "node:os";
8
8
  import { dirname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
9
9
  import { styleText } from "node:util";
@@ -4701,6 +4701,20 @@ function parseStrictPositiveId(value) {
4701
4701
  const n = Number(value.trim());
4702
4702
  return Number.isFinite(n) && n >= 1 && Number.isInteger(n) ? n : null;
4703
4703
  }
4704
+ function contextOnlyReplayOutcome(error, target) {
4705
+ return {
4706
+ ...target,
4707
+ status: "context_only",
4708
+ code: error.code,
4709
+ evaluated: false,
4710
+ message: error.message
4711
+ };
4712
+ }
4713
+ function emitContextOnlyReplayOutcome(outcome, opts) {
4714
+ if (opts.json) console.log(JSON.stringify(outcome, null, 2));
4715
+ else p.log.info(outcome.message);
4716
+ process.exitCode = 0;
4717
+ }
4704
4718
  function resolveOpenAIResponsesOverride(cliEnabled, configured) {
4705
4719
  return cliEnabled === true ? true : configured;
4706
4720
  }
@@ -5177,6 +5191,13 @@ function createMemoryExtractionReplayCommand() {
5177
5191
  ].join("\n"));
5178
5192
  p.outro("done");
5179
5193
  } catch (error) {
5194
+ if (error instanceof ContextOnlyReplayError) {
5195
+ emitContextOnlyReplayOutcome(contextOnlyReplayOutcome(error, {
5196
+ batchId: Number(opts.batchId),
5197
+ scenarioId: opts.scenario.trim()
5198
+ }), opts);
5199
+ return;
5200
+ }
5180
5201
  const message = error instanceof Error ? error.message : "Extraction replay failed";
5181
5202
  if (opts.json) emitJsonError("extraction_replay_failed", message);
5182
5203
  else {
@@ -5414,6 +5435,7 @@ function createMemoryExtractionBenchmarkCommand() {
5414
5435
  const observer = new ObserverClient(observerConfigWithOverrides);
5415
5436
  const outputFailures = [];
5416
5437
  const runs = [];
5438
+ const contextOnlySkips = [];
5417
5439
  for (let iteration = 1; iteration <= repetitions; iteration += 1) for (const batch of benchmark.batches) {
5418
5440
  const scenarioId = batch.scenarioId ?? benchmark.scenarioId;
5419
5441
  let selectedObserver = extractionReplayObserverIdentity(observer, null);
@@ -5432,6 +5454,17 @@ function createMemoryExtractionBenchmarkCommand() {
5432
5454
  transcriptBudget: transcriptBudget ?? void 0
5433
5455
  });
5434
5456
  } catch (error) {
5457
+ if (error instanceof ContextOnlyReplayError) {
5458
+ contextOnlySkips.push({
5459
+ ...contextOnlyReplayOutcome(error, {
5460
+ batchId: batch.batchId,
5461
+ scenarioId
5462
+ }),
5463
+ iteration,
5464
+ purpose: batch.purpose
5465
+ });
5466
+ continue;
5467
+ }
5435
5468
  if (!(error instanceof ObserverOutputError) && !(error instanceof ObserverOutputTransportError)) throw error;
5436
5469
  if (opts.observerTierRouting !== true) selectedObserver = extractionReplayObserverIdentity(observer, null);
5437
5470
  const failureCost = estimateBenchmarkAttemptCost(selectedObserver.model, error.telemetry.totalUsage);
@@ -5600,6 +5633,9 @@ function createMemoryExtractionBenchmarkCommand() {
5600
5633
  const knownElapsedRuns = attempts.filter((run) => run.telemetry.totalElapsedMs != null);
5601
5634
  const summary = {
5602
5635
  repetitions,
5636
+ scheduledTotal: benchmark.batches.length * repetitions,
5637
+ contextOnlySkipped: contextOnlySkips.length,
5638
+ contextOnlySkips,
5603
5639
  ...attemptSummary,
5604
5640
  summaryDispositionTotal: runs.filter((run) => run.quality != null).length,
5605
5641
  summaryDispositionMatches: runs.filter((run) => run.quality?.summaryDisposition.score === 1).length,
@@ -5674,6 +5710,7 @@ function createMemoryExtractionBenchmarkCommand() {
5674
5710
  `Temperature: ${observerSummary.transport === "mixed" ? "mixed" : observerSummary.temperature ?? "not transmitted"}`,
5675
5711
  `Transcript budget override: ${transcriptBudget ?? "default"}`,
5676
5712
  `Repetitions: ${summary.repetitions}`,
5713
+ `Context-only skips: ${summary.contextOnlySkipped} (${summary.scheduledTotal} scheduled; ${summary.total} observer attempts)`,
5677
5714
  `Shape-quality passes: ${summary.shapeQualityPasses}/${summary.shapeQualityTotal}`,
5678
5715
  `Shape-quality fails: ${summary.shapeQualityFails}`,
5679
5716
  `Expected-tier matches: ${summary.expectedTierMatches}/${summary.expectedTierTotal}`,
@@ -5687,6 +5724,7 @@ function createMemoryExtractionBenchmarkCommand() {
5687
5724
  `Tokens input/output: ${summary.output.overall.inputTokens}/${summary.output.overall.outputTokens} (${summary.output.overall.knownTokenRuns} measured run(s)); retained observations: ${summary.output.overall.retainedObservations}`,
5688
5725
  `Summary disposition matches: ${summary.output.overall.summaryDispositionMatches}/${summary.output.overall.summaryDispositionEvaluated}; contract integrity/semantic quality: ${summary.output.overall.contractIntegrityRate?.toFixed(3) ?? "n/a"}/${summary.output.overall.meanSemanticQuality?.toFixed(3) ?? "n/a"}`
5689
5726
  ].join("\n"));
5727
+ for (const skipped of contextOnlySkips) p.log.message(` [${skipped.batchId}#${skipped.iteration}] context_only — ${skipped.code}; not evaluated`);
5690
5728
  for (const run of runs) {
5691
5729
  const qualityLabel = run.quality?.weightedQualityScore == null ? "n/a" : run.quality.weightedQualityScore.toFixed(3);
5692
5730
  const costLabel = run.cost.total == null ? "n/a" : `$${run.cost.total.totalCostUsd.toFixed(6)}`;
@@ -5934,6 +5972,8 @@ function describeCandidate(candidate) {
5934
5972
  if (candidate.section) lines.push(` - section: ${candidate.section}`);
5935
5973
  if (candidate.reasons.length > 0) lines.push(` - reasons: ${candidate.reasons.join(", ")}`);
5936
5974
  if (scoreParts) lines.push(` - scores: ${scoreParts}`);
5975
+ const fusion = candidate.scores.fusion;
5976
+ if (fusion) lines.push(` - hybrid: fused_score=${fusion.fused_score.toPrecision(8)} fusion_rank=${fusion.fusion_rank}; combined_score is a legacy diagnostic, not the hybrid selection key`);
5937
5977
  if (candidate.preview) lines.push(` - preview: ${candidate.preview}`);
5938
5978
  return lines;
5939
5979
  }
@@ -7065,6 +7105,32 @@ var serveCommand = serveCmd.action(async (action, opts) => {
7065
7105
  });
7066
7106
  //#endregion
7067
7107
  //#region src/commands/setup-config.ts
7108
+ var OPENCODE_PLUGIN_SPEC = "@codemem/opencode-plugin";
7109
+ var LEGACY_OPENCODE_PLUGIN_SPECS = ["codemem", "@kunickiaj/codemem"];
7110
+ function matchesPluginSpec(entry, spec) {
7111
+ return typeof entry === "string" && (entry === spec || entry.startsWith(`${spec}@`));
7112
+ }
7113
+ function reconcileOpencodePluginConfig(config, { force }) {
7114
+ const plugins = Array.isArray(config.plugin) ? config.plugin : [];
7115
+ const isCanonicalSpec = (entry) => matchesPluginSpec(entry, OPENCODE_PLUGIN_SPEC);
7116
+ const isLegacySpec = (entry) => LEGACY_OPENCODE_PLUGIN_SPECS.some((spec) => matchesPluginSpec(entry, spec));
7117
+ const hasCanonicalSpec = plugins.some(isCanonicalSpec);
7118
+ const hasLegacySpec = plugins.some(isLegacySpec);
7119
+ if (hasCanonicalSpec && !hasLegacySpec && !force) return {
7120
+ config,
7121
+ changed: false,
7122
+ removedLegacy: false
7123
+ };
7124
+ const preserved = plugins.filter((entry) => !isCanonicalSpec(entry) && !isLegacySpec(entry));
7125
+ return {
7126
+ config: {
7127
+ ...config,
7128
+ plugin: [...preserved, OPENCODE_PLUGIN_SPEC]
7129
+ },
7130
+ changed: true,
7131
+ removedLegacy: hasLegacySpec
7132
+ };
7133
+ }
7068
7134
  function resolveOpencodeConfigPath(configDir) {
7069
7135
  const jsonPath = join(configDir, "opencode.json");
7070
7136
  if (existsSync(jsonPath)) return jsonPath;
@@ -7110,9 +7176,6 @@ function claudeConfigDir() {
7110
7176
  function codexConfigDir() {
7111
7177
  return process.env.CODEX_HOME?.trim() || join(homedir(), ".codex");
7112
7178
  }
7113
- /** The npm package name used in the OpenCode plugin array. */
7114
- var OPENCODE_PLUGIN_SPEC = "@codemem/opencode-plugin";
7115
- var LEGACY_OPENCODE_PLUGIN_SPECS = ["codemem", "@kunickiaj/codemem"];
7116
7179
  /** Remove legacy copied plugin JS file from ~/.config/opencode/plugins/codemem.js */
7117
7180
  function migrateLegacyOpencodePlugin() {
7118
7181
  const legacyPlugin = join(opencodeConfigDir(), "plugins", "codemem.js");
@@ -7196,21 +7259,14 @@ function installPlugin(force) {
7196
7259
  p.log.error(`Failed to parse ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
7197
7260
  return false;
7198
7261
  }
7199
- let plugins = config.plugin;
7200
- if (!Array.isArray(plugins)) plugins = [];
7201
- const isManagedPluginSpec = (entry) => typeof entry === "string" && [OPENCODE_PLUGIN_SPEC, ...LEGACY_OPENCODE_PLUGIN_SPECS].some((spec) => entry === spec || entry.startsWith(`${spec}@`));
7202
- const hasCanonicalSpec = plugins.some((entry) => typeof entry === "string" && (entry === OPENCODE_PLUGIN_SPEC || entry.startsWith(`${OPENCODE_PLUGIN_SPEC}@`)));
7203
- const hasLegacySpec = plugins.some((entry) => typeof entry === "string" && LEGACY_OPENCODE_PLUGIN_SPECS.some((spec) => entry === spec || entry.startsWith(`${spec}@`)));
7204
- if (hasCanonicalSpec && !hasLegacySpec && !force) {
7262
+ const result = reconcileOpencodePluginConfig(config, { force });
7263
+ if (!result.changed) {
7205
7264
  p.log.info(`Plugin "${OPENCODE_PLUGIN_SPEC}" already in plugin array`);
7206
7265
  return true;
7207
7266
  }
7208
- plugins = plugins.filter((entry) => !isManagedPluginSpec(entry));
7209
- if (hasLegacySpec) p.log.step("Removed legacy OpenCode plugin spec(s): codemem / @kunickiaj/codemem");
7210
- plugins.push(OPENCODE_PLUGIN_SPEC);
7211
- config.plugin = plugins;
7267
+ if (result.removedLegacy) p.log.step("Removed legacy OpenCode plugin spec(s): codemem / @kunickiaj/codemem");
7212
7268
  try {
7213
- writeJsonConfig(configPath, config);
7269
+ writeJsonConfig(configPath, result.config);
7214
7270
  p.log.success(`Plugin "${OPENCODE_PLUGIN_SPEC}" added to ${configPath}`);
7215
7271
  } catch (err) {
7216
7272
  p.log.error(`Failed to write ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -9083,7 +9139,64 @@ var INSTALL_TIMEOUT_MS = 42e4;
9083
9139
  var VERIFY_TIMEOUT_MS = 3e4;
9084
9140
  var PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
9085
9141
  var UPDATE_LOCK_FILE = "update-install.lock";
9142
+ var UPDATE_COMMAND_MAX_OUTPUT_BYTES = 65536;
9086
9143
  var UpdateInstallLockedError = class extends Error {};
9144
+ var PnpmOwnershipError = class extends Error {};
9145
+ function commandStderr(outputExceeded, timedOut, stderr) {
9146
+ if (outputExceeded) return "command output too large";
9147
+ if (timedOut) return "command timed out";
9148
+ return stderr;
9149
+ }
9150
+ function createOutputCapture(maxOutputBytes) {
9151
+ let exceeded = false;
9152
+ let outputBytes = 0;
9153
+ let stderr = "";
9154
+ let stdout = "";
9155
+ return {
9156
+ append(stream, chunk) {
9157
+ if (exceeded) return;
9158
+ outputBytes += Buffer.byteLength(chunk);
9159
+ if (maxOutputBytes !== void 0 && outputBytes > maxOutputBytes) {
9160
+ exceeded = true;
9161
+ return;
9162
+ }
9163
+ if (stream === "stderr") stderr += chunk;
9164
+ else stdout += chunk;
9165
+ },
9166
+ exceeded: () => exceeded,
9167
+ stderr: () => stderr,
9168
+ stdout: () => stdout
9169
+ };
9170
+ }
9171
+ function terminateWindowsProcessTree(pid) {
9172
+ if (process.platform !== "win32" || !pid) return false;
9173
+ const systemRoot = process.env.SystemRoot?.trim();
9174
+ if (!systemRoot || !isAbsolute(systemRoot)) return false;
9175
+ spawnSync(join(systemRoot, "System32", "taskkill.exe"), [
9176
+ "/PID",
9177
+ String(pid),
9178
+ "/T",
9179
+ "/F"
9180
+ ], {
9181
+ stdio: "ignore",
9182
+ windowsHide: true
9183
+ });
9184
+ return true;
9185
+ }
9186
+ function terminatePosixProcessGroup(pid, signal) {
9187
+ if (process.platform === "win32" || !pid) return false;
9188
+ try {
9189
+ process.kill(-pid, signal);
9190
+ return true;
9191
+ } catch {
9192
+ return false;
9193
+ }
9194
+ }
9195
+ function terminateCommand(child, signal) {
9196
+ if (terminateWindowsProcessTree(child.pid)) return;
9197
+ if (terminatePosixProcessGroup(child.pid, signal)) return;
9198
+ child.kill(signal);
9199
+ }
9087
9200
  function updateInstallLockPath() {
9088
9201
  return join(process.env.HOME?.trim() || homedir(), ".codemem", UPDATE_LOCK_FILE);
9089
9202
  }
@@ -9143,8 +9256,7 @@ function runCommand(command, args, timeoutMs, options = {}) {
9143
9256
  });
9144
9257
  let settled = false;
9145
9258
  let timedOut = false;
9146
- let stdout = "";
9147
- let stderr = "";
9259
+ const output = createOutputCapture(options.maxOutputBytes);
9148
9260
  let timer;
9149
9261
  const finish = (result) => {
9150
9262
  if (settled) return;
@@ -9152,28 +9264,7 @@ function runCommand(command, args, timeoutMs, options = {}) {
9152
9264
  clearTimeout(timer);
9153
9265
  resolve(result);
9154
9266
  };
9155
- const terminate = (signal) => {
9156
- if (process.platform === "win32" && child.pid) {
9157
- const systemRoot = process.env.SystemRoot?.trim();
9158
- if (systemRoot && isAbsolute(systemRoot)) {
9159
- spawnSync(join(systemRoot, "System32", "taskkill.exe"), [
9160
- "/PID",
9161
- String(child.pid),
9162
- "/T",
9163
- "/F"
9164
- ], {
9165
- stdio: "ignore",
9166
- windowsHide: true
9167
- });
9168
- return;
9169
- }
9170
- }
9171
- if (process.platform !== "win32" && child.pid) try {
9172
- process.kill(-child.pid, signal);
9173
- return;
9174
- } catch {}
9175
- child.kill(signal);
9176
- };
9267
+ const terminate = (signal) => terminateCommand(child, signal);
9177
9268
  timer = setTimeout(() => {
9178
9269
  timedOut = true;
9179
9270
  terminate("SIGTERM");
@@ -9182,34 +9273,43 @@ function runCommand(command, args, timeoutMs, options = {}) {
9182
9273
  child.stdout.setEncoding("utf8");
9183
9274
  child.stderr.setEncoding("utf8");
9184
9275
  child.stdout.on("data", (chunk) => {
9185
- stdout += chunk;
9276
+ output.append("stdout", chunk);
9186
9277
  });
9187
9278
  child.stderr.on("data", (chunk) => {
9188
- stderr += chunk;
9279
+ output.append("stderr", chunk);
9189
9280
  });
9190
9281
  child.once("error", (error) => {
9191
9282
  clearTimeout(timer);
9192
9283
  if (!settled) reject(error);
9193
9284
  });
9194
- child.once("close", (code) => finish({
9195
- exitCode: code ?? 1,
9196
- stdout,
9197
- stderr: timedOut ? "command timed out" : stderr
9198
- }));
9285
+ child.once("close", (code) => {
9286
+ const stderr = commandStderr(output.exceeded(), timedOut, output.stderr());
9287
+ finish({
9288
+ exitCode: code ?? 1,
9289
+ outputExceeded: output.exceeded(),
9290
+ stdout: output.stdout(),
9291
+ stderr
9292
+ });
9293
+ });
9199
9294
  });
9200
9295
  }
9201
9296
  async function resolveWindowsShim(name) {
9202
9297
  const systemRoot = process.env.SystemRoot?.trim();
9203
9298
  if (!systemRoot || !isAbsolute(systemRoot)) throw new Error("Windows SystemRoot is unavailable");
9204
- const result = await runCommand(join(systemRoot, "System32", "where.exe"), [name], 1e4, { cwd: join(systemRoot, "System32") });
9299
+ const result = await runCommand(join(systemRoot, "System32", "where.exe"), [name], 1e4, {
9300
+ cwd: join(systemRoot, "System32"),
9301
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES
9302
+ });
9303
+ if (result.outputExceeded) throw new Error(`unable to resolve ${name}: where.exe output too large`);
9205
9304
  const shim = result.stdout.split(/\r?\n/).map((value) => value.trim()).find((value) => isAbsolute(value));
9206
- if (result.exitCode !== 0 || !shim) throw new Error(`unable to resolve ${name} from PATH`);
9305
+ if (!shim) throw Object.assign(/* @__PURE__ */ new Error(`unable to resolve ${name} from PATH`), { code: "ENOENT" });
9306
+ if (result.exitCode !== 0) throw new Error(`where.exe failed while resolving ${name}`);
9207
9307
  return shim;
9208
9308
  }
9209
9309
  function windowsCommandLine(shim, args) {
9210
9310
  return `""${shim}" ${args.join(" ")}"`;
9211
9311
  }
9212
- async function resolveInstallCommand() {
9312
+ async function resolveNpmInstallCommand() {
9213
9313
  if (process.platform !== "win32") return {
9214
9314
  command: "npm",
9215
9315
  args: []
@@ -9227,6 +9327,31 @@ async function resolveInstallCommand() {
9227
9327
  cwd: join(systemRoot, "System32")
9228
9328
  };
9229
9329
  }
9330
+ async function resolvePnpmCommand() {
9331
+ if (process.platform !== "win32") return {
9332
+ command: "pnpm",
9333
+ args: []
9334
+ };
9335
+ const systemRoot = process.env.SystemRoot?.trim();
9336
+ if (!systemRoot || !isAbsolute(systemRoot)) throw new Error("Windows SystemRoot is unavailable");
9337
+ return {
9338
+ command: join(systemRoot, "System32", "cmd.exe"),
9339
+ args: [
9340
+ "/d",
9341
+ "/s",
9342
+ "/c",
9343
+ await resolveWindowsShim("pnpm.cmd")
9344
+ ],
9345
+ cwd: join(systemRoot, "System32"),
9346
+ windowsVerbatimArguments: true
9347
+ };
9348
+ }
9349
+ function resolvedCommandArgs(command, args) {
9350
+ if (process.platform !== "win32") return args;
9351
+ const shim = command.args[3];
9352
+ if (!shim) throw new Error("Windows command shim is unavailable");
9353
+ return [...command.args.slice(0, 3), windowsCommandLine(shim, args)];
9354
+ }
9230
9355
  async function resolveVerificationCommand() {
9231
9356
  if (process.platform !== "win32") return {
9232
9357
  command: "codemem",
@@ -9260,6 +9385,7 @@ function renderStatusWarning(error) {
9260
9385
  }
9261
9386
  function renderHumanStatus(status) {
9262
9387
  const warning = renderStatusWarning(status.error);
9388
+ if (status.install_kind === "repo-dev") return `Running from repository source (package metadata: ${status.current_version}). ${status.recommended_action}${warning}`;
9263
9389
  if (status.update_available) return `Update available${cacheQualifier(status.stale)}: ${status.current_version} → ${status.latest_version}. ${status.recommended_action}${warning}`;
9264
9390
  if (!status.channel || !isReleaseVersionForChannel(status.current_version, status.channel)) return `Unable to compare current version ${status.current_version} with ${status.latest_version}. ${status.recommended_action}${warning}`;
9265
9391
  return `${status.current_version} is up to date${cacheQualifier(status.stale)}.${warning}`;
@@ -9311,56 +9437,487 @@ function updateInstallArgs(npmArgs, targetVersion) {
9311
9437
  if (process.platform !== "win32") return installArgs;
9312
9438
  return [...npmArgs.slice(0, 3), windowsCommandLine(npmArgs[3] ?? "", installArgs)];
9313
9439
  }
9314
- async function installUpdate(options) {
9315
- let releaseInstallLock = null;
9440
+ function packageManagerEnvironment() {
9441
+ const env = { ...process.env };
9442
+ const protectedKeys = /* @__PURE__ */ new Set(["npm_config_registry", "npm_config_@codemem:registry"]);
9443
+ if (process.platform === "linux") protectedKeys.add("onnxruntime_node_install");
9444
+ for (const key of Object.keys(env)) if (protectedKeys.has(key.toLowerCase())) delete env[key];
9445
+ env.npm_config_registry = PUBLIC_NPM_REGISTRY;
9446
+ env["npm_config_@codemem:registry"] = PUBLIC_NPM_REGISTRY;
9447
+ if (process.platform === "linux") env.ONNXRUNTIME_NODE_INSTALL = "skip";
9448
+ return env;
9449
+ }
9450
+ function miseGlobalCwd() {
9451
+ if (process.platform !== "win32") return "/";
9452
+ const systemRoot = process.env.SystemRoot?.trim();
9453
+ if (systemRoot) {
9454
+ const root = win32.parse(systemRoot).root;
9455
+ if (root) return root;
9456
+ }
9457
+ return process.env.HOME?.trim() || homedir();
9458
+ }
9459
+ function updateInstallCwd() {
9460
+ return dirname(updateInstallLockPath());
9461
+ }
9462
+ async function resolveUpdateInstallCommand(installKind, targetVersion, pnpmCommand) {
9463
+ if (installKind === "mise") return {
9464
+ command: "mise",
9465
+ args: [
9466
+ "use",
9467
+ "-g",
9468
+ `npm:codemem@${targetVersion}`
9469
+ ],
9470
+ cwd: miseGlobalCwd(),
9471
+ env: packageManagerEnvironment()
9472
+ };
9473
+ if (installKind === "pnpm-global") {
9474
+ const pnpm = pnpmCommand ?? await resolvePnpmCommand();
9475
+ return {
9476
+ ...pnpm,
9477
+ args: resolvedCommandArgs(pnpm, [
9478
+ "add",
9479
+ "-g",
9480
+ "--registry",
9481
+ PUBLIC_NPM_REGISTRY,
9482
+ `--config.@codemem:registry=${PUBLIC_NPM_REGISTRY}`,
9483
+ `codemem@${targetVersion}`,
9484
+ `@codemem/embeddings@${targetVersion}`
9485
+ ]),
9486
+ cwd: updateInstallCwd(),
9487
+ env: packageManagerEnvironment()
9488
+ };
9489
+ }
9490
+ const npm = await resolveNpmInstallCommand();
9491
+ return {
9492
+ command: npm.command,
9493
+ args: updateInstallArgs(npm.args, targetVersion),
9494
+ cwd: npm.cwd,
9495
+ env: process.platform === "linux" ? {
9496
+ ...process.env,
9497
+ ONNXRUNTIME_NODE_INSTALL: "skip"
9498
+ } : void 0,
9499
+ windowsVerbatimArguments: process.platform === "win32"
9500
+ };
9501
+ }
9502
+ function installLaunchErrorMessage(installKind, targetVersion, error) {
9503
+ if ((installKind === "mise" || installKind === "pnpm-global") && error instanceof Error && error.code === "ENOENT") {
9504
+ if (installKind === "pnpm-global") return "pnpm was not found on PATH; install pnpm, then retry codemem update install";
9505
+ return `mise was not found on PATH; install mise, then run mise use -g npm:codemem@${targetVersion}`;
9506
+ }
9507
+ return error instanceof Error ? error.message : "update installation failed";
9508
+ }
9509
+ function failedInstallMessage(installKind) {
9510
+ if (installKind === "mise") return "mise installation failed";
9511
+ if (installKind === "pnpm-global") return "pnpm installation failed";
9512
+ return "npm installation failed";
9513
+ }
9514
+ async function runUpdateInstallCommand(installKind, targetVersion, pnpmCommand) {
9515
+ const install = await resolveUpdateInstallCommand(installKind, targetVersion, pnpmCommand);
9316
9516
  try {
9317
- const installKind = detectInstallKind({
9318
- entryPath: process.argv[1] ?? "",
9319
- env: process.env
9517
+ return await runCommand(install.command, install.args, INSTALL_TIMEOUT_MS, {
9518
+ cwd: install.cwd,
9519
+ env: install.env,
9520
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES,
9521
+ windowsVerbatimArguments: install.windowsVerbatimArguments
9320
9522
  });
9321
- const status = await getUpdateStatus({
9322
- currentVersion: VERSION,
9323
- installKind,
9324
- refresh: true
9523
+ } catch (error) {
9524
+ throw new Error(installLaunchErrorMessage(installKind, targetVersion, error));
9525
+ }
9526
+ }
9527
+ function parseMiseSourcePath(source) {
9528
+ if (!source || typeof source !== "object" || Array.isArray(source)) return null;
9529
+ const sourcePath = source.path;
9530
+ return typeof sourcePath === "string" && sourcePath ? sourcePath : null;
9531
+ }
9532
+ function parseMiseStateRecord(record) {
9533
+ if (!record || typeof record !== "object" || Array.isArray(record)) return null;
9534
+ const candidate = record;
9535
+ const sourcePath = parseMiseSourcePath(candidate.source);
9536
+ const version = candidate.version;
9537
+ const requestedVersion = candidate.requested_version;
9538
+ if (typeof candidate.active !== "boolean" || typeof candidate.install_path !== "string" || !candidate.install_path || version !== void 0 && (typeof version !== "string" || !version) || requestedVersion !== void 0 && (typeof requestedVersion !== "string" || !requestedVersion) || typeof version !== "string" && typeof requestedVersion !== "string" || !sourcePath) return null;
9539
+ return {
9540
+ active: candidate.active,
9541
+ installPath: candidate.install_path,
9542
+ requestedVersion: typeof requestedVersion === "string" ? requestedVersion : null,
9543
+ sourceIdentity: resolveComparablePath(sourcePath),
9544
+ sourcePath,
9545
+ version: typeof version === "string" ? version : null
9546
+ };
9547
+ }
9548
+ function parseMiseState(raw) {
9549
+ if (Buffer.byteLength(raw) > UPDATE_COMMAND_MAX_OUTPUT_BYTES) return null;
9550
+ let payload;
9551
+ try {
9552
+ payload = JSON.parse(raw);
9553
+ } catch {
9554
+ return null;
9555
+ }
9556
+ if (!Array.isArray(payload)) return null;
9557
+ if (payload.length === 0) return {
9558
+ empty: true,
9559
+ state: null
9560
+ };
9561
+ if (payload.length !== 1) return null;
9562
+ const state = parseMiseStateRecord(payload[0]);
9563
+ return state ? {
9564
+ empty: false,
9565
+ state
9566
+ } : null;
9567
+ }
9568
+ async function readMiseState(args, targetVersion, options = {}) {
9569
+ try {
9570
+ const result = await runCommand("mise", args, VERIFY_TIMEOUT_MS, {
9571
+ cwd: options.cwd,
9572
+ env: packageManagerEnvironment(),
9573
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES
9325
9574
  });
9326
- if (!status.auto_update_eligible || !status.latest_version) {
9327
- failInstall(options, "update_install_refused", status.recommended_action);
9328
- return;
9329
- }
9330
- const targetVersion = status.latest_version;
9331
- if (!status.channel || !isReleaseVersionForChannel(targetVersion, status.channel)) {
9332
- failInstall(options, "update_install_refused", "release version does not match the installed channel");
9333
- return;
9334
- }
9335
- releaseInstallLock = await acquireInstallLock();
9336
- const npm = await resolveInstallCommand();
9337
- const installation = await runCommand(npm.command, updateInstallArgs(npm.args, targetVersion), INSTALL_TIMEOUT_MS, {
9338
- cwd: npm.cwd,
9339
- env: process.platform === "linux" ? {
9340
- ...process.env,
9341
- ONNXRUNTIME_NODE_INSTALL: "skip"
9342
- } : void 0,
9343
- windowsVerbatimArguments: process.platform === "win32"
9575
+ if (result.exitCode !== 0 || result.outputExceeded) return null;
9576
+ return parseMiseState(result.stdout);
9577
+ } catch (error) {
9578
+ throw new Error(installLaunchErrorMessage("mise", targetVersion, error));
9579
+ }
9580
+ }
9581
+ function isPathWithin(path, root) {
9582
+ return path === root || path.startsWith(`${root}/`);
9583
+ }
9584
+ function isPathBelow(path, root) {
9585
+ return path.startsWith(`${root}/`);
9586
+ }
9587
+ function isPortableAbsolutePath(value) {
9588
+ return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value);
9589
+ }
9590
+ function isSafeAbsoluteDirectory(value) {
9591
+ if (!isPortableAbsolutePath(value)) return false;
9592
+ const normalized = resolveComparablePath(value);
9593
+ return normalized !== "/" && !/^[a-z]:$/i.test(normalized);
9594
+ }
9595
+ function resolveExistingComparablePath(value) {
9596
+ try {
9597
+ return resolveComparablePath(realpathSync(value));
9598
+ } catch {
9599
+ return null;
9600
+ }
9601
+ }
9602
+ function parsePnpmPackageState(value) {
9603
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
9604
+ const record = value;
9605
+ if (typeof record.path !== "string" || !isPortableAbsolutePath(record.path) || typeof record.version !== "string" || !record.version) return null;
9606
+ return {
9607
+ path: record.path,
9608
+ version: record.version
9609
+ };
9610
+ }
9611
+ function parsePnpmGlobalState(raw) {
9612
+ if (Buffer.byteLength(raw) > UPDATE_COMMAND_MAX_OUTPUT_BYTES) return null;
9613
+ let payload;
9614
+ try {
9615
+ payload = JSON.parse(raw);
9616
+ } catch {
9617
+ return null;
9618
+ }
9619
+ if (!Array.isArray(payload) || payload.length !== 1) return null;
9620
+ const topLevel = payload[0];
9621
+ if (!topLevel || typeof topLevel !== "object" || Array.isArray(topLevel)) return null;
9622
+ const topLevelRecord = topLevel;
9623
+ if (typeof topLevelRecord.private !== "boolean" || typeof topLevelRecord.path !== "string" || !isPortableAbsolutePath(topLevelRecord.path)) return null;
9624
+ const dependencies = topLevelRecord.dependencies;
9625
+ if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) return null;
9626
+ const records = dependencies;
9627
+ if (!Object.hasOwn(records, "codemem")) return null;
9628
+ const codemem = parsePnpmPackageState(records.codemem);
9629
+ if (!codemem) return null;
9630
+ if (!Object.hasOwn(records, "@codemem/embeddings")) return {
9631
+ codemem,
9632
+ embeddings: null,
9633
+ listRootPath: topLevelRecord.path
9634
+ };
9635
+ const embeddings = parsePnpmPackageState(records["@codemem/embeddings"]);
9636
+ return embeddings ? {
9637
+ codemem,
9638
+ embeddings,
9639
+ listRootPath: topLevelRecord.path
9640
+ } : null;
9641
+ }
9642
+ function parsePnpmDirectory(raw) {
9643
+ if (Buffer.byteLength(raw) > UPDATE_COMMAND_MAX_OUTPUT_BYTES) return null;
9644
+ const directories = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).filter(isSafeAbsoluteDirectory).map(resolveExistingComparablePath).filter((directory) => directory !== null);
9645
+ return directories.length === 1 ? directories[0] ?? null : null;
9646
+ }
9647
+ var PNPM_SETUP_GUIDANCE = "Run pnpm setup, then retry codemem update install";
9648
+ function isMissingPnpmGlobalBinDirectory(result) {
9649
+ const output = `${result.stdout}\n${result.stderr}`.toLowerCase();
9650
+ return output.includes("err_pnpm_global_bin_dir_not_in_path") || output.includes("configured global bin directory") && output.includes("is not in path");
9651
+ }
9652
+ async function runPnpmQuery(command, args) {
9653
+ try {
9654
+ return await runCommand(command.command, resolvedCommandArgs(command, args), VERIFY_TIMEOUT_MS, {
9655
+ cwd: updateInstallCwd(),
9656
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES,
9657
+ windowsVerbatimArguments: command.windowsVerbatimArguments
9344
9658
  });
9345
- if (installation.exitCode !== 0) {
9346
- failInstall(options, "update_install_failed", installation.stderr.trim() || "npm installation failed");
9347
- return;
9348
- }
9349
- const codemem = await resolveVerificationCommand();
9350
- const verification = await runCommand(codemem.command, process.platform === "win32" ? [...codemem.args.slice(0, 3), windowsCommandLine(codemem.args[3] ?? "", ["version"])] : ["version"], VERIFY_TIMEOUT_MS, {
9351
- cwd: codemem.cwd,
9352
- windowsVerbatimArguments: process.platform === "win32"
9659
+ } catch (error) {
9660
+ if (error instanceof Error && error.code === "ENOENT") throw new PnpmOwnershipError("pnpm was not found on PATH; install pnpm, then retry codemem update install");
9661
+ throw error;
9662
+ }
9663
+ }
9664
+ async function requirePnpmQuery(command, args) {
9665
+ const result = await runPnpmQuery(command, args);
9666
+ const label = `pnpm ${args.join(" ")}`;
9667
+ if (isMissingPnpmGlobalBinDirectory(result)) throw new PnpmOwnershipError(PNPM_SETUP_GUIDANCE);
9668
+ if (result.outputExceeded) throw new PnpmOwnershipError(`${label} returned too much output; inspect pnpm global state`);
9669
+ if (result.exitCode !== 0) throw new PnpmOwnershipError(`${label} failed${result.stderr.trim() ? `: ${result.stderr.trim()}` : "; inspect pnpm global configuration"}`);
9670
+ return result.stdout;
9671
+ }
9672
+ async function provePnpmGlobalOwnership(plan) {
9673
+ let command;
9674
+ try {
9675
+ command = await resolvePnpmCommand();
9676
+ } catch (error) {
9677
+ throw new PnpmOwnershipError(installLaunchErrorMessage("pnpm-global", plan.targetVersion, error));
9678
+ }
9679
+ const rootRaw = await requirePnpmQuery(command, ["root", "-g"]);
9680
+ const binRaw = await requirePnpmQuery(command, ["bin", "-g"]);
9681
+ const listRaw = await requirePnpmQuery(command, [
9682
+ "list",
9683
+ "-g",
9684
+ "--depth",
9685
+ "0",
9686
+ "--json"
9687
+ ]);
9688
+ const rootPath = parsePnpmDirectory(rootRaw);
9689
+ if (!rootPath) throw new PnpmOwnershipError("pnpm root -g did not return one absolute non-root path");
9690
+ const binPath = parsePnpmDirectory(binRaw);
9691
+ if (!binPath) throw new PnpmOwnershipError("pnpm bin -g did not return one absolute non-root path");
9692
+ const state = parsePnpmGlobalState(listRaw);
9693
+ if (!state) throw new PnpmOwnershipError("pnpm list -g returned malformed or ambiguous global package state");
9694
+ if (state.codemem.version !== VERSION) throw new PnpmOwnershipError(`pnpm global codemem is ${state.codemem.version}, but the running CLI is ${VERSION}`);
9695
+ const listRootPath = resolveExistingComparablePath(state.listRootPath);
9696
+ const legacyModulesPath = listRootPath ? resolveExistingComparablePath(join(listRootPath, "node_modules")) : null;
9697
+ if (!listRootPath || rootPath !== listRootPath && rootPath !== legacyModulesPath) throw new PnpmOwnershipError("pnpm root -g is neither the pnpm list -g root nor its node_modules directory");
9698
+ const packagePath = resolveExistingComparablePath(state.codemem.path);
9699
+ if (!packagePath || !isPathBelow(packagePath, listRootPath)) throw new PnpmOwnershipError("pnpm list -g root does not own the listed codemem package path");
9700
+ const entryPath = plan.runningEntryPath;
9701
+ const canonicalEntryPath = entryPath ? resolveExistingComparablePath(entryPath) : null;
9702
+ if (!canonicalEntryPath || !isPathWithin(canonicalEntryPath, packagePath)) throw new PnpmOwnershipError("the pnpm global codemem package does not own the running JavaScript entry");
9703
+ return {
9704
+ binPath,
9705
+ command,
9706
+ listRootPath
9707
+ };
9708
+ }
9709
+ function isUserOwnedMiseSource(state) {
9710
+ if (!isPortableAbsolutePath(state.sourcePath)) return false;
9711
+ const sourcePath = resolveComparablePath(state.sourcePath);
9712
+ const homePath = resolveComparablePath(process.env.HOME?.trim() || homedir());
9713
+ if (homePath === "/" || /^[a-z]:$/i.test(homePath)) return false;
9714
+ return isPathWithin(sourcePath, homePath);
9715
+ }
9716
+ function isLegacyUserMiseSource(state) {
9717
+ if (!isUserOwnedMiseSource(state)) return false;
9718
+ const home = process.env.HOME?.trim() || homedir();
9719
+ const configHome = process.env.XDG_CONFIG_HOME?.trim() || join(home, ".config");
9720
+ return state.sourceIdentity === resolveComparablePath(join(configHome, "mise.toml"));
9721
+ }
9722
+ function miseStateOwnsEntry(state, runningEntryPath) {
9723
+ if (!runningEntryPath) return false;
9724
+ if (!isPortableAbsolutePath(state.installPath)) return false;
9725
+ const installPath = resolveComparablePath(state.installPath);
9726
+ const entryPath = resolveComparablePath(runningEntryPath);
9727
+ if (installPath === "/" || /^[a-z]:$/i.test(installPath)) return false;
9728
+ return entryPath === installPath || entryPath.startsWith(`${installPath}/`);
9729
+ }
9730
+ async function proveGlobalMiseOwnership(plan) {
9731
+ const activeState = (await readMiseState([
9732
+ "ls",
9733
+ "npm:codemem",
9734
+ "--current",
9735
+ "--json"
9736
+ ], plan.targetVersion))?.state;
9737
+ if (!activeState?.active || !miseStateOwnsEntry(activeState, plan.runningEntryPath)) return null;
9738
+ const globalQuery = await readMiseState([
9739
+ "ls",
9740
+ "npm:codemem",
9741
+ "--global",
9742
+ "--json"
9743
+ ], plan.targetVersion, { cwd: miseGlobalCwd() });
9744
+ if (globalQuery?.empty && isLegacyUserMiseSource(activeState)) return activeState;
9745
+ const globalState = globalQuery?.state;
9746
+ if (!globalState?.active || activeState.sourceIdentity !== globalState.sourceIdentity || !isUserOwnedMiseSource(globalState)) return null;
9747
+ return globalState;
9748
+ }
9749
+ async function resolveExplicitUpdatePlan(options) {
9750
+ const detectedInstallKind = detectInstallKind({
9751
+ entryPath: process.argv[1] ?? "",
9752
+ env: process.env
9753
+ });
9754
+ const status = await getUpdateStatus({
9755
+ currentVersion: VERSION,
9756
+ installKind: detectedInstallKind,
9757
+ refresh: true
9758
+ });
9759
+ if (!isExplicitUpdateInstallEligible(status) || !status.latest_version) {
9760
+ failInstall(options, "update_install_refused", status.recommended_action);
9761
+ return null;
9762
+ }
9763
+ if (!status.channel || !isReleaseVersionForChannel(status.latest_version, status.channel)) {
9764
+ failInstall(options, "update_install_refused", "release version does not match the installed channel");
9765
+ return null;
9766
+ }
9767
+ return {
9768
+ installKind: status.install_kind,
9769
+ manualGuidance: status.recommended_action,
9770
+ runningEntryPath: detectedInstallKind === "mise" || detectedInstallKind === "pnpm-global" ? resolveRunningEntryPath(process.argv[1] ?? "") : null,
9771
+ targetVersion: status.latest_version
9772
+ };
9773
+ }
9774
+ function resolveRunningEntryPath(entryPath) {
9775
+ return resolveComparablePath(entryPath);
9776
+ }
9777
+ async function verifyMiseInstalledVersion(plan) {
9778
+ const globalState = (await readMiseState([
9779
+ "ls",
9780
+ "npm:codemem",
9781
+ "--global",
9782
+ "--json"
9783
+ ], plan.targetVersion, { cwd: miseGlobalCwd() }))?.state;
9784
+ if (!globalState?.active || globalState.version !== plan.targetVersion && globalState.requestedVersion !== plan.targetVersion) return false;
9785
+ const verification = await runCommand("mise", [
9786
+ "exec",
9787
+ "--",
9788
+ "codemem",
9789
+ "version"
9790
+ ], VERIFY_TIMEOUT_MS, {
9791
+ cwd: miseGlobalCwd(),
9792
+ env: packageManagerEnvironment(),
9793
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES
9794
+ });
9795
+ return !verification.outputExceeded && verification.exitCode === 0 && verification.stdout.trim() === plan.targetVersion;
9796
+ }
9797
+ function pnpmPackageStateError(state, ownership, targetVersion) {
9798
+ if (!state.embeddings) return "pnpm update completed, but @codemem/embeddings is absent from global package state";
9799
+ if (state.codemem.version !== targetVersion || state.embeddings.version !== targetVersion) return `pnpm update completed, but global package versions do not both equal ${targetVersion}`;
9800
+ if (resolveExistingComparablePath(state.listRootPath) !== ownership.listRootPath) return "pnpm update completed, but the pnpm list -g root changed after ownership was proven";
9801
+ if ([state.codemem.path, state.embeddings.path].map(resolveExistingComparablePath).some((packagePath) => !packagePath || !isPathBelow(packagePath, ownership.listRootPath))) return "pnpm update completed, but the pnpm list -g root does not own both package paths";
9802
+ return null;
9803
+ }
9804
+ async function verifyPnpmOwnedLauncher(plan, ownership) {
9805
+ const shimName = process.platform === "win32" ? "codemem.cmd" : "codemem";
9806
+ const shimPath = join(ownership.binPath, shimName);
9807
+ let verification;
9808
+ try {
9809
+ if (process.platform === "win32") verification = await runCommand(ownership.command.command, [
9810
+ "/d",
9811
+ "/s",
9812
+ "/c",
9813
+ windowsCommandLine(shimPath, ["version"])
9814
+ ], VERIFY_TIMEOUT_MS, {
9815
+ cwd: updateInstallCwd(),
9816
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES,
9817
+ windowsVerbatimArguments: true
9353
9818
  });
9354
- if (verification.exitCode !== 0 || verification.stdout.trim() !== targetVersion) {
9355
- failInstall(options, "update_verification_failed", "installed version verification failed");
9356
- return;
9357
- }
9358
- const result = {
9359
- previous_version: VERSION,
9360
- installed_version: targetVersion
9361
- };
9362
- if (options.json) console.log(JSON.stringify(result));
9363
- else console.log(`Updated codemem from ${VERSION} to ${targetVersion}.`);
9819
+ else verification = await runCommand(shimPath, ["version"], VERIFY_TIMEOUT_MS, {
9820
+ cwd: updateInstallCwd(),
9821
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES
9822
+ });
9823
+ } catch (error) {
9824
+ return `pnpm-owned codemem launcher could not be executed${error instanceof Error ? `: ${error.message}` : ""}`;
9825
+ }
9826
+ if (verification.outputExceeded) return "pnpm-owned codemem launcher returned too much output during version verification";
9827
+ if (verification.exitCode !== 0) return "pnpm-owned codemem launcher failed during version verification";
9828
+ const versionLines = verification.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(line));
9829
+ if (versionLines.length !== 1 || versionLines[0] !== plan.targetVersion) return `pnpm-owned codemem launcher did not report ${plan.targetVersion}`;
9830
+ return null;
9831
+ }
9832
+ async function verifyPnpmInstalledVersion(plan, ownership) {
9833
+ let listRaw;
9834
+ try {
9835
+ listRaw = await requirePnpmQuery(ownership.command, [
9836
+ "list",
9837
+ "-g",
9838
+ "--depth",
9839
+ "0",
9840
+ "--json"
9841
+ ]);
9842
+ } catch (error) {
9843
+ return error instanceof Error ? `pnpm update completed, but package-state verification failed: ${error.message}` : "pnpm update completed, but package-state verification failed";
9844
+ }
9845
+ const state = parsePnpmGlobalState(listRaw);
9846
+ if (!state) return "pnpm update completed, but global package state is malformed or ambiguous";
9847
+ const packageStateError = pnpmPackageStateError(state, ownership, plan.targetVersion);
9848
+ if (packageStateError) return packageStateError;
9849
+ return verifyPnpmOwnedLauncher(plan, ownership);
9850
+ }
9851
+ async function verifyInstalledVersion(plan) {
9852
+ if (plan.installKind === "mise") return verifyMiseInstalledVersion(plan);
9853
+ const codemem = await resolveVerificationCommand();
9854
+ const verificationArgs = process.platform === "win32" ? [...codemem.args.slice(0, 3), windowsCommandLine(codemem.args[3] ?? "", ["version"])] : ["version"];
9855
+ const verification = await runCommand(codemem.command, verificationArgs, VERIFY_TIMEOUT_MS, {
9856
+ cwd: codemem.cwd,
9857
+ maxOutputBytes: UPDATE_COMMAND_MAX_OUTPUT_BYTES,
9858
+ windowsVerbatimArguments: process.platform === "win32"
9859
+ });
9860
+ return !verification.outputExceeded && verification.exitCode === 0 && verification.stdout.trim() === plan.targetVersion;
9861
+ }
9862
+ function emitInstallSuccess(options, targetVersion) {
9863
+ const result = {
9864
+ previous_version: VERSION,
9865
+ installed_version: targetVersion
9866
+ };
9867
+ if (options.json) console.log(JSON.stringify(result));
9868
+ else console.log(`Updated codemem from ${VERSION} to ${targetVersion}.`);
9869
+ }
9870
+ async function resolvePnpmOwnershipForExecution(options, plan) {
9871
+ try {
9872
+ return await provePnpmGlobalOwnership(plan);
9873
+ } catch (error) {
9874
+ failInstall(options, "update_install_refused", error instanceof Error ? error.message : "could not prove pnpm global ownership");
9875
+ return null;
9876
+ }
9877
+ }
9878
+ async function executeExplicitUpdate(options, plan) {
9879
+ const globalMiseState = plan.installKind === "mise" ? await proveGlobalMiseOwnership(plan) : null;
9880
+ if (plan.installKind === "mise" && !globalMiseState) {
9881
+ failInstall(options, "update_install_refused", `Could not prove the active mise codemem installation is globally configured. ${plan.manualGuidance}`);
9882
+ return;
9883
+ }
9884
+ const pnpmOwnership = plan.installKind === "pnpm-global" ? await resolvePnpmOwnershipForExecution(options, plan) : null;
9885
+ if (plan.installKind === "pnpm-global" && !pnpmOwnership) return;
9886
+ if (pnpmOwnership) {
9887
+ await executePnpmUpdate(options, plan, pnpmOwnership);
9888
+ return;
9889
+ }
9890
+ const installation = await runUpdateInstallCommand(plan.installKind, plan.targetVersion);
9891
+ if (installation.exitCode !== 0 || installation.outputExceeded) {
9892
+ failInstall(options, "update_install_failed", installation.stderr.trim() || failedInstallMessage(plan.installKind));
9893
+ return;
9894
+ }
9895
+ if (!await verifyInstalledVersion(plan)) {
9896
+ failInstall(options, "update_verification_failed", plan.installKind === "mise" ? "mise updated global configuration, but installed version verification failed; inspect the global mise codemem state before retrying" : "installed version verification failed");
9897
+ return;
9898
+ }
9899
+ emitInstallSuccess(options, plan.targetVersion);
9900
+ }
9901
+ async function executePnpmUpdate(options, plan, ownership) {
9902
+ const installation = await runUpdateInstallCommand(plan.installKind, plan.targetVersion, ownership.command);
9903
+ if (installation.exitCode !== 0) {
9904
+ failInstall(options, "update_install_failed", isMissingPnpmGlobalBinDirectory(installation) ? PNPM_SETUP_GUIDANCE : installation.stderr.trim() || failedInstallMessage(plan.installKind));
9905
+ return;
9906
+ }
9907
+ const verificationError = await verifyPnpmInstalledVersion(plan, ownership);
9908
+ if (verificationError) {
9909
+ failInstall(options, "update_verification_failed", verificationError);
9910
+ return;
9911
+ }
9912
+ emitInstallSuccess(options, plan.targetVersion);
9913
+ }
9914
+ async function installUpdate(options) {
9915
+ let releaseInstallLock = null;
9916
+ try {
9917
+ const plan = await resolveExplicitUpdatePlan(options);
9918
+ if (!plan) return;
9919
+ releaseInstallLock = await acquireInstallLock();
9920
+ await executeExplicitUpdate(options, plan);
9364
9921
  } catch (error) {
9365
9922
  failInstall(options, error instanceof UpdateInstallLockedError ? "update_install_locked" : "update_install_failed", error instanceof Error ? error.message : "update installation failed");
9366
9923
  } finally {