@native-marketing/sdk 0.3.5 → 0.3.7

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
@@ -5922,7 +5922,8 @@ var knowledgeDiscoveryDescriptionSchema = z79.object({
5922
5922
  checkedAt: z79.string().datetime()
5923
5923
  }).strict();
5924
5924
  var knowledgeAdoptionCommandSchema = knowledgeDiscoveryReadQuerySchema.required().extend({
5925
- requestId: z79.string().min(1).max(128)
5925
+ requestId: z79.string().min(1).max(128),
5926
+ ref: knowledgeRemoteRefSchema.max(2048)
5926
5927
  }).strict();
5927
5928
  var knowledgeAdoptionResultSchema = z79.object({ result: sourceRefSchema, replayed: z79.boolean() }).strict();
5928
5929
  var knowledgeAdoptionReceiptQuerySchema = z79.object({ requestId: z79.string().min(1).max(128) }).strict();
@@ -5938,6 +5939,15 @@ var adoptedKnowledgeResourceSchema = z79.object({
5938
5939
  ref: knowledgeRemoteRefSchema,
5939
5940
  identityHash: z79.string().regex(/^sha256:[a-f0-9]{64}$/)
5940
5941
  }).strict();
5942
+ var knowledgeResourceDescriptorSchema = knowledgeDiscoveryItemSchema.pick({
5943
+ ref: true,
5944
+ identityHash: true,
5945
+ ownerTenantId: true,
5946
+ resourceType: true,
5947
+ kind: true,
5948
+ classification: true,
5949
+ title: true
5950
+ }).extend({ schemaVersion: z79.literal(1) }).strict();
5941
5951
 
5942
5952
  // packages/contracts/src/material-verification.ts
5943
5953
  import { z as z80 } from "zod";
@@ -6924,7 +6934,21 @@ var surveyRejections = [
6924
6934
  "PERSONAL_SURVEY_DRAFT_TRANSITION_IMMUTABLE"
6925
6935
  ];
