@ixo/editor 6.31.4 → 6.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { a6 as FlowNodeAuthzExtension, a7 as FlowNode, a8 as EvaluationStatus, F as FlowRuntimeStateManager, G as UcanService, g as InvocationStore, a9 as IxoEditorType, aa as PendingInvocation, ab as ActionServices, ac as ActionHandlers, ad as RunEventAppender, ae as TopicExecutionContext, af as TopicActionBridge, ag as ActionResult, ah as TopicActionWriteBackResult, U as UcanCapability, ai as FlowNodeRuntimeState, z as UcanDelegationStore, v as StoredDelegation, aj as ActionDefinition } from './runtime-DFPayq89.js';
1
+ import { a6 as FlowNodeAuthzExtension, a7 as FlowNode, a8 as EvaluationStatus, F as FlowRuntimeStateManager, G as UcanService, g as InvocationStore, a9 as IxoEditorType, aa as PendingInvocation, ab as ActionServices, ac as ActionHandlers, ad as RunEventAppender, ae as TopicExecutionContext, af as TopicActionBridge, ag as ActionResult, ah as TopicActionWriteBackResult, U as UcanCapability, ai as FlowNodeRuntimeState, z as UcanDelegationStore, v as StoredDelegation, aj as ActionDefinition } from './runtime-BFwvCQDF.js';
2
2
  import * as Y from 'yjs';
3
3
  import { Doc, Map } from 'yjs';
4
4
  import { MatrixClient } from 'matrix-js-sdk';
