@native-marketing/sdk 0.3.6 → 0.3.8

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
@@ -2570,6 +2570,7 @@ var permissionSchema = z32.enum([
2570
2570
  "feedback.manage",
2571
2571
  "recommendation.create",
2572
2572
  "package.download",
2573
+ "presentation.share",
2573
2574
  "source.read",
2574
2575
  "source.ingest",
2575
2576
  "source.content.read"
@@ -6934,7 +6935,13 @@ var surveyRejections = [
6934
6935
  "PERSONAL_SURVEY_DRAFT_TRANSITION_IMMUTABLE"
6935
6936
  ];
6936
6937
  function isKnownCapabilityRejection(code2, name) {
6937
- return capabilityRejectedErrorCodes.includes(code2) || name === "cf_repair_knowledge_reference" && [
6938
+ return name === "cf_issue_human_read_link" && [
6939
+ "HUMAN_TARGET_NOT_FOUND",
6940
+ "HUMAN_CONTENT_TOO_LARGE",
6941
+ "HUMAN_LINK_REQUEST_CONFLICT",
6942
+ "HUMAN_LINK_LIMIT",
6943
+ "HUMAN_LINK_SECRET_UNAVAILABLE"
6944
+ ].includes(code2) || name === "cf_revoke_human_read_link" && code2 === "HUMAN_LINK_REQUEST_CONFLICT" || name === "cf_cleanup_human_read_links" && code2 === "HUMAN_CLEANUP_INPUT_INVALID" || capabilityRejectedErrorCodes.includes(code2) || name === "cf_repair_knowledge_reference" && [
6938
6945
  "KNOWLEDGE_REFERENCE_REPAIR_CONFLICT",
6939
6946
  "KNOWLEDGE_REFERENCE_REPAIR_NOT_SUPPORTED",
6940
6947
  "KNOWLEDGE_REFERENCE_REPAIR_IDENTITY_MISMATCH",
@@ -7008,6 +7015,8 @@ function capabilityRecovery(code2, outcome, name) {
7008
7015
  const change2 = changeCapabilityRecovery(code2, outcome, name);
7009
7016
  if (change2) return change2;
7010
7017
  if (outcome === "UNKNOWN") {
7018
+ if (name === "cf_issue_human_read_link") return "FIND_ORIGINAL_RECEIPT";
7019
+ if (name === "cf_revoke_human_read_link") return "READ_ORIGINAL_LINK_STATE";
7011
7020
  if ([
7012
7021
  "cf_material_verification_start",
7013
7022
  "cf_material_verification_advance",
@@ -7305,6 +7314,110 @@ var knowledgeReferenceRepairCommandSchema = knowledgeReferenceRepairQuerySchema.
7305
7314
  }).strict();
7306
7315
  var knowledgeReferenceRepairReceiptQuerySchema = knowledgeAdoptionReceiptQuerySchema;
7307
7316
 
7317
+ // packages/contracts/src/agent/human-presentation.ts
7318
+ import { z as z103 } from "zod";
7319
+ var reference = z103.string().min(1).max(512);
7320
+ var digest = z103.string().regex(/^[a-f0-9]{64}$/u);
7321
+ var webUrl = z103.string().url().max(4096).refine((value) => {
7322
+ try {
7323
+ const url = new URL(value);
7324
+ return !url.username && !url.password && !url.search && (url.protocol === "https:" || url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname));
7325
+ } catch {
7326
+ return false;
7327
+ }
7328
+ });
7329
+ var packageCode = z103.string().regex(/^PKG-[0-9]{6,}$/u);
7330
+ var humanPresentationCapability = "com.native-marketing/human-presentation";
7331
+ var humanPresentationFeatures = Object.freeze({
7332
+ version: 1,
7333
+ subjects: ["CONTENT_PACKAGE"],
7334
+ interactions: ["CONTENT_PACKAGE_REVIEW"],
7335
+ links: ["AUTHENTICATED", "TEMPORARY_PUBLIC_READ"],
7336
+ publicRead: "SNAPSHOT"
7337
+ });
7338
+ var humanPresentationInputSchema = z103.object({ packageCode }).strict();
7339
+ var common3 = {
7340
+ linkRef: reference,
7341
+ kind: z103.literal("READABLE_CONTENT"),
7342
+ title: z103.string().min(1).max(500),
7343
+ subjectRef: reference,
7344
+ url: webUrl
7345
+ };
7346
+ var humanReadLinkSchema = z103.discriminatedUnion("access", [
7347
+ z103.object({
7348
+ ...common3,
7349
+ access: z103.literal("AUTHENTICATED"),
7350
+ representation: z103.literal("CURRENT_VIEW"),
7351
+ expiresAt: z103.null()
7352
+ }).strict(),
7353
+ z103.object({
7354
+ ...common3,
7355
+ access: z103.literal("TEMPORARY_PUBLIC_READ"),
7356
+ representation: z103.literal("SNAPSHOT"),
7357
+ snapshotRef: reference,
7358
+ contentSha256: digest,
7359
+ createdAt: z103.string().datetime(),
7360
+ expiresAt: z103.string().datetime()
7361
+ }).strict()
7362
+ ]);
7363
+ var humanInteractionSchema = z103.object({
7364
+ interactionRef: reference,
7365
+ kind: z103.literal("CONTENT_PACKAGE_REVIEW"),
7366
+ subjectRef: reference,
7367
+ title: z103.string().min(1).max(500),
7368
+ summary: z103.string().max(2e3),
7369
+ state: z103.enum(["PENDING", "APPROVED", "REJECTED", "RESOLVED"]),
7370
+ sourceState: z103.string().min(1).max(80),
7371
+ actionDigest: digest,
7372
+ expiresAt: z103.null(),
7373
+ reviewUrl: webUrl,
7374
+ canReview: z103.boolean()
7375
+ }).strict();
7376
+ var humanPresentationSchema = z103.object({
7377
+ schemaVersion: z103.literal(1),
7378
+ interactions: z103.array(humanInteractionSchema).max(16),
7379
+ links: z103.array(humanReadLinkSchema).max(16)
7380
+ }).strict();
7381
+ var humanReadableDocumentSchema = z103.object({
7382
+ schemaVersion: z103.literal(1),
7383
+ title: z103.string().min(1).max(500),
7384
+ subjectRef: reference,
7385
+ manifestHash: digest,
7386
+ sections: z103.array(
7387
+ z103.object({ heading: z103.string().min(1).max(500), text: z103.string().max(131072) }).strict()
7388
+ ).min(1).max(128)
7389
+ }).strict();
7390
+ var issueHumanReadLinkInputSchema = z103.object({
7391
+ requestId: z103.string().min(1).max(128),
7392
+ packageCode,
7393
+ expectedManifestHash: digest,
7394
+ access: z103.literal("TEMPORARY_PUBLIC_READ"),
7395
+ targetKeys: z103.array(z103.string().min(1).max(64)).min(1).max(32).refine((keys) => new Set(keys).size === keys.length),
7396
+ ttlSeconds: z103.number().int().min(60).max(86400).default(3600)
7397
+ }).strict();
7398
+ var humanReadLinkLookupSchema = z103.object({ linkRef: z103.string().uuid() }).strict();
7399
+ var humanReadLinkReceiptQuerySchema = z103.object({ requestId: z103.string().min(1).max(128) }).strict();
7400
+ var revokeHumanReadLinkInputSchema = humanReadLinkLookupSchema.extend({ requestId: z103.string().min(1).max(128) }).strict();
7401
+ var humanReadLinkResultSchema = z103.object({
7402
+ linkRef: z103.string().uuid(),
7403
+ issuanceRequestId: z103.string().min(1).max(128),
7404
+ state: z103.enum(["ACTIVE", "EXPIRED", "REVOKED", "UNAVAILABLE"]),
7405
+ packageCode,
7406
+ manifestHash: digest,
7407
+ expiresAt: z103.string().datetime(),
7408
+ human: humanPresentationSchema
7409
+ }).strict();
7410
+ var humanReadLinkReceiptSchema = z103.discriminatedUnion("status", [
7411
+ z103.object({ status: z103.literal("FOUND"), receipt: humanReadLinkResultSchema }).strict(),
7412
+ z103.object({ status: z103.literal("NOT_FOUND") }).strict()
7413
+ ]);
7414
+ var cleanupHumanReadLinksInputSchema = z103.object({ limit: z103.number().int().min(1).max(32).default(16) }).strict();
7415
+ var cleanupHumanReadLinksResultSchema = z103.object({
7416
+ reclaimed: z103.number().int().nonnegative().max(32),
7417
+ limit: z103.number().int().min(1).max(32)
7418
+ }).strict();
7419
+ var humanPresentationResultSchema = z103.object({ human: humanPresentationSchema }).strict();
7420
+
7308
7421
  // packages/contracts/src/agent/capability-receipts.ts
7309
7422
  var rule = (capability, schema2, operation, keys = [], field) => ({ capability, schema: schema2, operation, keys, field });
7310
7423
  var foundation = (operation, field) => rule(
@@ -7531,6 +7644,18 @@ var rules = {
7531
7644
  };
7532
7645
  var object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
7533
7646
  function capabilityReceiptRead(name, input) {
7647
+ if (name === "cf_issue_human_read_link") {
7648
+ const parsed2 = humanReadLinkReceiptQuerySchema.safeParse({
7649
+ requestId: object(input).requestId
7650
+ });
7651
+ if (!parsed2.success) return void 0;
7652
+ return {
7653
+ capability: "cf_get_human_read_link_receipt",
7654
+ arguments: parsed2.data,
7655
+ requiresDescription: true,
7656
+ requiresCurrentAuthorization: true
7657
+ };
7658
+ }
7534
7659
  const r = name && Object.hasOwn(rules, name) ? rules[name] : void 0;
7535
7660
  if (!r) return void 0;
7536
7661
  const raw = object(input), source = r.field ? object(Object.hasOwn(raw, r.field) ? raw[r.field] : void 0) : raw;
@@ -7553,13 +7678,18 @@ function capabilityReceiptRead(name, input) {
7553
7678
  }
7554
7679
 
7555
7680
  // packages/contracts/src/agent/capability-status.ts
7556
- import { z as z103 } from "zod";
7681
+ import { z as z104 } from "zod";
7557
7682
  var verification = {
7558
7683
  capability: "cf_material_verification_status",
7559
7684
  schema: materialVerificationIdSchema,
7560
7685
  key: "jobId"
7561
7686
  };
7562
7687
  var rules2 = {
7688
+ cf_revoke_human_read_link: {
7689
+ capability: "cf_get_human_read_link",
7690
+ schema: humanReadLinkLookupSchema,
7691
+ key: "linkRef"
7692
+ },
7563
7693
  cf_material_verification_start: { ...verification, from: "requestId" },
7564
7694
  cf_material_verification_advance: verification,
7565
7695
  cf_material_verification_retry: verification,
@@ -7571,7 +7701,7 @@ var rules2 = {
7571
7701
  },
7572
7702
  cf_tenant_material_scan_advance: {
7573
7703
  capability: "cf_tenant_material_scan_status",
7574
- schema: z103.object({}).strict()
7704
+ schema: z104.object({}).strict()
7575
7705
  },
7576
7706
  cf_sync_materials: {
7577
7707
  capability: "cf_reconcile_materials",
@@ -7598,6 +7728,218 @@ function capabilityStatusRead(name, input) {
7598
7728
  };
7599
7729
  }
7600
7730
 
7731
+ // packages/contracts/src/client-lifecycle.ts
7732
+ import { z as z105 } from "zod";
7733
+
7734
+ // packages/contracts/src/generated/client-release.ts
7735
+ var nativeClientRelease = {
7736
+ schemaVersion: 1,
7737
+ product: "native-marketing",
7738
+ version: "0.3.8",
7739
+ packages: {
7740
+ sdk: "@native-marketing/sdk",
7741
+ cli: "@native-marketing/cli"
7742
+ },
7743
+ contractVersion: 1,
7744
+ minimumClientVersion: "0.3.6",
7745
+ apiMajor: 1,
7746
+ nodeMajor: 24,
7747
+ changes: [
7748
+ "Unified typed human interaction cards and authenticated reading links across SDK, CLI and MCP.",
7749
+ "Explicitly authorized expiring public read-only package text snapshots with original request recovery and revocation.",
7750
+ "Bound human presentation responses to the configured Project, original issuance request and source version."
7751
+ ]
7752
+ };
7753
+
7754
+ // packages/contracts/src/client-lifecycle.ts
7755
+ var nativeReleaseCapability = "com.native-marketing/client-release";
7756
+ var releaseVersionSchema = z105.string().max(128).regex(
7757
+ /^(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-]+)*)?$/
7758
+ );
7759
+ var clientIdentitySchema = z105.object({
7760
+ version: releaseVersionSchema,
7761
+ contractVersion: z105.number().int().positive(),
7762
+ apiMajor: z105.number().int().positive()
7763
+ });
7764
+ var clientReleaseSchema = z105.object({
7765
+ schemaVersion: z105.literal(1),
7766
+ product: z105.literal("native-marketing"),
7767
+ version: releaseVersionSchema,
7768
+ packages: z105.object({
7769
+ sdk: z105.literal("@native-marketing/sdk"),
7770
+ cli: z105.literal("@native-marketing/cli")
7771
+ }),
7772
+ contractVersion: z105.number().int().positive(),
7773
+ minimumClientVersion: releaseVersionSchema,
7774
+ apiMajor: z105.number().int().positive(),
7775
+ nodeMajor: z105.number().int().positive(),
7776
+ changes: z105.array(z105.string().min(1).max(240)).max(8).default([])
7777
+ });
7778
+ var updatePolicySchema = z105.object({
7779
+ mode: z105.enum(["off", "notify", "auto"]).default("notify"),
7780
+ channel: z105.enum(["latest", "next", "beta"]).default("latest"),
7781
+ pin: releaseVersionSchema.nullable().default(null),
7782
+ intervalHours: z105.number().int().min(1).max(168).default(24)
7783
+ }).strict();
7784
+ var defaultUpdatePolicy = updatePolicySchema.parse({});
7785
+ function compareReleaseVersions(left, right) {
7786
+ const parse = (raw) => releaseVersionSchema.parse(raw).split("+")[0].split(/-(.*)/s);
7787
+ const a = parse(left), b = parse(right);
7788
+ const numbers = (x, y) => BigInt(x) < BigInt(y) ? -1 : BigInt(x) > BigInt(y) ? 1 : 0;
7789
+ const ac = a[0].split("."), bc = b[0].split(".");
7790
+ for (let i = 0; i < 3; i++) {
7791
+ const order = numbers(ac[i], bc[i]);
7792
+ if (order) return order;
7793
+ }
7794
+ if (a[1] === b[1]) return 0;
7795
+ if (!a[1] || !b[1]) return a[1] ? -1 : 1;
7796
+ const ap = a[1].split("."), bp = b[1].split(".");
7797
+ for (let i = 0; i < Math.max(ap.length, bp.length); i++) {
7798
+ const x = ap[i], y = bp[i];
7799
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
7800
+ if (x === y) continue;
7801
+ const xn = /^\d+$/.test(x), yn = /^\d+$/.test(y);
7802
+ return xn && yn ? numbers(x, y) : xn !== yn ? xn ? -1 : 1 : x < y ? -1 : 1;
7803
+ }
7804
+ return 0;
7805
+ }
7806
+ function assessNativeCompatibility(client, server) {
7807
+ client = clientIdentitySchema.parse(client);
7808
+ const result2 = (status, reason) => ({ status, reason, client, server: server ?? null });
7809
+ if (!server) return result2("UNKNOWN", "SERVER_METADATA_UNAVAILABLE");
7810
+ server = clientReleaseSchema.parse(server);
7811
+ if (client.contractVersion !== server.contractVersion)
7812
+ return result2("INCOMPATIBLE", "CONTRACT_MISMATCH");
7813
+ if (client.apiMajor !== server.apiMajor) return result2("INCOMPATIBLE", "API_MISMATCH");
7814
+ if (compareReleaseVersions(client.version, server.minimumClientVersion) < 0)
7815
+ return result2("INCOMPATIBLE", "CLIENT_TOO_OLD");
7816
+ return compareReleaseVersions(client.version, server.version) < 0 ? result2("UPGRADE_RECOMMENDED", "NEWER_CLIENT_AVAILABLE") : result2("COMPATIBLE", "CURRENT");
7817
+ }
7818
+
7819
+ // packages/contracts/src/client-update-policy.ts
7820
+ import { z as z106 } from "zod";
7821
+ var registryReleaseSchema = z106.object({
7822
+ name: z106.enum(["@native-marketing/sdk", "@native-marketing/cli"]),
7823
+ version: releaseVersionSchema,
7824
+ deprecated: z106.string().optional(),
7825
+ nativeMarketing: z106.object({
7826
+ contractVersion: z106.number().int().positive(),
7827
+ apiMajor: z106.number().int().positive(),
7828
+ nodeMajor: z106.number().int().positive(),
7829
+ changes: z106.array(z106.string().min(1).max(240)).max(8).optional()
7830
+ }).optional(),
7831
+ dist: z106.object({
7832
+ integrity: z106.string().max(512).regex(/^sha512-[A-Za-z0-9+/]{86}==$/)
7833
+ })
7834
+ });
7835
+ var clientUpdateStateSchema = z106.object({
7836
+ schemaVersion: z106.literal(1),
7837
+ policy: updatePolicySchema,
7838
+ lastCheck: z106.object({
7839
+ at: z106.number().int().nonnegative(),
7840
+ selector: z106.string().max(160),
7841
+ target: registryReleaseSchema
7842
+ }).strict().optional(),
7843
+ lastAttempt: z106.object({ at: z106.number().int().nonnegative(), selector: z106.string().max(160) }).strict().optional()
7844
+ }).strict();
7845
+ function planNativeUpdate(input) {
7846
+ const target = registryReleaseSchema.parse(input.target);
7847
+ const current = releaseVersionSchema.parse(input.currentVersion ?? nativeClientRelease.version);
7848
+ const policy = updatePolicySchema.parse(input.policy ?? {});
7849
+ const spec = `${target.name}@${target.version}`;
7850
+ const cli = target.name === nativeClientRelease.packages.cli;
7851
+ const result2 = (status, reason, eligible = false) => ({
7852
+ package: target.name,
7853
+ currentVersion: current,
7854
+ targetVersion: target.version,
7855
+ status,
7856
+ reason,
7857
+ eligibleForAutoUpdate: eligible,
7858
+ policy,
7859
+ commands: {
7860
+ npm: [
7861
+ "npm",
7862
+ "install",
7863
+ ...cli ? ["--global"] : ["--save-exact"],
7864
+ spec,
7865
+ "--ignore-scripts",
7866
+ "--registry=https://registry.npmjs.org/",
7867
+ "--@native-marketing:registry=https://registry.npmjs.org/"
7868
+ ],
7869
+ pnpm: ["pnpm", "add", ...cli ? ["--global"] : ["--save-exact"], spec, "--ignore-scripts"],
7870
+ yarn: cli ? null : ["yarn", "add", "--exact", spec]
7871
+ }
7872
+ });
7873
+ if (policy.pin && policy.pin !== target.version) return result2("BLOCKED", "PIN_MISMATCH");
7874
+ if (!policy.pin && policy.channel === "latest" && target.version.split("+")[0].includes("-"))
7875
+ return result2("BLOCKED", "CHANNEL_MISMATCH");
7876
+ const order = compareReleaseVersions(target.version, current);
7877
+ if (order < 0) return result2("BLOCKED", "DOWNGRADE_FORBIDDEN");
7878
+ if (target.deprecated !== void 0) return result2("BLOCKED", "DEPRECATED");
7879
+ if (!target.nativeMarketing) return result2("BLOCKED", "METADATA_UNAVAILABLE");
7880
+ const metadata = target.nativeMarketing;
7881
+ if (metadata.nodeMajor !== (input.nodeMajor ?? nativeClientRelease.nodeMajor))
7882
+ return result2("BLOCKED", "NODE_MISMATCH");
7883
+ if (metadata.contractVersion !== nativeClientRelease.contractVersion || metadata.apiMajor !== nativeClientRelease.apiMajor)
7884
+ return result2("BLOCKED", "CONTRACT_MISMATCH");
7885
+ if (input.server && assessNativeCompatibility(
7886
+ {
7887
+ version: target.version,
7888
+ contractVersion: metadata.contractVersion,
7889
+ apiMajor: metadata.apiMajor
7890
+ },
7891
+ input.server
7892
+ ).status === "INCOMPATIBLE")
7893
+ return result2("BLOCKED", "SERVER_INCOMPATIBLE");
7894
+ if (order === 0) return result2("CURRENT", "CURRENT");
7895
+ const from = current.split(/[.+-]/), to = target.version.split(/[.+-]/);
7896
+ const compatibleLine = from[0] === to[0] && (from[0] !== "0" || from[1] === to[1]);
7897
+ const stable = !current.split("+")[0].includes("-") && !target.version.split("+")[0].includes("-");
7898
+ return compatibleLine && stable ? result2("UPDATE_AVAILABLE", "COMPATIBLE_UPDATE", true) : result2("UPDATE_AVAILABLE", "REVIEW_REQUIRED");
7899
+ }
7900
+
7901
+ // packages/contracts/src/agent/human-presentation-validation.ts
7902
+ function validateHumanPresentationResource(human, resource, packageCode2) {
7903
+ try {
7904
+ const base2 = new URL(resource);
7905
+ const project = /^\/mcp\/projects\/(PRJ-[0-9]{6,})$/u.exec(base2.pathname)?.[1];
7906
+ if (!project || base2.username || base2.password || base2.search || base2.hash) return false;
7907
+ const review = (raw) => {
7908
+ const url = new URL(raw);
7909
+ return url.origin === base2.origin && !url.username && !url.password && !url.search && !url.hash && (packageCode2 ? url.pathname === `/projects/${project}/packages/${packageCode2}` : new RegExp(`^/projects/${project}/packages/PKG-[0-9]{6,}$`, "u").test(url.pathname));
7910
+ };
7911
+ return human.interactions.every((item) => review(item.reviewUrl)) && human.links.every((link) => {
7912
+ if (link.access === "AUTHENTICATED") return review(link.url);
7913
+ const url = new URL(link.url);
7914
+ return url.origin === base2.origin && !url.username && !url.password && !url.search && url.pathname === `/api/v1/human-read/${link.linkRef}` && /^#[A-Za-z0-9_-]{43}$/u.test(url.hash) && link.snapshotRef === `sha256:${link.contentSha256}` && Date.parse(link.expiresAt) > Date.parse(link.createdAt);
7915
+ });
7916
+ } catch {
7917
+ return false;
7918
+ }
7919
+ }
7920
+ function validateHumanPresentationResponse(parsed, resource, input, operation) {
7921
+ const value = parsed.status === "FOUND" ? parsed.receipt : parsed;
7922
+ if (!("human" in value)) return true;
7923
+ const human = value.human;
7924
+ if (!validateHumanPresentationResource(
7925
+ human,
7926
+ resource,
7927
+ typeof value.packageCode === "string" ? value.packageCode : input.packageCode
7928
+ ))
7929
+ return false;
7930
+ if (input.packageCode && value.packageCode && value.packageCode !== input.packageCode)
7931
+ return false;
7932
+ if (input.expectedManifestHash && value.manifestHash !== input.expectedManifestHash) return false;
7933
+ if (input.linkRef && value.linkRef !== input.linkRef) return false;
7934
+ if (input.requestId && operation !== "cf_revoke_human_read_link" && value.issuanceRequestId !== input.requestId)
7935
+ return false;
7936
+ const links = human.links;
7937
+ if (value.state === "ACTIVE" && (links.length !== 1 || links[0]?.access !== "TEMPORARY_PUBLIC_READ" || links[0].linkRef !== value.linkRef || links[0].expiresAt !== value.expiresAt))
7938
+ return false;
7939
+ if (value.state && value.state !== "ACTIVE" && links.length) return false;
7940
+ return true;
7941
+ }
7942
+
7601
7943
  // packages/cli-client/src/errors.ts
7602
7944
  var CliError = class extends Error {
7603
7945
  constructor(code2, message, outcome = "NOT_SENT", details) {
@@ -7650,6 +7992,9 @@ function verifyCapabilityDefinition(raw, name, expectedHash) {
7650
7992
  }
7651
7993
  var CapabilityDefinitionCache = class {
7652
7994
  values = /* @__PURE__ */ new Map();
7995
+ clear() {
7996
+ this.values.clear();
7997
+ }
7653
7998
  remember(value) {
7654
7999
  const verified = verifyCapabilityDefinition(value, value.definition.name);
7655
8000
  const key2 = `${verified.definition.name}:AGENT_V3:${verified.schemaSha256}`;
@@ -7988,13 +8333,106 @@ function object2(value) {
7988
8333
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7989
8334
  }
7990
8335
 
8336
+ // packages/cli-client/src/updates/version.ts
8337
+ import { readFile, realpath } from "node:fs/promises";
8338
+ import { dirname, join as join2 } from "node:path";
8339
+ function getNativeClientVersion() {
8340
+ return clientReleaseSchema.parse(nativeClientRelease);
8341
+ }
8342
+ async function getNativeCliVersion(executablePath) {
8343
+ const identity = { ...getNativeClientVersion(), sdkVersion: nativeClientRelease.version };
8344
+ if (!executablePath) return identity;
8345
+ try {
8346
+ const root = dirname(dirname(await realpath(executablePath)));
8347
+ const manifest = JSON.parse(await readFile(join2(root, "package.json"), "utf8"));
8348
+ if (manifest.name === nativeClientRelease.packages.cli)
8349
+ return { ...identity, version: releaseVersionSchema.parse(manifest.version) };
8350
+ } catch {
8351
+ }
8352
+ return identity;
8353
+ }
8354
+ function readNativeServerVersion(client) {
8355
+ const raw = client.getServerCapabilities()?.experimental?.[nativeReleaseCapability];
8356
+ let server;
8357
+ if (raw !== void 0) {
8358
+ const parsed = clientReleaseSchema.safeParse(raw);
8359
+ if (!parsed.success)
8360
+ throw new CliError(
8361
+ "INVALID_SERVER_RELEASE",
8362
+ "The advertised Native Marketing release contract is invalid."
8363
+ );
8364
+ server = parsed.data;
8365
+ }
8366
+ return {
8367
+ client: getNativeClientVersion(),
8368
+ serverInfo: client.getServerVersion() ?? null,
8369
+ mcpProtocolVersion: client.getNegotiatedProtocolVersion() ?? null,
8370
+ compatibility: assessNativeCompatibility(nativeClientRelease, server)
8371
+ };
8372
+ }
8373
+ function assertNativeCompatibility(result2, required = false) {
8374
+ if (result2.compatibility.status === "INCOMPATIBLE" || required && result2.compatibility.status === "UNKNOWN")
8375
+ throw new CliError(
8376
+ "CLIENT_INCOMPATIBLE",
8377
+ "Check version --server and update the client or connect to a compatible service. No business operation was sent.",
8378
+ "NOT_SENT",
8379
+ { compatibility: result2.compatibility }
8380
+ );
8381
+ }
8382
+ async function refreshNativeServerVersion(client, timeout) {
8383
+ const reply = await client.callTool(
8384
+ { name: "cf_get_client_release", arguments: {} },
8385
+ {
8386
+ timeout,
8387
+ allowInputRequired: true,
8388
+ toolDefinition: {
8389
+ name: "cf_get_client_release",
8390
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
8391
+ annotations: { readOnlyHint: true }
8392
+ }
8393
+ }
8394
+ ).catch(() => {
8395
+ throw new CliError(
8396
+ "VERSION_CHECK_UNAVAILABLE",
8397
+ "Cannot refresh the service release. Reconnect or refresh again before continuing."
8398
+ );
8399
+ });
8400
+ const text3 = reply.content?.find((item) => item.type === "text");
8401
+ let server;
8402
+ try {
8403
+ if (reply.isError) throw new Error();
8404
+ server = clientReleaseSchema.parse(
8405
+ reply.structuredContent ?? (text3?.type === "text" ? JSON.parse(text3.text) : null)
8406
+ );
8407
+ } catch {
8408
+ throw new CliError("INVALID_SERVER_RELEASE", "Cannot verify the current server release.");
8409
+ }
8410
+ const result2 = {
8411
+ ...readNativeServerVersion(client),
8412
+ compatibility: assessNativeCompatibility(nativeClientRelease, server)
8413
+ };
8414
+ return result2;
8415
+ }
8416
+
7991
8417
  // packages/cli-client/src/transport.ts
7992
- async function withClient(profile, timeout, operation) {
8418
+ var resources = /* @__PURE__ */ new WeakMap();
8419
+ async function withClient(profile, timeout, operation, options = {}) {
7993
8420
  const resource = resourceUrl(profile.resource);
7994
8421
  const accessToken = tokenText(profile.accessToken);
7995
8422
  const client = new Client(
7996
- { name: "content-factory-agent-cli", version: "0.1.0" },
7997
- { inputRequired: { autoFulfill: false } }
8423
+ { name: "@native-marketing/sdk", version: nativeClientRelease.version },
8424
+ {
8425
+ inputRequired: { autoFulfill: false },
8426
+ capabilities: {
8427
+ experimental: {
8428
+ [nativeReleaseCapability]: {
8429
+ version: nativeClientRelease.version,
8430
+ contractVersion: nativeClientRelease.contractVersion,
8431
+ apiMajor: nativeClientRelease.apiMajor
8432
+ }
8433
+ }
8434
+ }
8435
+ }
7998
8436
  );
7999
8437
  const transport = new StreamableHTTPClientTransport(resource, {
8000
8438
  authProvider: { token: async () => accessToken },
@@ -8006,6 +8444,7 @@ async function withClient(profile, timeout, operation) {
8006
8444
  reconnectionDelayGrowFactor: 1
8007
8445
  }
8008
8446
  });
8447
+ resources.set(client, resource.href);
8009
8448
  try {
8010
8449
  try {
8011
8450
  await client.connect(transport, { timeout });
@@ -8015,8 +8454,13 @@ async function withClient(profile, timeout, operation) {
8015
8454
  "Cannot authenticate/connect to the configured CF resource. No business operation was sent."
8016
8455
  );
8017
8456
  }
8457
+ const version = readNativeServerVersion(client);
8458
+ if (!options.allowIncompatible)
8459
+ assertNativeCompatibility(version, options.requireCompatibility);
8460
+ options.onVersion?.(version);
8018
8461
  return await operation(client);
8019
8462
  } finally {
8463
+ resources.delete(client);
8020
8464
  await client.close().catch(() => void 0);
8021
8465
  }
8022
8466
  }
@@ -8024,13 +8468,14 @@ async function callTool(client, tool5, input, timeout, readOnly, errorToolName =
8024
8468
  if (["cf_call_capability", "cf_read_capability", "cf_write_capability"].includes(tool5.name) && errorToolName === tool5.name && typeof input.name === "string" && /^cf_[a-z0-9_]{1,100}$/.test(input.name))
8025
8469
  errorToolName = input.name;
8026
8470
  const original = ["cf_call_capability", "cf_read_capability", "cf_write_capability"].includes(tool5.name) && input.name === errorToolName ? input.arguments : input;
8027
- const unknown = (code2, message) => {
8471
+ const unknown = (code2, message, human) => {
8028
8472
  const receipt = capabilityReceiptRead(errorToolName, original);
8029
8473
  const status = capabilityStatusRead(errorToolName, original);
8030
8474
  return new CliError(code2, message, "UNKNOWN", {
8031
8475
  recovery: capabilityRecovery(code2, "UNKNOWN", errorToolName),
8032
8476
  ...receipt ? { receipt } : {},
8033
- ...status ? { status } : {}
8477
+ ...status ? { status } : {},
8478
+ ...human ? { human } : {}
8034
8479
  });
8035
8480
  };
8036
8481
  let result2;
@@ -8052,16 +8497,21 @@ async function callTool(client, tool5, input, timeout, readOnly, errorToolName =
8052
8497
  );
8053
8498
  }
8054
8499
  if ("resultType" in result2 && result2.resultType === "input_required") {
8500
+ const raw = result2._meta?.[humanPresentationCapability];
8501
+ const parsed = raw && Buffer.byteLength(JSON.stringify(raw)) <= 128 * 1024 ? humanPresentationSchema.safeParse(raw) : null;
8502
+ const resource = resources.get(client);
8503
+ const human = parsed?.success && resource && validateHumanPresentationResource(parsed.data, resource) ? parsed.data : void 0;
8055
8504
  if (!readOnly)
8056
8505
  throw unknown(
8057
8506
  "INPUT_REQUIRED",
8058
- "Resolve additional input explicitly after confirming the original outcome. No automatic fulfilment or retry was made."
8507
+ "Resolve additional input explicitly after confirming the original outcome. No automatic fulfilment or retry was made.",
8508
+ human
8059
8509
  );
8060
8510
  throw new CliError(
8061
8511
  "INPUT_REQUIRED",
8062
8512
  "Resolve additional input explicitly; no automatic fulfilment or retry was made.",
8063
8513
  "REJECTED",
8064
- { recovery: "RESOLVE_INPUT_EXPLICITLY" }
8514
+ { recovery: "RESOLVE_INPUT_EXPLICITLY", ...human ? { human } : {} }
8065
8515
  );
8066
8516
  }
8067
8517
  if (result2.isError) {
@@ -8825,6 +9275,185 @@ async function uploadNativeMaterial(connection, file, timeout = 3e4) {
8825
9275
  return materialUploadCommandResultSchema.parse(await uploadFile(connection, file, timeout));
8826
9276
  }
8827
9277
 
9278
+ // packages/cli-client/src/human-presentation.ts
9279
+ var humanCommands = {
9280
+ "human show": {
9281
+ name: "cf_get_human_presentation",
9282
+ input: humanPresentationInputSchema,
9283
+ output: humanPresentationResultSchema,
9284
+ readOnly: true
9285
+ },
9286
+ "human issue-link": {
9287
+ name: "cf_issue_human_read_link",
9288
+ input: issueHumanReadLinkInputSchema,
9289
+ output: humanReadLinkResultSchema,
9290
+ readOnly: false
9291
+ },
9292
+ "human link": {
9293
+ name: "cf_get_human_read_link",
9294
+ input: humanReadLinkLookupSchema,
9295
+ output: humanReadLinkResultSchema,
9296
+ readOnly: true
9297
+ },
9298
+ "human receipt": {
9299
+ name: "cf_get_human_read_link_receipt",
9300
+ input: humanReadLinkReceiptQuerySchema,
9301
+ output: humanReadLinkReceiptSchema,
9302
+ readOnly: true
9303
+ },
9304
+ "human revoke-link": {
9305
+ name: "cf_revoke_human_read_link",
9306
+ input: revokeHumanReadLinkInputSchema,
9307
+ output: humanReadLinkResultSchema,
9308
+ readOnly: false
9309
+ },
9310
+ "human cleanup-links": {
9311
+ name: "cf_cleanup_human_read_links",
9312
+ input: cleanupHumanReadLinksInputSchema,
9313
+ output: cleanupHumanReadLinksResultSchema,
9314
+ readOnly: false
9315
+ }
9316
+ };
9317
+ function invalid6() {
9318
+ return new CliError(
9319
+ "INVALID_HUMAN_PRESENTATION",
9320
+ "The human presentation cannot be verified against this exact product resource."
9321
+ );
9322
+ }
9323
+ async function invoke2(client, resource, raw, name, inputSchema, outputSchema, readOnly, timeout) {
9324
+ const request = inputSchema.safeParse(raw);
9325
+ if (!request.success)
9326
+ throw new CliError("INVALID_HUMAN_INPUT", "Use the exact human presentation input schema.");
9327
+ const capability = client.getServerCapabilities()?.experimental?.[humanPresentationCapability];
9328
+ if (capability?.version !== 1)
9329
+ throw new CliError(
9330
+ "HUMAN_PRESENTATION_UNSUPPORTED",
9331
+ "This service has not declared human presentation version 1."
9332
+ );
9333
+ const tool5 = {
9334
+ name,
9335
+ inputSchema: {
9336
+ type: "object",
9337
+ ...inputSchema["~standard"].jsonSchema.input({ target: "draft-2020-12" })
9338
+ },
9339
+ annotations: { readOnlyHint: readOnly }
9340
+ };
9341
+ const result2 = await callTool(client, tool5, request.data, timeout, readOnly);
9342
+ try {
9343
+ const parsed = outputSchema.parse(result2);
9344
+ if (Buffer.byteLength(JSON.stringify(parsed)) > 128 * 1024) throw invalid6();
9345
+ if (!validateHumanPresentationResponse(
9346
+ parsed,
9347
+ resource,
9348
+ request.data,
9349
+ name
9350
+ ))
9351
+ throw invalid6();
9352
+ return parsed;
9353
+ } catch {
9354
+ const outcome = readOnly ? "REJECTED" : "UNKNOWN";
9355
+ const receipt = capabilityReceiptRead(name, request.data);
9356
+ const status = capabilityStatusRead(name, request.data);
9357
+ throw new CliError(
9358
+ "INVALID_HUMAN_PRESENTATION",
9359
+ "Cannot verify this exact response. Query the original request before another write.",
9360
+ outcome,
9361
+ {
9362
+ recovery: capabilityRecovery("INVALID_HUMAN_PRESENTATION", outcome, name),
9363
+ ...!readOnly && receipt ? { receipt } : {},
9364
+ ...!readOnly && status ? { status } : {},
9365
+ ...request.data.requestId ? { requestId: request.data.requestId } : {},
9366
+ ...request.data.linkRef ? { linkRef: request.data.linkRef } : {}
9367
+ }
9368
+ );
9369
+ }
9370
+ }
9371
+ function getNativeHumanPresentation(client, resource, input, timeout = 3e4) {
9372
+ return invoke2(
9373
+ client,
9374
+ resource,
9375
+ input,
9376
+ "cf_get_human_presentation",
9377
+ humanPresentationInputSchema,
9378
+ humanPresentationResultSchema,
9379
+ true,
9380
+ timeout
9381
+ );
9382
+ }
9383
+ function issueNativeHumanReadLink(client, resource, input, timeout = 3e4) {
9384
+ return invoke2(
9385
+ client,
9386
+ resource,
9387
+ input,
9388
+ "cf_issue_human_read_link",
9389
+ issueHumanReadLinkInputSchema,
9390
+ humanReadLinkResultSchema,
9391
+ false,
9392
+ timeout
9393
+ );
9394
+ }
9395
+ function getNativeHumanReadLink(client, resource, input, timeout = 3e4) {
9396
+ return invoke2(
9397
+ client,
9398
+ resource,
9399
+ input,
9400
+ "cf_get_human_read_link",
9401
+ humanReadLinkLookupSchema,
9402
+ humanReadLinkResultSchema,
9403
+ true,
9404
+ timeout
9405
+ );
9406
+ }
9407
+ function getNativeHumanReadLinkReceipt(client, resource, input, timeout = 3e4) {
9408
+ return invoke2(
9409
+ client,
9410
+ resource,
9411
+ input,
9412
+ "cf_get_human_read_link_receipt",
9413
+ humanReadLinkReceiptQuerySchema,
9414
+ humanReadLinkReceiptSchema,
9415
+ true,
9416
+ timeout
9417
+ );
9418
+ }
9419
+ function revokeNativeHumanReadLink(client, resource, input, timeout = 3e4) {
9420
+ return invoke2(
9421
+ client,
9422
+ resource,
9423
+ input,
9424
+ "cf_revoke_human_read_link",
9425
+ revokeHumanReadLinkInputSchema,
9426
+ humanReadLinkResultSchema,
9427
+ false,
9428
+ timeout
9429
+ );
9430
+ }
9431
+ function cleanupNativeHumanReadLinks(client, resource, input = {}, timeout = 3e4) {
9432
+ return invoke2(
9433
+ client,
9434
+ resource,
9435
+ input,
9436
+ "cf_cleanup_human_read_links",
9437
+ cleanupHumanReadLinksInputSchema,
9438
+ cleanupHumanReadLinksResultSchema,
9439
+ false,
9440
+ timeout
9441
+ );
9442
+ }
9443
+ async function runHumanCommand(client, resource, name, input, timeout) {
9444
+ const spec = humanCommands[name];
9445
+ return invoke2(
9446
+ client,
9447
+ resource,
9448
+ input,
9449
+ spec.name,
9450
+ spec.input,
9451
+ spec.output,
9452
+ spec.readOnly,
9453
+ timeout
9454
+ );
9455
+ }
9456
+
8828
9457
  // packages/cli-client/src/business-search.ts
8829
9458
  var tool4 = (name, schema2) => ({
8830
9459
  name,
@@ -8839,17 +9468,17 @@ var document = tool4("cf_read_business_document", businessDocumentInputSchema);
8839
9468
  async function searchNativeBusiness(client, raw = {}, timeout = 3e4) {
8840
9469
  checkTimeout3(timeout);
8841
9470
  const input = businessSearchQuerySchema.safeParse(raw);
8842
- if (!input.success) throw invalid6("INVALID_BUSINESS_SEARCH_QUERY", "NOT_SENT");
9471
+ if (!input.success) throw invalid7("INVALID_BUSINESS_SEARCH_QUERY", "NOT_SENT");
8843
9472
  const value = await callTool(client, search, input.data, timeout, true);
8844
9473
  const parsed = businessSearchPageSchema.safeParse(value);
8845
9474
  if (!parsed.success || Buffer.byteLength(JSON.stringify(value)) > 16 * 1024)
8846
- throw invalid6("INVALID_BUSINESS_SEARCH_REPLY");
9475
+ throw invalid7("INVALID_BUSINESS_SEARCH_REPLY");
8847
9476
  return parsed.data;
8848
9477
  }
8849
9478
  async function readNativeBusinessPage(client, raw, timeout = 3e4) {
8850
9479
  checkTimeout3(timeout);
8851
9480
  const input = businessContentPageReadSchema.safeParse(raw);
8852
- if (!input.success) throw invalid6("INVALID_BUSINESS_CONTENT_QUERY", "NOT_SENT");
9481
+ if (!input.success) throw invalid7("INVALID_BUSINESS_CONTENT_QUERY", "NOT_SENT");
8853
9482
  const { offset, expectedDocumentHash, ...sourceInput } = input.data;
8854
9483
  const args = businessDocumentInputSchema.parse({
8855
9484
  sourceTool: "cf_read_business_content",
@@ -8860,18 +9489,18 @@ async function readNativeBusinessPage(client, raw, timeout = 3e4) {
8860
9489
  const value = await callTool(client, document, args, timeout, true);
8861
9490
  const parsed = businessContentPageSchema.safeParse(value);
8862
9491
  if (!parsed.success || Buffer.byteLength(JSON.stringify(value)) > 6e3)
8863
- throw invalid6("INVALID_BUSINESS_CONTENT_REPLY");
9492
+ throw invalid7("INVALID_BUSINESS_CONTENT_REPLY");
8864
9493
  const p = parsed.data;
8865
9494
  if (p.sourceInput.ref !== sourceInput.ref || p.sourceInput.expectedVersion !== sourceInput.expectedVersion || p.offset !== offset || expectedDocumentHash && p.documentHash !== expectedDocumentHash || (p.hasMore ? p.nextOffset !== offset + [...p.text].length : p.nextOffset !== null) || p.hasMore !== offset + [...p.text].length < p.totalCharacters)
8866
- throw invalid6("INVALID_BUSINESS_CONTENT_REPLY");
9495
+ throw invalid7("INVALID_BUSINESS_CONTENT_REPLY");
8867
9496
  return p;
8868
9497
  }
8869
- function invalid6(code2, outcome = "REJECTED") {
9498
+ function invalid7(code2, outcome = "REJECTED") {
8870
9499
  return new CliError(code2, "Use the exact bounded search or content-page contract.", outcome);
8871
9500
  }
8872
9501
  function checkTimeout3(value) {
8873
9502
  if (!Number.isInteger(value) || value < 100 || value > 12e4)
8874
- throw invalid6("INVALID_TIMEOUT", "NOT_SENT");
9503
+ throw invalid7("INVALID_TIMEOUT", "NOT_SENT");
8875
9504
  }
8876
9505
 
8877
9506
  // packages/cli-client/src/client.ts
@@ -8882,43 +9511,103 @@ async function withNativeAgentClient(connection, action, options = {}) {
8882
9511
  return withClient(
8883
9512
  connection,
8884
9513
  timeout,
8885
- (client) => action({
8886
- readPackageFile: (input) => readNativePackageFile(connection, input, timeout),
8887
- readProjectMediaFile: (input) => readNativeProjectMediaFile(connection, input, timeout),
8888
- uploadProjectMedia: (file) => uploadNativeProjectMedia(connection, file, timeout),
8889
- uploadMaterial: (file) => uploadNativeMaterial(connection, file, timeout),
8890
- inspectTool: (name) => inspectNativeTool(client, name, timeout, definitions),
8891
- callTool: (name, input = {}, options2) => callNativeTool(client, name, input, connection.resource, options2, timeout, definitions),
8892
- listToolsPage: (input = {}) => listNativeToolsPage(client, input, timeout),
8893
- readCapabilitySchemaPage: (input) => readNativeCapabilitySchemaPage(client, input, timeout),
8894
- readDocumentPage: (input) => readNativeDocumentPage(client, input, timeout),
8895
- getBusinessSummary: (input) => getNativeBusinessSummary(client, input, timeout),
8896
- callCapability: (input) => callNativeCapability(client, input, timeout),
8897
- readCapability: (input) => readNativeCapability(client, input, timeout),
8898
- writeCapability: (input) => writeNativeCapability(client, input, timeout),
8899
- describeCapabilitySummary: (name) => readNativeCapabilityDescriptor(client, name, timeout),
8900
- searchBusiness: (input) => searchNativeBusiness(client, input, timeout),
8901
- readBusinessPage: (input) => readNativeBusinessPage(client, input, timeout),
8902
- findCapabilities: (input) => findNativeCapabilities(client, input, timeout),
8903
- discoverCapabilities: async (input) => {
8904
- const page2 = await findAgentCapabilities(client, input, timeout);
8905
- for (const item of page2.items) if (item.definition) definitions.remember(item.definition);
8906
- return page2;
8907
- },
8908
- describeCapability: async (name, expectedHash) => {
8909
- const cached = expectedHash ? definitions.get(name, expectedHash) : void 0;
8910
- if (cached) return cached;
8911
- const definition = await describeNativeCapability(client, name, timeout);
8912
- if (expectedHash && definition.schemaSha256 !== expectedHash)
8913
- throw new CliError(
8914
- "CAPABILITY_SCHEMA_CHANGED",
8915
- "Discover the current definition again.",
8916
- "REJECTED"
8917
- );
8918
- definitions.remember(definition);
8919
- return definition;
8920
- }
8921
- })
9514
+ (client) => {
9515
+ let version = readNativeServerVersion(client);
9516
+ let versionUnverified = false;
9517
+ client.setNotificationHandler("notifications/tools/list_changed", () => {
9518
+ definitions.clear();
9519
+ });
9520
+ return action(
9521
+ new Proxy(
9522
+ {
9523
+ getHumanPresentation: (input) => getNativeHumanPresentation(client, connection.resource, input, timeout),
9524
+ issueHumanReadLink: (input) => issueNativeHumanReadLink(client, connection.resource, input, timeout),
9525
+ getHumanReadLink: (input) => getNativeHumanReadLink(client, connection.resource, input, timeout),
9526
+ getHumanReadLinkReceipt: (input) => getNativeHumanReadLinkReceipt(client, connection.resource, input, timeout),
9527
+ revokeHumanReadLink: (input) => revokeNativeHumanReadLink(client, connection.resource, input, timeout),
9528
+ cleanupHumanReadLinks: (input = {}) => cleanupNativeHumanReadLinks(client, connection.resource, input, timeout),
9529
+ getVersion: () => structuredClone(version),
9530
+ refreshVersion: async () => {
9531
+ definitions.clear();
9532
+ try {
9533
+ version = await refreshNativeServerVersion(client, timeout);
9534
+ versionUnverified = false;
9535
+ } catch (error) {
9536
+ version = { ...version, compatibility: assessNativeCompatibility(version.client) };
9537
+ versionUnverified = true;
9538
+ throw error;
9539
+ }
9540
+ assertNativeCompatibility(version, options.requireCompatibility);
9541
+ options.onVersion?.(version);
9542
+ return structuredClone(version);
9543
+ },
9544
+ readPackageFile: (input) => readNativePackageFile(connection, input, timeout),
9545
+ readProjectMediaFile: (input) => readNativeProjectMediaFile(connection, input, timeout),
9546
+ uploadProjectMedia: (file) => uploadNativeProjectMedia(connection, file, timeout),
9547
+ uploadMaterial: (file) => uploadNativeMaterial(connection, file, timeout),
9548
+ inspectTool: (name) => inspectNativeTool(client, name, timeout, definitions),
9549
+ callTool: (name, input = {}, options2) => callNativeTool(
9550
+ client,
9551
+ name,
9552
+ input,
9553
+ connection.resource,
9554
+ options2,
9555
+ timeout,
9556
+ definitions
9557
+ ),
9558
+ listToolsPage: (input = {}) => listNativeToolsPage(client, input, timeout),
9559
+ readCapabilitySchemaPage: (input) => readNativeCapabilitySchemaPage(client, input, timeout),
9560
+ readDocumentPage: (input) => readNativeDocumentPage(client, input, timeout),
9561
+ getBusinessSummary: (input) => getNativeBusinessSummary(client, input, timeout),
9562
+ callCapability: (input) => callNativeCapability(client, input, timeout),
9563
+ readCapability: (input) => readNativeCapability(client, input, timeout),
9564
+ writeCapability: (input) => writeNativeCapability(client, input, timeout),
9565
+ describeCapabilitySummary: (name) => readNativeCapabilityDescriptor(client, name, timeout),
9566
+ searchBusiness: (input) => searchNativeBusiness(client, input, timeout),
9567
+ readBusinessPage: (input) => readNativeBusinessPage(client, input, timeout),
9568
+ findCapabilities: (input) => findNativeCapabilities(client, input, timeout),
9569
+ discoverCapabilities: async (input) => {
9570
+ const page2 = await findAgentCapabilities(client, input, timeout);
9571
+ for (const item of page2.items)
9572
+ if (item.definition) definitions.remember(item.definition);
9573
+ return page2;
9574
+ },
9575
+ describeCapability: async (name, expectedHash) => {
9576
+ const cached = expectedHash ? definitions.get(name, expectedHash) : void 0;
9577
+ if (cached) return cached;
9578
+ const definition = await describeNativeCapability(client, name, timeout);
9579
+ if (expectedHash && definition.schemaSha256 !== expectedHash)
9580
+ throw new CliError(
9581
+ "CAPABILITY_SCHEMA_CHANGED",
9582
+ "Discover the current definition again.",
9583
+ "REJECTED"
9584
+ );
9585
+ definitions.remember(definition);
9586
+ return definition;
9587
+ }
9588
+ },
9589
+ {
9590
+ get(target, name, receiver) {
9591
+ const method = Reflect.get(target, name, receiver);
9592
+ if (typeof method !== "function" || name === "getVersion" || name === "refreshVersion")
9593
+ return method;
9594
+ return async (...args) => {
9595
+ if (versionUnverified)
9596
+ throw new CliError(
9597
+ "CLIENT_VERSION_UNVERIFIED",
9598
+ "Verify the service release again or reconnect before continuing. No business operation was sent.",
9599
+ "NOT_SENT",
9600
+ { compatibility: version.compatibility }
9601
+ );
9602
+ assertNativeCompatibility(version, options.requireCompatibility);
9603
+ return Reflect.apply(method, target, args);
9604
+ };
9605
+ }
9606
+ }
9607
+ )
9608
+ );
9609
+ },
9610
+ options
8922
9611
  );
8923
9612
  }
8924
9613
  function checkTimeout4(timeout) {
@@ -9073,9 +9762,22 @@ var values = /* @__PURE__ */ new Set([
9073
9762
  "scope",
9074
9763
  "job",
9075
9764
  "view",
9076
- "schema-hash"
9765
+ "schema-hash",
9766
+ "mode",
9767
+ "channel",
9768
+ "pin",
9769
+ "interval-hours"
9770
+ ]);
9771
+ var flags = /* @__PURE__ */ new Set([
9772
+ "json",
9773
+ "stdin",
9774
+ "help",
9775
+ "version",
9776
+ "server",
9777
+ "strict",
9778
+ "allow-breaking",
9779
+ "dry-run"
9077
9780
  ]);
9078
- var flags = /* @__PURE__ */ new Set(["json", "stdin", "help"]);
9079
9781
  function parseArgs(args) {
9080
9782
  const options = {};
9081
9783
  const words = [];
@@ -9154,8 +9856,8 @@ async function login(store, rawResource, scope2, timeout, notify) {
9154
9856
  const state = randomBytes(32).toString("base64url");
9155
9857
  let resolveCode;
9156
9858
  let rejectCode;
9157
- const codePromise = new Promise((resolve, reject) => {
9158
- resolveCode = resolve;
9859
+ const codePromise = new Promise((resolve2, reject) => {
9860
+ resolveCode = resolve2;
9159
9861
  rejectCode = reject;
9160
9862
  });
9161
9863
  void codePromise.catch(() => void 0);
@@ -9186,9 +9888,9 @@ async function login(store, rawResource, scope2, timeout, notify) {
9186
9888
  });
9187
9889
  let timer;
9188
9890
  try {
9189
- await new Promise((resolve, reject) => {
9891
+ await new Promise((resolve2, reject) => {
9190
9892
  server.once("error", reject);
9191
- server.listen(0, "127.0.0.1", resolve);
9893
+ server.listen(0, "127.0.0.1", resolve2);
9192
9894
  });
9193
9895
  const address = server.address();
9194
9896
  if (!address || typeof address === "string")
@@ -9258,7 +9960,7 @@ Waiting up to 5 minutes. For remote/headless Agents, use auth import with a prov
9258
9960
  } finally {
9259
9961
  if (timer) clearTimeout(timer);
9260
9962
  server.closeAllConnections();
9261
- await new Promise((resolve) => server.close(() => resolve()));
9963
+ await new Promise((resolve2) => server.close(() => resolve2()));
9262
9964
  }
9263
9965
  });
9264
9966
  }
@@ -9333,6 +10035,10 @@ var fullHelp = {
9333
10035
  executable: "cf-agent",
9334
10036
  transport: "OAuth-authenticated HTTPS MCP; no local database",
9335
10037
  commands: [
10038
+ "version [--server [--strict] [--profile <name>]]",
10039
+ "update check [--channel latest|next|beta] [--pin <exact-version>|none]",
10040
+ "update apply [--dry-run] [--allow-breaking] [--channel latest|next|beta] [--pin <exact-version>|none]",
10041
+ "update policy [--mode off|notify|auto] [--channel latest|next|beta] [--pin <exact-version>|none] [--interval-hours <1..168>]",
9336
10042
  "auth login --resource <url> [--scope <scopes>] [--profile <name>]",
9337
10043
  "auth import --resource <url> --token-file <private-file> [--profile <name>]",
9338
10044
  "auth status|refresh|logout [--profile <name>]",
@@ -9355,6 +10061,7 @@ var fullHelp = {
9355
10061
  "tools inspect <cf_tool>",
9356
10062
  "tools call <cf_tool> [--input-file <file>|--stdin]",
9357
10063
  ...Object.keys(commandTools).map((name) => `${name} [--input-file <file>|--stdin]`),
10064
+ ...Object.keys(humanCommands).map((name) => `${name} [--input-file <file>|--stdin]`),
9358
10065
  "task read <kind> --job JOB-000001",
9359
10066
  "result submit <kind> (--input-file <file>|--stdin)"
9360
10067
  ],
@@ -9376,6 +10083,8 @@ var help = {
9376
10083
  executable: "cf-agent",
9377
10084
  transport: "OAuth-authenticated MCP; no local database",
9378
10085
  commands: [
10086
+ "version [--server [--strict]]",
10087
+ "update check|apply|policy (help update for channels, pins and automatic updates)",
9379
10088
  "auth login --resource <url> [--scope <scopes>]",
9380
10089
  "search [<text>] [--input-file <query.json>|--stdin]",
9381
10090
  "business read (--input-file <ref-and-page.json>|--stdin)",
@@ -9412,6 +10121,13 @@ function groupHelp(group) {
9412
10121
  function resolveBaseCommand(parsed) {
9413
10122
  const { words, options } = parsed;
9414
10123
  const name = words.join(" ");
10124
+ if (Object.hasOwn(humanCommands, name)) {
10125
+ if (Object.keys(options).some(
10126
+ (key2) => !["input-file", "stdin", "profile", "json", "timeout-ms"].includes(key2)
10127
+ ))
10128
+ throw new CliError("INVALID_OPTION", "Unsupported human presentation option.");
10129
+ return { mode: "human" };
10130
+ }
9415
10131
  if (name === "media file" || name === "packages file") {
9416
10132
  if (Object.keys(options).some(
9417
10133
  (k) => !["output-file", "profile", "input-file", "stdin", "timeout-ms", "json"].includes(k)
@@ -9520,6 +10236,21 @@ function resolveBaseCommand(parsed) {
9520
10236
  throw new CliError("INVALID_COMMAND", "Run help for supported commands.");
9521
10237
  }
9522
10238
  function resolveCommand(parsed) {
10239
+ if ([
10240
+ "mode",
10241
+ "channel",
10242
+ "pin",
10243
+ "interval-hours",
10244
+ "version",
10245
+ "server",
10246
+ "strict",
10247
+ "allow-breaking",
10248
+ "dry-run"
10249
+ ].some((key2) => parsed.options[key2]))
10250
+ throw new CliError(
10251
+ "INVALID_OPTION",
10252
+ "Version/update options apply only to version/update commands."
10253
+ );
9523
10254
  const removed = {
9524
10255
  doctor: "context",
9525
10256
  "knowledge sync-all": "knowledge discover",
@@ -9550,6 +10281,14 @@ function resolveCommand(parsed) {
9550
10281
  async function businessCommand(client, parsed, input, resource) {
9551
10282
  const resolved = resolveCommand(parsed);
9552
10283
  const { timeout, options } = parsed;
10284
+ if (resolved.mode === "human")
10285
+ return runHumanCommand(
10286
+ client,
10287
+ resource,
10288
+ parsed.words.join(" "),
10289
+ input,
10290
+ timeout
10291
+ );
9553
10292
  if (resolved.mode === "document")
9554
10293
  return readNativeDocumentPage(
9555
10294
  client,
@@ -9617,6 +10356,8 @@ async function businessCommand(client, parsed, input, resource) {
9617
10356
  // packages/cli-client/src/cli/command-input.ts
9618
10357
  function validateCommandInput(parsed, input) {
9619
10358
  const mode = resolveCommand(parsed).mode;
10359
+ if (mode === "human" && !humanCommands[parsed.words.join(" ")].input.safeParse(input).success)
10360
+ throw new CliError("INVALID_HUMAN_INPUT", "Use the exact human presentation JSON input.");
9620
10361
  if (mode === "upload" && parsed.words.join(" ") === "media upload" && !projectMediaWebUploadSchema.omit({ requestId: true }).safeParse(input).success)
9621
10362
  throw new CliError("INVALID_UPLOAD_INPUT", "Supply explicit real-media provenance JSON.");
9622
10363
  const schemas = {
@@ -9654,14 +10395,430 @@ function validateCommandInput(parsed, input) {
9654
10395
  throw new CliError("INVALID_PAGINATION", "Supply only an optional nonempty cursor.");
9655
10396
  }
9656
10397
 
10398
+ // packages/cli-client/src/updates/registry.ts
10399
+ async function checkNativeUpdates(options = {}) {
10400
+ const policy = updatePolicySchema.parse(options.policy ?? {});
10401
+ const current = releaseVersionSchema.safeParse(
10402
+ options.currentVersion ?? nativeClientRelease.version
10403
+ );
10404
+ if (!current.success)
10405
+ throw new CliError(
10406
+ "INVALID_UPDATE_VERSION",
10407
+ "The installed version must be an exact semantic version."
10408
+ );
10409
+ const timeout = options.timeoutMs ?? 5e3;
10410
+ if (!Number.isInteger(timeout) || timeout < 100 || timeout > 12e4)
10411
+ throw new CliError("INVALID_TIMEOUT", "Timeout must be 100\u2013120000 milliseconds.");
10412
+ const name = nativeClientRelease.packages[options.package ?? "sdk"];
10413
+ if (!name) throw new CliError("INVALID_UPDATE_PACKAGE", "Choose sdk or cli.");
10414
+ const selector = policy.pin ?? policy.channel;
10415
+ const url = `https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(selector)}`;
10416
+ let target;
10417
+ try {
10418
+ const response = await (options.fetch ?? fetch)(url, {
10419
+ redirect: "error",
10420
+ credentials: "omit",
10421
+ signal: AbortSignal.timeout(timeout),
10422
+ headers: { accept: "application/json" }
10423
+ });
10424
+ if (!response.ok || !response.body) throw new Error();
10425
+ const reader = response.body.getReader();
10426
+ const chunks = [];
10427
+ let size = 0;
10428
+ try {
10429
+ for (; ; ) {
10430
+ const { done, value } = await reader.read();
10431
+ if (done) break;
10432
+ size += value.byteLength;
10433
+ if (size > 128 * 1024) throw new Error();
10434
+ chunks.push(value);
10435
+ }
10436
+ } finally {
10437
+ await reader.cancel().catch(() => void 0);
10438
+ reader.releaseLock();
10439
+ }
10440
+ target = registryReleaseSchema.parse(JSON.parse(Buffer.concat(chunks).toString("utf8")));
10441
+ if (target.name !== name || policy.pin && target.version !== policy.pin) throw new Error();
10442
+ } catch {
10443
+ throw new CliError(
10444
+ "UPDATE_CHECK_UNAVAILABLE",
10445
+ "Cannot verify release metadata from the public npm registry. Existing software and credentials are unchanged."
10446
+ );
10447
+ }
10448
+ return {
10449
+ checkedAt: Date.now(),
10450
+ target,
10451
+ plan: planNativeUpdate({
10452
+ target,
10453
+ policy,
10454
+ nodeMajor: Number(process.versions.node.split(".")[0]),
10455
+ currentVersion: current.data,
10456
+ ...options.server ? { server: options.server } : {}
10457
+ })
10458
+ };
10459
+ }
10460
+
10461
+ // packages/cli-client/src/updates/store.ts
10462
+ import { lstat as lstat2, open as open6, rename as rename2, unlink as unlink2 } from "node:fs/promises";
10463
+ import { join as join3 } from "node:path";
10464
+ import { randomUUID as randomUUID3 } from "node:crypto";
10465
+ var UpdateStore = class {
10466
+ files;
10467
+ constructor(env) {
10468
+ const base2 = new ProfileStore(env).directory;
10469
+ this.files = new ProfileStore({ CF_AGENT_CONFIG_DIR: join3(base2, "client-lifecycle") }, "state");
10470
+ }
10471
+ async read() {
10472
+ try {
10473
+ await lstat2(this.files.path);
10474
+ } catch (error) {
10475
+ if (error.code === "ENOENT")
10476
+ return { schemaVersion: 1, policy: updatePolicySchema.parse({}) };
10477
+ throw error;
10478
+ }
10479
+ let raw;
10480
+ try {
10481
+ raw = JSON.parse(await readFileBounded(this.files.path, true));
10482
+ } catch {
10483
+ throw new CliError(
10484
+ "INVALID_UPDATE_CONFIGURATION",
10485
+ "Update state is unreadable. Inspect the client-lifecycle configuration."
10486
+ );
10487
+ }
10488
+ const parsed = clientUpdateStateSchema.safeParse(raw);
10489
+ if (!parsed.success)
10490
+ throw new CliError(
10491
+ "INVALID_UPDATE_CONFIGURATION",
10492
+ "Update state is invalid. Inspect the client-lifecycle configuration."
10493
+ );
10494
+ return parsed.data;
10495
+ }
10496
+ locked(action) {
10497
+ return this.files.locked(action);
10498
+ }
10499
+ async change(action) {
10500
+ return this.locked(async () => {
10501
+ const state = clientUpdateStateSchema.parse(action(await this.read()));
10502
+ const temporary = `${this.files.path}.${randomUUID3()}.tmp`;
10503
+ const file = await open6(temporary, "wx", 384);
10504
+ try {
10505
+ try {
10506
+ await file.writeFile(JSON.stringify(state) + "\n");
10507
+ await file.sync();
10508
+ } finally {
10509
+ await file.close();
10510
+ }
10511
+ await rename2(temporary, this.files.path);
10512
+ } finally {
10513
+ await unlink2(temporary).catch(() => void 0);
10514
+ }
10515
+ return state;
10516
+ });
10517
+ }
10518
+ };
10519
+ function effectiveUpdatePolicy(policy, env) {
10520
+ const parsed = updatePolicySchema.safeParse({
10521
+ ...policy,
10522
+ ...env.CF_AGENT_UPDATE_MODE ? { mode: env.CF_AGENT_UPDATE_MODE } : {},
10523
+ ...env.CF_AGENT_UPDATE_CHANNEL ? { channel: env.CF_AGENT_UPDATE_CHANNEL } : {},
10524
+ ...env.CF_AGENT_UPDATE_PIN ? { pin: env.CF_AGENT_UPDATE_PIN === "none" ? null : env.CF_AGENT_UPDATE_PIN } : {}
10525
+ });
10526
+ if (!parsed.success)
10527
+ throw new CliError("INVALID_UPDATE_CONFIGURATION", "Invalid update environment policy.");
10528
+ return parsed.data;
10529
+ }
10530
+
10531
+ // packages/cli-client/src/updates/install.ts
10532
+ import { execFile } from "node:child_process";
10533
+ import { promisify } from "node:util";
10534
+ import { readFile as readFile2, realpath as realpath2 } from "node:fs/promises";
10535
+ import { dirname as dirname2, join as join4, resolve } from "node:path";
10536
+ var execute = promisify(execFile);
10537
+ async function installCliUpdate(input) {
10538
+ const plan = planNativeUpdate({
10539
+ target: input.target,
10540
+ ...input.currentVersion ? { currentVersion: input.currentVersion } : {},
10541
+ policy: input.policy,
10542
+ nodeMajor: Number(process.versions.node.split(".")[0])
10543
+ });
10544
+ if (plan.package !== nativeClientRelease.packages.cli || plan.status !== "UPDATE_AVAILABLE" || !plan.eligibleForAutoUpdate && !input.allowBreaking)
10545
+ throw new CliError(
10546
+ "UPDATE_POLICY_BLOCKED",
10547
+ "This release cannot be installed under the selected policy.",
10548
+ "NOT_SENT",
10549
+ { plan }
10550
+ );
10551
+ if (!input.executablePath || process.platform === "win32")
10552
+ throw new CliError(
10553
+ "MANAGED_UPDATE_UNAVAILABLE",
10554
+ "Use the package manager that owns this installation.",
10555
+ "NOT_SENT",
10556
+ { plan }
10557
+ );
10558
+ const environment = Object.fromEntries(
10559
+ Object.entries(input.env).filter(
10560
+ ([key2, value]) => value !== void 0 && !/^(?:CF_AGENT_|CONTENT_FACTORY_)/i.test(key2)
10561
+ )
10562
+ );
10563
+ environment.CF_AGENT_UPDATE_MODE = "off";
10564
+ environment.NODE_OPTIONS = "--max-old-space-size=384";
10565
+ const options = { env: environment, timeout: input.timeoutMs, maxBuffer: 128 * 1024 };
10566
+ let packageRoot, prefix;
10567
+ try {
10568
+ packageRoot = dirname2(dirname2(await realpath2(input.executablePath)));
10569
+ const manifest = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10570
+ const root = await realpath2(
10571
+ (await execute("npm", ["root", "--global"], options)).stdout.trim()
10572
+ );
10573
+ prefix = await realpath2((await execute("npm", ["prefix", "--global"], options)).stdout.trim());
10574
+ 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"))
10575
+ throw new Error();
10576
+ } catch {
10577
+ throw new CliError(
10578
+ "MANAGED_UPDATE_UNAVAILABLE",
10579
+ "Automatic installation supports the active npm global installation. Use the owning project/package manager for other installs.",
10580
+ "NOT_SENT",
10581
+ { plan }
10582
+ );
10583
+ }
10584
+ const args = [
10585
+ "install",
10586
+ "--global",
10587
+ "--prefix",
10588
+ prefix,
10589
+ `${plan.package}@${plan.targetVersion}`,
10590
+ "--registry=https://registry.npmjs.org/",
10591
+ "--@native-marketing:registry=https://registry.npmjs.org/",
10592
+ "--ignore-scripts",
10593
+ "--no-audit",
10594
+ "--no-fund"
10595
+ ];
10596
+ const recovery = [
10597
+ "npm",
10598
+ "install",
10599
+ "--global",
10600
+ "--prefix",
10601
+ prefix,
10602
+ `${plan.package}@${plan.currentVersion}`,
10603
+ "--ignore-scripts",
10604
+ "--registry=https://registry.npmjs.org/",
10605
+ "--@native-marketing:registry=https://registry.npmjs.org/"
10606
+ ];
10607
+ const store = new UpdateStore(input.env);
10608
+ return store.locked(async () => {
10609
+ if (input.automatic) {
10610
+ const latest = effectiveUpdatePolicy((await store.read()).policy, input.env);
10611
+ if (latest.mode !== "auto" || (latest.pin ?? latest.channel) !== (input.policy.pin ?? input.policy.channel) || !planNativeUpdate({
10612
+ target: input.target,
10613
+ currentVersion: plan.currentVersion,
10614
+ policy: latest,
10615
+ nodeMajor: Number(process.versions.node.split(".")[0])
10616
+ }).eligibleForAutoUpdate)
10617
+ throw new CliError(
10618
+ "UPDATE_POLICY_CHANGED",
10619
+ "Automatic update policy changed. No installation or business operation was sent."
10620
+ );
10621
+ }
10622
+ const before = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10623
+ if (before.name !== plan.package || before.version !== plan.currentVersion)
10624
+ throw new CliError(
10625
+ "UPDATE_INSTALLATION_CHANGED",
10626
+ "The installed version changed. Check version before updating again."
10627
+ );
10628
+ try {
10629
+ await execute("npm", args, { ...options, cwd: prefix });
10630
+ const installed = JSON.parse(await readFile2(join4(packageRoot, "package.json"), "utf8"));
10631
+ if (installed.name !== plan.package || releaseVersionSchema.parse(installed.version) !== plan.targetVersion)
10632
+ throw new Error();
10633
+ const verified = await execute(
10634
+ process.execPath,
10635
+ [join4(packageRoot, "dist/cf.js"), "version", "--json"],
10636
+ options
10637
+ );
10638
+ const result2 = JSON.parse(verified.stdout);
10639
+ if (!result2.ok || result2.data?.version !== plan.targetVersion || result2.data?.sdkVersion !== plan.targetVersion)
10640
+ throw new Error();
10641
+ return {
10642
+ state: "UPDATED",
10643
+ package: plan.package,
10644
+ previousVersion: plan.currentVersion,
10645
+ installedVersion: plan.targetVersion,
10646
+ restartRequired: true,
10647
+ originalCommandExecuted: false,
10648
+ recovery
10649
+ };
10650
+ } catch {
10651
+ throw new CliError(
10652
+ "UPDATE_OUTCOME_UNKNOWN",
10653
+ "The installation may have changed. Inspect version before another update; use the recovery command if needed. The original business command was not sent.",
10654
+ "UNKNOWN",
10655
+ { expectedVersion: plan.targetVersion, recovery, originalCommandExecuted: false }
10656
+ );
10657
+ }
10658
+ });
10659
+ }
10660
+
10661
+ // packages/cli-client/src/updates/commands.ts
10662
+ function validateOptions(parsed, names) {
10663
+ if (Object.keys(parsed.options).some((name) => !["json", "timeout-ms", ...names].includes(name)))
10664
+ throw new CliError("INVALID_OPTION", "Unsupported version/update option. Use help update.");
10665
+ }
10666
+ function selectedPolicy(saved, parsed) {
10667
+ const options = parsed.options;
10668
+ const result2 = updatePolicySchema.safeParse({
10669
+ ...saved,
10670
+ ...options.mode ? { mode: options.mode } : {},
10671
+ ...options.channel ? { channel: options.channel } : {},
10672
+ ...options.pin ? { pin: options.pin === "none" ? null : options.pin } : {},
10673
+ ...options["interval-hours"] ? { intervalHours: Number(options["interval-hours"]) } : {}
10674
+ });
10675
+ if (!result2.success)
10676
+ throw new CliError(
10677
+ "INVALID_UPDATE_POLICY",
10678
+ "Use mode off/notify/auto, channel latest/next/beta, an exact pin or none, and interval-hours 1\u2013168."
10679
+ );
10680
+ return result2.data;
10681
+ }
10682
+ async function runLifecycleCommand(parsed, env, executablePath) {
10683
+ const { words, options, timeout } = parsed;
10684
+ if (options.version || words[0] === "version") {
10685
+ if (options.version && words.length !== 0 || !options.version && words.length !== 1)
10686
+ throw new CliError("INVALID_COMMAND", "Use version or --version.");
10687
+ validateOptions(parsed, ["version", "server", "strict", "profile"]);
10688
+ if (options.strict && !options.server)
10689
+ throw new CliError("INVALID_OPTION", "--strict requires version --server.");
10690
+ if (options.profile && !options.server)
10691
+ throw new CliError("INVALID_OPTION", "--profile requires version --server.");
10692
+ return options.server ? null : { command: "version", data: await getNativeCliVersion(executablePath) };
10693
+ }
10694
+ if (words[0] !== "update") return null;
10695
+ if (words.length !== 2 || !["check", "apply", "policy"].includes(words[1]))
10696
+ throw new CliError("INVALID_COMMAND", "Use update check/apply/policy.");
10697
+ const policyCommand = words[1] === "policy";
10698
+ validateOptions(
10699
+ parsed,
10700
+ policyCommand ? ["mode", "channel", "pin", "interval-hours"] : ["channel", "pin", ...words[1] === "apply" ? ["allow-breaking", "dry-run"] : []]
10701
+ );
10702
+ const store = new UpdateStore(env);
10703
+ const state = await store.read();
10704
+ if (policyCommand) {
10705
+ const changes = Object.keys(options).some(
10706
+ (name) => ["mode", "channel", "pin", "interval-hours"].includes(name)
10707
+ );
10708
+ const saved = changes ? await store.change((current) => ({
10709
+ ...current,
10710
+ policy: selectedPolicy(current.policy, parsed)
10711
+ })) : state;
10712
+ return {
10713
+ command: "update policy",
10714
+ data: {
10715
+ saved: saved.policy,
10716
+ effective: effectiveUpdatePolicy(saved.policy, env),
10717
+ lastCheckedAt: saved.lastCheck?.at ?? null
10718
+ }
10719
+ };
10720
+ }
10721
+ const policy = selectedPolicy(effectiveUpdatePolicy(state.policy, env), parsed);
10722
+ const currentVersion = (await getNativeCliVersion(executablePath)).version;
10723
+ const checked = await checkNativeUpdates({
10724
+ package: "cli",
10725
+ currentVersion,
10726
+ policy,
10727
+ timeoutMs: timeout
10728
+ });
10729
+ await store.change((current) => ({
10730
+ ...current,
10731
+ lastAttempt: { at: checked.checkedAt, selector: policy.pin ?? policy.channel },
10732
+ lastCheck: {
10733
+ at: checked.checkedAt,
10734
+ selector: policy.pin ?? policy.channel,
10735
+ target: checked.target
10736
+ }
10737
+ }));
10738
+ if (words[1] === "check" || options["dry-run"] || checked.plan.status === "CURRENT")
10739
+ return { command: words.join(" "), data: checked };
10740
+ const data = await installCliUpdate({
10741
+ target: checked.target,
10742
+ currentVersion,
10743
+ policy,
10744
+ timeoutMs: timeout,
10745
+ env,
10746
+ allowBreaking: Boolean(options["allow-breaking"]),
10747
+ ...executablePath ? { executablePath } : {}
10748
+ });
10749
+ return { command: "update apply", data };
10750
+ }
10751
+ async function maybeAutoUpdate(env, io, timeout) {
10752
+ if (!io.executablePath || env.CF_AGENT_UPDATE_MODE === "off" || env.CI && !env.CF_AGENT_UPDATE_MODE)
10753
+ return null;
10754
+ const notify = io.notify ?? ((message) => process.stderr.write(message + "\n"));
10755
+ try {
10756
+ const store = new UpdateStore(env);
10757
+ const state = await store.read();
10758
+ const policy = effectiveUpdatePolicy(state.policy, env);
10759
+ if (policy.mode === "off") return null;
10760
+ const now = Date.now(), selector = policy.pin ?? policy.channel;
10761
+ const age = state.lastAttempt ? now - state.lastAttempt.at : Infinity;
10762
+ if (state.lastAttempt?.selector === selector && age >= 0 && age < policy.intervalHours * 36e5)
10763
+ return null;
10764
+ let claimed = false;
10765
+ await store.change((current) => {
10766
+ const age2 = current.lastAttempt ? now - current.lastAttempt.at : Infinity;
10767
+ if (current.lastAttempt?.selector === selector && age2 >= 0 && age2 < policy.intervalHours * 36e5)
10768
+ return current;
10769
+ claimed = true;
10770
+ return { ...current, lastAttempt: { at: now, selector } };
10771
+ });
10772
+ if (!claimed) return null;
10773
+ const currentVersion = (await getNativeCliVersion(io.executablePath)).version;
10774
+ const checked = await checkNativeUpdates({
10775
+ package: "cli",
10776
+ currentVersion,
10777
+ policy,
10778
+ timeoutMs: Math.min(timeout, 2e3)
10779
+ });
10780
+ await store.change((current) => ({
10781
+ ...current,
10782
+ lastCheck: { at: checked.checkedAt, selector, target: checked.target }
10783
+ }));
10784
+ if (checked.plan.status === "CURRENT" || checked.plan.reason === "DOWNGRADE_FORBIDDEN" && !policy.pin)
10785
+ return null;
10786
+ if (policy.mode === "auto" && checked.plan.eligibleForAutoUpdate) {
10787
+ const data = await installCliUpdate({
10788
+ target: checked.target,
10789
+ currentVersion,
10790
+ automatic: true,
10791
+ policy,
10792
+ executablePath: io.executablePath,
10793
+ env,
10794
+ timeoutMs: timeout
10795
+ });
10796
+ notify(
10797
+ `Native Marketing updated to ${checked.plan.targetVersion}. Run the original command again.`
10798
+ );
10799
+ return { command: "update auto", data };
10800
+ }
10801
+ notify(
10802
+ `Native Marketing ${nativeClientRelease.version}: update ${checked.plan.targetVersion} (${checked.plan.reason}). Use update check or update apply.`
10803
+ );
10804
+ } catch (error) {
10805
+ if (error instanceof CliError && error.code === "UPDATE_OUTCOME_UNKNOWN") throw error;
10806
+ notify("Native Marketing update check/install is unavailable; use update check for details.");
10807
+ }
10808
+ return null;
10809
+ }
10810
+
9657
10811
  // packages/cli-client/src/cli/run.ts
9658
10812
  async function runNetworkCli(args, env = process.env, io = {}, executable = "cf") {
9659
10813
  let command5 = executable;
9660
10814
  try {
9661
10815
  const parsed = parseArgs(args);
9662
10816
  const { words, options, timeout } = parsed;
9663
- if (!words.length || words[0] === "help" || options.help)
10817
+ if ((!words.length || words[0] === "help" || options.help) && !options.version)
9664
10818
  return success("help", { ...commandHelp(words), executable });
10819
+ const local = await runLifecycleCommand(parsed, env, io.executablePath);
10820
+ if (local) return success(local.command, local.data);
10821
+ const remoteVersion = (words.join(" ") === "version" || options.version && !words.length) && options.server;
9665
10822
  const store = new ProfileStore(env, String(options.profile ?? "default"));
9666
10823
  if (words[0] === "auth") {
9667
10824
  if (words.length !== 2)
@@ -9733,10 +10890,14 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9733
10890
  "AUTH_OPTION_MISUSE",
9734
10891
  "Resource/token/scope options belong to auth commands. Business commands use the bound profile or CF_AGENT_RESOURCE and CF_AGENT_ACCESS_TOKEN together."
9735
10892
  );
9736
- resolveCommand(parsed);
9737
- command5 = words[0] === "search" ? "search" : words[0] === "capabilities" ? words.slice(0, 2).join(" ") : words.join(" ");
10893
+ if (!remoteVersion) resolveCommand(parsed);
10894
+ command5 = remoteVersion ? "version" : words[0] === "search" ? "search" : words[0] === "capabilities" ? words.slice(0, 2).join(" ") : words.join(" ");
10895
+ if (!remoteVersion) {
10896
+ const automatic = await maybeAutoUpdate(env, io, timeout);
10897
+ if (automatic) return success(automatic.command, automatic.data);
10898
+ }
9738
10899
  const input = options.stdin ? objectJson(await readStream(io.stdin ?? process.stdin)) : typeof options["input-file"] === "string" ? objectJson(await readFileBounded(options["input-file"])) : {};
9739
- validateCommandInput(parsed, input);
10900
+ if (!remoteVersion) validateCommandInput(parsed, input);
9740
10901
  let profile;
9741
10902
  if (env.CF_AGENT_ACCESS_TOKEN || env.CF_AGENT_RESOURCE) {
9742
10903
  if (options.profile || !env.CF_AGENT_ACCESS_TOKEN || !env.CF_AGENT_RESOURCE)
@@ -9749,7 +10910,18 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9749
10910
  accessToken: tokenText(env.CF_AGENT_ACCESS_TOKEN)
9750
10911
  };
9751
10912
  } else profile = await refreshProfile(store, timeout);
9752
- 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(
10913
+ const data = remoteVersion ? await withClient(
10914
+ profile,
10915
+ timeout,
10916
+ async (client) => ({
10917
+ ...readNativeServerVersion(client),
10918
+ cli: await getNativeCliVersion(io.executablePath)
10919
+ }),
10920
+ {
10921
+ allowIncompatible: !options.strict,
10922
+ requireCompatibility: Boolean(options.strict)
10923
+ }
10924
+ ) : 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(
9753
10925
  profile,
9754
10926
  String(options.file),
9755
10927
  String(options["request-id"]),
@@ -9758,7 +10930,15 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9758
10930
  ) : await withClient(
9759
10931
  profile,
9760
10932
  timeout,
9761
- (client) => businessCommand(client, parsed, input, profile.resource)
10933
+ (client) => businessCommand(client, parsed, input, profile.resource),
10934
+ {
10935
+ onVersion: (version) => {
10936
+ if (version.compatibility.status === "UPGRADE_RECOMMENDED")
10937
+ (io.notify ?? ((message) => process.stderr.write(message + "\n")))(
10938
+ `The service recommends Native Marketing ${version.compatibility.server.version}. Use update check.`
10939
+ );
10940
+ }
10941
+ }
9762
10942
  );
9763
10943
  return success(command5, data);
9764
10944
  } catch (error) {
@@ -9768,16 +10948,57 @@ async function runNetworkCli(args, env = process.env, io = {}, executable = "cf"
9768
10948
  function success(command5, data) {
9769
10949
  return { exitCode: 0, envelope: { ok: true, command: command5, data, error: null } };
9770
10950
  }
10951
+
10952
+ // packages/cli-client/src/cli/output.ts
10953
+ function formatNetworkCliResult(result2, json = false) {
10954
+ const { envelope } = result2;
10955
+ if (!json && envelope.ok && envelope.command.startsWith("human ")) {
10956
+ const data = envelope.data;
10957
+ const value = data.status === "FOUND" ? data.receipt : data;
10958
+ const parsed = humanPresentationSchema.safeParse(value.human);
10959
+ if (parsed.success) {
10960
+ const lines = [envelope.command, ...value.state ? [`\u72B6\u6001\uFF1A${value.state}`] : []];
10961
+ for (const card of parsed.data.interactions)
10962
+ lines.push(
10963
+ `${card.title} \xB7 ${card.state}`,
10964
+ card.summary,
10965
+ `\u6B63\u5F0F\u5BA1\u6838\u5165\u53E3\uFF08\u9700\u8981\u767B\u5F55\uFF09\uFF1A${card.reviewUrl}`
10966
+ );
10967
+ for (const link of parsed.data.links)
10968
+ lines.push(
10969
+ `${link.title} \xB7 \u9605\u8BFB`,
10970
+ link.access === "TEMPORARY_PUBLIC_READ" ? `\u4E34\u65F6\u516C\u5F00\u53EA\u8BFB\u5FEB\u7167\uFF1B\u6301\u94FE\u63A5\u8005\u65E0\u9700\u767B\u5F55\u3002\u5230\u671F\uFF1A${link.expiresAt}` : "\u5F53\u524D\u5185\u5BB9\uFF1B\u9700\u8981\u767B\u5F55\u3002",
10971
+ link.url
10972
+ );
10973
+ if (value.issuanceRequestId) lines.push(`\u539F\u7B7E\u53D1\u8BF7\u6C42\uFF1A${value.issuanceRequestId}`);
10974
+ if (!parsed.data.links.length && !parsed.data.interactions.length)
10975
+ lines.push("\u5F53\u524D\u65E0\u53EF\u7528\u9605\u8BFB\u94FE\u63A5\u6216\u4EA4\u4E92\u3002");
10976
+ return lines.join("\n") + "\n";
10977
+ }
10978
+ }
10979
+ return JSON.stringify(envelope, null, json ? void 0 : 2) + "\n";
10980
+ }
9771
10981
  export {
9772
10982
  CliError as NativeAgentClientError,
10983
+ assessNativeCompatibility,
9773
10984
  callNativeCapability,
9774
10985
  callNativeTool,
10986
+ checkNativeUpdates,
10987
+ cleanupNativeHumanReadLinks,
10988
+ defaultUpdatePolicy,
9775
10989
  describeNativeCapability,
9776
10990
  findAgentCapabilities,
9777
10991
  findNativeCapabilities,
10992
+ formatNetworkCliResult,
9778
10993
  getNativeBusinessSummary,
10994
+ getNativeClientVersion,
10995
+ getNativeHumanPresentation,
10996
+ getNativeHumanReadLink,
10997
+ getNativeHumanReadLinkReceipt,
9779
10998
  inspectNativeTool,
10999
+ issueNativeHumanReadLink,
9780
11000
  listNativeToolsPage,
11001
+ planNativeUpdate,
9781
11002
  projectMediaFileQuerySchema,
9782
11003
  readNativeBusinessPage,
9783
11004
  readNativeCapability,
@@ -9786,6 +11007,7 @@ export {
9786
11007
  readNativeDocumentPage,
9787
11008
  readNativePackageFile,
9788
11009
  readNativeProjectMediaFile,
11010
+ revokeNativeHumanReadLink,
9789
11011
  runNetworkCli,
9790
11012
  searchNativeBusiness,
9791
11013
  uploadNativeMaterial,