@aerovato/operator-helper 1.2.1 → 1.3.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
@@ -17998,7 +17998,7 @@ var Uint8Array2 = /* @__PURE__ */ instanceOf(globalThis.Uint8Array, {
17998
17998
  // package.json
17999
17999
  var package_default = {
18000
18000
  name: "@aerovato/operator-helper",
18001
- version: "1.2.1",
18001
+ version: "1.3.1",
18002
18002
  description: "Installation and setup CLI for Operator Memory",
18003
18003
  license: "BSD-3-Clause",
18004
18004
  author: "Aerovato Research",
@@ -18025,7 +18025,8 @@ var package_default = {
18025
18025
  node: ">=20"
18026
18026
  },
18027
18027
  files: [
18028
- "dist"
18028
+ "dist",
18029
+ "!dist/*.map"
18029
18030
  ],
18030
18031
  keywords: [
18031
18032
  "opencode",
@@ -19041,16 +19042,82 @@ var inspectMainIndex = fn2("inspectMainIndex")(function* (cwd, partitionRoot) {
19041
19042
 
19042
19043
  // src/commands/install/code-puppy.ts
19043
19044
  import { randomUUID } from "node:crypto";
19044
- import { lstat, mkdir as mkdir2, readFile as readFile3, rename as rename3, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
19045
+ import { mkdir as mkdir2, readFile as readFile4, rename as rename3, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
19045
19046
  import { join as join2 } from "node:path";
19046
19047
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19048
+
19049
+ // src/commands/common.ts
19050
+ import { lstat, readFile as readFile3 } from "node:fs/promises";
19051
+ function fileFailure(error) {
19052
+ return { exitCode: 1, output: fileErrorMessage(error) };
19053
+ }
19054
+ function fileErrorMessage(error) {
19055
+ if (error instanceof PathKindError) {
19056
+ return `✗ ${error.path}: Expected a ${error.expected}, found ${error.actual}`;
19057
+ }
19058
+ const path = error.reason instanceof SystemError ? `${error.reason.pathOrDescriptor}: ` : "";
19059
+ return `✗ ${path}${error.reason.description ?? error.message}`;
19060
+ }
19061
+ function runProcess(executable, arguments_, cwd, environment) {
19062
+ return gen2(function* () {
19063
+ const spawner = yield* ChildProcessSpawner;
19064
+ const command = make11(executable, [...arguments_], {
19065
+ cwd,
19066
+ env: environment ?? undefined,
19067
+ extendEnv: true
19068
+ });
19069
+ const execution = yield* scoped2(gen2(function* () {
19070
+ const handle = yield* spawner.spawn(command);
19071
+ const [stdout, stderr, exitCode] = yield* all2([
19072
+ handle.stdout.pipe(decodeText(), mkString),
19073
+ handle.stderr.pipe(decodeText(), mkString),
19074
+ handle.exitCode
19075
+ ], { concurrency: "unbounded" });
19076
+ return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode: Number(exitCode) };
19077
+ })).pipe(result2);
19078
+ if (isFailure2(execution)) {
19079
+ const error = execution.failure instanceof PlatformError ? execution.failure.reason.description ?? execution.failure.message : getErrorMessage(execution.failure);
19080
+ return { ok: false, error };
19081
+ }
19082
+ return {
19083
+ ok: true,
19084
+ ...execution.success,
19085
+ output: [execution.success.stdout, execution.success.stderr].filter(Boolean).join(`
19086
+ `)
19087
+ };
19088
+ });
19089
+ }
19090
+ async function pathKind(path) {
19091
+ try {
19092
+ const info = await lstat(path);
19093
+ return info.isFile() ? "file" : info.isDirectory() ? "directory" : "other";
19094
+ } catch (error) {
19095
+ if (isNodeError(error) && error.code === "ENOENT")
19096
+ return "missing";
19097
+ throw error;
19098
+ }
19099
+ }
19100
+ async function readOptionalFile(path) {
19101
+ try {
19102
+ return await readFile3(path, "utf8");
19103
+ } catch (error) {
19104
+ if (isNodeError(error) && error.code === "ENOENT")
19105
+ return null;
19106
+ throw error;
19107
+ }
19108
+ }
19109
+ function isNodeError(error) {
19110
+ return error instanceof Error && "code" in error;
19111
+ }
19112
+
19113
+ // src/commands/install/code-puppy.ts
19047
19114
  var CODE_PUPPY_MARKER = `Operator Memory managed Code Puppy plugin.
19048
19115
  `;
19049
19116
  var CODE_PUPPY_MARKER_FILE = ".operator-managed";
19050
19117
  var installCodePuppy = fn2("installCodePuppy")(function* (context) {
19051
19118
  return yield* promise2(async () => {
19052
19119
  try {
19053
- const source = await readFile3(await codePuppyAdapterPath(), "utf8");
19120
+ const source = await readFile4(await codePuppyAdapterPath(), "utf8");
19054
19121
  const plugins = join2(context.home, ".code_puppy", "plugins");
19055
19122
  const target = join2(plugins, "operator");
19056
19123
  const marker = join2(target, CODE_PUPPY_MARKER_FILE);
@@ -19069,13 +19136,13 @@ var installCodePuppy = fn2("installCodePuppy")(function* (context) {
19069
19136
  }
19070
19137
  return { exitCode: 0, output: "✓ Code Puppy plugin installed" };
19071
19138
  }
19072
- if (targetKind !== "directory" || await pathKind(marker) !== "file" || await readOptional(marker) !== CODE_PUPPY_MARKER) {
19139
+ if (targetKind !== "directory" || await pathKind(marker) !== "file" || await readOptionalFile(marker) !== CODE_PUPPY_MARKER) {
19073
19140
  return {
19074
19141
  exitCode: 1,
19075
19142
  output: `✗ Preserved unmanaged Code Puppy plugin at ${target}`
19076
19143
  };
19077
19144
  }
19078
- if (await readOptional(callbacks) === source) {
19145
+ if (await readOptionalFile(callbacks) === source) {
19079
19146
  return { exitCode: 0, output: "✓ Code Puppy plugin is current" };
19080
19147
  }
19081
19148
  const staged = `${callbacks}.tmp-${randomUUID()}`;
@@ -19107,36 +19174,116 @@ async function codePuppyAdapterPath() {
19107
19174
  }
19108
19175
  throw new Error("bundled Code Puppy adapter is missing");
19109
19176
  }
19110
- async function pathKind(path) {
19111
- try {
19112
- const info = await lstat(path);
19113
- return info.isFile() ? "file" : info.isDirectory() ? "directory" : "other";
19114
- } catch (error) {
19115
- if (isNodeError(error) && error.code === "ENOENT") {
19116
- return "missing";
19177
+
19178
+ // src/commands/install/codex.ts
19179
+ import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
19180
+ import { join as join3 } from "node:path";
19181
+ var MARKETPLACE_MARKER = `Operator Memory managed Codex marketplace.
19182
+ `;
19183
+ var MARKETPLACE_NAME = "operator-memory";
19184
+ var PLUGIN_NAME = "aerovato";
19185
+ var PLUGIN_ID = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
19186
+ var MARKETPLACE = `${JSON.stringify({
19187
+ name: MARKETPLACE_NAME,
19188
+ plugins: [
19189
+ {
19190
+ name: PLUGIN_NAME,
19191
+ source: {
19192
+ source: "npm",
19193
+ package: "@aerovato/operator-codex",
19194
+ version: "latest"
19195
+ },
19196
+ policy: { installation: "AVAILABLE" }
19117
19197
  }
19118
- throw error;
19198
+ ]
19199
+ }, null, 2)}
19200
+ `;
19201
+ var installCodex = fn2("installCodex")(function* (context) {
19202
+ const marketplace = yield* writeMarketplace(context.home);
19203
+ if (!marketplace.ok)
19204
+ return marketplace.result;
19205
+ const addMarketplace = yield* runProcess("codex", ["plugin", "marketplace", "add", marketplace.path, "--json"], context.cwd, { NPM_CONFIG_MIN_RELEASE_AGE: "0" });
19206
+ const addFailure = commandFailure(addMarketplace, "Codex marketplace installation failed");
19207
+ if (addFailure !== null)
19208
+ return addFailure;
19209
+ const install = yield* runProcess("codex", ["plugin", "add", PLUGIN_ID, "--json"], context.cwd, {
19210
+ NPM_CONFIG_MIN_RELEASE_AGE: "0"
19211
+ });
19212
+ const installFailure = commandFailure(install, "Codex plugin installation failed");
19213
+ if (installFailure !== null)
19214
+ return installFailure;
19215
+ const status = yield* runProcess("codex", ["plugin", "list", "--marketplace", MARKETPLACE_NAME, "--json"], context.cwd, { NPM_CONFIG_MIN_RELEASE_AGE: "0" });
19216
+ const statusFailure = commandFailure(status, "Could not verify Codex plugin installation");
19217
+ if (statusFailure !== null)
19218
+ return statusFailure;
19219
+ if (!(status.ok && isInstalledAndEnabled(status.stdout))) {
19220
+ return {
19221
+ exitCode: 1,
19222
+ output: "✗ Codex plugin installation finished but the plugin is not installed and enabled"
19223
+ };
19119
19224
  }
19225
+ return {
19226
+ exitCode: 0,
19227
+ output: [
19228
+ "✓ Codex plugin installed and enabled",
19229
+ "Start a new Codex session and approve the Operator hooks if prompted."
19230
+ ].join(`
19231
+ `)
19232
+ };
19233
+ });
19234
+ function writeMarketplace(home) {
19235
+ return promise2(async () => {
19236
+ const root = join3(home, ".operator-helper", "codex-marketplace");
19237
+ const marker = join3(root, ".operator-managed");
19238
+ const marketplace = join3(root, ".agents", "plugins", "marketplace.json");
19239
+ try {
19240
+ const kind = await pathKind(root);
19241
+ if (kind !== "missing" && (kind !== "directory" || await readOptionalFile(marker) !== MARKETPLACE_MARKER)) {
19242
+ return {
19243
+ ok: false,
19244
+ result: {
19245
+ exitCode: 1,
19246
+ output: `✗ Preserved unmanaged Codex marketplace at ${root}`
19247
+ }
19248
+ };
19249
+ }
19250
+ await mkdir3(join3(root, ".agents", "plugins"), { recursive: true });
19251
+ await writeFile4(marker, MARKETPLACE_MARKER);
19252
+ await writeFile4(marketplace, MARKETPLACE);
19253
+ return { ok: true, path: root };
19254
+ } catch (error) {
19255
+ return {
19256
+ ok: false,
19257
+ result: {
19258
+ exitCode: 1,
19259
+ output: `✗ Could not prepare Codex marketplace: ${getErrorMessage(error)}`
19260
+ }
19261
+ };
19262
+ }
19263
+ });
19120
19264
  }
19121
- async function readOptional(path) {
19265
+ function isInstalledAndEnabled(output) {
19122
19266
  try {
19123
- return await readFile3(path, "utf8");
19124
- } catch (error) {
19125
- if (isNodeError(error) && error.code === "ENOENT") {
19126
- return null;
19127
- }
19128
- throw error;
19267
+ const value = JSON.parse(output);
19268
+ if (typeof value !== "object" || value === null || !("installed" in value))
19269
+ return false;
19270
+ const installed = value.installed;
19271
+ return Array.isArray(installed) && installed.some((plugin) => typeof plugin === "object" && plugin !== null && ("pluginId" in plugin) && plugin.pluginId === PLUGIN_ID && ("installed" in plugin) && plugin.installed === true && ("enabled" in plugin) && plugin.enabled === true);
19272
+ } catch {
19273
+ return false;
19129
19274
  }
19130
19275
  }
19131
- function isNodeError(error) {
19132
- return error instanceof Error && "code" in error;
19276
+ function commandFailure(result, fallback) {
19277
+ if (!result.ok)
19278
+ return { exitCode: 1, output: `✗ Could not run codex: ${result.error}` };
19279
+ return result.exitCode === 0 ? null : { exitCode: result.exitCode, output: result.output || fallback };
19133
19280
  }
19281
+
19134
19282
  // src/commands/install/opencode.ts
19135
19283
  var OPENCODE_PLUGIN = "@aerovato/operator-opencode@latest";
19136
19284
  var installOpenCode = fn2("installOpenCode")(function* (context) {
19137
19285
  const fileSystem = yield* FileSystem;
19138
19286
  const path = yield* Path;
19139
- const spawner = yield* ChildProcessSpawner;
19140
19287
  const cacheRoot = process.env.XDG_CACHE_HOME || path.join(context.home, ".cache");
19141
19288
  const isCacheRemoved = yield* fileSystem.remove(path.join(cacheRoot, "opencode", "packages", "@aerovato", "operator-opencode@latest"), {
19142
19289
  recursive: true,
@@ -19148,85 +19295,39 @@ var installOpenCode = fn2("installOpenCode")(function* (context) {
19148
19295
  output: `✗ Could not clear the OpenCode plugin cache`
19149
19296
  };
19150
19297
  }
19151
- const command = make11("opencode", ["plugin", OPENCODE_PLUGIN, "--global", "--force"], {
19152
- cwd: context.cwd,
19153
- env: { NPM_CONFIG_MIN_RELEASE_AGE: "0" },
19154
- extendEnv: true
19155
- });
19156
- const execution = yield* scoped2(gen2(function* () {
19157
- const handle = yield* spawner.spawn(command);
19158
- const [stdout, stderr, exitCode] = yield* all2([
19159
- handle.stdout.pipe(decodeText(), mkString),
19160
- handle.stderr.pipe(decodeText(), mkString),
19161
- handle.exitCode
19162
- ], { concurrency: "unbounded" });
19163
- return { stdout, stderr, exitCode: Number(exitCode) };
19164
- })).pipe(result2);
19165
- if (isFailure2(execution)) {
19166
- const message = execution.failure instanceof PlatformError ? execution.failure.reason.description ?? execution.failure.message : getErrorMessage(execution.failure);
19167
- return { exitCode: 1, output: `✗ Could not run opencode: ${message}` };
19298
+ const execution = yield* runProcess("opencode", ["plugin", OPENCODE_PLUGIN, "--global", "--force"], context.cwd, { NPM_CONFIG_MIN_RELEASE_AGE: "0" });
19299
+ if (!execution.ok) {
19300
+ return { exitCode: 1, output: `✗ Could not run opencode: ${execution.error}` };
19168
19301
  }
19169
- const output = [execution.success.stdout.trim(), execution.success.stderr.trim()].filter(Boolean).join(`
19170
- `);
19171
- return execution.success.exitCode === 0 ? { exitCode: 0, output } : {
19172
- exitCode: execution.success.exitCode,
19173
- output: output || "OpenCode plugin installation failed"
19302
+ return execution.exitCode === 0 ? { exitCode: 0, output: execution.output } : {
19303
+ exitCode: execution.exitCode,
19304
+ output: execution.output || "OpenCode plugin installation failed"
19174
19305
  };
19175
19306
  });
19176
19307
 
19177
19308
  // src/commands/install/opencode-v2.ts
19178
19309
  var OPENCODE_V2_PLUGIN = "@aerovato/operator-opencode-v2@latest";
19179
19310
  var installOpenCodeV2 = fn2("installOpenCodeV2")(function* (context) {
19180
- const spawner = yield* ChildProcessSpawner;
19181
- const command = make11("opencode", ["plugin", "add", OPENCODE_V2_PLUGIN], {
19182
- cwd: context.cwd,
19183
- env: { NPM_CONFIG_MIN_RELEASE_AGE: "0" },
19184
- extendEnv: true
19185
- });
19186
- const execution = yield* scoped2(gen2(function* () {
19187
- const handle = yield* spawner.spawn(command);
19188
- const [stdout, stderr, exitCode] = yield* all2([
19189
- handle.stdout.pipe(decodeText(), mkString),
19190
- handle.stderr.pipe(decodeText(), mkString),
19191
- handle.exitCode
19192
- ], { concurrency: "unbounded" });
19193
- return { stdout, stderr, exitCode: Number(exitCode) };
19194
- })).pipe(result2);
19195
- if (isFailure2(execution)) {
19196
- const message = execution.failure instanceof PlatformError ? execution.failure.reason.description ?? execution.failure.message : getErrorMessage(execution.failure);
19197
- return { exitCode: 1, output: `✗ Could not run opencode: ${message}` };
19311
+ const execution = yield* runProcess("opencode", ["plugin", "add", OPENCODE_V2_PLUGIN], context.cwd, { NPM_CONFIG_MIN_RELEASE_AGE: "0" });
19312
+ if (!execution.ok) {
19313
+ return { exitCode: 1, output: `✗ Could not run opencode: ${execution.error}` };
19198
19314
  }
19199
- const output = [execution.success.stdout.trim(), execution.success.stderr.trim()].filter(Boolean).join(`
19200
- `);
19201
- return execution.success.exitCode === 0 ? { exitCode: 0, output } : {
19202
- exitCode: execution.success.exitCode,
19203
- output: output || "OpenCode V2 plugin installation failed"
19315
+ return execution.exitCode === 0 ? { exitCode: 0, output: execution.output } : {
19316
+ exitCode: execution.exitCode,
19317
+ output: execution.output || "OpenCode V2 plugin installation failed"
19204
19318
  };
19205
19319
  });
19206
19320
 
19207
19321
  // src/commands/install/pi.ts
19208
19322
  var PI_PLUGIN = "npm:@aerovato/operator-pi";
19209
19323
  var installPi = fn2("installPi")(function* (context) {
19210
- const spawner = yield* ChildProcessSpawner;
19211
- const command = make11("pi", ["install", PI_PLUGIN], { cwd: context.cwd });
19212
- const execution = yield* scoped2(gen2(function* () {
19213
- const handle = yield* spawner.spawn(command);
19214
- const [stdout, stderr, exitCode] = yield* all2([
19215
- handle.stdout.pipe(decodeText(), mkString),
19216
- handle.stderr.pipe(decodeText(), mkString),
19217
- handle.exitCode
19218
- ], { concurrency: "unbounded" });
19219
- return { stdout, stderr, exitCode: Number(exitCode) };
19220
- })).pipe(result2);
19221
- if (isFailure2(execution)) {
19222
- const message = execution.failure instanceof PlatformError ? execution.failure.reason.description ?? execution.failure.message : getErrorMessage(execution.failure);
19223
- return { exitCode: 1, output: `✗ Could not run pi: ${message}` };
19324
+ const execution = yield* runProcess("pi", ["install", PI_PLUGIN], context.cwd, null);
19325
+ if (!execution.ok) {
19326
+ return { exitCode: 1, output: `✗ Could not run pi: ${execution.error}` };
19224
19327
  }
19225
- const output = [execution.success.stdout.trim(), execution.success.stderr.trim()].filter(Boolean).join(`
19226
- `);
19227
- return execution.success.exitCode === 0 ? { exitCode: 0, output } : {
19228
- exitCode: execution.success.exitCode,
19229
- output: output || "Pi plugin installation failed"
19328
+ return execution.exitCode === 0 ? { exitCode: 0, output: execution.output } : {
19329
+ exitCode: execution.exitCode,
19330
+ output: execution.output || "Pi plugin installation failed"
19230
19331
  };
19231
19332
  });
19232
19333
 
@@ -19234,7 +19335,7 @@ var installPi = fn2("installPi")(function* (context) {
19234
19335
  import { resolve as resolve3 } from "node:path";
19235
19336
 
19236
19337
  // ../core/src/memory/project.ts
19237
- import { extname, join as join3, relative, sep } from "node:path";
19338
+ import { extname, join as join4, relative, sep } from "node:path";
19238
19339
 
19239
19340
  // ../core/src/utils.ts
19240
19341
  function success(value) {
@@ -19259,17 +19360,17 @@ function readString(value, key) {
19259
19360
 
19260
19361
  // ../core/src/memory/common.ts
19261
19362
  import { constants as constants2 } from "node:fs";
19262
- import { access as access3, readdir, readFile as readFile4, stat as stat3 } from "node:fs/promises";
19363
+ import { access as access3, readdir, readFile as readFile5, stat as stat3 } from "node:fs/promises";
19263
19364
  async function readOptionalContent(path) {
19264
19365
  try {
19265
- return success(await readFile4(path, "utf8"));
19366
+ return success(await readFile5(path, "utf8"));
19266
19367
  } catch (cause) {
19267
19368
  return hasNodeErrorCode(cause, "ENOENT") ? success(null) : failure({ path, cause });
19268
19369
  }
19269
19370
  }
19270
19371
  async function readContent(path) {
19271
19372
  try {
19272
- return success(await readFile4(path, "utf8"));
19373
+ return success(await readFile5(path, "utf8"));
19273
19374
  } catch (cause) {
19274
19375
  return failure({ path, cause });
19275
19376
  }
@@ -19348,13 +19449,13 @@ async function loadProjectPartition(root, loadFiles) {
19348
19449
  return hasNodeErrorCode(directory.error.cause, "ENOENT") ? success(loadFiles ? { exists: false, operatorInstructions: null, catalog: null, indexes: [] } : { exists: false }) : directory;
19349
19450
  }
19350
19451
  if (!loadFiles) {
19351
- for (const path of [join3(root, "operator.md"), join3(root, "catalog.md")]) {
19452
+ for (const path of [join4(root, "operator.md"), join4(root, "catalog.md")]) {
19352
19453
  const file = await checkOptionalReadableFile(path);
19353
19454
  if (!file.ok) {
19354
19455
  return file;
19355
19456
  }
19356
19457
  }
19357
- const indexRoot = join3(root, "index");
19458
+ const indexRoot = join4(root, "index");
19358
19459
  const indexPaths = await listMarkdownFiles(indexRoot, indexRoot);
19359
19460
  if (!indexPaths.ok) {
19360
19461
  return indexPaths;
@@ -19367,15 +19468,15 @@ async function loadProjectPartition(root, loadFiles) {
19367
19468
  }
19368
19469
  return success({ exists: true });
19369
19470
  }
19370
- const operatorInstructions = await readOptionalContent(join3(root, "operator.md"));
19471
+ const operatorInstructions = await readOptionalContent(join4(root, "operator.md"));
19371
19472
  if (!operatorInstructions.ok) {
19372
19473
  return operatorInstructions;
19373
19474
  }
19374
- const catalog = await readOptionalContent(join3(root, "catalog.md"));
19475
+ const catalog = await readOptionalContent(join4(root, "catalog.md"));
19375
19476
  if (!catalog.ok) {
19376
19477
  return catalog;
19377
19478
  }
19378
- const indexes = await readIndexes(join3(root, "index"));
19479
+ const indexes = await readIndexes(join4(root, "index"));
19379
19480
  if (!indexes.ok) {
19380
19481
  return indexes;
19381
19482
  }
@@ -19413,7 +19514,7 @@ async function listMarkdownFiles(root, directory) {
19413
19514
  }
19414
19515
  const paths = [];
19415
19516
  for (const entry of entries.value) {
19416
- const path = join3(directory, entry.name);
19517
+ const path = join4(directory, entry.name);
19417
19518
  if (entry.isDirectory()) {
19418
19519
  const nestedPaths = await listMarkdownFiles(root, path);
19419
19520
  if (!nestedPaths.ok) {
@@ -19434,14 +19535,14 @@ function compareStrings2(left, right) {
19434
19535
  }
19435
19536
 
19436
19537
  // ../core/src/memory/user.ts
19437
- import { join as join4 } from "node:path";
19538
+ import { join as join5 } from "node:path";
19438
19539
  async function loadUserPartition(root, loadFiles) {
19439
19540
  if (!loadFiles) {
19440
19541
  const directory = await readDirectory2(root);
19441
19542
  if (!directory.ok) {
19442
19543
  return hasNodeErrorCode(directory.error.cause, "ENOENT") ? success({ exists: false }) : directory;
19443
19544
  }
19444
- for (const path of [join4(root, "operator.md"), join4(root, "catalog.md")]) {
19545
+ for (const path of [join5(root, "operator.md"), join5(root, "catalog.md")]) {
19445
19546
  const file = await checkOptionalReadableFile(path);
19446
19547
  if (!file.ok) {
19447
19548
  return file;
@@ -19449,11 +19550,11 @@ async function loadUserPartition(root, loadFiles) {
19449
19550
  }
19450
19551
  return success({ exists: true });
19451
19552
  }
19452
- const operatorInstructions = await readOptionalContent(join4(root, "operator.md"));
19553
+ const operatorInstructions = await readOptionalContent(join5(root, "operator.md"));
19453
19554
  if (!operatorInstructions.ok) {
19454
19555
  return operatorInstructions;
19455
19556
  }
19456
- const catalog = await readOptionalContent(join4(root, "catalog.md"));
19557
+ const catalog = await readOptionalContent(join5(root, "catalog.md"));
19457
19558
  if (!catalog.ok) {
19458
19559
  return catalog;
19459
19560
  }
@@ -19979,18 +20080,6 @@ var hasTrackedPrivateFiles = fn2("hasTrackedPrivateFiles")(function* (cwd) {
19979
20080
  return tracked.trim() !== "";
19980
20081
  });
19981
20082
 
19982
- // src/commands/common.ts
19983
- function fileFailure(error) {
19984
- return { exitCode: 1, output: fileErrorMessage(error) };
19985
- }
19986
- function fileErrorMessage(error) {
19987
- if (error instanceof PathKindError) {
19988
- return `✗ ${error.path}: Expected a ${error.expected}, found ${error.actual}`;
19989
- }
19990
- const path = error.reason instanceof SystemError ? `${error.reason.pathOrDescriptor}: ` : "";
19991
- return `✗ ${path}${error.reason.description ?? error.message}`;
19992
- }
19993
-
19994
20083
  // src/commands/project/common.ts
19995
20084
  var PRIVATE_ROOT2 = ".operator";
19996
20085
  var SHARED_ROOT2 = ".operator-shared";
@@ -20240,92 +20329,10 @@ var userStatus = fn2("userStatus")(function* (context) {
20240
20329
  `) };
20241
20330
  });
20242
20331
 
20243
- // src/cli.ts
20244
- var HELP = `Operator Helper
20245
-
20246
- USER COMMANDS
20247
-
20248
- ${renderTable([
20249
- ["help", "Show help for operator-helper"],
20250
- ["version", "Show the installed version"],
20251
- ["operator-helper install opencode", "Install or update the OpenCode plugin"],
20252
- ["operator-helper install opencode-v2", "Install or update the OpenCode V2 plugin"],
20253
- ["operator-helper install pi", "Install or update the Pi plugin"],
20254
- ["operator-helper install code-puppy", "Install or update the Code Puppy plugin"]
20255
- ])}
20256
-
20257
- AGENT COMMANDS
20258
-
20259
- ${renderTable([
20260
- ["operator-helper user status", "Show User Partition status"],
20261
- ["operator-helper user init", "Initialize User Partition core files without overwriting content"],
20262
- ["operator-helper user guide", "Print the agent guide for completing User Setup"],
20263
- [
20264
- "operator-helper project status",
20265
- "Show Project Private, Shared, Git ignore, and tracking status"
20266
- ],
20267
- ["operator-helper project init", "Initialize project partitions and global Git ignore"],
20268
- ["operator-helper project guide", "Print the agent guide for completing Project Setup"],
20269
- ["operator-helper index status", "Show Private and Shared main Project Index status"],
20270
- ["operator-helper index guide", "Print the agent guide for building or refreshing indexes"],
20271
- ["operator-helper index lint", "Check Project Index structure and frontmatter"],
20272
- ["operator-helper memory check", "Check that all Operator memory can be loaded"],
20273
- ["operator-helper preamble", "Render the Operator preamble"]
20274
- ])}`;
20275
- function runCli(arguments_, context) {
20276
- return gen2(function* () {
20277
- if (arguments_.length === 1 && arguments_[0] === "help") {
20278
- return { exitCode: 0, output: HELP };
20279
- }
20280
- if (arguments_.length === 1 && arguments_[0] === "version") {
20281
- return { exitCode: 0, output: context.version };
20282
- }
20283
- if (arguments_.length === 1 && arguments_[0] === "preamble") {
20284
- return yield* preamble(context);
20285
- }
20286
- if (arguments_.length !== 2) {
20287
- return { exitCode: 2, output: HELP };
20288
- }
20289
- const command = `${arguments_[0]} ${arguments_[1]}`;
20290
- switch (command) {
20291
- case "user status":
20292
- return yield* userStatus(context);
20293
- case "user init":
20294
- return yield* userInit(context);
20295
- case "user guide":
20296
- return yield* userGuide();
20297
- case "project status":
20298
- return yield* projectStatus(context);
20299
- case "project init":
20300
- return yield* projectInit(context);
20301
- case "project guide":
20302
- return yield* projectGuide();
20303
- case "index status":
20304
- return yield* indexStatus(context);
20305
- case "index guide":
20306
- return yield* indexGuide();
20307
- case "index lint":
20308
- return yield* indexLint(context);
20309
- case "memory check":
20310
- return yield* memoryCheck(context);
20311
- case "install opencode":
20312
- return yield* installOpenCode(context);
20313
- case "install opencode-v2":
20314
- return yield* installOpenCodeV2(context);
20315
- case "install pi":
20316
- return yield* installPi(context);
20317
- case "install code-puppy":
20318
- return yield* installCodePuppy(context);
20319
- default:
20320
- return {
20321
- exitCode: 2,
20322
- output: `Unknown command: ${command}
20323
-
20324
- ${HELP}`
20325
- };
20326
- }
20327
- }).pipe(catch_2((error) => succeed6(fileFailure(error))));
20328
- }
20332
+ // src/update.ts
20333
+ import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
20334
+ import { realpathSync } from "node:fs";
20335
+ import { dirname as dirname2, join as join6, sep as sep2 } from "node:path";
20329
20336
 
20330
20337
  // src/npm-registry.ts
20331
20338
  class NpmRegistryError extends TaggedError2("NpmRegistryError") {
@@ -20363,9 +20370,6 @@ var NpmRegistry;
20363
20370
  })(NpmRegistry ||= {});
20364
20371
 
20365
20372
  // src/update.ts
20366
- import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
20367
- import { realpathSync } from "node:fs";
20368
- import { dirname as dirname2, join as join5, sep as sep2 } from "node:path";
20369
20373
  var HELPER_PACKAGE = "@aerovato/operator-helper";
20370
20374
  var UPDATE_TIMEOUT = "60 seconds";
20371
20375
  var SUCCESS_COOLDOWN = 60 * 60 * 1000;
@@ -20381,11 +20385,11 @@ var UpdateCheck = Union2([
20381
20385
  ]);
20382
20386
  var decodeUpdateCheck = decodeUnknownSync(fromJsonString2(UpdateCheck));
20383
20387
  function updateCheckPath(context) {
20384
- const cache = process.env.XDG_CACHE_HOME || join5(context.home, ".cache");
20385
- return join5(cache, "operator", "helper-update.json");
20388
+ const cache = process.env.XDG_CACHE_HOME || join6(context.home, ".cache");
20389
+ return join6(cache, "operator", "helper-update.json");
20386
20390
  }
20387
- var autoUpdate = fn2("autoUpdate")(function* (currentVersion, context) {
20388
- const cached = yield* promise2(() => readUpdateCheck(context));
20391
+ var autoUpdate = fn2("autoUpdate")(function* (currentVersion, context, bypassCache) {
20392
+ const cached = bypassCache ? null : yield* promise2(() => readUpdateCheck(context));
20389
20393
  if (cached !== null && isFresh(cached)) {
20390
20394
  if (cached.status === "unknown") {
20391
20395
  return { status: "unknown", latest: cached.latest };
@@ -20420,7 +20424,7 @@ var autoUpdate = fn2("autoUpdate")(function* (currentVersion, context) {
20420
20424
  const execution = yield* run3(spawner, command).pipe(timeout2(UPDATE_TIMEOUT), option2);
20421
20425
  if (isSome2(execution) && execution.value.exitCode === 0) {
20422
20426
  yield* promise2(() => writeUpdateCheck(context, { checkedAt: Date.now(), status: "current" }));
20423
- return { status: "updated" };
20427
+ return { status: "updated", latest: latest.value };
20424
20428
  }
20425
20429
  yield* promise2(() => writeUpdateCheck(context, { checkedAt: Date.now(), status: "failed" }));
20426
20430
  return { status: "failed" };
@@ -20432,7 +20436,7 @@ function isFresh(check) {
20432
20436
  }
20433
20437
  async function readUpdateCheck(context) {
20434
20438
  try {
20435
- return decodeUpdateCheck(await readFile5(updateCheckPath(context), "utf8"));
20439
+ return decodeUpdateCheck(await readFile6(updateCheckPath(context), "utf8"));
20436
20440
  } catch {
20437
20441
  return null;
20438
20442
  }
@@ -20440,8 +20444,8 @@ async function readUpdateCheck(context) {
20440
20444
  async function writeUpdateCheck(context, check) {
20441
20445
  const path = updateCheckPath(context);
20442
20446
  try {
20443
- await mkdir3(dirname2(path), { recursive: true, mode: 448 });
20444
- await writeFile4(path, JSON.stringify(check), { mode: 384 });
20447
+ await mkdir4(dirname2(path), { recursive: true, mode: 448 });
20448
+ await writeFile5(path, JSON.stringify(check), { mode: 384 });
20445
20449
  } catch {}
20446
20450
  }
20447
20451
  function detectInstallationChannel(spawner, cwd, executablePath) {
@@ -20504,6 +20508,118 @@ function parseVersion(value) {
20504
20508
  return [Number(match[1]), Number(match[2]), Number(match[3])];
20505
20509
  }
20506
20510
 
20511
+ // src/commands/upgrade.ts
20512
+ var upgrade = fn2("upgrade")(function* (context) {
20513
+ const result = yield* autoUpdate(context.version, context, true);
20514
+ switch (result.status) {
20515
+ case "current":
20516
+ return { exitCode: 0, output: `Operator Helper ${context.version} is up to date.` };
20517
+ case "updated":
20518
+ return { exitCode: 0, output: `Operator Helper updated to ${result.latest}.` };
20519
+ case "unknown":
20520
+ return {
20521
+ exitCode: 1,
20522
+ output: `Operator Helper ${result.latest} is available, but the update could not determine whether Bun or npm owns this installation. Update operator-helper manually using the original installation method.`
20523
+ };
20524
+ case "failed":
20525
+ return { exitCode: 1, output: "Operator Helper update failed." };
20526
+ }
20527
+ });
20528
+
20529
+ // src/cli.ts
20530
+ var HELP = `Operator Helper
20531
+
20532
+ USER COMMANDS
20533
+
20534
+ ${renderTable([
20535
+ ["help", "Show help for operator-helper"],
20536
+ ["version", "Show the installed version"],
20537
+ ["upgrade", "Update Operator Helper to the latest release"],
20538
+ ["operator-helper install codex", "Install or update the Codex plugin"],
20539
+ ["operator-helper install opencode", "Install or update the OpenCode plugin"],
20540
+ ["operator-helper install opencode-v2", "Install or update the OpenCode V2 plugin"],
20541
+ ["operator-helper install pi", "Install or update the Pi plugin"],
20542
+ ["operator-helper install code-puppy", "Install or update the Code Puppy plugin"]
20543
+ ])}
20544
+
20545
+ AGENT COMMANDS
20546
+
20547
+ ${renderTable([
20548
+ ["operator-helper user status", "Show User Partition status"],
20549
+ ["operator-helper user init", "Initialize User Partition core files without overwriting content"],
20550
+ ["operator-helper user guide", "Print the agent guide for completing User Setup"],
20551
+ [
20552
+ "operator-helper project status",
20553
+ "Show Project Private, Shared, Git ignore, and tracking status"
20554
+ ],
20555
+ ["operator-helper project init", "Initialize project partitions and global Git ignore"],
20556
+ ["operator-helper project guide", "Print the agent guide for completing Project Setup"],
20557
+ ["operator-helper index status", "Show Private and Shared main Project Index status"],
20558
+ ["operator-helper index guide", "Print the agent guide for building or refreshing indexes"],
20559
+ ["operator-helper index lint", "Check Project Index structure and frontmatter"],
20560
+ ["operator-helper memory check", "Check that all Operator memory can be loaded"],
20561
+ ["operator-helper preamble", "Render the Operator preamble"]
20562
+ ])}`;
20563
+ function runCli(arguments_, context) {
20564
+ return gen2(function* () {
20565
+ if (arguments_.length === 1 && arguments_[0] === "help") {
20566
+ return { exitCode: 0, output: HELP };
20567
+ }
20568
+ if (arguments_.length === 1 && arguments_[0] === "version") {
20569
+ return { exitCode: 0, output: context.version };
20570
+ }
20571
+ if (arguments_.length === 1 && arguments_[0] === "preamble") {
20572
+ return yield* preamble(context);
20573
+ }
20574
+ if (arguments_.length === 1 && arguments_[0] === "upgrade") {
20575
+ return yield* upgrade(context);
20576
+ }
20577
+ if (arguments_.length !== 2) {
20578
+ return { exitCode: 2, output: HELP };
20579
+ }
20580
+ const command = `${arguments_[0]} ${arguments_[1]}`;
20581
+ switch (command) {
20582
+ case "user status":
20583
+ return yield* userStatus(context);
20584
+ case "user init":
20585
+ return yield* userInit(context);
20586
+ case "user guide":
20587
+ return yield* userGuide();
20588
+ case "project status":
20589
+ return yield* projectStatus(context);
20590
+ case "project init":
20591
+ return yield* projectInit(context);
20592
+ case "project guide":
20593
+ return yield* projectGuide();
20594
+ case "index status":
20595
+ return yield* indexStatus(context);
20596
+ case "index guide":
20597
+ return yield* indexGuide();
20598
+ case "index lint":
20599
+ return yield* indexLint(context);
20600
+ case "memory check":
20601
+ return yield* memoryCheck(context);
20602
+ case "install codex":
20603
+ return yield* installCodex(context);
20604
+ case "install opencode":
20605
+ return yield* installOpenCode(context);
20606
+ case "install opencode-v2":
20607
+ return yield* installOpenCodeV2(context);
20608
+ case "install pi":
20609
+ return yield* installPi(context);
20610
+ case "install code-puppy":
20611
+ return yield* installCodePuppy(context);
20612
+ default:
20613
+ return {
20614
+ exitCode: 2,
20615
+ output: `Unknown command: ${command}
20616
+
20617
+ ${HELP}`
20618
+ };
20619
+ }
20620
+ }).pipe(catch_2((error) => succeed6(fileFailure(error))));
20621
+ }
20622
+
20507
20623
  // src/index.ts
20508
20624
  var SKIP_UPDATE_ENVIRONMENT_VARIABLE = "OPERATOR_HELPER_SKIP_UPDATE";
20509
20625
  var ChildProcessLayer = layer.pipe(provide2(layer3), provide2(layer5));
@@ -20517,7 +20633,7 @@ var main = gen2(function* () {
20517
20633
  version: package_default.version
20518
20634
  };
20519
20635
  if (process.env[SKIP_UPDATE_ENVIRONMENT_VARIABLE] !== "1") {
20520
- const update = yield* autoUpdate(package_default.version, environment);
20636
+ const update = yield* autoUpdate(package_default.version, environment, false);
20521
20637
  if (update.status === "updated") {
20522
20638
  const entrypoint = process.argv[1];
20523
20639
  if (entrypoint !== undefined) {
@@ -20546,4 +20662,4 @@ var main = gen2(function* () {
20546
20662
  }).pipe(provide4(LiveLayers));
20547
20663
  runMain2(main);
20548
20664
 
20549
- //# debugId=6692B2A2E88947E864756E2164756E21
20665
+ //# debugId=F79207A63C841C4D64756E2164756E21