@@ -74,8 +74,10 @@ var init_cid = __esm({
74
74
  // src/core/index.ts
75
75
  var core_exports = {};
76
76
  __export(core_exports, {
77
+ ACTION_MANIFEST_V2_SCHEMA: () => ACTION_MANIFEST_V2_SCHEMA,
77
78
  ACTION_MANIFEST_VERSION: () => ACTION_MANIFEST_VERSION,
78
79
  ACTION_REGISTRY_VERSION: () => ACTION_REGISTRY_VERSION,
80
+ ActionManifestV2VerificationError: () => ActionManifestV2VerificationError,
79
81
  ExplicitRunRequiredError: () => ExplicitRunRequiredError,
80
82
  FLOW_CONNECTIONS_MAP_KEY: () => FLOW_CONNECTIONS_MAP_KEY,
81
83
  FLOW_CONNECTION_BINDINGS_MAP_KEY: () => FLOW_CONNECTION_BINDINGS_MAP_KEY,
@@ -141,6 +143,7 @@ __export(core_exports, {
141
143
  canToActionType: () => canToActionType,
142
144
  canToType: () => canToType,
143
145
  cancelRun: () => cancelRun,
146
+ canonicalizeManifestV2Payload: () => canonicalizeManifestV2Payload,
144
147
  capabilityPatternCoversCan: () => capabilityPatternCoversCan,
145
148
  classifyBlockerCause: () => classifyBlockerCause,
146
149
  classifyNodeState: () => classifyNodeState,
@@ -150,6 +153,7 @@ __export(core_exports, {
150
153
  closeRun: () => closeRun,
151
154
  collectPhantomLegacyRun: () => collectPhantomLegacyRun,
152
155
  compileBaseUcanFlow: () => compileBaseUcanFlow,
156
+ computeActionManifestV2Digest: () => computeActionManifestV2Digest,
153
157
  computeAgentCommandId: () => computeAgentCommandId,
154
158
  computeCID: () => computeCID,
155
159
  computeJsonCID: () => computeJsonCID,
@@ -326,6 +330,7 @@ __export(core_exports, {
326
330
  setTempUcanEnforcementDisabled: () => setTempUcanEnforcementDisabled,
327
331
  setupFlowFromBaseUcan: () => setupFlowFromBaseUcan,
328
332
  sha256Digest: () => sha256Digest,
333
+ signActionManifestV2: () => signActionManifestV2,
329
334
  snapshotInputRefs: () => snapshotInputRefs,
330
335
  snapshotNode: () => snapshotNode,
331
336
  startRun: () => startRun,
@@ -355,6 +360,7 @@ __export(core_exports, {
355
360
  validateFlowAgentLease: () => validateFlowAgentLease,
356
361
  validateTopicSemanticRecord: () => validateTopicSemanticRecord,
357
362
  validateTopicSemanticRecordBatch: () => validateTopicSemanticRecordBatch,
363
+ verifyActionManifestV2: () => verifyActionManifestV2,
358
364
  verifyCompletion: () => verifyCompletion,
359
365
  writeActionState: () => writeActionState,
360
366
  writeCompiledBlocksToFragment: () => writeCompiledBlocksToFragment,
@@ -2677,12 +2683,11 @@ var PRESENTATION = {
2677
2683
  "qi/topic.action.receipt.record": { displayName: "Record Action Receipt", description: "Record a signed Action receipt against its Topic request" },
2678
2684
  "qi/topic.action.request": { displayName: "Request Topic Action", description: "Request an Action against the current Topic revision" },
2679
2685
  "qi/topic.context.link": { displayName: "Link Topic Context", description: "Link a referenced resource or service to the Topic" },
2680
- "qi/topic.contract.accept": { displayName: "Accept Topic Contract", description: "Accept the exact current Topic contract revision" },
2686
+ "qi/topic.contract.confirm-setup": { displayName: "Confirm Topic Setup", description: "Confirm the exact proposed Topic setup revision" },
2681
2687
  "qi/topic.decision.record": { displayName: "Record Topic Decision", description: "Record an authorised decision and its rationale" },
2682
2688
  "qi/topic.file.attach-reference": { displayName: "Attach File Reference", description: "Attach a pinned VFS file reference to the Topic" },
2683
2689
  "qi/topic.flow.bind": { displayName: "Bind Flow to Topic", description: "Bind a governed Flow revision to the Topic" },
2684
2690
  "qi/topic.flow.unbind": { displayName: "Unbind Flow from Topic", description: "Remove an existing Flow binding from the Topic" },
2685
- "qi/topic.outcome.confirm": { displayName: "Confirm Topic Outcome", description: "Confirm a proposed outcome using the stated authority" },
2686
2691
  "qi/topic.outcome.propose": { displayName: "Propose Topic Outcome", description: "Propose an evidence-backed outcome for review" },
2687
2692
  "qi/topic.status.transition": { displayName: "Change Topic Status", description: "Move the Topic between permitted lifecycle statuses" },
2688
2693
  "qi/wallet.fund": { displayName: "Fund Wallet", description: "Fund a wallet with an on-chain transfer" },
@@ -2763,7 +2768,11 @@ var ACTION_TYPE_ALIASES = {
2763
2768
  // qi/ixo.calendar.event.* instead.
2764
2769
  "qi/calendar.event.create": "qi/googlecalendar.event.create-self",
2765
2770
  "qi/calendar.event.update": "qi/googlecalendar.event.update-self",
2766
- "qi/calendar.event.list": "qi/googlecalendar.event.list-self"
2771
+ "qi/calendar.event.list": "qi/googlecalendar.event.list-self",
2772
+ // Topic v3 called setup confirmation "accept contract". Persisted Flow
2773
+ // documents keep that action key, so resolve it to the v4 confirmation
2774
+ // contract while new documents use the canonical name.
2775
+ "qi/topic.contract.accept": "qi/topic.contract.confirm-setup"
2767
2776
  };
2768
2777
  var aliases = new Map(Object.entries(ACTION_TYPE_ALIASES));
2769
2778
  function resolveActionType(type) {
@@ -3028,6 +3037,347 @@ function actionManifestIssues(manifest = generateActionManifest()) {
3028
3037
  return issues;
3029
3038
  }
3030
3039
 
3040
+ // src/core/lib/actionRegistry/manifestV2.ts
3041
+ var import__2 = __toESM(require("ajv/dist/2020.js"), 1);
3042
+
3043
+ // src/core/lib/actionRegistry/manifestV2.schema.ts
3044
+ var ACTION_MANIFEST_V2_SCHEMA = {
3045
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3046
+ $id: "https://ixo.world/schemas/qi/action-manifest-v2.schema.json",
3047
+ type: "object",
3048
+ additionalProperties: false,
3049
+ required: ["manifestVersion", "manifestId", "generatedAt", "package", "issuer", "compatibility", "actions", "primitives", "integrity"],
3050
+ properties: {
3051
+ manifestVersion: { const: "2.0" },
3052
+ manifestId: { type: "string", minLength: 1 },
3053
+ generatedAt: {
3054
+ type: "string",
3055
+ pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$"
3056
+ },
3057
+ package: {
3058
+ type: "object",
3059
+ additionalProperties: false,
3060
+ required: ["name", "version", "sourceCommit"],
3061
+ properties: {
3062
+ name: { type: "string", minLength: 1 },
3063
+ version: { type: "string", minLength: 1 },
3064
+ sourceCommit: { type: "string", minLength: 1 },
3065
+ buildId: { type: "string", minLength: 1 },
3066
+ distributionUrl: { type: "string", pattern: "^[a-zA-Z][a-zA-Z0-9+.-]*:" }
3067
+ }
3068
+ },
3069
+ issuer: {
3070
+ type: "object",
3071
+ additionalProperties: false,
3072
+ required: ["did", "verificationMethod"],
3073
+ properties: {
3074
+ did: { type: "string", pattern: "^did:[a-z0-9]+:.+" },
3075
+ verificationMethod: { type: "string", pattern: "^did:[a-z0-9]+:.+#.+" }
3076
+ }
3077
+ },
3078
+ compatibility: {
3079
+ type: "object",
3080
+ additionalProperties: false,
3081
+ required: ["engine", "flowSchemaVersions", "features"],
3082
+ properties: {
3083
+ engine: {
3084
+ type: "object",
3085
+ additionalProperties: false,
3086
+ required: ["versionRange"],
3087
+ properties: {
3088
+ versionRange: { type: "string", minLength: 1 }
3089
+ }
3090
+ },
3091
+ flowSchemaVersions: {
3092
+ type: "array",
3093
+ minItems: 1,
3094
+ uniqueItems: true,
3095
+ items: { type: "string", minLength: 1 }
3096
+ },
3097
+ features: {
3098
+ type: "array",
3099
+ minItems: 1,
3100
+ uniqueItems: true,
3101
+ items: { type: "string", minLength: 1 }
3102
+ }
3103
+ }
3104
+ },
3105
+ actions: {
3106
+ type: "array",
3107
+ items: { $ref: "#/$defs/contract" }
3108
+ },
3109
+ primitives: {
3110
+ type: "array",
3111
+ items: { $ref: "#/$defs/contract" }
3112
+ },
3113
+ integrity: {
3114
+ type: "object",
3115
+ additionalProperties: false,
3116
+ required: ["canonicalization", "digest", "signature"],
3117
+ properties: {
3118
+ canonicalization: { const: "RFC8785" },
3119
+ digest: {
3120
+ type: "object",
3121
+ additionalProperties: false,
3122
+ required: ["algorithm", "value"],
3123
+ properties: {
3124
+ algorithm: { const: "SHA-256" },
3125
+ value: { type: "string", pattern: "^sha256:[0-9a-f]{64}$" }
3126
+ }
3127
+ },
3128
+ signature: {
3129
+ type: "object",
3130
+ additionalProperties: false,
3131
+ required: ["algorithm", "verificationMethod", "value"],
3132
+ properties: {
3133
+ algorithm: { type: "string", minLength: 1 },
3134
+ verificationMethod: { type: "string", pattern: "^did:[a-z0-9]+:.+#.+" },
3135
+ value: { type: "string", minLength: 1 }
3136
+ }
3137
+ }
3138
+ }
3139
+ }
3140
+ },
3141
+ $defs: {
3142
+ contract: {
3143
+ type: "object",
3144
+ required: ["type", "contractVersion"],
3145
+ properties: {
3146
+ type: { type: "string", minLength: 1 },
3147
+ contractVersion: { type: "string", minLength: 1 },
3148
+ aliases: {
3149
+ type: "array",
3150
+ uniqueItems: true,
3151
+ items: { type: "string", minLength: 1 }
3152
+ }
3153
+ }
3154
+ }
3155
+ }
3156
+ };
3157
+
3158
+ // src/core/lib/actionRegistry/manifestV2.ts
3159
+ var ActionManifestV2VerificationError = class extends Error {
3160
+ constructor(code, message) {
3161
+ super(message);
3162
+ this.name = "ActionManifestV2VerificationError";
3163
+ this.code = code;
3164
+ }
3165
+ };
3166
+ var validateSignedManifest = new import__2.default({ allErrors: true, strict: false }).compile(ACTION_MANIFEST_V2_SCHEMA);
3167
+ var SIGNATURE_DOMAIN = "qi.action-manifest.v2\0";
3168
+ function isPlainObject(value) {
3169
+ const prototype = Object.getPrototypeOf(value);
3170
+ return prototype === Object.prototype || prototype === null;
3171
+ }
3172
+ function assertValidUnicode(value) {
3173
+ for (let index = 0; index < value.length; index += 1) {
3174
+ const codeUnit = value.charCodeAt(index);
3175
+ if (codeUnit >= 55296 && codeUnit <= 56319) {
3176
+ const next = value.charCodeAt(index + 1);
3177
+ if (!(next >= 56320 && next <= 57343)) {
3178
+ throw new TypeError("Manifest v2 contains an unpaired Unicode surrogate");
3179
+ }
3180
+ index += 1;
3181
+ } else if (codeUnit >= 56320 && codeUnit <= 57343) {
3182
+ throw new TypeError("Manifest v2 contains an unpaired Unicode surrogate");
3183
+ }
3184
+ }
3185
+ }
3186
+ function canonicalizeManifestV2Payload(payload) {
3187
+ const ancestors = /* @__PURE__ */ new Set();
3188
+ const serialize = (value) => {
3189
+ if (value === null || typeof value === "boolean") {
3190
+ return JSON.stringify(value);
3191
+ }
3192
+ if (typeof value === "string") {
3193
+ assertValidUnicode(value);
3194
+ return JSON.stringify(value);
3195
+ }
3196
+ if (typeof value === "number") {
3197
+ if (!Number.isFinite(value)) {
3198
+ throw new TypeError("Manifest v2 contains a non-finite number");
3199
+ }
3200
+ return JSON.stringify(value);
3201
+ }
3202
+ if (typeof value !== "object") {
3203
+ throw new TypeError(`Manifest v2 contains a non-JSON value: ${typeof value}`);
3204
+ }
3205
+ if (ancestors.has(value)) {
3206
+ throw new TypeError("Manifest v2 contains a circular reference");
3207
+ }
3208
+ ancestors.add(value);
3209
+ try {
3210
+ if (Array.isArray(value)) {
3211
+ return `[${value.map((entry) => serialize(entry)).join(",")}]`;
3212
+ }
3213
+ if (!isPlainObject(value)) {
3214
+ throw new TypeError("Manifest v2 contains a non-plain object");
3215
+ }
3216
+ return `{${Object.keys(value).sort().map((key) => {
3217
+ assertValidUnicode(key);
3218
+ return `${JSON.stringify(key)}:${serialize(value[key])}`;
3219
+ }).join(",")}}`;
3220
+ } finally {
3221
+ ancestors.delete(value);
3222
+ }
3223
+ };
3224
+ return serialize(payload);
3225
+ }
3226
+ async function computeActionManifestV2Digest(payload) {
3227
+ if (!globalThis.crypto?.subtle) {
3228
+ throw new Error("Web Crypto is required to digest an Action Manifest v2 contract");
3229
+ }
3230
+ const canonicalPayload = canonicalizeManifestV2Payload(payload);
3231
+ const digest2 = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalPayload));
3232
+ const hex = Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("");
3233
+ return `sha256:${hex}`;
3234
+ }
3235
+ function signatureInput(digest2) {
3236
+ return new TextEncoder().encode(`${SIGNATURE_DOMAIN}${digest2}`);
3237
+ }
3238
+ function schemaFailure() {
3239
+ const details = (validateSignedManifest.errors || []).map((error) => `${error.instancePath || "/"} ${error.message || "is invalid"}`).join("; ");
3240
+ return new ActionManifestV2VerificationError("INVALID_MANIFEST", details ? `Action Manifest v2 is invalid: ${details}` : "Action Manifest v2 is invalid");
3241
+ }
3242
+ function payloadFromSignedManifest(manifest) {
3243
+ const { integrity: _integrity, ...payload } = manifest;
3244
+ return payload;
3245
+ }
3246
+ function assertContractIdentities(payload) {
3247
+ const contracts = [...payload.actions, ...payload.primitives];
3248
+ const canonicalTypes = /* @__PURE__ */ new Set();
3249
+ for (const contract of contracts) {
3250
+ if (canonicalTypes.has(contract.type)) {
3251
+ throw new ActionManifestV2VerificationError("DUPLICATE_CONTRACT_TYPE", `Manifest contains duplicate canonical contract type: ${contract.type}`);
3252
+ }
3253
+ canonicalTypes.add(contract.type);
3254
+ }
3255
+ for (const [groupName, group] of [
3256
+ ["actions", payload.actions],
3257
+ ["primitives", payload.primitives]
3258
+ ]) {
3259
+ for (let index = 1; index < group.length; index += 1) {
3260
+ if (group[index - 1].type > group[index].type) {
3261
+ throw new ActionManifestV2VerificationError("UNSORTED_CONTRACTS", `Manifest ${groupName} must be sorted by canonical type`);
3262
+ }
3263
+ }
3264
+ }
3265
+ const claimedNames = new Map(Array.from(canonicalTypes, (type) => [type, type]));
3266
+ for (const contract of contracts) {
3267
+ const aliases2 = contract.aliases;
3268
+ if (!Array.isArray(aliases2)) continue;
3269
+ for (const alias of aliases2) {
3270
+ const existingOwner = claimedNames.get(alias);
3271
+ if (existingOwner) {
3272
+ throw new ActionManifestV2VerificationError("AMBIGUOUS_ALIAS", `Manifest alias ${alias} conflicts with contract ${existingOwner}`);
3273
+ }
3274
+ claimedNames.set(alias, contract.type);
3275
+ }
3276
+ }
3277
+ }
3278
+ function deepFreeze(value) {
3279
+ for (const child of Object.values(value)) {
3280
+ if (typeof child === "object" && child !== null && !Object.isFrozen(child)) {
3281
+ deepFreeze(child);
3282
+ }
3283
+ }
3284
+ return Object.freeze(value);
3285
+ }
3286
+ async function signActionManifestV2(payload, signer) {
3287
+ if (signer.issuerDid !== payload.issuer.did || signer.verificationMethod !== payload.issuer.verificationMethod) {
3288
+ throw new ActionManifestV2VerificationError("SIGNER_MISMATCH", "The Manifest v2 signer does not match the declared issuer verification method");
3289
+ }
3290
+ assertContractIdentities(payload);
3291
+ let digest2;
3292
+ try {
3293
+ digest2 = await computeActionManifestV2Digest(payload);
3294
+ } catch (error) {
3295
+ throw new ActionManifestV2VerificationError(
3296
+ "INVALID_MANIFEST",
3297
+ error instanceof Error ? `Action Manifest v2 cannot be canonicalized: ${error.message}` : "Action Manifest v2 cannot be canonicalized"
3298
+ );
3299
+ }
3300
+ const signature = await signer.sign(signatureInput(digest2));
3301
+ if (!signature) {
3302
+ throw new ActionManifestV2VerificationError("INVALID_SIGNATURE", "The Manifest v2 signer returned an empty signature");
3303
+ }
3304
+ const signed = {
3305
+ ...payload,
3306
+ integrity: {
3307
+ canonicalization: "RFC8785",
3308
+ digest: {
3309
+ algorithm: "SHA-256",
3310
+ value: digest2
3311
+ },
3312
+ signature: {
3313
+ algorithm: signer.algorithm,
3314
+ verificationMethod: signer.verificationMethod,
3315
+ value: signature
3316
+ }
3317
+ }
3318
+ };
3319
+ if (!validateSignedManifest(signed)) {
3320
+ throw schemaFailure();
3321
+ }
3322
+ assertContractIdentities(payload);
3323
+ return signed;
3324
+ }
3325
+ async function verifyActionManifestV2(candidate, trustPolicy) {
3326
+ if (typeof candidate !== "object" || candidate === null || !("manifestVersion" in candidate) || candidate.manifestVersion !== "2.0") {
3327
+ throw new ActionManifestV2VerificationError("UNSUPPORTED_MANIFEST_VERSION", "Only Action Manifest version 2.0 can cross this execution boundary");
3328
+ }
3329
+ if (!("integrity" in candidate) || typeof candidate.integrity !== "object") {
3330
+ throw new ActionManifestV2VerificationError("UNSIGNED_MANIFEST", "A signature and digest are required to load Action Manifest v2 for execution");
3331
+ }
3332
+ if (!validateSignedManifest(candidate)) {
3333
+ throw schemaFailure();
3334
+ }
3335
+ const manifest = candidate;
3336
+ const { issuer, integrity } = manifest;
3337
+ assertContractIdentities(manifest);
3338
+ if (!trustPolicy.trustedIssuerDids.includes(issuer.did)) {
3339
+ throw new ActionManifestV2VerificationError("UNTRUSTED_ISSUER", `Manifest issuer is not trusted: ${issuer.did}`);
3340
+ }
3341
+ if (trustPolicy.revokedIssuerDids?.includes(issuer.did)) {
3342
+ throw new ActionManifestV2VerificationError("REVOKED_ISSUER", `Manifest issuer is revoked: ${issuer.did}`);
3343
+ }
3344
+ if (integrity.signature.verificationMethod !== issuer.verificationMethod || !integrity.signature.verificationMethod.startsWith(`${issuer.did}#`)) {
3345
+ throw new ActionManifestV2VerificationError("VERIFICATION_METHOD_MISMATCH", "The signature verification method does not belong to the declared manifest issuer");
3346
+ }
3347
+ if (!trustPolicy.allowedSignatureAlgorithms.includes(integrity.signature.algorithm)) {
3348
+ throw new ActionManifestV2VerificationError("DISALLOWED_SIGNATURE_ALGORITHM", `Manifest signature algorithm is not allowed: ${integrity.signature.algorithm}`);
3349
+ }
3350
+ let digest2;
3351
+ try {
3352
+ digest2 = await computeActionManifestV2Digest(payloadFromSignedManifest(manifest));
3353
+ } catch (error) {
3354
+ throw new ActionManifestV2VerificationError(
3355
+ "INVALID_MANIFEST",
3356
+ error instanceof Error ? `Action Manifest v2 cannot be canonicalized: ${error.message}` : "Action Manifest v2 cannot be canonicalized"
3357
+ );
3358
+ }
3359
+ if (digest2 !== integrity.digest.value) {
3360
+ throw new ActionManifestV2VerificationError("DIGEST_MISMATCH", "Manifest payload does not match its signed digest");
3361
+ }
3362
+ let validSignature = false;
3363
+ try {
3364
+ validSignature = await trustPolicy.verifySignature({
3365
+ issuerDid: issuer.did,
3366
+ verificationMethod: integrity.signature.verificationMethod,
3367
+ algorithm: integrity.signature.algorithm,
3368
+ data: signatureInput(digest2),
3369
+ signature: integrity.signature.value
3370
+ });
3371
+ } catch {
3372
+ validSignature = false;
3373
+ }
3374
+ if (!validSignature) {
3375
+ throw new ActionManifestV2VerificationError("INVALID_SIGNATURE", "Manifest signature verification failed");
3376
+ }
3377
+ const trustedSnapshot = JSON.parse(JSON.stringify(manifest));
3378
+ return deepFreeze(trustedSnapshot);
3379
+ }
3380
+
3031
3381
  // src/core/lib/actionRegistry/inputRequirements.ts
3032
3382
  function isBlankInputValue(value) {
3033
3383
  if (value == null) return true;
@@ -10717,7 +11067,7 @@ function stripHtml(s) {
10717
11067
  }
10718
11068
 
10719
11069
  // src/core/lib/actionRegistry/actions/evalRubric/schemaGate.ts
10720
- var import__2 = __toESM(require("ajv/dist/2020.js"), 1);
11070
+ var import__3 = __toESM(require("ajv/dist/2020.js"), 1);
10721
11071
 
10722
11072
  // src/core/lib/actionRegistry/actions/evalRubric/types.ts
10723
11073
  var RUBRIC_CTX_TOKENS = [
@@ -10790,7 +11140,7 @@ async function getValidator(fetchSchema, evalEngineUrl) {
10790
11140
  if (compiledValidator) return compiledValidator;
10791
11141
  const schema = await fetchSchema(evalEngineUrl);
10792
11142
  if (!schema || typeof schema !== "object") throw new Error("the rules service returned no schema");
10793
- const validate = new import__2.default({ allErrors: true, strict: false }).compile(schema);
11143
+ const validate = new import__3.default({ allErrors: true, strict: false }).compile(schema);
10794
11144
  compiledValidator = validate;
10795
11145
  return validate;
10796
11146
  }
@@ -12955,6 +13305,7 @@ registerTopicOperation({
12955
13305
  executorPreference: { type: "string", enum: ["qi-flow", "qiforge", "mcp"] },
12956
13306
  bindingId: { type: "string" },
12957
13307
  confirmationPolicy: { type: "string", enum: ["inherit", "required"] },
13308
+ transitionCode: { type: "string" },
12958
13309
  idempotencyKey: { type: "string" }
12959
13310
  }
12960
13311
  },
@@ -12973,6 +13324,7 @@ registerTopicOperation({
12973
13324
  const inputDigest = requiredString(inputs.inputDigest, "inputDigest");
12974
13325
  const derived = (purpose) => sha256Digest({ purpose, parentRequestId: topic.requestId, topicId: topic.topicId, actionType: target.type, inputDigest });
12975
13326
  return {
13327
+ ...inputs.transitionCode ? { transitionCode: String(inputs.transitionCode) } : {},
12976
13328
  request: {
12977
13329
  version: 1,
12978
13330
  requestId: String(inputs.requestId || derived("topic-action-request")),
@@ -13038,9 +13390,15 @@ registerTopicOperation({
13038
13390
  ability: "topic/change-status",
13039
13391
  inputSchema: {
13040
13392
  type: "object",
13041
- required: ["from", "to", "reason"],
13393
+ required: ["from", "to", "transitionCode", "reason"],
13042
13394
  additionalProperties: false,
13043
- properties: { from: { type: "string" }, to: { type: "string" }, reason: { type: "string" }, idempotencyKey: { type: "string" } }
13395
+ properties: {
13396
+ from: { type: "string" },
13397
+ to: { type: "string" },
13398
+ transitionCode: { type: "string" },
13399
+ reason: { type: "string" },
13400
+ idempotencyKey: { type: "string" }
13401
+ }
13044
13402
  },
13045
13403
  buildPayload: async (inputs, ctx) => {
13046
13404
  const from = requiredString(inputs.from, "from");
@@ -13053,16 +13411,21 @@ registerTopicOperation({
13053
13411
  const outcome = projection.outcome;
13054
13412
  if (completion?.requiresOutcomeRecord === true && !outcome?.outcomeRecordId) throw new Error("Topic policy requires an accepted outcome record before resolution");
13055
13413
  }
13056
- return { from, to, reason: requiredString(inputs.reason, "reason") };
13414
+ return {
13415
+ from,
13416
+ to,
13417
+ transitionCode: requiredString(inputs.transitionCode, "transitionCode"),
13418
+ reason: requiredString(inputs.reason, "reason")
13419
+ };
13057
13420
  }
13058
13421
  });
13059
13422
  registerTopicOperation({
13060
- type: "qi/topic.contract.accept",
13061
- can: "topic/contract.accept",
13062
- operationType: "accept-contract",
13423
+ type: "qi/topic.contract.confirm-setup",
13424
+ can: "topic/contract.confirm-setup",
13425
+ operationType: "confirm-setup",
13063
13426
  confirmation: true,
13064
13427
  owner: "human",
13065
- ability: "topic/accept-contract",
13428
+ ability: "topic/confirm-setup",
13066
13429
  inputSchema: {
13067
13430
  type: "object",
13068
13431
  required: ["contractRevision", "contractDigest", "confirmationReference"],
@@ -13071,6 +13434,7 @@ registerTopicOperation({
13071
13434
  contractRevision: { type: "string" },
13072
13435
  contractDigest: { type: "string", pattern: "^sha256:" },
13073
13436
  confirmationReference: { type: "string" },
13437
+ transitionCode: { type: "string" },
13074
13438
  idempotencyKey: { type: "string" }
13075
13439
  }
13076
13440
  },
@@ -13078,8 +13442,13 @@ registerTopicOperation({
13078
13442
  const revision = requiredString(inputs.contractRevision, "contractRevision");
13079
13443
  const digest2 = requiredString(inputs.contractDigest, "contractDigest");
13080
13444
  if (revision !== topicContext(ctx).contract.revision || digest2 !== topicContext(ctx).contract.digest)
13081
- throw new Error("Contract acceptance must target the exact effective revision and digest");
13082
- return { contractRevision: revision, contractDigest: digest2, confirmationReference: requiredString(inputs.confirmationReference, "confirmationReference") };
13445
+ throw new Error("Setup confirmation must target the exact proposed contract revision and digest");
13446
+ return {
13447
+ contractRevision: revision,
13448
+ contractDigest: digest2,
13449
+ confirmationReference: requiredString(inputs.confirmationReference, "confirmationReference"),
13450
+ ...inputs.transitionCode ? { transitionCode: String(inputs.transitionCode) } : {}
13451
+ };
13083
13452
  }
13084
13453
  });
13085
13454
  registerTopicOperation({
@@ -13103,35 +13472,6 @@ registerTopicOperation({
13103
13472
  }
13104
13473
  })
13105
13474
  });
13106
- registerTopicOperation({
13107
- type: "qi/topic.outcome.confirm",
13108
- can: "topic/outcome.confirm",
13109
- operationType: "update-contract",
13110
- confirmation: true,
13111
- owner: "human",
13112
- ability: "topic/update-contract",
13113
- inputSchema: {
13114
- type: "object",
13115
- required: ["proposedOutcomeRecordId", "confirmationAuthorityDid", "confirmationReference"],
13116
- additionalProperties: false,
13117
- properties: {
13118
- proposedOutcomeRecordId: { type: "string" },
13119
- confirmationAuthorityDid: { type: "string", pattern: "^did:" },
13120
- confirmationReference: { type: "string" },
13121
- idempotencyKey: { type: "string" }
13122
- }
13123
- },
13124
- buildPayload: (inputs) => ({
13125
- patch: {
13126
- outcome: {
13127
- status: "achieved",
13128
- outcomeRecordId: requiredString(inputs.proposedOutcomeRecordId, "proposedOutcomeRecordId"),
13129
- confirmedBy: requiredString(inputs.confirmationAuthorityDid, "confirmationAuthorityDid"),
13130
- confirmationReference: requiredString(inputs.confirmationReference, "confirmationReference")
13131
- }
13132
- }
13133
- })
13134
- });
13135
13475
  registerTopicOperation({
13136
13476
  type: "qi/topic.decision.record",
13137
13477
  can: "topic/decision.record",
@@ -13540,6 +13880,60 @@ registerSemanticAction({
13540
13880
  occurredAt: String(inputs.occurredAt || (/* @__PURE__ */ new Date()).toISOString())
13541
13881
  })
13542
13882
  });
13883
+ registerAction({
13884
+ type: "qi/topic.remind",
13885
+ can: "topic/reminder.deliver",
13886
+ displayName: "Send a Topic reminder",
13887
+ description: "Posts a reminder into the Topic thread and notifies the people responsible for it.",
13888
+ sideEffect: true,
13889
+ proof: { fields: ["deliveredAt"] },
13890
+ done: doneWhenCompleted,
13891
+ defaultRequiresConfirmation: false,
13892
+ executionOwner: "agent",
13893
+ riskTier: "low",
13894
+ requiredServices: ["topic"],
13895
+ eligibleForTimeTrigger: true,
13896
+ scheduling: {
13897
+ riskTier: "R0",
13898
+ misfirePolicies: ["run_once_immediately", "skip"],
13899
+ // Reminders never queue: two firings of the same reminder are the same
13900
+ // reminder, and delivering it twice is the failure mode, not the goal.
13901
+ overlapPolicies: ["skip"],
13902
+ approvalRequirement: "none",
13903
+ idempotencyStrategy: "idempotency_key",
13904
+ inputModes: ["resolve_at_fire"],
13905
+ runModes: ["new_run_per_occurrence"]
13906
+ },
13907
+ topic: topicMetadata(ALL_KINDS2, [], ["topic/manage-reminder"], "contextual"),
13908
+ inputSchema: {
13909
+ type: "object",
13910
+ required: ["recipients"],
13911
+ additionalProperties: false,
13912
+ properties: {
13913
+ recipients: { type: "array", items: { type: "string" } },
13914
+ message: { type: "string" },
13915
+ idempotencyKey: { type: "string" }
13916
+ }
13917
+ },
13918
+ outputSchema: [
13919
+ { path: "deliveredAt", displayName: "Delivered at", type: "string" },
13920
+ { path: "recipients", displayName: "Reminded", type: "string" }
13921
+ ],
13922
+ run: async (inputs, ctx) => {
13923
+ const service = topicService(ctx);
13924
+ if (!service.deliverReminder) throw new Error("The host did not grant a Topic reminder delivery service");
13925
+ const recipients = requiredArray(inputs.recipients, "recipients");
13926
+ if (recipients.length === 0) throw new Error("A reminder needs at least one recipient");
13927
+ return {
13928
+ output: await service.deliverReminder({
13929
+ context: topicContext(ctx),
13930
+ recipients,
13931
+ message: String(inputs.message || ""),
13932
+ idempotencyKey: idempotencyKey("qi/topic.remind", inputs, ctx)
13933
+ })
13934
+ };
13935
+ }
13936
+ });
13543
13937
 
13544
13938
  // src/core/lib/actionRegistry/actions/calendar/eventCreate.types.ts
13545
13939
  function parseAttendeesField(raw) {
@@ -22616,8 +23010,10 @@ function createOracleInitFlowTemplate() {
22616
23010
  }
22617
23011
  // Annotate the CommonJS export names for ESM import in node:
22618
23012
  0 && (module.exports = {
23013
+ ACTION_MANIFEST_V2_SCHEMA,
22619
23014
  ACTION_MANIFEST_VERSION,
22620
23015
  ACTION_REGISTRY_VERSION,
23016
+ ActionManifestV2VerificationError,
22621
23017
  ExplicitRunRequiredError,
22622
23018
  FLOW_CONNECTIONS_MAP_KEY,
22623
23019
  FLOW_CONNECTION_BINDINGS_MAP_KEY,
@@ -22683,6 +23079,7 @@ function createOracleInitFlowTemplate() {
22683
23079
  canToActionType,
22684
23080
  canToType,
22685
23081
  cancelRun,
23082
+ canonicalizeManifestV2Payload,
22686
23083
  capabilityPatternCoversCan,
22687
23084
  classifyBlockerCause,
22688
23085
  classifyNodeState,
@@ -22692,6 +23089,7 @@ function createOracleInitFlowTemplate() {
22692
23089
  closeRun,
22693
23090
  collectPhantomLegacyRun,
22694
23091
  compileBaseUcanFlow,
23092
+ computeActionManifestV2Digest,
22695
23093
  computeAgentCommandId,
22696
23094
  computeCID,
22697
23095
  computeJsonCID,
@@ -22868,6 +23266,7 @@ function createOracleInitFlowTemplate() {
22868
23266
  setTempUcanEnforcementDisabled,
22869
23267
  setupFlowFromBaseUcan,
22870
23268
  sha256Digest,
23269
+ signActionManifestV2,
22871
23270
  snapshotInputRefs,
22872
23271
  snapshotNode,
22873
23272
  startRun,
@@ -22897,6 +23296,7 @@ function createOracleInitFlowTemplate() {
22897
23296
  validateFlowAgentLease,
22898
23297
  validateTopicSemanticRecord,
22899
23298
  validateTopicSemanticRecordBatch,
23299
+ verifyActionManifestV2,
22900
23300
  verifyCompletion,
22901
23301
  writeActionState,
22902
23302
  writeCompiledBlocksToFragment,