6926
6936
  function isKnownCapabilityRejection(code2, name) {
6927
- return capabilityRejectedErrorCodes.includes(code2) || name === "cf_adopt_discovered_knowledge" && [
6937
+ return capabilityRejectedErrorCodes.includes(code2) || name === "cf_repair_knowledge_reference" && [
6938
+ "KNOWLEDGE_REFERENCE_REPAIR_CONFLICT",
6939
+ "KNOWLEDGE_REFERENCE_REPAIR_NOT_SUPPORTED",
6940
+ "KNOWLEDGE_REFERENCE_REPAIR_IDENTITY_MISMATCH",
6941
+ "KNOWLEDGE_DISCOVERY_IDENTITY_CHANGED",
6942
+ "KNOWLEDGE_DISCOVERY_FORBIDDEN",
6943
+ "KNOWLEDGE_DISCOVERY_UNAVAILABLE",
6944
+ "KNOWLEDGE_CATALOG_UNAVAILABLE",
6945
+ "KNOWLEDGE_TENANT_IDENTITY_CHANGED",
6946
+ "KNOWLEDGE_CATALOG_SCOPE_NOT_CONFIGURED",
6947
+ "KNOWLEDGE_PROVIDER_AUTH_REQUIRED",
6948
+ "KNOWLEDGE_ARTIFACT_ACCESS_DENIED",
6949
+ "KNOWLEDGE_ARTIFACT_TOO_LARGE",
6950
+ "KNOWLEDGE_ARTIFACT_DOWNLOAD_BUSY"
6951
+ ].includes(code2) || name === "cf_adopt_discovered_knowledge" && [
6928
6952
  "KNOWLEDGE_DISCOVERY_IDENTITY_CHANGED",
6929
6953
  "KNOWLEDGE_DISCOVERY_FORBIDDEN",
6930
6954
  "KNOWLEDGE_DISCOVERY_TEXT_TOO_LARGE",
@@ -7261,6 +7285,26 @@ var eventExchangePageSchema = z101.object({
7261
7285
  nextAfter: z101.string().max(256).nullable()
7262
7286
  }).strict();
7263
7287
 
7288
+ // packages/contracts/src/knowledge-reference-repair.ts
7289
+ import { z as z102 } from "zod";
7290
+ var knowledgeReferenceRepairQuerySchema = z102.object({
7291
+ sourceRef: stableRefSchema.refine((value) => value.startsWith("cf://source/"))
7292
+ }).strict();
7293
+ var knowledgeReferenceRepairPreviewSchema = z102.object({
7294
+ sourceRef: knowledgeReferenceRepairQuerySchema.shape.sourceRef,
7295
+ remoteRef: z102.string().min(1).max(2048),
7296
+ basisHash: z102.string().regex(/^sha256:[a-f0-9]{64}$/),
7297
+ sourceTenantId: z102.string().min(1).max(256),
7298
+ item: knowledgeDiscoveryItemSchema,
7299
+ byteLength: z102.number().int().nonnegative().safe(),
7300
+ verified: z102.literal(true)
7301
+ }).strict();
7302
+ var knowledgeReferenceRepairCommandSchema = knowledgeReferenceRepairQuerySchema.extend({
7303
+ requestId: z102.string().min(1).max(128),
7304
+ expectedBasisHash: knowledgeReferenceRepairPreviewSchema.shape.basisHash
7305
+ }).strict();
7306
+ var knowledgeReferenceRepairReceiptQuerySchema = knowledgeAdoptionReceiptQuerySchema;
7307
+
7264
7308
  // packages/contracts/src/agent/capability-receipts.ts
7265
7309
  var rule = (capability, schema2, operation, keys = [], field) => ({ capability, schema: schema2, operation, keys, field });
7266
7310
  var foundation = (operation, field) => rule(
@@ -7282,6 +7326,10 @@ var execution = (family, operation) => ({
7282
7326
  });
7283
7327
  var learning = (op) => rule("cf_get_learning_command_receipt", learningReceiptSchema, op);
7284
7328
  var rules = {
7329
+ cf_repair_knowledge_reference: rule(
7330
+ "cf_get_knowledge_reference_repair_receipt",
7331
+ knowledgeReferenceRepairReceiptQuerySchema
7332
+ ),
7285
7333
  cf_configure_event_exchange: rule(
7286
7334
  "cf_get_event_exchange_receipt",
7287
7335
  eventExchangeReceiptQuerySchema
@@ -7505,7 +7553,7 @@ function capabilityReceiptRead(name, input) {
7505
7553
  }
7506
7554
 
7507
7555
  // packages/contracts/src/agent/capability-status.ts
7508
- import { z as z102 } from "zod";
7556
+ import { z as z103 } from "zod";
7509
7557
  var verification = {
7510
7558
  capability: "cf_material_verification_status",
7511
7559
  schema: materialVerificationIdSchema,
@@ -7523,7 +7571,7 @@ var rules2 = {
7523
7571
  },
7524
7572
  cf_tenant_material_scan_advance: {
7525
7573
  capability: "cf_tenant_material_scan_status",
7526
- schema: z102.object({}).strict()
7574
+ schema: z103.object({}).strict()
7527
7575
  },
7528
7576
  cf_sync_materials: {
7529
7577
  capability: "cf_reconcile_materials",
@@ -7550,6 +7598,176 @@ function capabilityStatusRead(name, input) {
7550
7598
  };
7551
7599
  }
7552
7600
 
7601
+ // packages/contracts/src/client-lifecycle.ts
7602
+ import { z as z104 } from "zod";
7603
+
7604
+ // packages/contracts/src/generated/client-release.ts
7605
+ var nativeClientRelease = {
7606
+ schemaVersion: 1,
7607
+ product: "native-marketing",
7608
+ version: "0.3.7",
7609
+ packages: {
7610
+ sdk: "@native-marketing/sdk",
7611
+ cli: "@native-marketing/cli"
7612
+ },
7613
+ contractVersion: 1,
7614
+ minimumClientVersion: "0.3.6",
7615
+ apiMajor: 1,
7616
+ nodeMajor: 24,
7617
+ changes: [
7618
+ "Unified SDK, CLI and MCP release discovery and compatibility checks.",
7619
+ "Configurable CLI update notifications, pins and compatible automatic updates.",
7620
+ "Upgrade verification and explicit continuation without replaying business commands."
7621
+ ]
7622
+ };
7623
+
7624
+ // packages/contracts/src/client-lifecycle.ts
7625
+ var nativeReleaseCapability = "com.native-marketing/client-release";
7626
+ var releaseVersionSchema = z104.string().max(128).regex(
7627
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
7628
+ );
7629
+ var clientIdentitySchema = z104.object({
7630
+ version: releaseVersionSchema,
7631
+ contractVersion: z104.number().int().positive(),
7632
+ apiMajor: z104.number().int().positive()
7633
+ });
7634
+ var clientReleaseSchema = z104.object({
7635
+ schemaVersion: z104.literal(1),
7636
+ product: z104.literal("native-marketing"),
7637
+ version: releaseVersionSchema,
7638
+ packages: z104.object({
7639
+ sdk: z104.literal("@native-marketing/sdk"),
7640
+ cli: z104.literal("@native-marketing/cli")
7641
+ }),
7642
+ contractVersion: z104.number().int().positive(),
7643
+ minimumClientVersion: releaseVersionSchema,
7644
+ apiMajor: z104.number().int().positive(),
7645
+ nodeMajor: z104.number().int().positive(),
7646
+ changes: z104.array(z104.string().min(1).max(240)).max(8).default([])
7647
+ });
7648
+ var updatePolicySchema = z104.object({
7649
+ mode: z104.enum(["off", "notify", "auto"]).default("notify"),
7650
+ channel: z104.enum(["latest", "next", "beta"]).default("latest"),
7651
+ pin: releaseVersionSchema.nullable().default(null),
7652
+ intervalHours: z104.number().int().min(1).max(168).default(24)
7653
+ }).strict();
7654
+ var defaultUpdatePolicy = updatePolicySchema.parse({});
7655
+ function compareReleaseVersions(left, right) {
7656
+ const parse = (raw) => releaseVersionSchema.parse(raw).split("+")[0].split(/-(.*)/s);
7657
+ const a = parse(left), b = parse(right);
7658
+ const numbers = (x, y) => BigInt(x) < BigInt(y) ? -1 : BigInt(x) > BigInt(y) ? 1 : 0;
7659
+ const ac = a[0].split("."), bc = b[0].split(".");
7660
+ for (let i = 0; i < 3; i++) {
7661
+ const order = numbers(ac[i], bc[i]);
7662
+ if (order) return order;
7663
+ }
7664
+ if (a[1] === b[1]) return 0;
7665
+ if (!a[1] || !b[1]) return a[1] ? -1 : 1;
7666
+ const ap = a[1].split("."), bp = b[1].split(".");
7667
+ for (let i = 0; i < Math.max(ap.length, bp.length); i++) {
7668
+ const x = ap[i], y = bp[i];
7669
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
7670
+ if (x === y) continue;
7671
+ const xn = /^\d+$/.test(x), yn = /^\d+$/.test(y);
7672
+ return xn && yn ? numbers(x, y) : xn !== yn ? xn ? -1 : 1 : x < y ? -1 : 1;
7673
+ }
7674
+ return 0;
7675
+ }
7676
+ function assessNativeCompatibility(client, server) {
7677
+ client = clientIdentitySchema.parse(client);
7678
+ const result2 = (status, reason) => ({ status, reason, client, server: server ?? null });
7679
+ if (!server) return result2("UNKNOWN", "SERVER_METADATA_UNAVAILABLE");
7680
+ server = clientReleaseSchema.parse(server);
7681
+ if (client.contractVersion !== server.contractVersion)
7682
+ return result2("INCOMPATIBLE", "CONTRACT_MISMATCH");
7683
+ if (client.apiMajor !== server.apiMajor) return result2("INCOMPATIBLE", "API_MISMATCH");
7684
+ if (compareReleaseVersions(client.version, server.minimumClientVersion) < 0)
7685
+ return result2("INCOMPATIBLE", "CLIENT_TOO_OLD");
7686
+ return compareReleaseVersions(client.version, server.version) < 0 ? result2("UPGRADE_RECOMMENDED", "NEWER_CLIENT_AVAILABLE") : result2("COMPATIBLE", "CURRENT");
7687
+ }
7688
+
7689
+ // packages/contracts/src/client-update-policy.ts
7690
+ import { z as z105 } from "zod";
7691
+ var registryReleaseSchema = z105.object({
7692
+ name: z105.enum(["@native-marketing/sdk", "@native-marketing/cli"]),
7693
+ version: releaseVersionSchema,
7694
+ deprecated: z105.string().optional(),
7695
+ nativeMarketing: z105.object({
7696
+ contractVersion: z105.number().int().positive(),
7697
+ apiMajor: z105.number().int().positive(),
7698
+ nodeMajor: z105.number().int().positive(),
7699
+ changes: z105.array(z105.string().min(1).max(240)).max(8).optional()
7700
+ }).optional(),
7701
+ dist: z105.object({
7702
+ integrity: z105.string().max(512).regex(/^sha512-[A-Za-z0-9+/]{86}==$/)
7703
+ })
7704
+ });
7705
+ var clientUpdateStateSchema = z105.object({
7706
+ schemaVersion: z105.literal(1),
7707
+ policy: updatePolicySchema,
7708
+ lastCheck: z105.object({
7709
+ at: z105.number().int().nonnegative(),
7710
+ selector: z105.string().max(160),
7711
+ target: registryReleaseSchema
7712
+ }).strict().optional(),
7713
+ lastAttempt: z105.object({ at: z105.number().int().nonnegative(), selector: z105.string().max(160) }).strict().optional()
7714
+ }).strict();
7715
+ function planNativeUpdate(input) {
7716
+ const target = registryReleaseSchema.parse(input.target);
7717
+ const current = releaseVersionSchema.parse(input.currentVersion ?? nativeClientRelease.version);
7718
+ const policy = updatePolicySchema.parse(input.policy ?? {});
7719
+ const spec = `${target.name}@${target.version}`;
7720
+ const cli = target.name === nativeClientRelease.packages.cli;
7721
+ const result2 = (status, reason, eligible = false) => ({
7722
+ package: target.name,
7723
+ currentVersion: current,
7724
+ targetVersion: target.version,
7725
+ status,
7726
+ reason,
7727
+ eligibleForAutoUpdate: eligible,
7728
+ policy,
7729
+ commands: {
7730
+ npm: [
7731
+ "npm",
7732
+ "install",
7733
+ ...cli ? ["--global"] : ["--save-exact"],
7734
+ spec,
7735
+ "--ignore-scripts",
7736
+ "--registry=https://registry.npmjs.org/",
7737
+ "--@native-marketing:registry=https://registry.npmjs.org/"
7738
+ ],
7739
+ pnpm: ["pnpm", "add", ...cli ? ["--global"] : ["--save-exact"], spec, "--ignore-scripts"],
7740
+ yarn: cli ? null : ["yarn", "add", "--exact", spec]
7741
+ }
7742
+ });
7743
+ if (policy.pin && policy.pin !== target.version) return result2("BLOCKED", "PIN_MISMATCH");
7744
+ if (!policy.pin && policy.channel === "latest" && target.version.split("+")[0].includes("-"))
7745
+ return result2("BLOCKED", "CHANNEL_MISMATCH");
7746
+ const order = compareReleaseVersions(target.version, current);
7747
+ if (order < 0) return result2("BLOCKED", "DOWNGRADE_FORBIDDEN");
7748
+ if (target.deprecated !== void 0) return result2("BLOCKED", "DEPRECATED");
7749
+ if (!target.nativeMarketing) return result2("BLOCKED", "METADATA_UNAVAILABLE");
7750
+ const metadata = target.nativeMarketing;
7751
+ if (metadata.nodeMajor !== (input.nodeMajor ?? nativeClientRelease.nodeMajor))
7752
+ return result2("BLOCKED", "NODE_MISMATCH");
7753
+ if (metadata.contractVersion !== nativeClientRelease.contractVersion || metadata.apiMajor !== nativeClientRelease.apiMajor)
7754
+ return result2("BLOCKED", "CONTRACT_MISMATCH");
7755
+ if (input.server && assessNativeCompatibility(
7756
+ {
7757
+ version: target.version,
7758
+ contractVersion: metadata.contractVersion,
7759
+ apiMajor: metadata.apiMajor
7760
+ },
7761
+ input.server
7762
+ ).status === "INCOMPATIBLE")
7763
+ return result2("BLOCKED", "SERVER_INCOMPATIBLE");
7764
+ if (order === 0) return result2("CURRENT", "CURRENT");
7765
+ const from = current.split(/[.+-]/), to = target.version.split(/[.+-]/);
7766
+ const compatibleLine = from[0] === to[0] && (from[0] !== "0" || from[1] === to[1]);
7767
+ const stable = !current.split("+")[0].includes("-") && !target.version.split("+")[0].includes("-");
7768
+ return compatibleLine && stable ? result2("UPDATE_AVAILABLE", "COMPATIBLE_UPDATE", true) : result2("UPDATE_AVAILABLE", "REVIEW_REQUIRED");
7769
+ }
7770
+
7553
7771
  // packages/cli-client/src/errors.ts
7554
7772
  var CliError = class extends Error {
7555
7773
  constructor(code2, message, outcome = "NOT_SENT", details) {
@@ -7602,6 +7820,9 @@ function verifyCapabilityDefinition(raw, name, expectedHash) {
7602
7820
  }
7603
7821
  var CapabilityDefinitionCache = class {
7604
7822
  values = /* @__PURE__ */ new Map();
7823
+ clear() {
7824
+ this.values.clear();
7825
+ }
7605
7826
  remember(value) {
7606
7827
  const verified = verifyCapabilityDefinition(value, value.definition.name);
7607
7828
  const key2 = `${verified.definition.name}:AGENT_V3:${verified.schemaSha256}`;
@@ -7940,13 +8161,105 @@ function object2(value) {
7940
8161
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7941
8162
  }
7942
8163
 
8164
+ // packages/cli-client/src/updates/version.ts
8165
+ import { readFile, realpath } from "node:fs/promises";
8166
+ import { dirname, join as join2 } from "node:path";
8167
+ function getNativeClientVersion() {
8168
+ return clientReleaseSchema.parse(nativeClientRelease);
8169
+ }
8170
+ async function getNativeCliVersion(executablePath) {
8171
+ const identity = { ...getNativeClientVersion(), sdkVersion: nativeClientRelease.version };
8172
+ if (!executablePath) return identity;
8173
+ try {
8174
+ const root = dirname(dirname(await realpath(executablePath)));
8175
+ const manifest = JSON.parse(await readFile(join2(root, "package.json"), "utf8"));
8176
+ if (manifest.name === nativeClientRelease.packages.cli)
8177
+ return { ...identity, version: releaseVersionSchema.parse(manifest.version) };
8178
+ } catch {
8179
+ }
8180
+ return identity;
8181
+ }
8182
+ function readNativeServerVersion(client) {
8183
+ const raw = client.getServerCapabilities()?.experimental?.[nativeReleaseCapability];
8184
+ let server;
8185
+ if (raw !== void 0) {
8186
+ const parsed = clientReleaseSchema.safeParse(raw);
8187
+ if (!parsed.success)
8188
+ throw new CliError(
8189
+ "INVALID_SERVER_RELEASE",
8190
+ "The advertised Native Marketing release contract is invalid."
8191
+ );
8192
+ server = parsed.data;
8193
+ }
8194
+ return {
8195
+ client: getNativeClientVersion(),
8196
+ serverInfo: client.getServerVersion() ?? null,
8197
+ mcpProtocolVersion: client.getNegotiatedProtocolVersion() ?? null,
8198
+ compatibility: assessNativeCompatibility(nativeClientRelease, server)
8199
+ };
8200
+ }
8201
+ function assertNativeCompatibility(result2, required = false) {
8202
+ if (result2.compatibility.status === "INCOMPATIBLE" || required && result2.compatibility.status === "UNKNOWN")
8203
+ throw new CliError(
8204
+ "CLIENT_INCOMPATIBLE",
8205
+ "Check version --server and update the client or connect to a compatible service. No business operation was sent.",
8206
+ "NOT_SENT",
8207
+ { compatibility: result2.compatibility }
8208
+ );
8209
+ }
8210
+ async function refreshNativeServerVersion(client, timeout) {
8211
+ const reply = await client.callTool(
8212
+ { name: "cf_get_client_release", arguments: {} },
8213
+ {
8214
+ timeout,
8215
+ allowInputRequired: true,
8216
+ toolDefinition: {
8217
+ name: "cf_get_client_release",
8218
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
8219
+ annotations: { readOnlyHint: true }
8220
+ }
8221
+ }
8222
+ ).catch(() => {
8223
+ throw new CliError(
8224
+ "VERSION_CHECK_UNAVAILABLE",
8225
+ "Cannot refresh the service release. Reconnect or refresh again before continuing."
8226
+ );
8227
+ });
8228
+ const text3 = reply.content?.find((item) => item.type === "text");
8229
+ let server;
8230
+ try {
8231
+ if (reply.isError) throw new Error();
8232
+ server = clientReleaseSchema.parse(
8233
+ reply.structuredContent ?? (text3?.type === "text" ? JSON.parse(text3.text) : null)
8234
+ );
8235
+ } catch {
8236
+ throw new CliError("INVALID_SERVER_RELEASE", "Cannot verify the current server release.");
8237
+ }
8238
+ const result2 = {
8239
+ ...readNativeServerVersion(client),
8240
+ compatibility: assessNativeCompatibility(nativeClientRelease, server)
8241
+ };
8242
+ return result2;
8243
+ }
8244
+
7943
8245
  // packages/cli-client/src/transport.ts
7944
- async function withClient(profile, timeout, operation) {
8246
+ async function withClient(profile, timeout, operation, options = {}) {
7945
8247
  const resource = resourceUrl(profile.resource);
7946
8248
  const accessToken = tokenText(profile.accessToken);
7947
8249
  const client = new Client(
7948
- { name: "content-factory-agent-cli", version: "0.1.0" },
7949
- { inputRequired: { autoFulfill: false } }
8250
+ { name: "@native-marketing/sdk", version: nativeClientRelease.version },
8251
+ {
8252
+ inputRequired: { autoFulfill: false },
8253
+ capabilities: {
8254
+ experimental: {
8255
+ [nativeReleaseCapability]: {
8256
+ version: nativeClientRelease.version,
8257
+ contractVersion: nativeClientRelease.contractVersion,
8258
+ apiMajor: nativeClientRelease.apiMajor
8259
+ }
8260
+ }
8261
+ }
8262
+ }
7950
8263
  );
7951
8264
  const transport = new StreamableHTTPClientTransport(resource, {
7952
8265
  authProvider: { token: async () => accessToken },
@@ -7967,6 +8280,10 @@ async function withClient(profile, timeout, operation) {
7967
8280
  "Cannot authenticate/connect to the configured CF resource. No business operation was sent."
7968
8281
  );
7969
8282
  }
8283
+ const version = readNativeServerVersion(client);
8284
+ if (!options.allowIncompatible)
8285
+ assertNativeCompatibility(version, options.requireCompatibility);
8286
+ options.onVersion?.(version);
7970
8287
  return await operation(client);
7971
8288
  } finally {
7972
8289
  await client.close().catch(() => void 0);
@@ -8834,43 +9151,97 @@ async function withNativeAgentClient(connection, action, options = {}) {
8834
9151
  return withClient(
8835
9152
  connection,
8836
9153
  timeout,
8837
- (client) => action({
8838
- readPackageFile: (input) => readNativePackageFile(connection, input, timeout),
8839
- readProjectMediaFile: (input) => readNativeProjectMediaFile(connection, input, timeout),
8840
- uploadProjectMedia: (file) => uploadNativeProjectMedia(connection, file, timeout),
8841
- uploadMaterial: (file) => uploadNativeMaterial(connection, file, timeout),
8842
- inspectTool: (name) => inspectNativeTool(client, name, timeout, definitions),
8843
- callTool: (name, input = {}, options2) => callNativeTool(client, name, input, connection.resource, options2, timeout, definitions),
8844
- listToolsPage: (input = {}) => listNativeToolsPage(client, input, timeout),
8845
- readCapabilitySchemaPage: (input) => readNativeCapabilitySchemaPage(client, input, timeout),
8846
- readDocumentPage: (input) => readNativeDocumentPage(client, input, timeout),
8847
- getBusinessSummary: (input) => getNativeBusinessSummary(client, input, timeout),
8848
- callCapability: (input) => callNativeCapability(client, input, timeout),
8849
- readCapability: (input) => readNativeCapability(client, input, timeout),
8850
- writeCapability: (input) => writeNativeCapability(client, input, timeout),
8851
- describeCapabilitySummary: (name) => readNativeCapabilityDescriptor(client, name, timeout),
8852
- searchBusiness: (input) => searchNativeBusiness(client, input, timeout),
8853
- readBusinessPage: (input) => readNativeBusinessPage(client, input, timeout),
8854
- findCapabilities: (input) => findNativeCapabilities(client, input, timeout),
8855
- discoverCapabilities: async (input) => {
8856
- const page2 = await findAgentCapabilities(client, input, timeout);
8857
- for (const item of page2.items) if (item.definition) definitions.remember(item.definition);
8858
- return page2;
8859
- },
8860
- describeCapability: async (name, expectedHash) => {
8861
- const cached = expectedHash ? definitions.get(name, expectedHash) : void 0;
8862
- if (cached) return cached;
8863
- const definition = await describeNativeCapability(client, name, timeout);
8864
- if (expectedHash && definition.schemaSha256 !== expectedHash)
8865
- throw new CliError(
8866
- "CAPABILITY_SCHEMA_CHANGED",
8867
- "Discover the current definition again.",
8868
- "REJECTED"
8869
- );
8870
- definitions.remember(definition);
8871
- return definition;
8872
- }
8873
- })
9154
+ (client) => {
9155
+ let version = readNativeServerVersion(client);
9156
+ let versionUnverified = false;
9157
+ client.setNotificationHandler("notifications/tools/list_changed", () => {
9158
+ definitions.clear();
9159
+ });
9160
+ return action(
9161
+ new Proxy(
9162
+ {
9163
+ getVersion: () => structuredClone(version),
9164
+ refreshVersion: async () => {
9165
+ definitions.clear();
9166
+ try {
9167
+ version = await refreshNativeServerVersion(client, timeout);
9168
+ versionUnverified = false;
9169
+ } catch (error) {
9170
+ version = { ...version, compatibility: assessNativeCompatibility(version.client) };
9171
+ versionUnverified = true;
9172
+ throw error;
9173
+ }
9174
+ assertNativeCompatibility(version, options.requireCompatibility);
9175
+ options.onVersion?.(version);
9176
+ return structuredClone(version);
9177
+ },
9178
+ readPackageFile: (input) => readNativePackageFile(connection, input, timeout),
9179
+ readProjectMediaFile: (input) => readNativeProjectMediaFile(connection, input, timeout),
9180
+ uploadProjectMedia: (file) => uploadNativeProjectMedia(connection, file, timeout),
9181
+ uploadMaterial: (file) => uploadNativeMaterial(connection, file, timeout),
9182
+ inspectTool: (name) => inspectNativeTool(client, name, timeout, definitions),
9183
+ callTool: (name, input = {}, options2) => callNativeTool(
9184
+ client,
9185
+ name,
9186
+ input,
9187
+ connection.resource,
9188
+ options2,
9189
+ timeout,
9190
+ definitions
9191
+ ),
9192
+ listToolsPage: (input = {}) => listNativeToolsPage(client, input, timeout),
9193
+ readCapabilitySchemaPage: (input) => readNativeCapabilitySchemaPage(client, input, timeout),
9194
+ readDocumentPage: (input) => readNativeDocumentPage(client, input, timeout),
9195
+ getBusinessSummary: (input) => getNativeBusinessSummary(client, input, timeout),
9196
+ callCapability: (input) => callNativeCapability(client, input, timeout),
9197
+ readCapability: (input) => readNativeCapability(client, input, timeout),
9198
+ writeCapability: (input) => writeNativeCapability(client, input, timeout),
9199
+ describeCapabilitySummary: (name) => readNativeCapabilityDescriptor(client, name, timeout),
9200
+ searchBusiness: (input) => searchNativeBusiness(client, input, timeout),
9201
+ readBusinessPage: (input) => readNativeBusinessPage(client, input, timeout),
9202
+ findCapabilities: (input) => findNativeCapabilities(client, input, timeout),
9203
+ discoverCapabilities: async (input) => {
9204
+ const page2 = await findAgentCapabilities(client, input, timeout);
9205
+ for (const item of page2.items)
9206
+ if (item.definition) definitions.remember(item.definition);
9207
+ return page2;
9208
+ },
9209
+ describeCapability: async (name, expectedHash) => {
9210
+ const cached = expectedHash ? definitions.get(name, expectedHash) : void 0;
9211
+ if (cached) return cached;
9212
+ const definition = await describeNativeCapability(client, name, timeout);
9213
+ if (expectedHash && definition.schemaSha256 !== expectedHash)
9214
+ throw new CliError(
9215
+ "CAPABILITY_SCHEMA_CHANGED",
9216
+ "Discover the current definition again.",
9217
+ "REJECTED"
9218
+ );
9219
+ definitions.remember(definition);
9220
+ return definition;
9221
+ }
9222
+ },
9223
+ {
9224
+ get(target, name, receiver) {
9225
+ const method = Reflect.get(target, name, receiver);
9226
+ if (typeof method !== "function" || name === "getVersion" || name === "refreshVersion")
9227
+ return method;
9228
+ return async (...args) => {
9229
+ if (versionUnverified)
9230
+ throw new CliError(
9231
+ "CLIENT_VERSION_UNVERIFIED",
9232
+ "Verify the service release again or reconnect before continuing. No business operation was sent.",
9233
+ "NOT_SENT",
9234
+ { compatibility: version.compatibility }
9235
+ );
9236
+ assertNativeCompatibility(version, options.requireCompatibility);
9237
+ return Reflect.apply(method, target, args);
9238
+ };
9239
+ }
9240
+ }
9241
+ )
9242
+ );
9243
+ },
9244
+ options
8874
9245
  );
8875
9246
  }
8876
9247
  function checkTimeout4(timeout) {
@@ -9025,9 +9396,22 @@ var values = /* @__PURE__ */ new Set([
9025
9396
  "scope",
9026
9397
  "job",
9027
9398
  "view",
9028
- "schema-hash"
9399
+ "schema-hash",
9400
+ "mode",
9401
+ "channel",
9402
+ "pin",
9403
+ "interval-hours"
9404
+ ]);
9405
+ var flags = /* @__PURE__ */ new Set([
9406
+ "json",
9407
+ "stdin",
9408
+ "help",
9409
+ "version",
9410
+ "server",
9411
+ "strict",
9412
+ "allow-breaking",
9413
+ "dry-run"
9029
9414
  ]);
9030
- var flags = /* @__PURE__ */ new Set(["json", "stdin", "help"]);
9031
9415
  function parseArgs(args) {
9032
9416
  const options = {};
9033
9417
  const words = [];
@@ -9106,8 +9490,8 @@ async function login(store, rawResource, scope2, timeout, notify) {
9106
9490
  const state = randomBytes(32).toString("base64url");
9107
9491
  let resolveCode;
9108
9492
  let rejectCode;
9109
- const codePromise = new Promise((resolve, reject) => {
9110
- resolveCode = resolve;
9493
+ const codePromise = new Promise((resolve2, reject) => {
9494
+ resolveCode = resolve2;
9111
9495
  rejectCode = reject;
9112
9496
  });
9113
9497
  void codePromise.catch(() => void 0);
@@ -9138,9 +9522,9 @@ async function login(store, rawResource, scope2, timeout, notify) {
9138
9522
  });
9139
9523
  let timer;
9140
9524
  try {
9141
- await new Promise((resolve, reject) => {
9525
+ await new Promise((resolve2, reject) => {
9142
9526
  server.once("error", reject);
9143
- server.listen(0, "127.0.0.1", resolve);
9527
+ server.listen(0, "127.0.0.1", resolve2);
9144
9528
  });
9145
9529
  const address = server.address();
9146
9530
  if (!address || typeof address === "string")
@@ -9210,7 +9594,7 @@ Waiting up to 5 minutes. For remote/headless Agents, use auth import with a prov
9210
9594
  } finally {
9211
9595
  if (timer) clearTimeout(timer);
9212
9596
  server.closeAllConnections();
9213
- await new Promise((resolve) => server.close(() => resolve()));
9597
+ await new Promise((resolve2) => server.close(() => resolve2()));
9214
9598
  }
9215
9599
  });
9216
9600
  }
@@ -9254,6 +9638,9 @@ var commandTools = {
9254
9638
  "knowledge discover": "cf_discover_knowledge",
9255
9639
  "knowledge adopt": "cf_adopt_discovered_knowledge",
9256
9640
  "knowledge adoption-receipt": "cf_get_knowledge_adoption_receipt",
9641
+ "knowledge repair-preview": "cf_preview_knowledge_reference_repair",
9642
+ "knowledge repair-reference": "cf_repair_knowledge_reference",
9643
+ "knowledge repair-receipt": "cf_get_knowledge_reference_repair_receipt",
9257
9644
  "knowledge read-discovered": "cf_read_discovered_knowledge",
9258
9645
  "knowledge describe-discovered": "cf_describe_discovered_knowledge",
9259
9646
  "knowledge materials": "cf_list_materials",
@@ -9282,6 +9669,10 @@ var fullHelp = {
9282
9669
  executable: "cf-agent",
9283
9670
  transport: "OAuth-authenticated HTTPS MCP; no local database",
9284
9671
  commands: [
9672
+ "version [--server [--strict] [--profile <name>]]",
9673
+ "update check [--channel latest|next|beta] [--pin <exact-version>|none]",
9674
+ "update apply [--dry-run] [--allow-breaking] [--channel latest|next|beta] [--pin <exact-version>|none]",
9675
+ "update policy [--mode off|notify|auto] [--channel latest|next|beta] [--pin <exact-version>|none] [--interval-hours <1..168>]",
9285
9676
  "auth login --resource <url> [--scope <scopes>] [--profile <name>]",
9286
9677
  "auth import --resource <url> --token-file <private-file> [--profile <name>]",
9287
9678
  "auth status|refresh|logout [--profile <name>]",
@@ -9325,6 +9716,8 @@ var help = {
9325
9716
  executable: "cf-agent",
9326
9717
  transport: "OAuth-authenticated MCP; no local database",
9327
9718
  commands: [
9719
+ "version [--server [--strict]]",
9720
+ "update check|apply|policy (help update for channels, pins and automatic updates)",
9328
9721
  "auth login --resource <url> [--scope <scopes>]",
9329
9722
  "search [<text>] [--input-file <query.json>|--stdin]",
9330
9723
  "business read (--input-file <ref-and-page.json>|--stdin)",
@@ -9469,6 +9862,21 @@ function resolveBaseCommand(parsed) {
9469
9862
  throw new CliError("INVALID_COMMAND", "Run help for supported commands.");
9470
9863
  }
9471
9864
  function resolveCommand(parsed) {
9865
+ if ([
9866
+ "mode",
9867
+ "channel",
9868
+ "pin",
9869
+ "interval-hours",
9870
+ "version",
9871
+ "server",
9872
+ "strict",
9873
+ "allow-breaking",
9874
+ "dry-run"
9875
+ ].some((key2) => parsed.options[key2]))
9876
+ throw new CliError(
9877
+ "INVALID_OPTION",
9878
+ "Version/update options apply only to version/update commands."
9879
+ );
9472
9880
  const removed = {
9473
9881
  doctor: "context",
9474
9882
  "knowledge sync-all": "knowledge discover",
@@ -9603,14 +10011,430 @@ function validateCommandInput(parsed, input) {
9603
10011
  throw new CliError("INVALID_PAGINATION", "Supply only an optional nonempty cursor.");
9604
10012
  }
9605
10013
 
10014
+ // packages/cli-client/src/updates/registry.ts
10015
+ async function checkNativeUpdates(options = {}) {
10016
+ const policy = updatePolicySchema.parse(options.policy ?? {});
10017
+ const current = releaseVersionSchema.safeParse(
10018
+ options.currentVersion ?? nativeClientRelease.version
10019
+ );
10020
+ if (!current.success)
10021
+ throw new CliError(
10022
+ "INVALID_UPDATE_VERSION",
10023
+ "The installed version must be an exact semantic version."
10024
+ );
10025
+ const timeout = options.timeoutMs ?? 5e3;
10026
+ if (!Number.isInteger(timeout) || timeout < 100 || timeout > 12e4)
10027
+ throw new CliError("INVALID_TIMEOUT", "Timeout must be 100\u2013120000 milliseconds.");
10028
+ const name = nativeClientRelease.packages[options.package ?? "sdk"];
10029
+ if (!name) throw new CliError("INVALID_UPDATE_PACKAGE", "Choose sdk or cli.");
10030
+ const selector = policy.pin ?? policy.channel;
10031
+ const url = `https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(selector)}`;
10032
+ let target;
10033
+ try {
10034
+ const response = await (options.fetch ?? fetch)(url, {
10035
+ redirect: "error",
10036
+ credentials: "omit",
10037
+ signal: AbortSignal.timeout(timeout),
10038
+ headers: { accept: "application/json" }
10039
+ });
10040
+ if (!response.ok || !response.body) throw new Error();
10041
+ const reader = response.body.getReader();
10042
+ const chunks = [];
10043
+ let size = 0;
10044
+ try {
10045
+ for (; ; ) {
10046
+ const { done, value } = await reader.read();
10047
+ if (done) break;
10048
+ size += value.byteLength;
10049
+ if (size > 128 * 1024) throw new Error();
10050
+ chunks.push(value);
10051
+ }
10052
+ } finally {
10053
+ await reader.cancel().catch(() => void 0);
10054
+ reader.releaseLock();
10055
+ }
10056
+ target = registryReleaseSchema.parse(JSON.parse(Buffer.concat(chunks).toString("utf8")));
10057
+ if (target.name !== name || policy.pin && target.version !== policy.pin) throw new Error();
10058
+ } catch {
10059
+ throw new CliError(
10060
+ "UPDATE_CHECK_UNAVAILABLE",
10061
+ "Cannot verify release metadata from the public npm registry. Existing software and credentials are unchanged."
10062
+ );
10063
+ }
10064
+ return {
10065
+ checkedAt: Date.now(),
10066
+ target,
10067
+ plan: planNativeUpdate({
10068
+ target,
10069
+ policy,
10070
+ nodeMajor: Number(process.versions.node.split(".")[0]),
10071
+ currentVersion: current.data,
10072
+ ...options.server ? { server: options.server } : {}
10073
+ })
10074
+ };
10075
+ }
10076
+
10077
+ // packages/cli-client/src/updates/store.ts
10078
+ import { lstat as lstat2, open as open6, rename as rename2, unlink as unlink2 } from "node:fs/promises";
10079
+ import { join as join3 } from "node:path";
10080
+ import { randomUUID as randomUUID3 } from "node:crypto";
10081
+ var UpdateStore = class {
10082
+ files;
10083
+ constructor(env) {
10084
+ const base2 = new ProfileStore(env).directory;
10085
+ this.files = new ProfileStore({ CF_AGENT_CONFIG_DIR: join3(base2, "client-lifecycle") }, "state");
10086
+ }
10087
+ async read() {
10088
+ try {
10089
+ await lstat2(this.files.path);
10090
+ } catch (error) {
10091
+ if (error.code === "ENOENT")
10092
+ return { schemaVersion: 1, policy: updatePolicySchema.parse({}) };
10093
+ throw error;
10094
+ }
10095
+ let raw;
10096
+ try {
10097
+ raw = JSON.parse(await readFileBounded(this.files.path, true));
10098
+ } catch {
10099
+ throw new CliError(
10100
+ "INVALID_UPDATE_CONFIGURATION",
10101
+ "Update state is unreadable. Inspect the client-lifecycle configuration."
10102
+ );
10103
+ }
10104
+ const parsed = clientUpdateStateSchema.safeParse(raw);
10105
+ if (!parsed.success)
10106
+ throw new CliError(
10107
+ "INVALID_UPDATE_CONFIGURATION",
10108
+ "Update state is invalid. Inspect the client-lifecycle configuration."
10109
+ );
10110
+ return parsed.data;
10111
+ }
10112
+ locked(action) {
10113
+ return this.files.locked(action);
10114
+ }
10115
+ async change(action) {
10116
+ return this.locked(async () => {
10117
+ const state = clientUpdateStateSchema.parse(action(await this.read()));
10118
+ const temporary = `${this.files.path}.${randomUUID3()}.tmp`;
10119
+ const file = await open6(temporary, "wx", 384);
10120
+ try {
10121
+ try {
10122
+ await file.writeFile(JSON.stringify(state) + "\n");
10123
+ await file.sync();
10124
+ } finally {
10125
+ await file.close();
10126
+ }
10127
+ await rename2(temporary, this.files.path);
10128
+ } finally {
10129
+ await unlink2(temporary).catch(() => void 0);
10130
+ }
10131
+ return state;
10132
+ });
10133
+ }
10134
+ };
10135
+ function effectiveUpdatePolicy(policy, env) {
10136
+ const parsed = updatePolicySchema.safeParse({
10137
+ ...policy,
10138
+ ...env.CF_AGENT_UPDATE_MODE ? { mode: env.CF_AGENT_UPDATE_MODE } : {},
10139
+ ...env.CF_AGENT_UPDATE_CHANNEL ? { channel: env.CF_AGENT_UPDATE_CHANNEL } : {},
10140
+ ...env.CF_AGENT_UPDATE_PIN ? { pin: env.CF_AGENT_UPDATE_PIN === "none" ? null : env.CF_AGENT_UPDATE_PIN } : {}
10141
+ });
10142
+ if (!parsed.success)
10143
+ throw new CliError("INVALID_UPDATE_CONFIGURATION", "Invalid update environment policy.");
10144
+ return parsed.data;
10145
+ }
10146
+
10147
+ // packages/cli-client/src/updates/install.ts
10148
+ import { execFile } from "node:child_process";
10149
+ import { promisify } from "node:util";
10150
+ import { readFile as readFile2, realpath as realpath2 } from "node:fs/promises";
10151
+ import { dirname as dirname2, join as join4, resolve } from "node:path";
10152
+ var execute = promisify(execFile);
10153
+ async function installCliUpdate(input) {
10154
+ const plan = planNativeUpdate({
10155
+ target: input.target,
10156
+ ...input.currentVersion ? { currentVersion: input.currentVersion } : {},
10157
+ policy: input.policy,
10158
+ nodeMajor: Number(process.versions.node.split(".")[0])
10159
+ });
10160
+ if (plan.package !== nativeClientRelease.packages.cli || plan.status !== "UPDATE_AVAILABLE" || !plan.eligibleForAutoUpdate && !input.allowBreaking)
10161
+ throw new CliError(
10162
+ "UPDATE_POLICY_BLOCKED",
10163
+ "This release cannot be installed under the selected policy.",
10164
+ "NOT_SENT",
10165
+ { plan }
10166
+ );
10167
+ if (!input.executablePath || process.platform === "win32")
10168
+ throw new CliError(
10169
+ "MANAGED_UPDATE_UNAVAILABLE",
10170
+ "Use the package manager that owns this installation.",
10171
+ "NOT_SENT",
10172
+ { plan }
10173
+ );
10174
+ const environment = Object.fromEntries(
10175
+ Object.entries(input.env).filter(
10176
+ ([key2, value]) => value !== void 0 && !/^(?:CF_AGENT_|CONTENT_FACTORY_)/i.test(key2)
10177
+ )
10178
+ );
10179
+ environment.CF_AGENT_UPDATE_MODE = "off";
10180
+ environment.NODE_OPTIONS = "--max-old-space-size=384";
10181
+ const options = { env: environment, timeout: input.timeoutMs, maxBuffer: 128 * 1024 };
10182
+ let packageRoot, prefix;
10183
+ try {
10184
+ packageRoot = dirname2(dirname2(await realpath2(input.executablePath)));
10185
+ const manifest = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10186
+ const root = await realpath2(
10187
+ (await execute("npm", ["root", "--global"], options)).stdout.trim()
10188
+ );
10189
+ prefix = await realpath2((await execute("npm", ["prefix", "--global"], options)).stdout.trim());
10190
+ if (manifest.name !== nativeClientRelease.packages.cli || manifest.version !== plan.currentVersion || packageRoot !== await realpath2(join4(root, "@native-marketing/cli")) || packageRoot !== resolve(prefix, "lib/node_modules/@native-marketing/cli"))
10191
+ throw new Error();
10192
+ } catch {
10193
+ throw new CliError(
10194
+ "MANAGED_UPDATE_UNAVAILABLE",
10195
+ "Automatic installation supports the active npm global installation. Use the owning project/package manager for other installs.",
10196
+ "NOT_SENT",
10197
+ { plan }
10198
+ );
10199
+ }
10200
+ const args = [
10201
+ "install",
10202
+ "--global",
10203
+ "--prefix",
10204
+ prefix,
10205
+ `${plan.package}@${plan.targetVersion}`,
10206
+ "--registry=https://registry.npmjs.org/",
10207
+ "--@native-marketing:registry=https://registry.npmjs.org/",
10208
+ "--ignore-scripts",
10209
+ "--no-audit",
10210
+ "--no-fund"
10211
+ ];
10212
+ const recovery = [
10213
+ "npm",
10214
+ "install",
10215
+ "--global",
10216
+ "--prefix",
10217
+ prefix,
10218
+ `${plan.package}@${plan.currentVersion}`,
10219
+ "--ignore-scripts",
10220
+ "--registry=https://registry.npmjs.org/",
10221
+ "--@native-marketing:registry=https://registry.npmjs.org/"
10222
+ ];
10223
+ const store = new UpdateStore(input.env);
10224
+ return store.locked(async () => {
10225
+ if (input.automatic) {
10226
+ const latest = effectiveUpdatePolicy((await store.read()).policy, input.env);
10227
+ if (latest.mode !== "auto" || (latest.pin ?? latest.channel) !== (input.policy.pin ?? input.policy.channel) || !planNativeUpdate({
10228
+ target: input.target,
10229
+ currentVersion: plan.currentVersion,
10230
+ policy: latest,
10231
+ nodeMajor: Number(process.versions.node.split(".")[0])
10232
+ }).eligibleForAutoUpdate)
10233
+ throw new CliError(
10234
+ "UPDATE_POLICY_CHANGED",
10235
+ "Automatic update policy changed. No installation or business operation was sent."
10236
+ );
10237
+ }
10238
+ const before = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10239
+ if (before.name !== plan.package || before.version !== plan.currentVersion)
10240
+ throw new CliError(
10241
+ "UPDATE_INSTALLATION_CHANGED",
10242
+ "The installed version changed. Check version before updating again."
10243
+ );
10244
+ try {
10245
+ await execute("npm", args, { ...options, cwd: prefix });
10246
+ const installed = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10247
+ if (installed.name !== plan.package || releaseVersionSchema.parse(installed.version) !== plan.targetVersion)
10248
+ throw new Error();
10249
+ const verified = await execute(
10250
+ process.execPath,
10251
+ [join4(packageRoot, "dist/cf.js"), "version", "--json"],
10252
+ options
10253
+ );
10254
+ const result2 = JSON.parse(verified.stdout);
10255
+ if (!result2.ok || result2.data?.version !== plan.targetVersion || result2.data?.sdkVersion !== plan.targetVersion)
10256
+ throw new Error();
10257
+ return {
10258
+ state: "UPDATED",
10259
+ package: plan.package,
10260
+ previousVersion: plan.currentVersion,
10261
+ installedVersion: plan.targetVersion,
10262
+ restartRequired: true,
10263
+ originalCommandExecuted: false,
10264
+ recovery
10265
+ };
10266
+ } catch {
10267
+ throw new CliError(
10268
+ "UPDATE_OUTCOME_UNKNOWN",
10269
+ "The installation may have changed. Inspect version before another update; use the recovery command if needed. The original business command was not sent.",
10270
+ "UNKNOWN",
10271
+ { expectedVersion: plan.targetVersion, recovery, originalCommandExecuted: false }
10272
+ );
10273
+ }
10274
+ });
10275
+ }
10276
+
10277
+ // packages/cli-client/src/updates/commands.ts
10278
+ function validateOptions(parsed, names) {
10279
+ if (Object.keys(parsed.options).some((name) => !["json", "timeout-ms", ...names].includes(name)))
10280
+ throw new CliError("INVALID_OPTION", "Unsupported version/update option. Use help update.");
10281
+ }
10282
+ function selectedPolicy(saved, parsed) {
10283
+ const options = parsed.options;
10284
+ const result2 = updatePolicySchema.safeParse({
10285
+ ...saved,
10286
+ ...options.mode ? { mode: options.mode } : {},
10287
+ ...options.channel ? { channel: options.channel } : {},
10288
+ ...options.pin ? { pin: options.pin === "none" ? null : options.pin } : {},
10289
+ ...options["interval-hours"] ? { intervalHours: Number(options["interval-hours"]) } : {}
10290
+ });
10291
+ if (!result2.success)
10292
+ throw new CliError(
10293
+ "INVALID_UPDATE_POLICY",
10294
+ "Use mode off/notify/auto, channel latest/next/beta, an exact pin or none, and interval-hours 1\u2013168."
10295
+ );
10296
+ return result2.data;
10297
+ }
10298
+ async function runLifecycleCommand(parsed, env, executablePath) {
10299
+ const { words, options, timeout } = parsed;
10300
+ if (options.version || words[0] === "version") {
10301
+ if (options.version && words.length !== 0 || !options.version && words.length !== 1)
10302
+ throw new CliError("INVALID_COMMAND", "Use version or --version.");
10303
+ validateOptions(parsed, ["version", "server", "strict", "profile"]);
10304
+ if (options.strict && !options.server)
10305
+ throw new CliError("INVALID_OPTION", "--strict requires version --server.");
10306
+ if (options.profile && !options.server)
10307
+ throw new CliError("INVALID_OPTION", "--profile requires version --server.");
10308
+ return options.server ? null : { command: "version", data: await getNativeCliVersion(executablePath) };
10309
+ }
10310
+ if (words[0] !== "update") return null;
10311
+ if (words.length !== 2 || !["check", "apply", "policy"].includes(words[1]))
10312
+ throw new CliError("INVALID_COMMAND", "Use update check/apply/policy.");
10313
+ const policyCommand = words[1] === "policy";
10314
+ validateOptions(
10315
+ parsed,
10316
+ policyCommand ? ["mode", "channel", "pin", "interval-hours"] : ["channel", "pin", ...words[1] === "apply" ? ["allow-breaking", "dry-run"] : []]
10317
+ );
10318
+ const store = new UpdateStore(env);
10319
+ const state = await store.read();
10320
+ if (policyCommand) {
10321
+ const changes = Object.keys(options).some(
10322
+ (name) => ["mode", "channel", "pin", "interval-hours"].includes(name)
10323
+ );
10324
+ const saved = changes ? await store.change((current) => ({
10325
+ ...current,
10326
+ policy: selectedPolicy(current.policy, parsed)
10327
+ })) : state;
10328
+ return {
10329
+ command: "update policy",
10330
+ data: {
10331
+ saved: saved.policy,
10332
+ effective: effectiveUpdatePolicy(saved.policy, env),
10333
+ lastCheckedAt: saved.lastCheck?.at ?? null
10334
+ }
10335
+ };
10336
+ }
10337
+ const policy = selectedPolicy(effectiveUpdatePolicy(state.policy, env), parsed);
10338
+ const currentVersion = (await getNativeCliVersion(executablePath)).version;
10339
+ const checked = await checkNativeUpdates({
10340
+ package: "cli",
10341
+ currentVersion,
10342
+ policy,
10343
+ timeoutMs: timeout
10344
+ });
10345
+ await store.change((current) => ({
10346
+ ...current,
10347
+ lastAttempt: { at: checked.checkedAt, selector: policy.pin ?? policy.channel },
10348
+ lastCheck: {
10349
+ at: checked.checkedAt,
10350
+ selector: policy.pin ?? policy.channel,
10351
+ target: checked.target
10352
+ }
10353
+ }));
10354
+ if (words[1] === "check" || options["dry-run"] || checked.plan.status === "CURRENT")
10355
+ return { command: words.join(" "), data: checked };
10356
+ const data = await installCliUpdate({
10357
+ target: checked.target,
10358
+ currentVersion,
10359
+ policy,
10360
+ timeoutMs: timeout,
10361
+ env,
10362
+ allowBreaking: Boolean(options["allow-breaking"]),
10363
+ ...executablePath ? { executablePath } : {}
10364
+ });
10365
+ return { command: "update apply", data };
10366
+ }
10367
+ async function maybeAutoUpdate(env, io, timeout) {
10368
+ if (!io.executablePath || env.CF_AGENT_UPDATE_MODE === "off" || env.CI && !env.CF_AGENT_UPDATE_MODE)
10369
+ return null;
10370
+ const notify = io.notify ?? ((message) => process.stderr.write(message + "\n"));
10371
+ try {
10372
+ const store = new UpdateStore(env);
10373
+ const state = await store.read();
10374
+ const policy = effectiveUpdatePolicy(state.policy, env);
10375
+ if (policy.mode === "off") return null;
10376
+ const now = Date.now(), selector = policy.pin ?? policy.channel;
10377
+ const age = state.lastAttempt ? now - state.lastAttempt.at : Infinity;
10378
+ if (state.lastAttempt?.selector === selector && age >= 0 && age < policy.intervalHours * 36e5)
10379
+ return null;
10380
+ let claimed = false;
10381
+ await store.change((current) => {
10382
+ const age2 = current.lastAttempt ? now - current.lastAttempt.at : Infinity;
10383
+ if (current.lastAttempt?.selector === selector && age2 >= 0 && age2 < policy.intervalHours * 36e5)
10384
+ return current;
10385
+ claimed = true;
10386
+ return { ...current, lastAttempt: { at: now, selector } };
10387
+ });
10388
+ if (!claimed) return null;
10389
+ const currentVersion = (await getNativeCliVersion(io.executablePath)).version;
10390
+ const checked = await checkNativeUpdates({
10391
+ package: "cli",
10392
+ currentVersion,
10393
+ policy,
10394
+ timeoutMs: Math.min(timeout, 2e3)
10395
+ });
10396
+ await store.change((current) => ({
10397
+ ...current,
10398
+ lastCheck: { at: checked.checkedAt, selector, target: checked.target }
10399
+ }));
10400
+ if (checked.plan.status === "CURRENT" || checked.plan.reason === "DOWNGRADE_FORBIDDEN" && !policy.pin)
10401
+ return null;
10402
+ if (policy.mode === "auto" && checked.plan.eligibleForAutoUpdate) {
10403
+ const data = await installCliUpdate({
10404
+ target: checked.target,
10405
+ currentVersion,
10406
+ automatic: true,
10407
+ policy,
10408
+ executablePath: io.executablePath,
10409
+ env,
10410
+ timeoutMs: timeout
10411
+ });
10412
+ notify(
10413
+ `Native Marketing updated to ${checked.plan.targetVersion}. Run the original command again.`
10414
+ );
10415
+ return { command: "update auto", data };
10416
+ }
10417
+ notify(
10418
+ `Native Marketing ${nativeClientRelease.version}: update ${checked.plan.targetVersion} (${checked.plan.reason}). Use update check or update apply.`
10419
+ );
10420
+ } catch (error) {
10421
+ if (error instanceof CliError && error.code === "UPDATE_OUTCOME_UNKNOWN") throw error;
10422
+ notify("Native Marketing update check/install is unavailable; use update check for details.");
10423
+ }
10424
+ return null;
10425
+ }
10426
+
9606
10427
  // packages/cli-client/src/cli/run.ts
9607
10428
  async function runNetworkCli(args, env = process.env, io = {}, executable = "cf") {
9608
10429
  let command5 = executable;
9609
10430
  try {
9610
10431
  const parsed = parseArgs(args);
9611
10432
  const { words, options, timeout } = parsed;
9612
- if (!words.length || words[0] === "help" || options.help)
10433
+ if ((!words.length || words[0] === "help" || options.help) && !options.version)
9613
10434
  return success("help", { ...commandHelp(words), executable });
10435
+ const local = await runLifecycleCommand(parsed, env, io.executablePath);
10436
+ if (local) return success(local.command, local.data);
10437
+ const remoteVersion = (words.join(" ") === "version" || options.version && !words.length) && options.server;
9614
10438
  const store = new ProfileStore(env, String(options.profile ?? "default"));
9615
10439
  if (words[0] === "auth") {
9616
10440
  if (words.length !== 2)
@@ -9682,10 +10506,14 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9682
10506
  "AUTH_OPTION_MISUSE",
9683
10507
  "Resource/token/scope options belong to auth commands. Business commands use the bound profile or CF_AGENT_RESOURCE and CF_AGENT_ACCESS_TOKEN together."
9684
10508
  );
9685
- resolveCommand(parsed);
9686
- command5 = words[0] === "search" ? "search" : words[0] === "capabilities" ? words.slice(0, 2).join(" ") : words.join(" ");
10509
+ if (!remoteVersion) resolveCommand(parsed);
10510
+ command5 = remoteVersion ? "version" : words[0] === "search" ? "search" : words[0] === "capabilities" ? words.slice(0, 2).join(" ") : words.join(" ");
10511
+ if (!remoteVersion) {
10512
+ const automatic = await maybeAutoUpdate(env, io, timeout);
10513
+ if (automatic) return success(automatic.command, automatic.data);
10514
+ }
9687
10515
  const input = options.stdin ? objectJson(await readStream(io.stdin ?? process.stdin)) : typeof options["input-file"] === "string" ? objectJson(await readFileBounded(options["input-file"])) : {};
9688
- validateCommandInput(parsed, input);
10516
+ if (!remoteVersion) validateCommandInput(parsed, input);
9689
10517
  let profile;
9690
10518
  if (env.CF_AGENT_ACCESS_TOKEN || env.CF_AGENT_RESOURCE) {
9691
10519
  if (options.profile || !env.CF_AGENT_ACCESS_TOKEN || !env.CF_AGENT_RESOURCE)
@@ -9698,7 +10526,18 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9698
10526
  accessToken: tokenText(env.CF_AGENT_ACCESS_TOKEN)
9699
10527
  };
9700
10528
  } else profile = await refreshProfile(store, timeout);
9701
- const data = resolveCommand(parsed).mode === "package-file" ? await downloadPackageFile(profile, input, String(options["output-file"]), timeout) : resolveCommand(parsed).mode === "media-file" ? await downloadProjectMedia(profile, input, String(options["output-file"]), timeout) : resolveCommand(parsed).mode === "upload" ? await uploadLocalMaterial(
10529
+ const data = remoteVersion ? await withClient(
10530
+ profile,
10531
+ timeout,
10532
+ async (client) => ({
10533
+ ...readNativeServerVersion(client),
10534
+ cli: await getNativeCliVersion(io.executablePath)
10535
+ }),
10536
+ {
10537
+ allowIncompatible: !options.strict,
10538
+ requireCompatibility: Boolean(options.strict)
10539
+ }
10540
+ ) : resolveCommand(parsed).mode === "package-file" ? await downloadPackageFile(profile, input, String(options["output-file"]), timeout) : resolveCommand(parsed).mode === "media-file" ? await downloadProjectMedia(profile, input, String(options["output-file"]), timeout) : resolveCommand(parsed).mode === "upload" ? await uploadLocalMaterial(
9702
10541
  profile,
9703
10542
  String(options.file),
9704
10543
  String(options["request-id"]),
@@ -9707,7 +10546,15 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9707
10546
  ) : await withClient(
9708
10547
  profile,
9709
10548
  timeout,
9710
- (client) => businessCommand(client, parsed, input, profile.resource)
10549
+ (client) => businessCommand(client, parsed, input, profile.resource),
10550
+ {
10551
+ onVersion: (version) => {
10552
+ if (version.compatibility.status === "UPGRADE_RECOMMENDED")
10553
+ (io.notify ?? ((message) => process.stderr.write(message + "\n")))(
10554
+ `The service recommends Native Marketing ${version.compatibility.server.version}. Use update check.`
10555
+ );
10556
+ }
10557
+ }
9711
10558
  );
9712
10559
  return success(command5, data);
9713
10560
  } catch (error) {
@@ -9719,14 +10566,19 @@ function success(command5, data) {
9719
10566
  }
9720
10567
  export {
9721
10568
  CliError as NativeAgentClientError,
10569
+ assessNativeCompatibility,
9722
10570
  callNativeCapability,
9723
10571
  callNativeTool,
10572
+ checkNativeUpdates,
10573
+ defaultUpdatePolicy,
9724
10574
  describeNativeCapability,
9725
10575
  findAgentCapabilities,
9726
10576
  findNativeCapabilities,
9727
10577
  getNativeBusinessSummary,
10578
+ getNativeClientVersion,
9728
10579
  inspectNativeTool,
9729
10580
  listNativeToolsPage,
10581
+ planNativeUpdate,
9730
10582
  projectMediaFileQuerySchema,
9731
10583
  readNativeBusinessPage,
9732
10584
  readNativeCapability,