@everfir/az8-cli 0.3.0-preview.2 → 0.3.0
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/CHANGELOG.md +58 -0
- package/README.md +40 -13
- package/RELEASE.md +6 -6
- package/dist/main.js +1191 -434
- package/package.json +2 -2
- package/skills/az8-cli/SKILL.md +65 -16
package/dist/main.js
CHANGED
|
@@ -2387,7 +2387,7 @@ var require_websocket = __commonJS({
|
|
|
2387
2387
|
var http = __require("http");
|
|
2388
2388
|
var net2 = __require("net");
|
|
2389
2389
|
var tls = __require("tls");
|
|
2390
|
-
var { randomBytes, createHash:
|
|
2390
|
+
var { randomBytes, createHash: createHash5 } = __require("crypto");
|
|
2391
2391
|
var { Duplex, Readable } = __require("stream");
|
|
2392
2392
|
var { URL: URL2 } = __require("url");
|
|
2393
2393
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -3047,7 +3047,7 @@ var require_websocket = __commonJS({
|
|
|
3047
3047
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
3048
3048
|
return;
|
|
3049
3049
|
}
|
|
3050
|
-
const digest =
|
|
3050
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
3051
3051
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
3052
3052
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
3053
3053
|
return;
|
|
@@ -3414,7 +3414,7 @@ var require_websocket_server = __commonJS({
|
|
|
3414
3414
|
var EventEmitter3 = __require("events");
|
|
3415
3415
|
var http = __require("http");
|
|
3416
3416
|
var { Duplex } = __require("stream");
|
|
3417
|
-
var { createHash:
|
|
3417
|
+
var { createHash: createHash5 } = __require("crypto");
|
|
3418
3418
|
var extension2 = require_extension();
|
|
3419
3419
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3420
3420
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3715,7 +3715,7 @@ var require_websocket_server = __commonJS({
|
|
|
3715
3715
|
);
|
|
3716
3716
|
}
|
|
3717
3717
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3718
|
-
const digest =
|
|
3718
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
3719
3719
|
const headers = [
|
|
3720
3720
|
"HTTP/1.1 101 Switching Protocols",
|
|
3721
3721
|
"Upgrade: websocket",
|
|
@@ -4822,6 +4822,58 @@ function normalize(value) {
|
|
|
4822
4822
|
return (value ?? "").trim().toLowerCase().replaceAll(/[\s_]+/g, "-");
|
|
4823
4823
|
}
|
|
4824
4824
|
|
|
4825
|
+
// ../../packages/project-canvas-runtime/dist/generation/workflow-access.js
|
|
4826
|
+
function resolveWorkflowDefinitionAccess(definition, accessTier) {
|
|
4827
|
+
if (accessTier === "paid") {
|
|
4828
|
+
return { accessReason: "paid-account", availableForAccount: true };
|
|
4829
|
+
}
|
|
4830
|
+
if (normalize2(getInternalTag(definition, "available")) === "free") {
|
|
4831
|
+
return { accessReason: "free-tier-eligible", availableForAccount: true };
|
|
4832
|
+
}
|
|
4833
|
+
return { accessReason: "requires-paid-account", availableForAccount: false };
|
|
4834
|
+
}
|
|
4835
|
+
function isWorkflowDefinitionAvailable(definition, accessTier) {
|
|
4836
|
+
return resolveWorkflowDefinitionAccess(definition, accessTier).availableForAccount;
|
|
4837
|
+
}
|
|
4838
|
+
function normalize2(value) {
|
|
4839
|
+
return (value ?? "").trim().toLowerCase().replaceAll(/[\s_]+/g, "-");
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
// ../../packages/project-canvas-runtime/dist/generation/workflow-default.js
|
|
4843
|
+
function selectDefaultWorkflowDefinition(input) {
|
|
4844
|
+
const compatible = input.definitions.filter((definition) => isDefaultCompatible(definition, input.contentType));
|
|
4845
|
+
const preferred = input.preference && compatible.find((definition) => definition.id === input.preference?.definitionId);
|
|
4846
|
+
if (preferred) {
|
|
4847
|
+
return { definition: preferred, preference: input.preference, source: "preference" };
|
|
4848
|
+
}
|
|
4849
|
+
const fallback = compatible[0] ?? null;
|
|
4850
|
+
return {
|
|
4851
|
+
definition: fallback,
|
|
4852
|
+
preference: null,
|
|
4853
|
+
source: fallback ? "fallback" : "none"
|
|
4854
|
+
};
|
|
4855
|
+
}
|
|
4856
|
+
function isDefaultCompatible(definition, contentType) {
|
|
4857
|
+
const metadata = resolveWorkflowDefinitionMetadata(definition);
|
|
4858
|
+
if (metadata.target !== contentType)
|
|
4859
|
+
return false;
|
|
4860
|
+
if (!definition.outputSchema.some((output) => output.dataType === contentType))
|
|
4861
|
+
return false;
|
|
4862
|
+
if (getInternalTag(definition, "function") && !getInternalTag(definition, "capability")) {
|
|
4863
|
+
return false;
|
|
4864
|
+
}
|
|
4865
|
+
return definition.inputSchema.some((slot) => !isConfigSlot(slot));
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
// ../../packages/project-canvas-runtime/dist/generation/workflow-target.js
|
|
4869
|
+
function resolveWorkflowTargetFromSnapshot(snapshot, workflowRunId) {
|
|
4870
|
+
const targetIds = new Set(snapshot.viewNodes.flatMap((viewNode) => readGenerationHistory(viewNode.history).some((entry) => entry.runtime.instanceIds.includes(workflowRunId)) ? [viewNode.id] : []));
|
|
4871
|
+
if (targetIds.size === 1) {
|
|
4872
|
+
return { status: "resolved", viewNodeId: [...targetIds][0] };
|
|
4873
|
+
}
|
|
4874
|
+
return { status: targetIds.size > 1 ? "ambiguous" : "unresolved" };
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4825
4877
|
// ../../node_modules/.pnpm/lib0@0.2.117/node_modules/lib0/math.js
|
|
4826
4878
|
var floor = Math.floor;
|
|
4827
4879
|
var abs = Math.abs;
|
|
@@ -8238,10 +8290,10 @@ var YEvent = class {
|
|
|
8238
8290
|
}
|
|
8239
8291
|
};
|
|
8240
8292
|
var getPathTo = (parent, child) => {
|
|
8241
|
-
const
|
|
8293
|
+
const path10 = [];
|
|
8242
8294
|
while (child._item !== null && child !== parent) {
|
|
8243
8295
|
if (child._item.parentSub !== null) {
|
|
8244
|
-
|
|
8296
|
+
path10.unshift(child._item.parentSub);
|
|
8245
8297
|
} else {
|
|
8246
8298
|
let i = 0;
|
|
8247
8299
|
let c = (
|
|
@@ -8254,12 +8306,12 @@ var getPathTo = (parent, child) => {
|
|
|
8254
8306
|
}
|
|
8255
8307
|
c = c.right;
|
|
8256
8308
|
}
|
|
8257
|
-
|
|
8309
|
+
path10.unshift(i);
|
|
8258
8310
|
}
|
|
8259
8311
|
child = /** @type {AbstractType<any>} */
|
|
8260
8312
|
child._item.parent;
|
|
8261
8313
|
}
|
|
8262
|
-
return
|
|
8314
|
+
return path10;
|
|
8263
8315
|
};
|
|
8264
8316
|
var warnPrematureAccess = () => {
|
|
8265
8317
|
warn("Invalid access: Add Yjs type to a document before reading data.");
|
|
@@ -14095,7 +14147,7 @@ var CANVAS_OPERATION_REGISTRY = [
|
|
|
14095
14147
|
},
|
|
14096
14148
|
required: ["contentType"]
|
|
14097
14149
|
}),
|
|
14098
|
-
write2("createGenerationTarget", "Create
|
|
14150
|
+
write2("createGenerationTarget", "Create an audio, image, text, or video target with an eligible default Draft when available", "undoable", {
|
|
14099
14151
|
properties: {
|
|
14100
14152
|
contentType: { enum: ["audio", "image", "text", "video"], type: "string" },
|
|
14101
14153
|
name: stringSchema(),
|
|
@@ -14159,7 +14211,7 @@ var CANVAS_OPERATION_REGISTRY = [
|
|
|
14159
14211
|
},
|
|
14160
14212
|
required: ["idempotencyKey", "source"]
|
|
14161
14213
|
}),
|
|
14162
|
-
write2("editGenerationDraft", "Edit
|
|
14214
|
+
write2("editGenerationDraft", "Edit prompt, config, or Workflow Definition, resolving an eligible default for a null Draft", "silent", {
|
|
14163
14215
|
properties: {
|
|
14164
14216
|
config: { additionalProperties: { type: ["boolean", "number", "string"] }, type: "object" },
|
|
14165
14217
|
definitionId: stringSchema(),
|
|
@@ -14177,7 +14229,28 @@ var CANVAS_OPERATION_REGISTRY = [
|
|
|
14177
14229
|
}),
|
|
14178
14230
|
write2("insertPromptReference", "Bind one visible image, text, or video View Node and place its platform At token in the Prompt", "silent", {
|
|
14179
14231
|
properties: {
|
|
14180
|
-
placement: {
|
|
14232
|
+
placement: {
|
|
14233
|
+
anyOf: [
|
|
14234
|
+
{ enum: ["start", "end"], type: "string" },
|
|
14235
|
+
{
|
|
14236
|
+
additionalProperties: false,
|
|
14237
|
+
properties: {
|
|
14238
|
+
anchor: {
|
|
14239
|
+
additionalProperties: false,
|
|
14240
|
+
properties: {
|
|
14241
|
+
occurrence: { minimum: 1, type: "integer" },
|
|
14242
|
+
text: stringSchema()
|
|
14243
|
+
},
|
|
14244
|
+
required: ["text"],
|
|
14245
|
+
type: "object"
|
|
14246
|
+
},
|
|
14247
|
+
kind: { enum: ["before", "after"], type: "string" }
|
|
14248
|
+
},
|
|
14249
|
+
required: ["anchor", "kind"],
|
|
14250
|
+
type: "object"
|
|
14251
|
+
}
|
|
14252
|
+
]
|
|
14253
|
+
},
|
|
14181
14254
|
referenceViewNodeId: stringSchema(),
|
|
14182
14255
|
viewNodeId: stringSchema()
|
|
14183
14256
|
},
|
|
@@ -14997,7 +15070,156 @@ function isConfigValueValid(value, property, normalizedEnum = normalizeConfigEnu
|
|
|
14997
15070
|
return true;
|
|
14998
15071
|
}
|
|
14999
15072
|
|
|
15073
|
+
// ../../packages/project-canvas-runtime/dist/generation/planning-contract.js
|
|
15074
|
+
function generationPlanningIssue(code, message, slotName, field) {
|
|
15075
|
+
return {
|
|
15076
|
+
code,
|
|
15077
|
+
message,
|
|
15078
|
+
severity: "error",
|
|
15079
|
+
...slotName ? { slotName } : {},
|
|
15080
|
+
...field ? { field } : {}
|
|
15081
|
+
};
|
|
15082
|
+
}
|
|
15083
|
+
|
|
15084
|
+
// ../../packages/project-canvas-runtime/dist/generation/planning-config.js
|
|
15085
|
+
function createGenerationConfigDefaults(definition, preferred) {
|
|
15086
|
+
const slots = generationConfigSlots(definition);
|
|
15087
|
+
if (slots.length === 0)
|
|
15088
|
+
return null;
|
|
15089
|
+
if (slots.length !== 1)
|
|
15090
|
+
return null;
|
|
15091
|
+
const slot = slots[0];
|
|
15092
|
+
const properties = slot.jsonSchema?.properties ?? {};
|
|
15093
|
+
const slotDefaults = readConfigDefaults(slot.defaultValue);
|
|
15094
|
+
return Object.fromEntries(Object.entries(properties).map(([name, property]) => {
|
|
15095
|
+
const preferredValue = preferred?.[name];
|
|
15096
|
+
if (preferredValue !== void 0 && isConfigValueValid(preferredValue, property)) {
|
|
15097
|
+
return [name, preferredValue];
|
|
15098
|
+
}
|
|
15099
|
+
const slotDefault = normalizeSchemaConfigValue(slotDefaults[name], property.type);
|
|
15100
|
+
return [
|
|
15101
|
+
name,
|
|
15102
|
+
slotDefault !== void 0 && isConfigValueValid(slotDefault, property) ? slotDefault : configFallback(property, normalizeConfigEnum(property))
|
|
15103
|
+
];
|
|
15104
|
+
}));
|
|
15105
|
+
}
|
|
15106
|
+
async function createGenerationConfigPlan(definition, requested, runtime) {
|
|
15107
|
+
const slots = generationConfigSlots(definition);
|
|
15108
|
+
if (slots.length === 0) {
|
|
15109
|
+
return {
|
|
15110
|
+
fields: [],
|
|
15111
|
+
issues: requested ? [generationPlanningIssue("config-not-supported", "This Workflow Definition does not accept configuration.")] : [],
|
|
15112
|
+
values: null
|
|
15113
|
+
};
|
|
15114
|
+
}
|
|
15115
|
+
if (slots.length !== 1) {
|
|
15116
|
+
return {
|
|
15117
|
+
fields: [],
|
|
15118
|
+
issues: [
|
|
15119
|
+
generationPlanningIssue("multiple-config-slots-unsupported", "Generation Planning currently requires exactly one configuration slot.")
|
|
15120
|
+
],
|
|
15121
|
+
values: null
|
|
15122
|
+
};
|
|
15123
|
+
}
|
|
15124
|
+
const slot = slots[0];
|
|
15125
|
+
const properties = slot.jsonSchema?.properties ?? {};
|
|
15126
|
+
const slotDefaults = readConfigDefaults(slot.defaultValue);
|
|
15127
|
+
const values = {};
|
|
15128
|
+
const issues = [];
|
|
15129
|
+
for (const name of Object.keys(requested ?? {})) {
|
|
15130
|
+
if (!properties[name]) {
|
|
15131
|
+
issues.push(generationPlanningIssue("config-field-unknown", `Unknown configuration field: ${name}.`, slot.name, name));
|
|
15132
|
+
}
|
|
15133
|
+
}
|
|
15134
|
+
const fields = await Promise.all(Object.entries(properties).map(async ([name, property]) => {
|
|
15135
|
+
const normalizedEnum = normalizeConfigEnum(property);
|
|
15136
|
+
if (normalizedEnum?.invalidValues.length) {
|
|
15137
|
+
issues.push(generationPlanningIssue("config-enum-invalid", `Configuration ${name} contains enum values that do not match ${property.type}.`, slot.name, name));
|
|
15138
|
+
}
|
|
15139
|
+
const requestedValue = Object.hasOwn(requested ?? {}, name) ? requested?.[name] : normalizeSchemaConfigValue(slotDefaults[name], property.type);
|
|
15140
|
+
const fallback = configFallback(property, normalizedEnum);
|
|
15141
|
+
if (requestedValue !== void 0 && !isConfigValueValid(requestedValue, property)) {
|
|
15142
|
+
issues.push(generationPlanningIssue("config-value-invalid", `Configuration ${name} is outside its allowed values.`, slot.name, name));
|
|
15143
|
+
}
|
|
15144
|
+
const value = requestedValue !== void 0 && isConfigValueValid(requestedValue, property) ? requestedValue : fallback;
|
|
15145
|
+
values[name] = value;
|
|
15146
|
+
const dynamicOptions = await readDynamicOptions(runtime, name, property, value, issues, slot.name);
|
|
15147
|
+
return {
|
|
15148
|
+
description: property.description ?? "",
|
|
15149
|
+
name,
|
|
15150
|
+
required: slot.jsonSchema?.required?.includes(name) ?? false,
|
|
15151
|
+
type: property.type,
|
|
15152
|
+
value,
|
|
15153
|
+
...property.maximum === void 0 ? {} : { maximum: property.maximum },
|
|
15154
|
+
...property.minimum === void 0 ? {} : { minimum: property.minimum },
|
|
15155
|
+
...dynamicOptions ?? normalizedEnum?.options ? { options: dynamicOptions ?? normalizedEnum?.options } : {}
|
|
15156
|
+
};
|
|
15157
|
+
}));
|
|
15158
|
+
for (const name of slot.jsonSchema?.required ?? []) {
|
|
15159
|
+
if (values[name] === "") {
|
|
15160
|
+
issues.push(generationPlanningIssue("config-field-required", `Configuration ${name} requires a value.`, slot.name, name));
|
|
15161
|
+
}
|
|
15162
|
+
}
|
|
15163
|
+
return { fields, issues, values };
|
|
15164
|
+
}
|
|
15165
|
+
function readConfigDefaults(value) {
|
|
15166
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
15167
|
+
return {};
|
|
15168
|
+
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "boolean" || typeof entry[1] === "string" || typeof entry[1] === "number" && Number.isFinite(entry[1])));
|
|
15169
|
+
}
|
|
15170
|
+
async function readDynamicOptions(runtime, name, property, current, issues, slotName) {
|
|
15171
|
+
const source = property.dynamicEnum;
|
|
15172
|
+
if (property.type !== "string" || !source?.modelKey || !runtime.getDynamicEnumValues)
|
|
15173
|
+
return null;
|
|
15174
|
+
try {
|
|
15175
|
+
const remote = await runtime.getDynamicEnumValues({
|
|
15176
|
+
modelKey: source.modelKey,
|
|
15177
|
+
paramName: name,
|
|
15178
|
+
provider: source.provider
|
|
15179
|
+
});
|
|
15180
|
+
const values = typeof current === "string" && current.trim() ? [current] : [];
|
|
15181
|
+
for (const item of remote)
|
|
15182
|
+
if (!values.includes(item))
|
|
15183
|
+
values.push(item);
|
|
15184
|
+
return values;
|
|
15185
|
+
} catch {
|
|
15186
|
+
issues.push({
|
|
15187
|
+
code: "dynamic-options-unavailable",
|
|
15188
|
+
field: name,
|
|
15189
|
+
message: `Dynamic options for configuration ${name} are temporarily unavailable.`,
|
|
15190
|
+
severity: "warning",
|
|
15191
|
+
slotName
|
|
15192
|
+
});
|
|
15193
|
+
return null;
|
|
15194
|
+
}
|
|
15195
|
+
}
|
|
15196
|
+
function configFallback(property, normalizedEnum) {
|
|
15197
|
+
const normalizedDefault = normalizeSchemaConfigValue(property.default, property.type);
|
|
15198
|
+
if (normalizedDefault !== void 0 && isConfigValueValid(normalizedDefault, property)) {
|
|
15199
|
+
return normalizedDefault;
|
|
15200
|
+
}
|
|
15201
|
+
const first = normalizedEnum?.options[0];
|
|
15202
|
+
if (first !== void 0)
|
|
15203
|
+
return first;
|
|
15204
|
+
if (property.type === "boolean")
|
|
15205
|
+
return false;
|
|
15206
|
+
if (property.type === "number") {
|
|
15207
|
+
return property.minimum ?? (property.maximum && property.maximum < 0 ? property.maximum : 0);
|
|
15208
|
+
}
|
|
15209
|
+
return "";
|
|
15210
|
+
}
|
|
15211
|
+
function generationConfigSlots(definition) {
|
|
15212
|
+
return definition.inputSchema.filter((slot) => slot.dataType === "json" && (slot.required || isConfigSlot(slot)));
|
|
15213
|
+
}
|
|
15214
|
+
|
|
15000
15215
|
// ../../packages/project-canvas-runtime/dist/generation/draft-edit.js
|
|
15216
|
+
function createInitialGenerationDraft(definition, preferredConfig, now) {
|
|
15217
|
+
const config2 = createGenerationConfigDefaults(definition, preferredConfig);
|
|
15218
|
+
return editGenerationDraft(null, definition, {
|
|
15219
|
+
definitionId: definition.id,
|
|
15220
|
+
...config2 ? { config: config2 } : {}
|
|
15221
|
+
}, now);
|
|
15222
|
+
}
|
|
15001
15223
|
function editGenerationDraft(current, definition, input, now) {
|
|
15002
15224
|
const changedDefinition = current?.definitionId !== definition.id;
|
|
15003
15225
|
const draft = !current || changedDefinition ? {
|
|
@@ -15068,7 +15290,7 @@ function insertPromptReferenceIntoDraft(draft, definition, reference, sourceData
|
|
|
15068
15290
|
const prompt = promptInput.content;
|
|
15069
15291
|
const token = `{{@${binding.value.sourceDataType}:${binding.slotName}:${binding.index}:${reference.id}|view-node|${encodeURIComponent(reference.viewNodeId)}}}`;
|
|
15070
15292
|
const content = placement === "start" ? prompt.trim() ? `${token}
|
|
15071
|
-
${prompt}` : token : prompt.trim() ? `${prompt}${prompt.endsWith("\n") ? "" : "\n"}${token}` : token;
|
|
15293
|
+
${prompt}` : token : placement === "end" ? prompt.trim() ? `${prompt}${prompt.endsWith("\n") ? "" : "\n"}${token}` : token : insertAtPromptAnchor(prompt, token, placement);
|
|
15072
15294
|
return {
|
|
15073
15295
|
...structuredClone(withoutExistingToken),
|
|
15074
15296
|
inputs: {
|
|
@@ -15129,23 +15351,72 @@ function appendPromptReferenceToken(draft, slotName, referenceId, viewNodeId, no
|
|
|
15129
15351
|
};
|
|
15130
15352
|
}
|
|
15131
15353
|
function removePromptReferenceToken(draft, referenceId) {
|
|
15132
|
-
const pattern = new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN, "g");
|
|
15133
15354
|
const slots = Object.fromEntries(Object.entries(draft.inputs.slots).map(([slotName, values]) => [
|
|
15134
15355
|
slotName,
|
|
15135
15356
|
values.map((value) => {
|
|
15136
15357
|
if (value.kind !== "literal" || value.assetType !== "text")
|
|
15137
15358
|
return value;
|
|
15138
|
-
|
|
15139
|
-
const content = line.replace(pattern, (token, _type, _slot, _index, bindingId) => bindingId === referenceId ? "" : token);
|
|
15140
|
-
return content.trim() ? [content] : [];
|
|
15141
|
-
});
|
|
15142
|
-
return { ...value, content: lines.join("\n") };
|
|
15359
|
+
return { ...value, content: removeReferenceTokenFromContent(value.content, referenceId) };
|
|
15143
15360
|
})
|
|
15144
15361
|
]));
|
|
15145
15362
|
return { ...draft, inputs: { slots } };
|
|
15146
15363
|
}
|
|
15364
|
+
function insertAtPromptAnchor(prompt, token, placement) {
|
|
15365
|
+
const anchor = placement.anchor.text;
|
|
15366
|
+
if (!anchor.trim())
|
|
15367
|
+
throw new Error("placement.anchor.text must be non-empty.");
|
|
15368
|
+
const indexes = [];
|
|
15369
|
+
let from2 = 0;
|
|
15370
|
+
while (from2 <= prompt.length - anchor.length) {
|
|
15371
|
+
const index2 = prompt.indexOf(anchor, from2);
|
|
15372
|
+
if (index2 < 0)
|
|
15373
|
+
break;
|
|
15374
|
+
indexes.push(index2);
|
|
15375
|
+
from2 = index2 + Math.max(anchor.length, 1);
|
|
15376
|
+
}
|
|
15377
|
+
if (indexes.length === 0) {
|
|
15378
|
+
throw new Error(`Prompt anchor ${JSON.stringify(anchor)} does not exist.`);
|
|
15379
|
+
}
|
|
15380
|
+
const occurrence = placement.anchor.occurrence;
|
|
15381
|
+
if (occurrence === void 0 && indexes.length !== 1) {
|
|
15382
|
+
throw new Error(`Prompt anchor ${JSON.stringify(anchor)} is ambiguous; placement.anchor.occurrence is required.`);
|
|
15383
|
+
}
|
|
15384
|
+
const index = indexes[(occurrence ?? 1) - 1];
|
|
15385
|
+
if (index === void 0) {
|
|
15386
|
+
throw new Error(`Prompt anchor ${JSON.stringify(anchor)} does not have occurrence ${String(occurrence)}.`);
|
|
15387
|
+
}
|
|
15388
|
+
const insertionIndex = placement.kind === "before" ? index : index + anchor.length;
|
|
15389
|
+
return `${prompt.slice(0, insertionIndex)}${token}${prompt.slice(insertionIndex)}`;
|
|
15390
|
+
}
|
|
15391
|
+
function removeReferenceTokenFromContent(content, referenceId) {
|
|
15392
|
+
const matches2 = [...content.matchAll(new RegExp(PROMPT_REFERENCE_TOKEN_PATTERN, "g"))].filter((match) => match[4] === referenceId);
|
|
15393
|
+
let next = content;
|
|
15394
|
+
for (const match of matches2.reverse()) {
|
|
15395
|
+
let start = match.index;
|
|
15396
|
+
let end = start + match[0].length;
|
|
15397
|
+
if (start === 0 && next[end] === "\n")
|
|
15398
|
+
end += 1;
|
|
15399
|
+
else if (end === next.length && next[start - 1] === "\n")
|
|
15400
|
+
start -= 1;
|
|
15401
|
+
next = `${next.slice(0, start)}${next.slice(end)}`;
|
|
15402
|
+
}
|
|
15403
|
+
return next;
|
|
15404
|
+
}
|
|
15147
15405
|
function createDefaultSlots(definition) {
|
|
15406
|
+
const promptSlot = findPromptSlot(definition);
|
|
15407
|
+
const config2 = createGenerationConfigDefaults(definition);
|
|
15408
|
+
const configSlots = definition.inputSchema.filter((slot) => slot.dataType === "json");
|
|
15409
|
+
const configSlot = configSlots.length === 1 ? configSlots[0] : void 0;
|
|
15148
15410
|
return Object.fromEntries(definition.inputSchema.map((slot) => {
|
|
15411
|
+
if (slot === promptSlot) {
|
|
15412
|
+
return [slot.name, [literal({ id: definition.id }, slot.name, "text", "")]];
|
|
15413
|
+
}
|
|
15414
|
+
if (slot === configSlot && config2) {
|
|
15415
|
+
return [
|
|
15416
|
+
slot.name,
|
|
15417
|
+
[literal({ id: definition.id }, slot.name, "json", JSON.stringify(config2))]
|
|
15418
|
+
];
|
|
15419
|
+
}
|
|
15149
15420
|
if (slot.defaultValue === void 0)
|
|
15150
15421
|
return [slot.name, []];
|
|
15151
15422
|
const content = slot.dataType === "json" ? JSON.stringify(slot.defaultValue) : String(slot.defaultValue);
|
|
@@ -15172,11 +15443,14 @@ function requireSingleSlot(definition, dataType, purpose) {
|
|
|
15172
15443
|
return slots[0];
|
|
15173
15444
|
}
|
|
15174
15445
|
function requirePromptSlot(definition) {
|
|
15175
|
-
const slot =
|
|
15446
|
+
const slot = findPromptSlot(definition);
|
|
15176
15447
|
if (!slot)
|
|
15177
15448
|
throw new Error("Workflow Definition must expose a prompt slot.");
|
|
15178
15449
|
return slot;
|
|
15179
15450
|
}
|
|
15451
|
+
function findPromptSlot(definition) {
|
|
15452
|
+
return definition.inputSchema.find((candidate) => candidate.name === "prompt" && candidate.dataType === "text") ?? definition.inputSchema.find((candidate) => candidate.required && candidate.dataType === "text") ?? definition.inputSchema.find((candidate) => candidate.dataType === "text");
|
|
15453
|
+
}
|
|
15180
15454
|
function validateConfig(slot, config2) {
|
|
15181
15455
|
const schema = slot.jsonSchema;
|
|
15182
15456
|
if (!schema)
|
|
@@ -15248,124 +15522,6 @@ function requirePrimaryOutput(definition, contentType) {
|
|
|
15248
15522
|
return output;
|
|
15249
15523
|
}
|
|
15250
15524
|
|
|
15251
|
-
// ../../packages/project-canvas-runtime/dist/generation/planning-contract.js
|
|
15252
|
-
function generationPlanningIssue(code, message, slotName, field) {
|
|
15253
|
-
return {
|
|
15254
|
-
code,
|
|
15255
|
-
message,
|
|
15256
|
-
severity: "error",
|
|
15257
|
-
...slotName ? { slotName } : {},
|
|
15258
|
-
...field ? { field } : {}
|
|
15259
|
-
};
|
|
15260
|
-
}
|
|
15261
|
-
|
|
15262
|
-
// ../../packages/project-canvas-runtime/dist/generation/planning-config.js
|
|
15263
|
-
async function createGenerationConfigPlan(definition, requested, runtime) {
|
|
15264
|
-
const slots = definition.inputSchema.filter((slot2) => slot2.dataType === "json" && (slot2.required || isConfigSlot(slot2)));
|
|
15265
|
-
if (slots.length === 0) {
|
|
15266
|
-
return {
|
|
15267
|
-
fields: [],
|
|
15268
|
-
issues: requested ? [generationPlanningIssue("config-not-supported", "This Workflow Definition does not accept configuration.")] : [],
|
|
15269
|
-
values: null
|
|
15270
|
-
};
|
|
15271
|
-
}
|
|
15272
|
-
if (slots.length !== 1) {
|
|
15273
|
-
return {
|
|
15274
|
-
fields: [],
|
|
15275
|
-
issues: [
|
|
15276
|
-
generationPlanningIssue("multiple-config-slots-unsupported", "Generation Planning currently requires exactly one configuration slot.")
|
|
15277
|
-
],
|
|
15278
|
-
values: null
|
|
15279
|
-
};
|
|
15280
|
-
}
|
|
15281
|
-
const slot = slots[0];
|
|
15282
|
-
const properties = slot.jsonSchema?.properties ?? {};
|
|
15283
|
-
const slotDefaults = readConfigDefaults(slot.defaultValue);
|
|
15284
|
-
const values = {};
|
|
15285
|
-
const issues = [];
|
|
15286
|
-
for (const name of Object.keys(requested ?? {})) {
|
|
15287
|
-
if (!properties[name]) {
|
|
15288
|
-
issues.push(generationPlanningIssue("config-field-unknown", `Unknown configuration field: ${name}.`, slot.name, name));
|
|
15289
|
-
}
|
|
15290
|
-
}
|
|
15291
|
-
const fields = await Promise.all(Object.entries(properties).map(async ([name, property]) => {
|
|
15292
|
-
const normalizedEnum = normalizeConfigEnum(property);
|
|
15293
|
-
if (normalizedEnum?.invalidValues.length) {
|
|
15294
|
-
issues.push(generationPlanningIssue("config-enum-invalid", `Configuration ${name} contains enum values that do not match ${property.type}.`, slot.name, name));
|
|
15295
|
-
}
|
|
15296
|
-
const requestedValue = Object.hasOwn(requested ?? {}, name) ? requested?.[name] : normalizeSchemaConfigValue(slotDefaults[name], property.type);
|
|
15297
|
-
const fallback = configFallback(property, normalizedEnum);
|
|
15298
|
-
if (requestedValue !== void 0 && !isConfigValueValid(requestedValue, property)) {
|
|
15299
|
-
issues.push(generationPlanningIssue("config-value-invalid", `Configuration ${name} is outside its allowed values.`, slot.name, name));
|
|
15300
|
-
}
|
|
15301
|
-
const value = requestedValue !== void 0 && isConfigValueValid(requestedValue, property) ? requestedValue : fallback;
|
|
15302
|
-
values[name] = value;
|
|
15303
|
-
const dynamicOptions = await readDynamicOptions(runtime, name, property, value, issues, slot.name);
|
|
15304
|
-
return {
|
|
15305
|
-
description: property.description ?? "",
|
|
15306
|
-
name,
|
|
15307
|
-
required: slot.jsonSchema?.required?.includes(name) ?? false,
|
|
15308
|
-
type: property.type,
|
|
15309
|
-
value,
|
|
15310
|
-
...property.maximum === void 0 ? {} : { maximum: property.maximum },
|
|
15311
|
-
...property.minimum === void 0 ? {} : { minimum: property.minimum },
|
|
15312
|
-
...dynamicOptions ?? normalizedEnum?.options ? { options: dynamicOptions ?? normalizedEnum?.options } : {}
|
|
15313
|
-
};
|
|
15314
|
-
}));
|
|
15315
|
-
for (const name of slot.jsonSchema?.required ?? []) {
|
|
15316
|
-
if (values[name] === "") {
|
|
15317
|
-
issues.push(generationPlanningIssue("config-field-required", `Configuration ${name} requires a value.`, slot.name, name));
|
|
15318
|
-
}
|
|
15319
|
-
}
|
|
15320
|
-
return { fields, issues, values };
|
|
15321
|
-
}
|
|
15322
|
-
function readConfigDefaults(value) {
|
|
15323
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
15324
|
-
return {};
|
|
15325
|
-
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "boolean" || typeof entry[1] === "string" || typeof entry[1] === "number" && Number.isFinite(entry[1])));
|
|
15326
|
-
}
|
|
15327
|
-
async function readDynamicOptions(runtime, name, property, current, issues, slotName) {
|
|
15328
|
-
const source = property.dynamicEnum;
|
|
15329
|
-
if (property.type !== "string" || !source?.modelKey || !runtime.getDynamicEnumValues)
|
|
15330
|
-
return null;
|
|
15331
|
-
try {
|
|
15332
|
-
const remote = await runtime.getDynamicEnumValues({
|
|
15333
|
-
modelKey: source.modelKey,
|
|
15334
|
-
paramName: name,
|
|
15335
|
-
provider: source.provider
|
|
15336
|
-
});
|
|
15337
|
-
const values = typeof current === "string" && current.trim() ? [current] : [];
|
|
15338
|
-
for (const item of remote)
|
|
15339
|
-
if (!values.includes(item))
|
|
15340
|
-
values.push(item);
|
|
15341
|
-
return values;
|
|
15342
|
-
} catch {
|
|
15343
|
-
issues.push({
|
|
15344
|
-
code: "dynamic-options-unavailable",
|
|
15345
|
-
field: name,
|
|
15346
|
-
message: `Dynamic options for configuration ${name} are temporarily unavailable.`,
|
|
15347
|
-
severity: "warning",
|
|
15348
|
-
slotName
|
|
15349
|
-
});
|
|
15350
|
-
return null;
|
|
15351
|
-
}
|
|
15352
|
-
}
|
|
15353
|
-
function configFallback(property, normalizedEnum) {
|
|
15354
|
-
const normalizedDefault = normalizeSchemaConfigValue(property.default, property.type);
|
|
15355
|
-
if (normalizedDefault !== void 0 && isConfigValueValid(normalizedDefault, property)) {
|
|
15356
|
-
return normalizedDefault;
|
|
15357
|
-
}
|
|
15358
|
-
const first = normalizedEnum?.options[0];
|
|
15359
|
-
if (first !== void 0)
|
|
15360
|
-
return first;
|
|
15361
|
-
if (property.type === "boolean")
|
|
15362
|
-
return false;
|
|
15363
|
-
if (property.type === "number") {
|
|
15364
|
-
return property.minimum ?? (property.maximum && property.maximum < 0 ? property.maximum : 0);
|
|
15365
|
-
}
|
|
15366
|
-
return "";
|
|
15367
|
-
}
|
|
15368
|
-
|
|
15369
15525
|
// ../../packages/project-canvas-runtime/dist/generation/planning-execution.js
|
|
15370
15526
|
function createGenerationExecutionOperations(input) {
|
|
15371
15527
|
const operations = [];
|
|
@@ -15374,10 +15530,10 @@ function createGenerationExecutionOperations(input) {
|
|
|
15374
15530
|
definitionId: input.definition.id,
|
|
15375
15531
|
viewNodeId: input.targetViewNodeId
|
|
15376
15532
|
};
|
|
15377
|
-
if (resolvePromptSlot(input.definition) && input.prompt !== readGenerationDraftPrompt(input.currentDraft)) {
|
|
15533
|
+
if (resolvePromptSlot(input.definition) && (definitionChanges || input.prompt !== readGenerationDraftPrompt(input.currentDraft))) {
|
|
15378
15534
|
editInput.prompt = input.prompt;
|
|
15379
15535
|
}
|
|
15380
|
-
if (!sameConfig(input.config, readGenerationDraftConfig(input.currentDraft))
|
|
15536
|
+
if (input.config && (definitionChanges || !sameConfig(input.config, readGenerationDraftConfig(input.currentDraft)))) {
|
|
15381
15537
|
editInput.config = input.config;
|
|
15382
15538
|
}
|
|
15383
15539
|
if (definitionChanges || Object.keys(editInput).length > 2) {
|
|
@@ -16056,9 +16212,12 @@ var CoreNodeCreativeLoop = class {
|
|
|
16056
16212
|
if (name === "createGenerationTarget")
|
|
16057
16213
|
return this.createGenerationTarget(input, timeoutMs);
|
|
16058
16214
|
if (name === "planGeneration") {
|
|
16215
|
+
if (input.definitionId !== void 0) {
|
|
16216
|
+
await this.requireSelectableDefinition(requireString3(input.definitionId, "definitionId"));
|
|
16217
|
+
}
|
|
16059
16218
|
return {
|
|
16060
16219
|
result: await planGeneration(input, {
|
|
16061
|
-
definitions:
|
|
16220
|
+
definitions: this.selectableDefinitions(),
|
|
16062
16221
|
foundationData: this.systems.foundationData,
|
|
16063
16222
|
getSnapshot: () => this.context.getSnapshot(),
|
|
16064
16223
|
projectContentProjection: this.projection,
|
|
@@ -16086,15 +16245,23 @@ var CoreNodeCreativeLoop = class {
|
|
|
16086
16245
|
throw new Error(`Operation ${name} is outside the Core Node creative loop.`);
|
|
16087
16246
|
}
|
|
16088
16247
|
getDefinitions(detail, definitionId) {
|
|
16089
|
-
const definitions = [...this.definitions.values()].filter((definition) =>
|
|
16248
|
+
const definitions = [...this.definitions.values()].filter((definition) => {
|
|
16249
|
+
if (definitionId)
|
|
16250
|
+
return definition.id === definitionId;
|
|
16251
|
+
return isWorkflowDefinitionAvailable(definition, this.systems.workflowAccessTier);
|
|
16252
|
+
});
|
|
16090
16253
|
return {
|
|
16091
|
-
definitions: definitions.map((definition) =>
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16254
|
+
definitions: definitions.map((definition) => {
|
|
16255
|
+
const access = resolveWorkflowDefinitionAccess(definition, this.systems.workflowAccessTier);
|
|
16256
|
+
return detail ? { ...structuredClone(definition), ...access } : {
|
|
16257
|
+
...access,
|
|
16258
|
+
description: definition.description,
|
|
16259
|
+
id: definition.id,
|
|
16260
|
+
name: definition.name,
|
|
16261
|
+
outputs: definition.outputSchema.map((output) => output.dataType),
|
|
16262
|
+
tags: definition.tags,
|
|
16263
|
+
version: definition.version
|
|
16264
|
+
};
|
|
16098
16265
|
})
|
|
16099
16266
|
};
|
|
16100
16267
|
}
|
|
@@ -16105,6 +16272,18 @@ var CoreNodeCreativeLoop = class {
|
|
|
16105
16272
|
for (const id2 of ids)
|
|
16106
16273
|
await this.recoverWorkflowRun(id2, timeoutMs);
|
|
16107
16274
|
}
|
|
16275
|
+
observePendingWorkflowRuns(ids, timeoutMs) {
|
|
16276
|
+
for (const id2 of new Set(ids)) {
|
|
16277
|
+
if (!this.isPending(id2))
|
|
16278
|
+
continue;
|
|
16279
|
+
void this.recoverWorkflowRun(id2, timeoutMs).catch((error51) => {
|
|
16280
|
+
if (isSettlementWriteAttempt(error51))
|
|
16281
|
+
this.context.reportBackgroundError(error51);
|
|
16282
|
+
else
|
|
16283
|
+
this.scheduleWorkflowRunRecovery(id2, timeoutMs, error51);
|
|
16284
|
+
});
|
|
16285
|
+
}
|
|
16286
|
+
}
|
|
16108
16287
|
close() {
|
|
16109
16288
|
this.closed = true;
|
|
16110
16289
|
for (const subscription of this.subscriptions.values())
|
|
@@ -16203,10 +16382,14 @@ var CoreNodeCreativeLoop = class {
|
|
|
16203
16382
|
assertOnlyKeys3(input, ["contentType", "name", "position"]);
|
|
16204
16383
|
const contentType = requireString3(input.contentType, "contentType");
|
|
16205
16384
|
requireSupportedContentType(contentType);
|
|
16385
|
+
const targetContentType = contentType;
|
|
16386
|
+
const selection = await this.resolveDefaultDefinition(targetContentType);
|
|
16387
|
+
const draft = selection.definition ? createInitialGenerationDraft(selection.definition, selection.preference?.config, this.context.now()) : null;
|
|
16206
16388
|
const viewNode = this.createResourceViewNode(contentType, input.position, optionalString2(input.name), {
|
|
16207
16389
|
creationIntent: "blank",
|
|
16208
16390
|
...contentType === "text" ? { mode: "content" } : {}
|
|
16209
16391
|
}, "generated");
|
|
16392
|
+
viewNode.draft = draft ? toDocumentJson(draft) : null;
|
|
16210
16393
|
await this.context.commit({
|
|
16211
16394
|
after: [viewNode],
|
|
16212
16395
|
before: [],
|
|
@@ -16214,24 +16397,39 @@ var CoreNodeCreativeLoop = class {
|
|
|
16214
16397
|
label: "Create generation target",
|
|
16215
16398
|
timeoutMs
|
|
16216
16399
|
});
|
|
16217
|
-
|
|
16400
|
+
if (draft)
|
|
16401
|
+
await this.rememberWorkflowPreference(targetContentType, draft);
|
|
16402
|
+
return attention(viewNode.id, {
|
|
16403
|
+
...draft ? { definitionId: draft.definitionId, draftId: draft.id } : {},
|
|
16404
|
+
draftInitialized: Boolean(draft),
|
|
16405
|
+
selectionSource: selection.source,
|
|
16406
|
+
viewNodeId: viewNode.id
|
|
16407
|
+
});
|
|
16218
16408
|
}
|
|
16219
16409
|
async editDraft(input, timeoutMs) {
|
|
16220
16410
|
assertOnlyKeys3(input, ["config", "definitionId", "prompt", "viewNodeId"]);
|
|
16221
16411
|
const current = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
|
|
16222
16412
|
const existing = readGenerationDraft(current.draft);
|
|
16223
|
-
const
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16413
|
+
const contentType = current.contentType;
|
|
16414
|
+
const explicitDefinitionId = optionalString2(input.definitionId);
|
|
16415
|
+
const resolved = existing ? {
|
|
16416
|
+
definition: await this.requireSelectableDefinition(explicitDefinitionId ?? existing.definitionId),
|
|
16417
|
+
preference: null,
|
|
16418
|
+
source: explicitDefinitionId ? "explicit" : "existing"
|
|
16419
|
+
} : explicitDefinitionId ? await this.resolveExplicitDefinition(contentType, explicitDefinitionId) : await this.resolveDefaultDefinition(contentType);
|
|
16420
|
+
const definition = resolved.definition;
|
|
16421
|
+
if (!definition) {
|
|
16422
|
+
throw Object.assign(new Error(`No compatible Workflow Definition is available for ${contentType}.`), { code: "no-compatible-workflow" });
|
|
16423
|
+
}
|
|
16227
16424
|
requirePrimaryOutput(definition, current.contentType);
|
|
16228
16425
|
if (input.prompt === void 0 && input.config === void 0 && input.definitionId === void 0) {
|
|
16229
16426
|
throw new Error("Draft edit requires definitionId, prompt, or config.");
|
|
16230
16427
|
}
|
|
16231
16428
|
const config2 = input.config === void 0 ? void 0 : parseConfig2(input.config);
|
|
16232
|
-
const
|
|
16429
|
+
const baseDraft = existing ?? createInitialGenerationDraft(definition, resolved.preference?.config, this.context.now());
|
|
16430
|
+
const nextDraft = editGenerationDraft(baseDraft, definition, {
|
|
16233
16431
|
...config2 ? { config: config2 } : {},
|
|
16234
|
-
...input.definitionId === void 0 ? {} : { definitionId },
|
|
16432
|
+
...input.definitionId === void 0 ? {} : { definitionId: definition.id },
|
|
16235
16433
|
...input.prompt === void 0 ? {} : { prompt: requirePlainString2(input.prompt, "prompt") }
|
|
16236
16434
|
}, this.context.now());
|
|
16237
16435
|
const after = {
|
|
@@ -16246,13 +16444,19 @@ var CoreNodeCreativeLoop = class {
|
|
|
16246
16444
|
label: "Edit generation Draft",
|
|
16247
16445
|
timeoutMs
|
|
16248
16446
|
});
|
|
16249
|
-
|
|
16447
|
+
await this.rememberWorkflowPreference(contentType, nextDraft);
|
|
16448
|
+
return attention(current.id, {
|
|
16449
|
+
definitionId: nextDraft.definitionId,
|
|
16450
|
+
draftId: nextDraft.id,
|
|
16451
|
+
selectionSource: resolved.source,
|
|
16452
|
+
viewNodeId: current.id
|
|
16453
|
+
});
|
|
16250
16454
|
}
|
|
16251
16455
|
async addVisualReference(input, timeoutMs) {
|
|
16252
16456
|
assertOnlyKeys3(input, ["referenceViewNodeId", "viewNodeId"]);
|
|
16253
16457
|
const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
|
|
16254
16458
|
const draft = requireDraft(target);
|
|
16255
|
-
const definition = await this.
|
|
16459
|
+
const definition = await this.requireSelectableDefinition(draft.definitionId);
|
|
16256
16460
|
const referenceViewNodeId = requireString3(input.referenceViewNodeId, "referenceViewNodeId");
|
|
16257
16461
|
const sourceDataType = await this.resolveReferenceDataType(referenceViewNodeId);
|
|
16258
16462
|
const referenceId = `input_ref_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
@@ -16264,14 +16468,12 @@ var CoreNodeCreativeLoop = class {
|
|
|
16264
16468
|
assertOnlyKeys3(input, ["placement", "referenceViewNodeId", "viewNodeId"]);
|
|
16265
16469
|
const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
|
|
16266
16470
|
const draft = requireDraft(target);
|
|
16267
|
-
const definition = await this.
|
|
16471
|
+
const definition = await this.requireSelectableDefinition(draft.definitionId);
|
|
16268
16472
|
const referenceViewNodeId = requireString3(input.referenceViewNodeId, "referenceViewNodeId");
|
|
16269
16473
|
const sourceDataType = await this.resolveReferenceDataType(referenceViewNodeId);
|
|
16270
16474
|
const existing = Object.values(draft.inputs.slots).flat().find((reference) => reference.kind === "view-node" && reference.viewNodeId === referenceViewNodeId);
|
|
16271
16475
|
const referenceId = existing?.id ?? `input_ref_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
16272
|
-
const placement = input.placement
|
|
16273
|
-
if (!placement)
|
|
16274
|
-
throw new Error("placement must be start or end.");
|
|
16476
|
+
const placement = parsePromptReferencePlacement(input.placement);
|
|
16275
16477
|
const nextDraft = insertPromptReferenceIntoDraft(draft, definition, { id: referenceId, kind: "view-node", viewNodeId: referenceViewNodeId }, sourceDataType, placement, this.context.now());
|
|
16276
16478
|
await this.replaceDraft(target, nextDraft, "Insert Prompt Reference", timeoutMs);
|
|
16277
16479
|
return attention(target.id, { placement, referenceId, viewNodeId: target.id });
|
|
@@ -16292,7 +16494,7 @@ var CoreNodeCreativeLoop = class {
|
|
|
16292
16494
|
assertOnlyKeys3(input, ["viewNodeId"]);
|
|
16293
16495
|
const target = this.requireTarget(requireString3(input.viewNodeId, "viewNodeId"));
|
|
16294
16496
|
const draft = requireDraft(target);
|
|
16295
|
-
const definition = await this.
|
|
16497
|
+
const definition = await this.requireSelectableDefinition(draft.definitionId);
|
|
16296
16498
|
const output = requirePrimaryOutput(definition, target.contentType);
|
|
16297
16499
|
const prepared = await prepareGenerationInput({
|
|
16298
16500
|
definition,
|
|
@@ -16708,6 +16910,40 @@ var CoreNodeCreativeLoop = class {
|
|
|
16708
16910
|
this.coreNodes.set(id2, node);
|
|
16709
16911
|
return structuredClone(node);
|
|
16710
16912
|
}
|
|
16913
|
+
async resolveDefaultDefinition(contentType) {
|
|
16914
|
+
const preference = await this.readWorkflowPreference(contentType);
|
|
16915
|
+
return selectDefaultWorkflowDefinition({
|
|
16916
|
+
contentType,
|
|
16917
|
+
definitions: this.selectableDefinitions(),
|
|
16918
|
+
preference
|
|
16919
|
+
});
|
|
16920
|
+
}
|
|
16921
|
+
async resolveExplicitDefinition(contentType, definitionId) {
|
|
16922
|
+
const definition = await this.requireSelectableDefinition(definitionId);
|
|
16923
|
+
requirePrimaryOutput(definition, contentType);
|
|
16924
|
+
const preference = await this.readWorkflowPreference(contentType);
|
|
16925
|
+
return {
|
|
16926
|
+
definition,
|
|
16927
|
+
preference: preference?.definitionId === definition.id ? preference : null,
|
|
16928
|
+
source: "explicit"
|
|
16929
|
+
};
|
|
16930
|
+
}
|
|
16931
|
+
async readWorkflowPreference(contentType) {
|
|
16932
|
+
try {
|
|
16933
|
+
return await this.systems.workflowPreferences?.read(contentType) ?? null;
|
|
16934
|
+
} catch {
|
|
16935
|
+
return null;
|
|
16936
|
+
}
|
|
16937
|
+
}
|
|
16938
|
+
async rememberWorkflowPreference(contentType, draft) {
|
|
16939
|
+
try {
|
|
16940
|
+
await this.systems.workflowPreferences?.write(contentType, {
|
|
16941
|
+
config: readGenerationDraftConfig(draft) ?? {},
|
|
16942
|
+
definitionId: draft.definitionId
|
|
16943
|
+
});
|
|
16944
|
+
} catch {
|
|
16945
|
+
}
|
|
16946
|
+
}
|
|
16711
16947
|
async requireDefinition(id2) {
|
|
16712
16948
|
const cached2 = this.definitions.get(id2);
|
|
16713
16949
|
if (cached2)
|
|
@@ -16718,6 +16954,16 @@ var CoreNodeCreativeLoop = class {
|
|
|
16718
16954
|
this.definitions.set(id2, definition);
|
|
16719
16955
|
return definition;
|
|
16720
16956
|
}
|
|
16957
|
+
async requireSelectableDefinition(id2) {
|
|
16958
|
+
const definition = await this.requireDefinition(id2);
|
|
16959
|
+
if (!isWorkflowDefinitionAvailable(definition, this.systems.workflowAccessTier)) {
|
|
16960
|
+
throw Object.assign(new Error(`Workflow Definition ${id2} is not available to the authenticated account.`), { code: "workflow-not-available-for-account" });
|
|
16961
|
+
}
|
|
16962
|
+
return definition;
|
|
16963
|
+
}
|
|
16964
|
+
selectableDefinitions() {
|
|
16965
|
+
return [...this.definitions.values()].filter((definition) => isWorkflowDefinitionAvailable(definition, this.systems.workflowAccessTier));
|
|
16966
|
+
}
|
|
16721
16967
|
async resolveReferenceDataType(referenceViewNodeId) {
|
|
16722
16968
|
const referenceViewNode = this.requireViewNode(referenceViewNodeId);
|
|
16723
16969
|
if (referenceViewNode.type !== "resource") {
|
|
@@ -16921,6 +17167,38 @@ function requireString3(value, field) {
|
|
|
16921
17167
|
throw new Error(`${field} must be non-empty.`);
|
|
16922
17168
|
return value.trim();
|
|
16923
17169
|
}
|
|
17170
|
+
function parsePromptReferencePlacement(value) {
|
|
17171
|
+
if (value === void 0 || value === "end")
|
|
17172
|
+
return "end";
|
|
17173
|
+
if (value === "start")
|
|
17174
|
+
return "start";
|
|
17175
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
17176
|
+
throw new Error("placement must be start, end, or an anchor placement object.");
|
|
17177
|
+
}
|
|
17178
|
+
const placement = value;
|
|
17179
|
+
assertOnlyKeys3(placement, ["anchor", "kind"]);
|
|
17180
|
+
if (placement.kind !== "before" && placement.kind !== "after") {
|
|
17181
|
+
throw new Error("placement.kind must be before or after.");
|
|
17182
|
+
}
|
|
17183
|
+
if (typeof placement.anchor !== "object" || placement.anchor === null || Array.isArray(placement.anchor)) {
|
|
17184
|
+
throw new Error("placement.anchor must be an object.");
|
|
17185
|
+
}
|
|
17186
|
+
const anchor = placement.anchor;
|
|
17187
|
+
assertOnlyKeys3(anchor, ["occurrence", "text"]);
|
|
17188
|
+
const text = requirePlainString2(anchor.text, "placement.anchor.text");
|
|
17189
|
+
if (!text.trim())
|
|
17190
|
+
throw new Error("placement.anchor.text must be non-empty.");
|
|
17191
|
+
if (anchor.occurrence !== void 0 && (!Number.isInteger(anchor.occurrence) || anchor.occurrence < 1)) {
|
|
17192
|
+
throw new Error("placement.anchor.occurrence must be a positive integer.");
|
|
17193
|
+
}
|
|
17194
|
+
return {
|
|
17195
|
+
anchor: {
|
|
17196
|
+
...anchor.occurrence === void 0 ? {} : { occurrence: anchor.occurrence },
|
|
17197
|
+
text
|
|
17198
|
+
},
|
|
17199
|
+
kind: placement.kind
|
|
17200
|
+
};
|
|
17201
|
+
}
|
|
16924
17202
|
function requirePlainString2(value, field) {
|
|
16925
17203
|
if (typeof value !== "string")
|
|
16926
17204
|
throw new Error(`${field} must be a string.`);
|
|
@@ -17278,8 +17556,8 @@ function parsePosition3(value) {
|
|
|
17278
17556
|
return { x: position.x, y: position.y };
|
|
17279
17557
|
}
|
|
17280
17558
|
function deriveName(url2, contentType) {
|
|
17281
|
-
const
|
|
17282
|
-
const filename = decodeURIComponent(
|
|
17559
|
+
const path10 = new URL(url2).pathname;
|
|
17560
|
+
const filename = decodeURIComponent(path10.split("/").filter(Boolean).at(-1) ?? "");
|
|
17283
17561
|
const withoutExtension = filename.replace(/\.[a-z0-9]+$/i, "").trim();
|
|
17284
17562
|
return withoutExtension || `Imported ${contentType}`;
|
|
17285
17563
|
}
|
|
@@ -17384,9 +17662,12 @@ var MediaUploader = class {
|
|
|
17384
17662
|
this.systems = systems;
|
|
17385
17663
|
this.projection = systems.projectContentProjection;
|
|
17386
17664
|
}
|
|
17387
|
-
async execute(input, timeoutMs) {
|
|
17665
|
+
async execute(input, timeoutMs, onProgress) {
|
|
17388
17666
|
const request = normalizeUploadRequest(input);
|
|
17389
|
-
const
|
|
17667
|
+
const safeProgress = safeProgressListener(onProgress);
|
|
17668
|
+
const prepared = await this.systems.mediaUpload.prepare(request.source, {
|
|
17669
|
+
onProgress: safeProgress
|
|
17670
|
+
});
|
|
17390
17671
|
try {
|
|
17391
17672
|
const descriptor2 = requireValidDescriptor(prepared.descriptor);
|
|
17392
17673
|
const intent = await createIntent(request, descriptor2);
|
|
@@ -17420,9 +17701,10 @@ var MediaUploader = class {
|
|
|
17420
17701
|
let uploaded = false;
|
|
17421
17702
|
let coreNodeId;
|
|
17422
17703
|
try {
|
|
17423
|
-
const object2 = await prepared.upload({ timeoutMs });
|
|
17704
|
+
const object2 = await prepared.upload({ onProgress: safeProgress, timeoutMs });
|
|
17424
17705
|
uploaded = true;
|
|
17425
17706
|
const fileUrl = requireUploadedMediaUrl(object2.url);
|
|
17707
|
+
await safeProgress({ operation: "uploadMedia", stage: "creating-content" });
|
|
17426
17708
|
const completion = await this.systems.projectContent.completeMediaUploads(this.context.projectId, [
|
|
17427
17709
|
{
|
|
17428
17710
|
asset: {
|
|
@@ -17456,6 +17738,7 @@ var MediaUploader = class {
|
|
|
17456
17738
|
await this.updateBindingStatus(viewNode, "failed", errorMessage2(error51), timeoutMs);
|
|
17457
17739
|
throw error51;
|
|
17458
17740
|
}
|
|
17741
|
+
await safeProgress({ operation: "uploadMedia", stage: "updating-canvas" });
|
|
17459
17742
|
await this.updateBindingStatus(viewNode, "ready", null, timeoutMs);
|
|
17460
17743
|
return result2(viewNode.id, coreNodeId, intent, true, uploaded);
|
|
17461
17744
|
} finally {
|
|
@@ -17559,6 +17842,14 @@ var MediaUploader = class {
|
|
|
17559
17842
|
return after;
|
|
17560
17843
|
}
|
|
17561
17844
|
};
|
|
17845
|
+
function safeProgressListener(listener) {
|
|
17846
|
+
return async (progress) => {
|
|
17847
|
+
try {
|
|
17848
|
+
await listener?.(progress);
|
|
17849
|
+
} catch {
|
|
17850
|
+
}
|
|
17851
|
+
};
|
|
17852
|
+
}
|
|
17562
17853
|
var MediaUploadIndeterminateError = class extends Error {
|
|
17563
17854
|
indeterminate = true;
|
|
17564
17855
|
timedOut = false;
|
|
@@ -18328,6 +18619,8 @@ var SemanticCanvasRuntime = class {
|
|
|
18328
18619
|
this.unsubscribeRemote = options.document.subscribeRemoteChange(() => {
|
|
18329
18620
|
const previous = this.snapshot;
|
|
18330
18621
|
this.snapshot = options.document.getSnapshot();
|
|
18622
|
+
const previousPending = new Set(previous.pendingWorkflowInstanceIds);
|
|
18623
|
+
const addedPendingWorkflowInstanceIds = this.snapshot.pendingWorkflowInstanceIds.filter((id2) => !previousPending.has(id2));
|
|
18331
18624
|
const viewNodeChanges = diffSemanticViewNodes(previous.viewNodes, this.snapshot.viewNodes);
|
|
18332
18625
|
this.projectionRevision += 1;
|
|
18333
18626
|
this.emit({
|
|
@@ -18339,6 +18632,9 @@ var SemanticCanvasRuntime = class {
|
|
|
18339
18632
|
revision: this.projectionRevision
|
|
18340
18633
|
});
|
|
18341
18634
|
this.scheduleProjectContentRefresh();
|
|
18635
|
+
if (addedPendingWorkflowInstanceIds.length > 0) {
|
|
18636
|
+
this.creativeLoop?.observePendingWorkflowRuns(addedPendingWorkflowInstanceIds, 15e3);
|
|
18637
|
+
}
|
|
18342
18638
|
});
|
|
18343
18639
|
}
|
|
18344
18640
|
get revision() {
|
|
@@ -18421,7 +18717,7 @@ var SemanticCanvasRuntime = class {
|
|
|
18421
18717
|
this.listeners.add(listener);
|
|
18422
18718
|
return () => this.listeners.delete(listener);
|
|
18423
18719
|
}
|
|
18424
|
-
async execute(name, input, timeoutMs) {
|
|
18720
|
+
async execute(name, input, timeoutMs, options = {}) {
|
|
18425
18721
|
this.requireCapability(name);
|
|
18426
18722
|
if (name === "importExternalMedia") {
|
|
18427
18723
|
if (!this.externalMediaImporter)
|
|
@@ -18432,7 +18728,7 @@ var SemanticCanvasRuntime = class {
|
|
|
18432
18728
|
if (name === "uploadMedia") {
|
|
18433
18729
|
if (!this.mediaUploader)
|
|
18434
18730
|
throw new Error("Media upload system is unavailable.");
|
|
18435
|
-
const result3 = await this.mediaUploader.execute(input, timeoutMs);
|
|
18731
|
+
const result3 = await this.mediaUploader.execute(input, timeoutMs, options.onProgress);
|
|
18436
18732
|
return { ...result3, revision: this.projectionRevision };
|
|
18437
18733
|
}
|
|
18438
18734
|
if (isCreativeLoopOperation(name)) {
|
|
@@ -18766,6 +19062,8 @@ function createCreativeLoop(options, projectContentProjection, context) {
|
|
|
18766
19062
|
foundationData: options.foundationData,
|
|
18767
19063
|
projectContent: options.projectContent,
|
|
18768
19064
|
projectContentProjection,
|
|
19065
|
+
workflowAccessTier: options.workflowAccessTier ?? "paid",
|
|
19066
|
+
workflowPreferences: options.workflowPreferences,
|
|
18769
19067
|
workflowRuntime: options.workflowRuntime
|
|
18770
19068
|
};
|
|
18771
19069
|
return new CoreNodeCreativeLoop(context, systems);
|
|
@@ -18845,6 +19143,114 @@ function normalizeCreationProvenanceSuffix(value) {
|
|
|
18845
19143
|
return normalized;
|
|
18846
19144
|
}
|
|
18847
19145
|
|
|
19146
|
+
// src/cli/workflow-preference-store.ts
|
|
19147
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
19148
|
+
import { chmod, lstat, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
19149
|
+
import { homedir } from "node:os";
|
|
19150
|
+
import path from "node:path";
|
|
19151
|
+
var FORMAT = "az8.workflow-preference.v1";
|
|
19152
|
+
function createNodeWorkflowPreferenceStore(options) {
|
|
19153
|
+
const accountId = options.accountId.trim();
|
|
19154
|
+
if (!accountId) throw new Error("Workflow preference scope requires an account id.");
|
|
19155
|
+
const env = options.env ?? process.env;
|
|
19156
|
+
const stateRoot = path.resolve(
|
|
19157
|
+
options.stateRoot ?? env.AZ8_CLI_STATE_DIR ?? path.join(env.XDG_STATE_HOME ?? path.join(homedir(), ".local", "state"), "az8-cli")
|
|
19158
|
+
);
|
|
19159
|
+
const directory = path.join(stateRoot, "workflow-preferences");
|
|
19160
|
+
return {
|
|
19161
|
+
async read(contentType) {
|
|
19162
|
+
await ensurePrivateDirectory(directory);
|
|
19163
|
+
const filePath = preferencePath(directory, options.environment, accountId, contentType);
|
|
19164
|
+
try {
|
|
19165
|
+
await assertPrivateRegularFile(filePath);
|
|
19166
|
+
return parseStoredPreference(
|
|
19167
|
+
JSON.parse(await readFile(filePath, "utf8")),
|
|
19168
|
+
options.environment,
|
|
19169
|
+
accountId,
|
|
19170
|
+
contentType
|
|
19171
|
+
);
|
|
19172
|
+
} catch (error51) {
|
|
19173
|
+
if (error51.code === "ENOENT") return null;
|
|
19174
|
+
return null;
|
|
19175
|
+
}
|
|
19176
|
+
},
|
|
19177
|
+
async write(contentType, preference) {
|
|
19178
|
+
const normalized = normalizePreference(preference);
|
|
19179
|
+
await ensurePrivateDirectory(directory);
|
|
19180
|
+
const value = {
|
|
19181
|
+
accountId,
|
|
19182
|
+
contentType,
|
|
19183
|
+
environment: options.environment,
|
|
19184
|
+
format: FORMAT,
|
|
19185
|
+
preference: normalized
|
|
19186
|
+
};
|
|
19187
|
+
await writeJsonAtomic(
|
|
19188
|
+
preferencePath(directory, options.environment, accountId, contentType),
|
|
19189
|
+
value
|
|
19190
|
+
);
|
|
19191
|
+
}
|
|
19192
|
+
};
|
|
19193
|
+
}
|
|
19194
|
+
function parseStoredPreference(value, environment, accountId, contentType) {
|
|
19195
|
+
if (!isRecord2(value) || value.format !== FORMAT || value.environment !== environment || value.accountId !== accountId || value.contentType !== contentType) {
|
|
19196
|
+
return null;
|
|
19197
|
+
}
|
|
19198
|
+
try {
|
|
19199
|
+
return normalizePreference(value.preference);
|
|
19200
|
+
} catch {
|
|
19201
|
+
return null;
|
|
19202
|
+
}
|
|
19203
|
+
}
|
|
19204
|
+
function normalizePreference(value) {
|
|
19205
|
+
if (!isRecord2(value) || typeof value.definitionId !== "string" || !value.definitionId.trim()) {
|
|
19206
|
+
throw new Error("Workflow preference requires a Definition id.");
|
|
19207
|
+
}
|
|
19208
|
+
if (!isRecord2(value.config)) throw new Error("Workflow preference config must be an object.");
|
|
19209
|
+
const config2 = Object.fromEntries(
|
|
19210
|
+
Object.entries(value.config).filter(
|
|
19211
|
+
(entry) => typeof entry[1] === "boolean" || typeof entry[1] === "string" || typeof entry[1] === "number" && Number.isFinite(entry[1])
|
|
19212
|
+
)
|
|
19213
|
+
);
|
|
19214
|
+
return { config: config2, definitionId: value.definitionId.trim() };
|
|
19215
|
+
}
|
|
19216
|
+
function preferencePath(directory, environment, accountId, contentType) {
|
|
19217
|
+
const digest = createHash("sha256").update(`${environment}\0${accountId}\0${contentType}`).digest("hex");
|
|
19218
|
+
return path.join(directory, `${digest}.json`);
|
|
19219
|
+
}
|
|
19220
|
+
async function ensurePrivateDirectory(directory) {
|
|
19221
|
+
await mkdir(directory, { mode: 448, recursive: true });
|
|
19222
|
+
const metadata = await lstat(directory);
|
|
19223
|
+
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
19224
|
+
throw new Error("Workflow preference state path is not a private directory.");
|
|
19225
|
+
}
|
|
19226
|
+
if (typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
|
|
19227
|
+
throw new Error("Workflow preference state directory has a different owner.");
|
|
19228
|
+
}
|
|
19229
|
+
await chmod(directory, 448);
|
|
19230
|
+
}
|
|
19231
|
+
async function assertPrivateRegularFile(filePath) {
|
|
19232
|
+
const metadata = await lstat(filePath);
|
|
19233
|
+
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
19234
|
+
throw new Error("Workflow preference state is not a regular file.");
|
|
19235
|
+
}
|
|
19236
|
+
if (typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
|
|
19237
|
+
throw new Error("Workflow preference state has a different owner.");
|
|
19238
|
+
}
|
|
19239
|
+
if ((metadata.mode & 63) !== 0) {
|
|
19240
|
+
throw new Error("Workflow preference state is not owner-private.");
|
|
19241
|
+
}
|
|
19242
|
+
}
|
|
19243
|
+
async function writeJsonAtomic(filePath, value) {
|
|
19244
|
+
const temporary = `${filePath}.${randomUUID()}.tmp`;
|
|
19245
|
+
await writeFile(temporary, `${JSON.stringify(value, null, 2)}
|
|
19246
|
+
`, { mode: 384 });
|
|
19247
|
+
await rename(temporary, filePath);
|
|
19248
|
+
await chmod(filePath, 384);
|
|
19249
|
+
}
|
|
19250
|
+
function isRecord2(value) {
|
|
19251
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19252
|
+
}
|
|
19253
|
+
|
|
18848
19254
|
// src/integrations/backend.ts
|
|
18849
19255
|
var BackendRequestError = class extends Error {
|
|
18850
19256
|
code;
|
|
@@ -18873,7 +19279,7 @@ var Az8BackendClient = class {
|
|
|
18873
19279
|
this.config = config2;
|
|
18874
19280
|
}
|
|
18875
19281
|
config;
|
|
18876
|
-
async request(
|
|
19282
|
+
async request(path10, options = {}) {
|
|
18877
19283
|
const method = options.method ?? "GET";
|
|
18878
19284
|
const token = await this.config.credentials.getToken();
|
|
18879
19285
|
const attempts = options.write ? 1 : 2;
|
|
@@ -18881,7 +19287,7 @@ var Az8BackendClient = class {
|
|
|
18881
19287
|
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
18882
19288
|
let response;
|
|
18883
19289
|
try {
|
|
18884
|
-
response = await this.fetchWithDeadline(
|
|
19290
|
+
response = await this.fetchWithDeadline(path10, token, method, options);
|
|
18885
19291
|
} catch (error51) {
|
|
18886
19292
|
if (options.write) throw new IndeterminateBackendWriteError(error51);
|
|
18887
19293
|
lastError = error51;
|
|
@@ -18893,11 +19299,11 @@ var Az8BackendClient = class {
|
|
|
18893
19299
|
}
|
|
18894
19300
|
throw lastError;
|
|
18895
19301
|
}
|
|
18896
|
-
async fetchWithDeadline(
|
|
19302
|
+
async fetchWithDeadline(path10, token, method, options) {
|
|
18897
19303
|
const abortController2 = new AbortController();
|
|
18898
19304
|
const timeout = setTimeout(() => abortController2.abort(), options.timeoutMs ?? 15e3);
|
|
18899
19305
|
try {
|
|
18900
|
-
return await this.config.fetch(`${this.config.backendUrl}/${
|
|
19306
|
+
return await this.config.fetch(`${this.config.backendUrl}/${path10.replace(/^\/+/, "")}`, {
|
|
18901
19307
|
method,
|
|
18902
19308
|
headers: {
|
|
18903
19309
|
Cookie: `token=${token}`,
|
|
@@ -18942,15 +19348,22 @@ function toAuthenticatedAccount(profile) {
|
|
|
18942
19348
|
const accountId = profile.accountId.trim();
|
|
18943
19349
|
if (!accountId)
|
|
18944
19350
|
throw new Error("Authenticated account profile is missing account id.");
|
|
19351
|
+
const accessTier = isFreeAccount(profile) ? "free" : "paid";
|
|
18945
19352
|
const nickname = profile.nickname?.trim();
|
|
18946
19353
|
if (nickname)
|
|
18947
|
-
return { accountId, displayName: nickname };
|
|
19354
|
+
return { accessTier, accountId, displayName: nickname };
|
|
18948
19355
|
const emailName = profile.email.split("@")[0]?.trim();
|
|
18949
19356
|
return {
|
|
19357
|
+
accessTier,
|
|
18950
19358
|
accountId,
|
|
18951
19359
|
displayName: emailName || `User ${accountId}`
|
|
18952
19360
|
};
|
|
18953
19361
|
}
|
|
19362
|
+
function isFreeAccount(profile) {
|
|
19363
|
+
if (profile.identities)
|
|
19364
|
+
return !profile.identities.includes("valid_user");
|
|
19365
|
+
return (profile.subscriptionType?.trim().toLowerCase() || "free") === "free";
|
|
19366
|
+
}
|
|
18954
19367
|
|
|
18955
19368
|
// src/integrations/account-profile.ts
|
|
18956
19369
|
function createAz8AccountProfileClient(config2) {
|
|
@@ -18985,7 +19398,13 @@ function createAz8AccountProfileRepository(config2) {
|
|
|
18985
19398
|
return {
|
|
18986
19399
|
accountId: String(payload.data.account_id),
|
|
18987
19400
|
email: payload.data.email,
|
|
18988
|
-
...payload.data.
|
|
19401
|
+
...Array.isArray(payload.data.identities) ? {
|
|
19402
|
+
identities: payload.data.identities.filter(
|
|
19403
|
+
(value) => typeof value === "string"
|
|
19404
|
+
)
|
|
19405
|
+
} : {},
|
|
19406
|
+
...payload.data.nickname === void 0 ? {} : { nickname: payload.data.nickname },
|
|
19407
|
+
...payload.data.subscription_type === void 0 ? {} : { subscriptionType: payload.data.subscription_type }
|
|
18989
19408
|
};
|
|
18990
19409
|
}
|
|
18991
19410
|
};
|
|
@@ -19635,10 +20054,10 @@ async function parseStatusEvent(event, onStatus) {
|
|
|
19635
20054
|
}
|
|
19636
20055
|
|
|
19637
20056
|
// src/media/upload.ts
|
|
19638
|
-
import { createHash } from "node:crypto";
|
|
20057
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
19639
20058
|
import { constants } from "node:fs";
|
|
19640
|
-
import { lstat, open } from "node:fs/promises";
|
|
19641
|
-
import
|
|
20059
|
+
import { lstat as lstat2, open } from "node:fs/promises";
|
|
20060
|
+
import path2 from "node:path";
|
|
19642
20061
|
import { Transform } from "node:stream";
|
|
19643
20062
|
|
|
19644
20063
|
// ../../node_modules/.pnpm/strtok3@10.3.5/node_modules/strtok3/lib/stream/Errors.js
|
|
@@ -23510,10 +23929,12 @@ var HASH_BUFFER_BYTES = 256 * 1024;
|
|
|
23510
23929
|
function createNodeCanvasMediaUploadSystem(config2, cwd = process.cwd()) {
|
|
23511
23930
|
const backend = new Az8BackendClient(config2);
|
|
23512
23931
|
return {
|
|
23513
|
-
async prepare(sourceReference) {
|
|
23932
|
+
async prepare(sourceReference, options) {
|
|
23933
|
+
const report = createProgressReporter(options?.onProgress);
|
|
23934
|
+
await report({ bytesCompleted: 0, operation: "uploadMedia", stage: "inspecting" });
|
|
23514
23935
|
const source = await openUploadSource(sourceReference, cwd);
|
|
23515
23936
|
try {
|
|
23516
|
-
const descriptor2 = await inspectUploadSource(source.handle, source.absolutePath);
|
|
23937
|
+
const descriptor2 = await inspectUploadSource(source.handle, source.absolutePath, report);
|
|
23517
23938
|
return createPreparedUpload(config2, backend, source.handle, source.absolutePath, descriptor2);
|
|
23518
23939
|
} catch (error51) {
|
|
23519
23940
|
await source.handle.close().catch(() => void 0);
|
|
@@ -23524,10 +23945,10 @@ function createNodeCanvasMediaUploadSystem(config2, cwd = process.cwd()) {
|
|
|
23524
23945
|
}
|
|
23525
23946
|
async function openUploadSource(sourceReference, cwd) {
|
|
23526
23947
|
if (!sourceReference.trim()) throw new Error("Media upload source must not be blank.");
|
|
23527
|
-
const absolutePath =
|
|
23948
|
+
const absolutePath = path2.resolve(cwd, sourceReference);
|
|
23528
23949
|
let sourceStat;
|
|
23529
23950
|
try {
|
|
23530
|
-
sourceStat = await
|
|
23951
|
+
sourceStat = await lstat2(absolutePath);
|
|
23531
23952
|
} catch {
|
|
23532
23953
|
throw new Error("Media upload source does not exist or cannot be inspected.");
|
|
23533
23954
|
}
|
|
@@ -23547,12 +23968,12 @@ async function openUploadSource(sourceReference, cwd) {
|
|
|
23547
23968
|
}
|
|
23548
23969
|
return { absolutePath, handle };
|
|
23549
23970
|
}
|
|
23550
|
-
async function inspectUploadSource(handle, absolutePath) {
|
|
23971
|
+
async function inspectUploadSource(handle, absolutePath, report) {
|
|
23551
23972
|
const before = await handle.stat();
|
|
23552
23973
|
if (!Number.isSafeInteger(before.size) || before.size < 1) {
|
|
23553
23974
|
throw new Error("Media upload source must contain at least one byte.");
|
|
23554
23975
|
}
|
|
23555
|
-
const hash2 =
|
|
23976
|
+
const hash2 = createHash2("sha256");
|
|
23556
23977
|
const header = Buffer.allocUnsafe(Math.min(FILE_TYPE_HEADER_BYTES, before.size));
|
|
23557
23978
|
const buffer = Buffer.allocUnsafe(Math.min(HASH_BUFFER_BYTES, before.size));
|
|
23558
23979
|
let bytes = 0;
|
|
@@ -23566,6 +23987,7 @@ async function inspectUploadSource(handle, absolutePath) {
|
|
|
23566
23987
|
chunk2.copy(header, bytes, 0, Math.min(chunk2.byteLength, header.byteLength - bytes));
|
|
23567
23988
|
}
|
|
23568
23989
|
bytes += bytesRead;
|
|
23990
|
+
await report(uploadProgress("inspecting", bytes, before.size));
|
|
23569
23991
|
}
|
|
23570
23992
|
const after = await handle.stat();
|
|
23571
23993
|
if (after.size !== before.size || after.mtimeMs !== before.mtimeMs) {
|
|
@@ -23579,7 +24001,7 @@ async function inspectUploadSource(handle, absolutePath) {
|
|
|
23579
24001
|
return {
|
|
23580
24002
|
bytes,
|
|
23581
24003
|
extension: detected.ext,
|
|
23582
|
-
fileName:
|
|
24004
|
+
fileName: path2.basename(absolutePath),
|
|
23583
24005
|
lastModified: Math.max(0, Math.round(after.mtimeMs)),
|
|
23584
24006
|
mediaType,
|
|
23585
24007
|
mimeType: detected.mime,
|
|
@@ -23602,6 +24024,10 @@ function createPreparedUpload(config2, backend, handle, absolutePath, descriptor
|
|
|
23602
24024
|
if (closed) throw new Error("Prepared media upload is already closed.");
|
|
23603
24025
|
if (attempted) throw new Error("Prepared media upload can only be attempted once.");
|
|
23604
24026
|
attempted = true;
|
|
24027
|
+
await reportProgress(options?.onProgress, {
|
|
24028
|
+
operation: "uploadMedia",
|
|
24029
|
+
stage: "requesting-upload"
|
|
24030
|
+
});
|
|
23605
24031
|
const presign = await backend.request("core_nodes/upload/presign", {
|
|
23606
24032
|
json: { format: descriptor2.extension, type: descriptor2.mediaType },
|
|
23607
24033
|
method: "POST",
|
|
@@ -23610,12 +24036,20 @@ function createPreparedUpload(config2, backend, handle, absolutePath, descriptor
|
|
|
23610
24036
|
});
|
|
23611
24037
|
const uploadUrl = requireHttpUrl(presign.upload_url, "upload");
|
|
23612
24038
|
const fileUrl = requireHttpUrl(presign.file_url, "file");
|
|
23613
|
-
await putPreparedFile(
|
|
24039
|
+
await putPreparedFile(
|
|
24040
|
+
config2,
|
|
24041
|
+
handle,
|
|
24042
|
+
absolutePath,
|
|
24043
|
+
descriptor2,
|
|
24044
|
+
uploadUrl,
|
|
24045
|
+
options?.timeoutMs,
|
|
24046
|
+
createProgressReporter(options?.onProgress)
|
|
24047
|
+
);
|
|
23614
24048
|
return { url: fileUrl };
|
|
23615
24049
|
}
|
|
23616
24050
|
};
|
|
23617
24051
|
}
|
|
23618
|
-
async function putPreparedFile(config2, handle, absolutePath, descriptor2, uploadUrl, timeoutMs) {
|
|
24052
|
+
async function putPreparedFile(config2, handle, absolutePath, descriptor2, uploadUrl, timeoutMs, report) {
|
|
23619
24053
|
const originalStat = await handle.stat();
|
|
23620
24054
|
const uploadHandle = await open(absolutePath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
23621
24055
|
let uploadStat;
|
|
@@ -23634,13 +24068,17 @@ async function putPreparedFile(config2, handle, absolutePath, descriptor2, uploa
|
|
|
23634
24068
|
() => controller.abort(new Error("Media upload timed out.")),
|
|
23635
24069
|
timeoutMs ?? 3e5
|
|
23636
24070
|
);
|
|
23637
|
-
const hash2 =
|
|
24071
|
+
const hash2 = createHash2("sha256");
|
|
23638
24072
|
let bytes = 0;
|
|
24073
|
+
await report(uploadProgress("uploading", 0, descriptor2.bytes));
|
|
23639
24074
|
const meter = new Transform({
|
|
23640
24075
|
transform(chunk2, _encoding, callback) {
|
|
23641
24076
|
hash2.update(chunk2);
|
|
23642
24077
|
bytes += chunk2.byteLength;
|
|
23643
|
-
|
|
24078
|
+
Promise.resolve(report(uploadProgress("uploading", bytes, descriptor2.bytes))).then(
|
|
24079
|
+
() => callback(null, chunk2),
|
|
24080
|
+
callback
|
|
24081
|
+
);
|
|
23644
24082
|
}
|
|
23645
24083
|
});
|
|
23646
24084
|
const source = uploadHandle.createReadStream({
|
|
@@ -23676,6 +24114,35 @@ async function putPreparedFile(config2, handle, absolutePath, descriptor2, uploa
|
|
|
23676
24114
|
throw new Error("Media upload source changed before the upload completed.");
|
|
23677
24115
|
}
|
|
23678
24116
|
}
|
|
24117
|
+
function createProgressReporter(listener) {
|
|
24118
|
+
let lastStage = "";
|
|
24119
|
+
let lastReportedAt = 0;
|
|
24120
|
+
return async (progress) => {
|
|
24121
|
+
if (!listener) return;
|
|
24122
|
+
const now = Date.now();
|
|
24123
|
+
const complete = progress.bytesTotal !== void 0 && progress.bytesCompleted === progress.bytesTotal;
|
|
24124
|
+
const stageChanged = progress.stage !== lastStage;
|
|
24125
|
+
if (!stageChanged && !complete && now - lastReportedAt < 500) return;
|
|
24126
|
+
lastStage = progress.stage;
|
|
24127
|
+
lastReportedAt = now;
|
|
24128
|
+
await reportProgress(listener, progress);
|
|
24129
|
+
};
|
|
24130
|
+
}
|
|
24131
|
+
async function reportProgress(listener, progress) {
|
|
24132
|
+
try {
|
|
24133
|
+
await listener?.(progress);
|
|
24134
|
+
} catch {
|
|
24135
|
+
}
|
|
24136
|
+
}
|
|
24137
|
+
function uploadProgress(stage, bytesCompleted, bytesTotal) {
|
|
24138
|
+
return {
|
|
24139
|
+
bytesCompleted,
|
|
24140
|
+
bytesTotal,
|
|
24141
|
+
operation: "uploadMedia",
|
|
24142
|
+
percent: Math.min(100, Math.round(bytesCompleted / bytesTotal * 1e3) / 10),
|
|
24143
|
+
stage
|
|
24144
|
+
};
|
|
24145
|
+
}
|
|
23679
24146
|
function requireHttpUrl(value, kind) {
|
|
23680
24147
|
if (typeof value !== "string" || !value.trim()) {
|
|
23681
24148
|
throw new Error(`Media upload presign returned no ${kind} URL.`);
|
|
@@ -23744,8 +24211,19 @@ var COLLABORATION_SESSION_STATES = [
|
|
|
23744
24211
|
];
|
|
23745
24212
|
|
|
23746
24213
|
// src/canvas/watch/interest-registry.ts
|
|
24214
|
+
var SYSTEM_WORKFLOW_TERMINAL_INTEREST_KEY = "system.workflow-terminal";
|
|
23747
24215
|
var CollaborationInterestRegistry = class {
|
|
23748
24216
|
interests = /* @__PURE__ */ new Map();
|
|
24217
|
+
constructor(includeSystemWorkflowTerminal = false) {
|
|
24218
|
+
if (includeSystemWorkflowTerminal) {
|
|
24219
|
+
this.interests.set(SYSTEM_WORKFLOW_TERMINAL_INTEREST_KEY, {
|
|
24220
|
+
filter: { terminalOnly: true },
|
|
24221
|
+
key: SYSTEM_WORKFLOW_TERMINAL_INTEREST_KEY,
|
|
24222
|
+
kind: "workflow",
|
|
24223
|
+
system: true
|
|
24224
|
+
});
|
|
24225
|
+
}
|
|
24226
|
+
}
|
|
23749
24227
|
patch(input) {
|
|
23750
24228
|
const upserts = input.upsert ?? [];
|
|
23751
24229
|
const removals = input.remove ?? [];
|
|
@@ -23755,6 +24233,9 @@ var CollaborationInterestRegistry = class {
|
|
|
23755
24233
|
for (const entry of upserts) {
|
|
23756
24234
|
const key = requireKey(entry.key);
|
|
23757
24235
|
const current = next.get(key);
|
|
24236
|
+
if (current?.system) {
|
|
24237
|
+
throw interestError("system-interest-readonly", `System Interest ${key} cannot be changed.`);
|
|
24238
|
+
}
|
|
23758
24239
|
if (entry.patch.kind !== void 0 && !isInterestKind(entry.patch.kind)) {
|
|
23759
24240
|
throw interestError(
|
|
23760
24241
|
"interest-kind-invalid",
|
|
@@ -23775,6 +24256,9 @@ var CollaborationInterestRegistry = class {
|
|
|
23775
24256
|
}
|
|
23776
24257
|
for (const rawKey of removals) {
|
|
23777
24258
|
const key = requireKey(rawKey);
|
|
24259
|
+
if (next.get(key)?.system) {
|
|
24260
|
+
throw interestError("system-interest-readonly", `System Interest ${key} cannot be removed.`);
|
|
24261
|
+
}
|
|
23778
24262
|
if (next.delete(key)) changedKeys.push(key);
|
|
23779
24263
|
}
|
|
23780
24264
|
this.interests.clear();
|
|
@@ -23813,7 +24297,7 @@ function matches(interest, fact) {
|
|
|
23813
24297
|
return !filter.states || filter.states.includes(fact.state);
|
|
23814
24298
|
}
|
|
23815
24299
|
function patchFilter(current, patch) {
|
|
23816
|
-
if (!
|
|
24300
|
+
if (!isRecord3(patch)) {
|
|
23817
24301
|
throw interestError("interest-filter-invalid", "Interest filter patch must be an object.");
|
|
23818
24302
|
}
|
|
23819
24303
|
const next = structuredClone(current);
|
|
@@ -23828,7 +24312,7 @@ function validateFilter(kind, filter) {
|
|
|
23828
24312
|
validateFilterEntries(kind, Object.entries(filter));
|
|
23829
24313
|
}
|
|
23830
24314
|
function validateFilterPatch(kind, filter) {
|
|
23831
|
-
if (!
|
|
24315
|
+
if (!isRecord3(filter)) {
|
|
23832
24316
|
throw interestError("interest-filter-invalid", "Interest filter patch must be an object.");
|
|
23833
24317
|
}
|
|
23834
24318
|
validateFilterEntries(kind, Object.entries(filter));
|
|
@@ -23922,7 +24406,7 @@ function assertAllowed(values, allowed, label) {
|
|
|
23922
24406
|
function isInterestKind(value) {
|
|
23923
24407
|
return value === "canvas" || value === "session" || value === "workflow";
|
|
23924
24408
|
}
|
|
23925
|
-
function
|
|
24409
|
+
function isRecord3(value) {
|
|
23926
24410
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23927
24411
|
}
|
|
23928
24412
|
function interestError(code, message) {
|
|
@@ -23930,11 +24414,11 @@ function interestError(code, message) {
|
|
|
23930
24414
|
}
|
|
23931
24415
|
|
|
23932
24416
|
// src/canvas/watch/project-observation.ts
|
|
23933
|
-
function projectCanvasObservation(observation, observedAt) {
|
|
24417
|
+
function projectCanvasObservation(observation, observedAt, workflowTarget) {
|
|
23934
24418
|
const viewNodeFacts = (observation.viewNodeChanges ?? []).map(
|
|
23935
24419
|
(change) => projectViewNodeChange(change, observation.kind, observedAt)
|
|
23936
24420
|
);
|
|
23937
|
-
return observation.workflowRun ? [...viewNodeFacts, projectWorkflowRun(observation.workflowRun, observedAt)] : viewNodeFacts;
|
|
24421
|
+
return observation.workflowRun ? [...viewNodeFacts, projectWorkflowRun(observation.workflowRun, observedAt, workflowTarget)] : viewNodeFacts;
|
|
23938
24422
|
}
|
|
23939
24423
|
function projectSessionState(input) {
|
|
23940
24424
|
return {
|
|
@@ -23969,7 +24453,7 @@ function projectViewNodeChange(change, source, observedAt) {
|
|
|
23969
24453
|
...typeof viewNode.type === "string" ? { viewNodeType: viewNode.type } : {}
|
|
23970
24454
|
};
|
|
23971
24455
|
}
|
|
23972
|
-
function projectWorkflowRun(run, observedAt) {
|
|
24456
|
+
function projectWorkflowRun(run, observedAt, target) {
|
|
23973
24457
|
const terminal = isTerminalWorkflowRunStatus(run.status);
|
|
23974
24458
|
return {
|
|
23975
24459
|
changeKind: terminal ? `workflow.${run.status}` : "workflow.progress",
|
|
@@ -23980,6 +24464,7 @@ function projectWorkflowRun(run, observedAt) {
|
|
|
23980
24464
|
status: run.status,
|
|
23981
24465
|
summary: {
|
|
23982
24466
|
definitionId: run.definitionId,
|
|
24467
|
+
workflowRunId: run.id,
|
|
23983
24468
|
...run.error ? {
|
|
23984
24469
|
error: {
|
|
23985
24470
|
...run.error.code ? { code: run.error.code } : {},
|
|
@@ -23987,8 +24472,10 @@ function projectWorkflowRun(run, observedAt) {
|
|
|
23987
24472
|
}
|
|
23988
24473
|
} : {},
|
|
23989
24474
|
...run.progress === void 0 ? {} : { progress: run.progress },
|
|
24475
|
+
...target?.status === "resolved" ? { viewNodeId: target.viewNodeId } : terminal ? { targetResolution: target?.status ?? "unresolved" } : {},
|
|
23990
24476
|
...run.outputs.length > 0 ? {
|
|
23991
24477
|
outputs: run.outputs.map((output) => ({
|
|
24478
|
+
coreNodeId: output.coreNodeId,
|
|
23992
24479
|
role: output.role,
|
|
23993
24480
|
slotName: output.slotName,
|
|
23994
24481
|
...output.viewNodeId ? { viewNodeId: output.viewNodeId } : {}
|
|
@@ -24002,7 +24489,7 @@ function projectWorkflowRun(run, observedAt) {
|
|
|
24002
24489
|
function summarizeViewNode(change) {
|
|
24003
24490
|
const viewNode = change.after ?? change.before;
|
|
24004
24491
|
if (!viewNode) return {};
|
|
24005
|
-
const data =
|
|
24492
|
+
const data = isRecord4(viewNode.data) ? viewNode.data : {};
|
|
24006
24493
|
const summary = {
|
|
24007
24494
|
...typeof viewNode.contentType === "string" ? { contentType: viewNode.contentType } : {},
|
|
24008
24495
|
...typeof data.label === "string" ? { name: data.label } : {},
|
|
@@ -24013,10 +24500,10 @@ function summarizeViewNode(change) {
|
|
|
24013
24500
|
if (typeof data.color === "string") summary.color = data.color;
|
|
24014
24501
|
if (typeof data.creator_name === "string") summary.creatorName = data.creator_name;
|
|
24015
24502
|
}
|
|
24016
|
-
if (change.changedFields.includes("position") &&
|
|
24503
|
+
if (change.changedFields.includes("position") && isRecord4(viewNode.position)) {
|
|
24017
24504
|
summary.position = structuredClone(viewNode.position);
|
|
24018
24505
|
}
|
|
24019
|
-
if (change.changedFields.includes("size") &&
|
|
24506
|
+
if (change.changedFields.includes("size") && isRecord4(viewNode.size)) {
|
|
24020
24507
|
summary.size = structuredClone(viewNode.size);
|
|
24021
24508
|
}
|
|
24022
24509
|
if (change.changedFields.includes("parent")) summary.parentId = viewNode.parentId ?? null;
|
|
@@ -24034,7 +24521,7 @@ function fieldGroup(field) {
|
|
|
24034
24521
|
if (field === "parent" || field === "stacking") return "hierarchy";
|
|
24035
24522
|
return field;
|
|
24036
24523
|
}
|
|
24037
|
-
function
|
|
24524
|
+
function isRecord4(value) {
|
|
24038
24525
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24039
24526
|
}
|
|
24040
24527
|
function safeWorkflowMessage(value) {
|
|
@@ -24043,7 +24530,7 @@ function safeWorkflowMessage(value) {
|
|
|
24043
24530
|
|
|
24044
24531
|
// src/canvas/watch/watch.ts
|
|
24045
24532
|
var AgentCollaborationWatch = class {
|
|
24046
|
-
interests
|
|
24533
|
+
interests;
|
|
24047
24534
|
maxChangesPerDelivery;
|
|
24048
24535
|
maxPendingChanges;
|
|
24049
24536
|
maxRecentResults;
|
|
@@ -24054,6 +24541,7 @@ var AgentCollaborationWatch = class {
|
|
|
24054
24541
|
activeWait = null;
|
|
24055
24542
|
continuityLost = false;
|
|
24056
24543
|
constructor(options = {}) {
|
|
24544
|
+
this.interests = new CollaborationInterestRegistry(options.includeSystemWorkflowTerminal);
|
|
24057
24545
|
this.maxChangesPerDelivery = positive(
|
|
24058
24546
|
options.maxChangesPerDelivery ?? 64,
|
|
24059
24547
|
"maxChangesPerDelivery"
|
|
@@ -24289,7 +24777,7 @@ var CanvasSession = class {
|
|
|
24289
24777
|
this.projectId = projectId;
|
|
24290
24778
|
this.dependencies = dependencies;
|
|
24291
24779
|
this.clientInstanceId = clientInstanceId;
|
|
24292
|
-
this.watch = dependencies.watch ?? new AgentCollaborationWatch();
|
|
24780
|
+
this.watch = dependencies.watch ?? new AgentCollaborationWatch({ includeSystemWorkflowTerminal: true });
|
|
24293
24781
|
this.health = {
|
|
24294
24782
|
connectionAttempts: 0,
|
|
24295
24783
|
connectionId: null,
|
|
@@ -24308,6 +24796,7 @@ var CanvasSession = class {
|
|
|
24308
24796
|
unsubscribeRuntime = null;
|
|
24309
24797
|
observationListeners = /* @__PURE__ */ new Set();
|
|
24310
24798
|
knownWorkflowRunIds = /* @__PURE__ */ new Set();
|
|
24799
|
+
knownWorkflowTargets = /* @__PURE__ */ new Map();
|
|
24311
24800
|
projectionRevision = 0;
|
|
24312
24801
|
actorId = null;
|
|
24313
24802
|
collaborationContext = null;
|
|
@@ -24372,17 +24861,29 @@ var CanvasSession = class {
|
|
|
24372
24861
|
projectContents: contentSync.contents,
|
|
24373
24862
|
projectId: authenticated.id,
|
|
24374
24863
|
role: authenticated.role,
|
|
24864
|
+
workflowAccessTier: actor.accessTier,
|
|
24375
24865
|
workflowDefinitions,
|
|
24866
|
+
workflowPreferences: this.dependencies.workflowPreferences?.(actor),
|
|
24376
24867
|
workflowRuntime
|
|
24377
24868
|
});
|
|
24378
24869
|
this.runtime = runtime;
|
|
24379
24870
|
for (const workflowRunId of runtime.getSnapshot().pendingWorkflowInstanceIds) {
|
|
24380
24871
|
this.knownWorkflowRunIds.add(workflowRunId);
|
|
24872
|
+
this.retainWorkflowTarget(workflowRunId);
|
|
24381
24873
|
}
|
|
24382
24874
|
this.projectionRevision = runtime.revision;
|
|
24383
24875
|
this.unsubscribeRuntime = runtime.subscribe((observation) => {
|
|
24384
24876
|
this.projectionRevision = observation.revision;
|
|
24385
|
-
|
|
24877
|
+
if (observation.workflowRun) {
|
|
24878
|
+
this.knownWorkflowRunIds.add(observation.workflowRun.id);
|
|
24879
|
+
}
|
|
24880
|
+
this.watch.recordMany(
|
|
24881
|
+
projectCanvasObservation(
|
|
24882
|
+
observation,
|
|
24883
|
+
Date.now(),
|
|
24884
|
+
observation.workflowRun ? this.resolveWorkflowTarget(observation.workflowRun.id) : void 0
|
|
24885
|
+
)
|
|
24886
|
+
);
|
|
24386
24887
|
const legacyObservation = {
|
|
24387
24888
|
...observation.changedViewNodeIds ? { changedViewNodeIds: observation.changedViewNodeIds } : {},
|
|
24388
24889
|
kind: observation.kind,
|
|
@@ -24400,14 +24901,29 @@ var CanvasSession = class {
|
|
|
24400
24901
|
throw error51;
|
|
24401
24902
|
}
|
|
24402
24903
|
}
|
|
24403
|
-
async execute(name, input, timeoutMs) {
|
|
24904
|
+
async execute(name, input, timeoutMs, options = {}) {
|
|
24404
24905
|
const runtime = this.requireRuntime();
|
|
24405
24906
|
if (typeof input.workflowRunId === "string" && input.workflowRunId) {
|
|
24406
24907
|
this.knownWorkflowRunIds.add(input.workflowRunId);
|
|
24407
24908
|
}
|
|
24408
|
-
|
|
24909
|
+
let result3;
|
|
24910
|
+
try {
|
|
24911
|
+
result3 = await runtime.execute(name, input, timeoutMs, options);
|
|
24912
|
+
} catch (error51) {
|
|
24913
|
+
const indeterminate = readCanvasOperationIndeterminateResult(error51);
|
|
24914
|
+
if (typeof indeterminate?.workflowRunId === "string" && indeterminate.workflowRunId && typeof indeterminate.viewNodeId === "string" && indeterminate.viewNodeId) {
|
|
24915
|
+
this.knownWorkflowRunIds.add(indeterminate.workflowRunId);
|
|
24916
|
+
this.knownWorkflowTargets.set(indeterminate.workflowRunId, indeterminate.viewNodeId);
|
|
24917
|
+
}
|
|
24918
|
+
throw error51;
|
|
24919
|
+
}
|
|
24409
24920
|
if (typeof result3.result.workflowRunId === "string" && result3.result.workflowRunId) {
|
|
24410
24921
|
this.knownWorkflowRunIds.add(result3.result.workflowRunId);
|
|
24922
|
+
if (typeof result3.result.viewNodeId === "string" && result3.result.viewNodeId) {
|
|
24923
|
+
this.knownWorkflowTargets.set(result3.result.workflowRunId, result3.result.viewNodeId);
|
|
24924
|
+
} else {
|
|
24925
|
+
this.retainWorkflowTarget(result3.result.workflowRunId);
|
|
24926
|
+
}
|
|
24411
24927
|
}
|
|
24412
24928
|
this.projectionRevision = result3.revision;
|
|
24413
24929
|
if (result3.attention) this.publishAttention(result3.attention);
|
|
@@ -24431,7 +24947,8 @@ var CanvasSession = class {
|
|
|
24431
24947
|
if (!isWorkflowRun(workflowRun)) continue;
|
|
24432
24948
|
for (const fact of projectCanvasObservation(
|
|
24433
24949
|
{ kind: "workflow", revision: result3.revision, workflowRun },
|
|
24434
|
-
Date.now()
|
|
24950
|
+
Date.now(),
|
|
24951
|
+
this.resolveWorkflowTarget(workflowRun.id)
|
|
24435
24952
|
)) {
|
|
24436
24953
|
this.watch.recordAuthoritativeWorkflow(fact);
|
|
24437
24954
|
}
|
|
@@ -24530,6 +25047,28 @@ var CanvasSession = class {
|
|
|
24530
25047
|
this.document = null;
|
|
24531
25048
|
this.health.connectionId = null;
|
|
24532
25049
|
}
|
|
25050
|
+
resolveWorkflowTarget(workflowRunId) {
|
|
25051
|
+
const retained = this.knownWorkflowTargets.get(workflowRunId);
|
|
25052
|
+
if (!this.runtime) {
|
|
25053
|
+
return retained ? { status: "resolved", viewNodeId: retained } : { status: "unresolved" };
|
|
25054
|
+
}
|
|
25055
|
+
const current = resolveWorkflowTargetFromSnapshot(this.runtime.getSnapshot(), workflowRunId);
|
|
25056
|
+
if (current.status === "ambiguous") return current;
|
|
25057
|
+
if (current.status === "resolved") {
|
|
25058
|
+
if (retained && retained !== current.viewNodeId) return { status: "ambiguous" };
|
|
25059
|
+
this.knownWorkflowTargets.set(workflowRunId, current.viewNodeId);
|
|
25060
|
+
return current;
|
|
25061
|
+
}
|
|
25062
|
+
return retained ? { status: "resolved", viewNodeId: retained } : current;
|
|
25063
|
+
}
|
|
25064
|
+
retainWorkflowTarget(workflowRunId) {
|
|
25065
|
+
if (!this.runtime) return { status: "unresolved" };
|
|
25066
|
+
const resolution = resolveWorkflowTargetFromSnapshot(this.runtime.getSnapshot(), workflowRunId);
|
|
25067
|
+
if (resolution.status === "resolved") {
|
|
25068
|
+
this.knownWorkflowTargets.set(workflowRunId, resolution.viewNodeId);
|
|
25069
|
+
}
|
|
25070
|
+
return resolution;
|
|
25071
|
+
}
|
|
24533
25072
|
transition(state, onState) {
|
|
24534
25073
|
const previousState = this.health.state;
|
|
24535
25074
|
this.health.state = state;
|
|
@@ -24588,7 +25127,12 @@ var CanvasClient = class {
|
|
|
24588
25127
|
session;
|
|
24589
25128
|
receipts = [];
|
|
24590
25129
|
constructor(config2, projectId, session) {
|
|
24591
|
-
this.session = session ?? new CanvasSession(config2, projectId
|
|
25130
|
+
this.session = session ?? new CanvasSession(config2, projectId, void 0, {
|
|
25131
|
+
workflowPreferences: (actor) => createNodeWorkflowPreferenceStore({
|
|
25132
|
+
accountId: actor.accountId,
|
|
25133
|
+
environment: config2.environment
|
|
25134
|
+
})
|
|
25135
|
+
});
|
|
24592
25136
|
}
|
|
24593
25137
|
async connect(displayName, onState) {
|
|
24594
25138
|
await this.session.connect(displayName, onState);
|
|
@@ -24654,7 +25198,9 @@ var CanvasClient = class {
|
|
|
24654
25198
|
};
|
|
24655
25199
|
this.receipts.push(receipt);
|
|
24656
25200
|
try {
|
|
24657
|
-
const operation = await this.session.execute(name, input.input, input.timeoutMs ?? 15e3
|
|
25201
|
+
const operation = await this.session.execute(name, input.input, input.timeoutMs ?? 15e3, {
|
|
25202
|
+
onProgress: input.onProgress
|
|
25203
|
+
});
|
|
24658
25204
|
Object.assign(receipt, {
|
|
24659
25205
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24660
25206
|
projectionRevisionAfter: operation.revision,
|
|
@@ -24747,8 +25293,8 @@ function readTimedOut(value) {
|
|
|
24747
25293
|
}
|
|
24748
25294
|
|
|
24749
25295
|
// src/cli/config.ts
|
|
24750
|
-
import { readFile } from "node:fs/promises";
|
|
24751
|
-
import
|
|
25296
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
25297
|
+
import path3 from "node:path";
|
|
24752
25298
|
var DEFAULT_ENV_FILE = ".env.local";
|
|
24753
25299
|
var DEFAULT_ENVIRONMENT = "production";
|
|
24754
25300
|
var ENVIRONMENT_ORIGINS = {
|
|
@@ -24758,7 +25304,7 @@ var ENVIRONMENT_ORIGINS = {
|
|
|
24758
25304
|
async function resolveCliConfig(options, dependencies) {
|
|
24759
25305
|
const cwd = dependencies.cwd ?? process.cwd();
|
|
24760
25306
|
const envFile = options.envFile;
|
|
24761
|
-
const fileEnvironment = envFile ? await readEnvironmentFile(
|
|
25307
|
+
const fileEnvironment = envFile ? await readEnvironmentFile(path3.resolve(cwd, envFile)) : await readDefaultEnvironmentFile(cwd);
|
|
24762
25308
|
const environmentVariables = {
|
|
24763
25309
|
...fileEnvironment,
|
|
24764
25310
|
...dependencies.env ?? process.env
|
|
@@ -24780,6 +25326,7 @@ async function resolveCliConfig(options, dependencies) {
|
|
|
24780
25326
|
return token;
|
|
24781
25327
|
}
|
|
24782
25328
|
},
|
|
25329
|
+
environment,
|
|
24783
25330
|
fetch: dependencies.fetch ?? globalThis.fetch,
|
|
24784
25331
|
serviceUrl: normalizeUrl(
|
|
24785
25332
|
options.serviceUrl ?? environmentVariables.AZ8_SERVICE_URL ?? `${origin}/api`
|
|
@@ -24793,7 +25340,7 @@ function readEnvironment(value) {
|
|
|
24793
25340
|
}
|
|
24794
25341
|
async function readEnvironmentFile(filePath) {
|
|
24795
25342
|
try {
|
|
24796
|
-
const contents = await
|
|
25343
|
+
const contents = await readFile2(filePath, "utf8");
|
|
24797
25344
|
return Object.fromEntries(
|
|
24798
25345
|
contents.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap((line) => {
|
|
24799
25346
|
const separator = line.indexOf("=");
|
|
@@ -24809,11 +25356,11 @@ async function readEnvironmentFile(filePath) {
|
|
|
24809
25356
|
}
|
|
24810
25357
|
}
|
|
24811
25358
|
async function readDefaultEnvironmentFile(cwd) {
|
|
24812
|
-
let directory =
|
|
25359
|
+
let directory = path3.resolve(cwd);
|
|
24813
25360
|
while (true) {
|
|
24814
|
-
const environment = await readEnvironmentFile(
|
|
25361
|
+
const environment = await readEnvironmentFile(path3.join(directory, DEFAULT_ENV_FILE));
|
|
24815
25362
|
if (Object.keys(environment).length > 0) return environment;
|
|
24816
|
-
const parent =
|
|
25363
|
+
const parent = path3.dirname(directory);
|
|
24817
25364
|
if (parent === directory) return {};
|
|
24818
25365
|
directory = parent;
|
|
24819
25366
|
}
|
|
@@ -24823,11 +25370,11 @@ function normalizeUrl(value) {
|
|
|
24823
25370
|
}
|
|
24824
25371
|
|
|
24825
25372
|
// src/agent-session/rpc.ts
|
|
24826
|
-
import { chmod, unlink } from "node:fs/promises";
|
|
25373
|
+
import { chmod as chmod2, unlink } from "node:fs/promises";
|
|
24827
25374
|
import net from "node:net";
|
|
24828
25375
|
var MAX_RPC_REQUEST_BYTES = 1024 * 1024;
|
|
24829
25376
|
var MAX_RPC_RESPONSE_BYTES = 16 * 1024 * 1024;
|
|
24830
|
-
async function requestAgentSession(socketPath, request, timeoutMs = 5e3, signal) {
|
|
25377
|
+
async function requestAgentSession(socketPath, request, timeoutMs = 5e3, signal, onProgress) {
|
|
24831
25378
|
return new Promise((resolve, reject) => {
|
|
24832
25379
|
const socket = net.createConnection(socketPath);
|
|
24833
25380
|
let source = "";
|
|
@@ -24857,14 +25404,23 @@ async function requestAgentSession(socketPath, request, timeoutMs = 5e3, signal)
|
|
|
24857
25404
|
finish(rpcError("session-rpc-too-large", "Agent Session RPC response is too large."));
|
|
24858
25405
|
return;
|
|
24859
25406
|
}
|
|
24860
|
-
|
|
24861
|
-
|
|
24862
|
-
|
|
24863
|
-
const
|
|
24864
|
-
|
|
24865
|
-
|
|
24866
|
-
|
|
24867
|
-
|
|
25407
|
+
while (!settled) {
|
|
25408
|
+
const newline = source.indexOf("\n");
|
|
25409
|
+
if (newline < 0) return;
|
|
25410
|
+
const line = source.slice(0, newline);
|
|
25411
|
+
source = source.slice(newline + 1);
|
|
25412
|
+
try {
|
|
25413
|
+
const message = JSON.parse(line);
|
|
25414
|
+
if ("type" in message && message.type === "progress") {
|
|
25415
|
+
void Promise.resolve(onProgress?.(message.progress)).catch(() => void 0);
|
|
25416
|
+
continue;
|
|
25417
|
+
}
|
|
25418
|
+
const response = message;
|
|
25419
|
+
if (!response.ok) finish(rpcError(response.error.code, response.error.message));
|
|
25420
|
+
else finish(void 0, response.value);
|
|
25421
|
+
} catch {
|
|
25422
|
+
finish(rpcError("invalid-session-rpc", "Agent Session RPC response is invalid."));
|
|
25423
|
+
}
|
|
24868
25424
|
}
|
|
24869
25425
|
});
|
|
24870
25426
|
socket.once("error", (error51) => finish(error51));
|
|
@@ -24903,7 +25459,10 @@ async function listenAgentSessionRpc(socketPath, handler) {
|
|
|
24903
25459
|
handled = true;
|
|
24904
25460
|
try {
|
|
24905
25461
|
const request = JSON.parse(source.slice(0, newline));
|
|
24906
|
-
const value = await handler(request, {
|
|
25462
|
+
const value = await handler(request, {
|
|
25463
|
+
reportProgress: (progress) => writeProgress(socket, progress),
|
|
25464
|
+
signal: abortController2.signal
|
|
25465
|
+
});
|
|
24907
25466
|
writeResponse(socket, { ok: true, value });
|
|
24908
25467
|
} catch (error51) {
|
|
24909
25468
|
writeResponse(
|
|
@@ -24923,7 +25482,7 @@ async function listenAgentSessionRpc(socketPath, handler) {
|
|
|
24923
25482
|
resolve();
|
|
24924
25483
|
});
|
|
24925
25484
|
});
|
|
24926
|
-
await
|
|
25485
|
+
await chmod2(socketPath, 384);
|
|
24927
25486
|
return {
|
|
24928
25487
|
async close() {
|
|
24929
25488
|
const closed = new Promise(
|
|
@@ -24935,6 +25494,13 @@ async function listenAgentSessionRpc(socketPath, handler) {
|
|
|
24935
25494
|
}
|
|
24936
25495
|
};
|
|
24937
25496
|
}
|
|
25497
|
+
function writeProgress(socket, progress) {
|
|
25498
|
+
if (socket.destroyed || !socket.writable) return Promise.resolve();
|
|
25499
|
+
return new Promise((resolve) => {
|
|
25500
|
+
socket.write(`${JSON.stringify({ progress, type: "progress" })}
|
|
25501
|
+
`, () => resolve());
|
|
25502
|
+
});
|
|
25503
|
+
}
|
|
24938
25504
|
function writeResponse(socket, response) {
|
|
24939
25505
|
if (socket.destroyed) return;
|
|
24940
25506
|
socket.end(`${JSON.stringify(response)}
|
|
@@ -24961,20 +25527,20 @@ async function unlinkIfPresent(filePath) {
|
|
|
24961
25527
|
}
|
|
24962
25528
|
|
|
24963
25529
|
// src/agent-session/state-store.ts
|
|
24964
|
-
import { createHash as
|
|
25530
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
24965
25531
|
import {
|
|
24966
|
-
chmod as
|
|
24967
|
-
lstat as
|
|
24968
|
-
mkdir,
|
|
25532
|
+
chmod as chmod3,
|
|
25533
|
+
lstat as lstat3,
|
|
25534
|
+
mkdir as mkdir2,
|
|
24969
25535
|
readdir,
|
|
24970
|
-
readFile as
|
|
25536
|
+
readFile as readFile3,
|
|
24971
25537
|
realpath,
|
|
24972
|
-
rename,
|
|
25538
|
+
rename as rename2,
|
|
24973
25539
|
unlink as unlink2,
|
|
24974
|
-
writeFile
|
|
25540
|
+
writeFile as writeFile2
|
|
24975
25541
|
} from "node:fs/promises";
|
|
24976
|
-
import { homedir } from "node:os";
|
|
24977
|
-
import
|
|
25542
|
+
import { homedir as homedir2 } from "node:os";
|
|
25543
|
+
import path4 from "node:path";
|
|
24978
25544
|
|
|
24979
25545
|
// src/agent-session/types.ts
|
|
24980
25546
|
var AGENT_SESSION_FORMAT = "az8.agent-session.v1";
|
|
@@ -24987,44 +25553,44 @@ var AgentSessionStateStore = class {
|
|
|
24987
25553
|
stateRoot;
|
|
24988
25554
|
env;
|
|
24989
25555
|
constructor(options = {}) {
|
|
24990
|
-
this.cwd =
|
|
25556
|
+
this.cwd = path4.resolve(options.cwd ?? process.cwd());
|
|
24991
25557
|
this.env = options.env ?? process.env;
|
|
24992
|
-
this.stateRoot =
|
|
24993
|
-
options.stateRoot ?? this.env.AZ8_CLI_STATE_DIR ??
|
|
25558
|
+
this.stateRoot = path4.resolve(
|
|
25559
|
+
options.stateRoot ?? this.env.AZ8_CLI_STATE_DIR ?? path4.join(this.env.XDG_STATE_HOME ?? path4.join(homedir2(), ".local", "state"), "az8-cli")
|
|
24994
25560
|
);
|
|
24995
25561
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
24996
|
-
const defaultRuntimeRoot = process.platform === "linux" && this.env.XDG_RUNTIME_DIR ?
|
|
24997
|
-
this.runtimeRoot =
|
|
25562
|
+
const defaultRuntimeRoot = process.platform === "linux" && this.env.XDG_RUNTIME_DIR ? path4.join(this.env.XDG_RUNTIME_DIR, "az8-cli") : path4.join("/tmp", `az8-cli-${uid}`);
|
|
25563
|
+
this.runtimeRoot = path4.resolve(options.runtimeRoot ?? defaultRuntimeRoot);
|
|
24998
25564
|
}
|
|
24999
25565
|
createSessionId() {
|
|
25000
|
-
return `session_${
|
|
25566
|
+
return `session_${randomUUID2()}`;
|
|
25001
25567
|
}
|
|
25002
25568
|
async initialize() {
|
|
25003
25569
|
await Promise.all([
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25570
|
+
ensurePrivateDirectory2(this.stateRoot),
|
|
25571
|
+
ensurePrivateDirectory2(this.runtimeRoot),
|
|
25572
|
+
ensurePrivateDirectory2(this.descriptorsDirectory()),
|
|
25573
|
+
ensurePrivateDirectory2(this.contextsDirectory()),
|
|
25574
|
+
ensurePrivateDirectory2(this.launchesDirectory())
|
|
25009
25575
|
]);
|
|
25010
25576
|
}
|
|
25011
25577
|
descriptorPath(sessionId) {
|
|
25012
|
-
return
|
|
25578
|
+
return path4.join(this.descriptorsDirectory(), `${requireSessionId(sessionId)}.json`);
|
|
25013
25579
|
}
|
|
25014
25580
|
socketPath(sessionId) {
|
|
25015
|
-
const digest =
|
|
25016
|
-
return
|
|
25581
|
+
const digest = createHash3("sha256").update(requireSessionId(sessionId)).digest("hex").slice(0, 24);
|
|
25582
|
+
return path4.join(this.runtimeRoot, `${digest}.sock`);
|
|
25017
25583
|
}
|
|
25018
25584
|
async writeDescriptor(descriptor2) {
|
|
25019
25585
|
assertDescriptor(descriptor2);
|
|
25020
25586
|
await this.initialize();
|
|
25021
|
-
await
|
|
25587
|
+
await writeJsonAtomic2(this.descriptorPath(descriptor2.sessionId), descriptor2);
|
|
25022
25588
|
}
|
|
25023
25589
|
async readDescriptor(sessionId) {
|
|
25024
25590
|
await this.initialize();
|
|
25025
25591
|
const filePath = this.descriptorPath(sessionId);
|
|
25026
|
-
await
|
|
25027
|
-
const value = JSON.parse(await
|
|
25592
|
+
await assertPrivateRegularFile2(filePath);
|
|
25593
|
+
const value = JSON.parse(await readFile3(filePath, "utf8"));
|
|
25028
25594
|
assertDescriptor(value);
|
|
25029
25595
|
return value;
|
|
25030
25596
|
}
|
|
@@ -25046,25 +25612,25 @@ var AgentSessionStateStore = class {
|
|
|
25046
25612
|
}
|
|
25047
25613
|
async writeLaunchSpec(spec) {
|
|
25048
25614
|
await this.initialize();
|
|
25049
|
-
const filePath =
|
|
25050
|
-
await
|
|
25615
|
+
const filePath = path4.join(this.launchesDirectory(), `${requireSessionId(spec.sessionId)}.json`);
|
|
25616
|
+
await writeJsonAtomic2(filePath, spec);
|
|
25051
25617
|
return filePath;
|
|
25052
25618
|
}
|
|
25053
25619
|
async deleteLaunchSpec(sessionId) {
|
|
25054
25620
|
await unlinkIfPresent2(
|
|
25055
|
-
|
|
25621
|
+
path4.join(this.launchesDirectory(), `${requireSessionId(sessionId)}.json`)
|
|
25056
25622
|
);
|
|
25057
25623
|
}
|
|
25058
25624
|
async selectCurrent(sessionId) {
|
|
25059
25625
|
await this.readDescriptor(sessionId);
|
|
25060
25626
|
const context = await this.contextIdentity();
|
|
25061
|
-
await
|
|
25627
|
+
await writeJsonAtomic2(this.contextPath(context), { context, sessionId });
|
|
25062
25628
|
}
|
|
25063
25629
|
async readCurrent() {
|
|
25064
25630
|
await this.initialize();
|
|
25065
25631
|
const context = await this.contextIdentity();
|
|
25066
25632
|
try {
|
|
25067
|
-
const value = JSON.parse(await
|
|
25633
|
+
const value = JSON.parse(await readFile3(this.contextPath(context), "utf8"));
|
|
25068
25634
|
if (value.context !== context || typeof value.sessionId !== "string") return void 0;
|
|
25069
25635
|
return requireSessionId(value.sessionId);
|
|
25070
25636
|
} catch (error51) {
|
|
@@ -25088,13 +25654,13 @@ var AgentSessionStateStore = class {
|
|
|
25088
25654
|
return requireSessionId(selected);
|
|
25089
25655
|
}
|
|
25090
25656
|
descriptorsDirectory() {
|
|
25091
|
-
return
|
|
25657
|
+
return path4.join(this.stateRoot, "sessions");
|
|
25092
25658
|
}
|
|
25093
25659
|
contextsDirectory() {
|
|
25094
|
-
return
|
|
25660
|
+
return path4.join(this.stateRoot, "contexts");
|
|
25095
25661
|
}
|
|
25096
25662
|
launchesDirectory() {
|
|
25097
|
-
return
|
|
25663
|
+
return path4.join(this.stateRoot, "launches");
|
|
25098
25664
|
}
|
|
25099
25665
|
async contextIdentity() {
|
|
25100
25666
|
const override = this.env.AZ8_CONTEXT?.trim();
|
|
@@ -25106,16 +25672,16 @@ var AgentSessionStateStore = class {
|
|
|
25106
25672
|
}
|
|
25107
25673
|
}
|
|
25108
25674
|
contextPath(context) {
|
|
25109
|
-
const digest =
|
|
25110
|
-
return
|
|
25675
|
+
const digest = createHash3("sha256").update(context).digest("hex");
|
|
25676
|
+
return path4.join(this.contextsDirectory(), `${digest}.json`);
|
|
25111
25677
|
}
|
|
25112
25678
|
};
|
|
25113
25679
|
async function readAndDeleteLaunchSpec(filePath) {
|
|
25114
|
-
if (
|
|
25680
|
+
if (path4.basename(path4.dirname(filePath)) !== "launches") {
|
|
25115
25681
|
throw sessionStateError("invalid-session-launch", "Session launch path is invalid.");
|
|
25116
25682
|
}
|
|
25117
|
-
await
|
|
25118
|
-
const value = JSON.parse(await
|
|
25683
|
+
await assertPrivateRegularFile2(filePath);
|
|
25684
|
+
const value = JSON.parse(await readFile3(filePath, "utf8"));
|
|
25119
25685
|
assertLaunchSpec(value, filePath);
|
|
25120
25686
|
await unlinkIfPresent2(filePath);
|
|
25121
25687
|
return value;
|
|
@@ -25137,30 +25703,30 @@ function assertLaunchSpec(value, launchPath) {
|
|
|
25137
25703
|
throw sessionStateError("invalid-session-launch", "Session launch descriptor is invalid.");
|
|
25138
25704
|
}
|
|
25139
25705
|
const sessionId = requireSessionId(value.sessionId);
|
|
25140
|
-
const stateRoot =
|
|
25141
|
-
const expectedLaunch =
|
|
25142
|
-
if (
|
|
25706
|
+
const stateRoot = path4.resolve(value.stateRoot);
|
|
25707
|
+
const expectedLaunch = path4.join(stateRoot, "launches", `${sessionId}.json`);
|
|
25708
|
+
if (path4.resolve(launchPath) !== expectedLaunch) {
|
|
25143
25709
|
throw sessionStateError(
|
|
25144
25710
|
"invalid-session-launch",
|
|
25145
25711
|
"Session launch identity does not match its path."
|
|
25146
25712
|
);
|
|
25147
25713
|
}
|
|
25148
|
-
const expectedDescriptor =
|
|
25149
|
-
if (
|
|
25714
|
+
const expectedDescriptor = path4.join(stateRoot, "sessions", `${sessionId}.json`);
|
|
25715
|
+
if (path4.resolve(value.descriptorPath) !== expectedDescriptor) {
|
|
25150
25716
|
throw sessionStateError("invalid-session-launch", "Session descriptor path is invalid.");
|
|
25151
25717
|
}
|
|
25152
|
-
const socketDigest =
|
|
25153
|
-
const expectedSocket =
|
|
25154
|
-
|
|
25718
|
+
const socketDigest = createHash3("sha256").update(sessionId).digest("hex").slice(0, 24);
|
|
25719
|
+
const expectedSocket = path4.join(
|
|
25720
|
+
path4.resolve(value.runtimeRoot),
|
|
25155
25721
|
`${socketDigest}.sock`
|
|
25156
25722
|
);
|
|
25157
|
-
if (
|
|
25723
|
+
if (path4.resolve(value.socketPath) !== expectedSocket) {
|
|
25158
25724
|
throw sessionStateError("invalid-session-launch", "Session socket path is invalid.");
|
|
25159
25725
|
}
|
|
25160
25726
|
}
|
|
25161
|
-
async function
|
|
25162
|
-
await
|
|
25163
|
-
const metadata = await
|
|
25727
|
+
async function ensurePrivateDirectory2(directory) {
|
|
25728
|
+
await mkdir2(directory, { mode: 448, recursive: true });
|
|
25729
|
+
const metadata = await lstat3(directory);
|
|
25164
25730
|
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
25165
25731
|
throw sessionStateError(
|
|
25166
25732
|
"unsafe-session-state",
|
|
@@ -25173,10 +25739,10 @@ async function ensurePrivateDirectory(directory) {
|
|
|
25173
25739
|
"Session state directory has a different owner."
|
|
25174
25740
|
);
|
|
25175
25741
|
}
|
|
25176
|
-
await
|
|
25742
|
+
await chmod3(directory, 448);
|
|
25177
25743
|
}
|
|
25178
|
-
async function
|
|
25179
|
-
const metadata = await
|
|
25744
|
+
async function assertPrivateRegularFile2(filePath) {
|
|
25745
|
+
const metadata = await lstat3(filePath);
|
|
25180
25746
|
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
25181
25747
|
throw sessionStateError("unsafe-session-state", "Session state file is not a regular file.");
|
|
25182
25748
|
}
|
|
@@ -25187,12 +25753,12 @@ async function assertPrivateRegularFile(filePath) {
|
|
|
25187
25753
|
throw sessionStateError("unsafe-session-state", "Session state file is not owner-private.");
|
|
25188
25754
|
}
|
|
25189
25755
|
}
|
|
25190
|
-
async function
|
|
25191
|
-
const temporary = `${filePath}.${
|
|
25192
|
-
await
|
|
25756
|
+
async function writeJsonAtomic2(filePath, value) {
|
|
25757
|
+
const temporary = `${filePath}.${randomUUID2()}.tmp`;
|
|
25758
|
+
await writeFile2(temporary, `${JSON.stringify(value, null, 2)}
|
|
25193
25759
|
`, { mode: 384 });
|
|
25194
|
-
await
|
|
25195
|
-
await
|
|
25760
|
+
await rename2(temporary, filePath);
|
|
25761
|
+
await chmod3(filePath, 384);
|
|
25196
25762
|
}
|
|
25197
25763
|
async function unlinkIfPresent2(filePath) {
|
|
25198
25764
|
try {
|
|
@@ -25339,6 +25905,7 @@ async function startAgentSessionDaemon(spec, dependencies = {}) {
|
|
|
25339
25905
|
return await client.executeOperation({
|
|
25340
25906
|
input: request.input,
|
|
25341
25907
|
name: request.name,
|
|
25908
|
+
onProgress: context.reportProgress,
|
|
25342
25909
|
requestId: request.requestId,
|
|
25343
25910
|
...request.timeoutMs ? { timeoutMs: request.timeoutMs } : {}
|
|
25344
25911
|
});
|
|
@@ -25347,6 +25914,7 @@ async function startAgentSessionDaemon(spec, dependencies = {}) {
|
|
|
25347
25914
|
() => client.executeOperation({
|
|
25348
25915
|
input: request.input,
|
|
25349
25916
|
name: request.name,
|
|
25917
|
+
onProgress: context.reportProgress,
|
|
25350
25918
|
requestId: request.requestId,
|
|
25351
25919
|
...request.timeoutMs ? { timeoutMs: request.timeoutMs } : {}
|
|
25352
25920
|
})
|
|
@@ -25383,7 +25951,13 @@ async function createCanvasClient(spec, dependencies) {
|
|
|
25383
25951
|
...dependencies,
|
|
25384
25952
|
cwd: spec.cwd
|
|
25385
25953
|
});
|
|
25386
|
-
const session = new CanvasSession(config2, spec.projectId
|
|
25954
|
+
const session = new CanvasSession(config2, spec.projectId, void 0, {
|
|
25955
|
+
workflowPreferences: (actor) => createNodeWorkflowPreferenceStore({
|
|
25956
|
+
accountId: actor.accountId,
|
|
25957
|
+
environment: config2.environment,
|
|
25958
|
+
stateRoot: spec.stateRoot
|
|
25959
|
+
})
|
|
25960
|
+
});
|
|
25387
25961
|
const client = new CanvasClient(config2, spec.projectId, session);
|
|
25388
25962
|
await client.connect(spec.clientName);
|
|
25389
25963
|
return {
|
|
@@ -25437,13 +26011,13 @@ function assertRequest(request) {
|
|
|
25437
26011
|
code: "invalid-watch-timeout"
|
|
25438
26012
|
});
|
|
25439
26013
|
}
|
|
25440
|
-
if (request.kind === "interests.patch" && !
|
|
26014
|
+
if (request.kind === "interests.patch" && !isRecord5(request.input)) invalidPayload();
|
|
25441
26015
|
if (request.kind === "query") {
|
|
25442
|
-
if (!
|
|
26016
|
+
if (!isRecord5(request.input) || typeof request.input.target !== "string") invalidPayload();
|
|
25443
26017
|
parseCanvasQueryTarget(request.input.target);
|
|
25444
26018
|
}
|
|
25445
26019
|
if (request.kind === "operation") {
|
|
25446
|
-
if (!
|
|
26020
|
+
if (!isRecord5(request.input) || typeof request.name !== "string" || typeof request.requestId !== "string" || request.requestId.length === 0 || request.timeoutMs !== void 0 && (!Number.isInteger(request.timeoutMs) || request.timeoutMs < 1)) {
|
|
25447
26021
|
invalidPayload();
|
|
25448
26022
|
}
|
|
25449
26023
|
}
|
|
@@ -25459,7 +26033,7 @@ function invalidPayload() {
|
|
|
25459
26033
|
code: "invalid-session-request"
|
|
25460
26034
|
});
|
|
25461
26035
|
}
|
|
25462
|
-
function
|
|
26036
|
+
function isRecord5(value) {
|
|
25463
26037
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25464
26038
|
}
|
|
25465
26039
|
function readErrorCode2(error51) {
|
|
@@ -25795,6 +26369,11 @@ var CanvasProtocolServer = class {
|
|
|
25795
26369
|
const outcome = await this.client.executeOperation({
|
|
25796
26370
|
input: request.payload.input,
|
|
25797
26371
|
name: request.payload.name,
|
|
26372
|
+
onProgress: (progress) => this.output.emitMandatory({
|
|
26373
|
+
payload: progress,
|
|
26374
|
+
requestId: request.requestId,
|
|
26375
|
+
type: "operationProgress"
|
|
26376
|
+
}),
|
|
25798
26377
|
requestId: request.requestId,
|
|
25799
26378
|
...request.payload.timeoutMs ? { timeoutMs: request.payload.timeoutMs } : {}
|
|
25800
26379
|
});
|
|
@@ -26191,7 +26770,7 @@ function humanReadableArgName(arg) {
|
|
|
26191
26770
|
// ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/command.js
|
|
26192
26771
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
26193
26772
|
import childProcess from "node:child_process";
|
|
26194
|
-
import
|
|
26773
|
+
import path5 from "node:path";
|
|
26195
26774
|
import fs from "node:fs";
|
|
26196
26775
|
import process2 from "node:process";
|
|
26197
26776
|
import { stripVTControlCharacters as stripVTControlCharacters2 } from "node:util";
|
|
@@ -28177,9 +28756,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
28177
28756
|
args2 = args2.slice();
|
|
28178
28757
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
28179
28758
|
function findFile(baseDir, baseName) {
|
|
28180
|
-
const localBin =
|
|
28759
|
+
const localBin = path5.resolve(baseDir, baseName);
|
|
28181
28760
|
if (fs.existsSync(localBin)) return localBin;
|
|
28182
|
-
if (sourceExt.includes(
|
|
28761
|
+
if (sourceExt.includes(path5.extname(baseName))) return void 0;
|
|
28183
28762
|
const foundExt = sourceExt.find(
|
|
28184
28763
|
(ext) => fs.existsSync(`${localBin}${ext}`)
|
|
28185
28764
|
);
|
|
@@ -28197,17 +28776,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
28197
28776
|
} catch {
|
|
28198
28777
|
resolvedScriptPath = this._scriptPath;
|
|
28199
28778
|
}
|
|
28200
|
-
executableDir =
|
|
28201
|
-
|
|
28779
|
+
executableDir = path5.resolve(
|
|
28780
|
+
path5.dirname(resolvedScriptPath),
|
|
28202
28781
|
executableDir
|
|
28203
28782
|
);
|
|
28204
28783
|
}
|
|
28205
28784
|
if (executableDir) {
|
|
28206
28785
|
let localFile = findFile(executableDir, executableFile);
|
|
28207
28786
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
28208
|
-
const legacyName =
|
|
28787
|
+
const legacyName = path5.basename(
|
|
28209
28788
|
this._scriptPath,
|
|
28210
|
-
|
|
28789
|
+
path5.extname(this._scriptPath)
|
|
28211
28790
|
);
|
|
28212
28791
|
if (legacyName !== this._name) {
|
|
28213
28792
|
localFile = findFile(
|
|
@@ -28218,7 +28797,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
28218
28797
|
}
|
|
28219
28798
|
executableFile = localFile || executableFile;
|
|
28220
28799
|
}
|
|
28221
|
-
const launchWithNode = sourceExt.includes(
|
|
28800
|
+
const launchWithNode = sourceExt.includes(path5.extname(executableFile));
|
|
28222
28801
|
let proc;
|
|
28223
28802
|
if (process2.platform !== "win32") {
|
|
28224
28803
|
if (launchWithNode) {
|
|
@@ -29135,7 +29714,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29135
29714
|
* @return {Command}
|
|
29136
29715
|
*/
|
|
29137
29716
|
nameFromFilename(filename) {
|
|
29138
|
-
this._name =
|
|
29717
|
+
this._name = path5.basename(filename, path5.extname(filename));
|
|
29139
29718
|
return this;
|
|
29140
29719
|
}
|
|
29141
29720
|
/**
|
|
@@ -29149,9 +29728,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29149
29728
|
* @param {string} [path]
|
|
29150
29729
|
* @return {(string|null|Command)}
|
|
29151
29730
|
*/
|
|
29152
|
-
executableDir(
|
|
29153
|
-
if (
|
|
29154
|
-
this._executableDir =
|
|
29731
|
+
executableDir(path10) {
|
|
29732
|
+
if (path10 === void 0) return this._executableDir;
|
|
29733
|
+
this._executableDir = path10;
|
|
29155
29734
|
return this;
|
|
29156
29735
|
}
|
|
29157
29736
|
/**
|
|
@@ -29407,8 +29986,8 @@ function useColor() {
|
|
|
29407
29986
|
var program = new Command();
|
|
29408
29987
|
|
|
29409
29988
|
// src/canvas/one-shot.ts
|
|
29410
|
-
import { readFile as
|
|
29411
|
-
import
|
|
29989
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
29990
|
+
import path6 from "node:path";
|
|
29412
29991
|
var MAX_INPUT_BYTES = 1024 * 1024;
|
|
29413
29992
|
var PROCESS_SCOPED_OPERATIONS = /* @__PURE__ */ new Set(["redo", "undo"]);
|
|
29414
29993
|
var PROCESS_SCOPED_QUERIES = /* @__PURE__ */ new Set(["receipt.detail", "receipts.summary"]);
|
|
@@ -29434,6 +30013,9 @@ async function runCanvasOneShot(config2, command, dependencies = {}) {
|
|
|
29434
30013
|
input: command.input,
|
|
29435
30014
|
name: command.name,
|
|
29436
30015
|
requestId: command.requestId,
|
|
30016
|
+
...dependencies.onProgress ? {
|
|
30017
|
+
onProgress: (progress) => dependencies.onProgress?.({ ...progress, requestId: command.requestId })
|
|
30018
|
+
} : {},
|
|
29437
30019
|
...command.timeoutMs ? { timeoutMs: command.timeoutMs } : {}
|
|
29438
30020
|
});
|
|
29439
30021
|
return operationResult(command, outcome);
|
|
@@ -29457,9 +30039,9 @@ async function readCanvasOneShotInputOptions(options, dependencies = {}) {
|
|
|
29457
30039
|
let source = "{}";
|
|
29458
30040
|
if (inline !== void 0) source = inline;
|
|
29459
30041
|
if (file2 !== void 0) {
|
|
29460
|
-
const filePath =
|
|
30042
|
+
const filePath = path6.resolve(dependencies.cwd ?? process.cwd(), file2);
|
|
29461
30043
|
try {
|
|
29462
|
-
source = dependencies.readFile ? await dependencies.readFile(filePath) : await
|
|
30044
|
+
source = dependencies.readFile ? await dependencies.readFile(filePath) : await readFile4(filePath, "utf8");
|
|
29463
30045
|
} catch {
|
|
29464
30046
|
throw canvasClientFailure(
|
|
29465
30047
|
"invalid-operation-input",
|
|
@@ -29580,9 +30162,9 @@ function formatZodError(error51) {
|
|
|
29580
30162
|
}
|
|
29581
30163
|
|
|
29582
30164
|
// src/media/download.ts
|
|
29583
|
-
import { createHash as
|
|
29584
|
-
import { link, lstat as
|
|
29585
|
-
import
|
|
30165
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
30166
|
+
import { link, lstat as lstat4, open as open2, rename as rename3, stat, unlink as unlink3 } from "node:fs/promises";
|
|
30167
|
+
import path7 from "node:path";
|
|
29586
30168
|
|
|
29587
30169
|
// ../../packages/foundation-data/dist/media.js
|
|
29588
30170
|
var CoreNodeMediaResolutionError = class extends Error {
|
|
@@ -29619,21 +30201,24 @@ function resolveDownloadableCoreNodeMedia(coreNode) {
|
|
|
29619
30201
|
|
|
29620
30202
|
// src/media/download.ts
|
|
29621
30203
|
var DEFAULT_RESOLUTION_TIMEOUT_MS = 15e3;
|
|
30204
|
+
var DEFAULT_DOWNLOAD_ATTEMPTS = 3;
|
|
29622
30205
|
var FILE_TYPE_HEADER_BYTES2 = 64 * 1024;
|
|
29623
30206
|
var MediaDownloadError = class extends Error {
|
|
29624
|
-
constructor(code, message, exitCode, retryable) {
|
|
30207
|
+
constructor(code, message, exitCode, retryable, details = {}) {
|
|
29625
30208
|
super(message);
|
|
29626
30209
|
this.code = code;
|
|
29627
30210
|
this.exitCode = exitCode;
|
|
29628
30211
|
this.retryable = retryable;
|
|
30212
|
+
this.details = details;
|
|
29629
30213
|
this.name = "MediaDownloadError";
|
|
29630
30214
|
}
|
|
29631
30215
|
code;
|
|
29632
30216
|
exitCode;
|
|
29633
30217
|
retryable;
|
|
30218
|
+
details;
|
|
29634
30219
|
};
|
|
29635
30220
|
async function runCanvasMediaDownload(config2, command, dependencies = {}) {
|
|
29636
|
-
const requestedAbsolutePath =
|
|
30221
|
+
const requestedAbsolutePath = path7.resolve(dependencies.cwd ?? process.cwd(), command.outputPath);
|
|
29637
30222
|
let outputTarget;
|
|
29638
30223
|
try {
|
|
29639
30224
|
outputTarget = await prepareOutputTarget(
|
|
@@ -29645,48 +30230,86 @@ async function runCanvasMediaDownload(config2, command, dependencies = {}) {
|
|
|
29645
30230
|
} catch (error51) {
|
|
29646
30231
|
return failureResult2(command, error51, requestedAbsolutePath);
|
|
29647
30232
|
}
|
|
29648
|
-
|
|
29649
|
-
|
|
29650
|
-
|
|
29651
|
-
|
|
29652
|
-
|
|
29653
|
-
|
|
29654
|
-
|
|
29655
|
-
|
|
29656
|
-
|
|
29657
|
-
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
|
|
29661
|
-
|
|
29662
|
-
|
|
29663
|
-
media = await resolveMediaSource(client, command, dependencies.randomUUID);
|
|
29664
|
-
} catch (error51) {
|
|
29665
|
-
return failureResult2(command, error51, outputTarget.absolutePath);
|
|
29666
|
-
} finally {
|
|
29667
|
-
client?.close();
|
|
30233
|
+
const maximumAttempts = dependencies.maxAttempts ?? DEFAULT_DOWNLOAD_ATTEMPTS;
|
|
30234
|
+
if (!Number.isInteger(maximumAttempts) || maximumAttempts < 1 || maximumAttempts > 3) {
|
|
30235
|
+
return failureResult2(
|
|
30236
|
+
command,
|
|
30237
|
+
new MediaDownloadError(
|
|
30238
|
+
"invalid-download-attempts",
|
|
30239
|
+
"Download attempt limit must be between 1 and 3.",
|
|
30240
|
+
1,
|
|
30241
|
+
false,
|
|
30242
|
+
{ phase: "setup" }
|
|
30243
|
+
),
|
|
30244
|
+
outputTarget.absolutePath,
|
|
30245
|
+
0,
|
|
30246
|
+
0
|
|
30247
|
+
);
|
|
29668
30248
|
}
|
|
29669
|
-
|
|
29670
|
-
|
|
29671
|
-
|
|
29672
|
-
|
|
29673
|
-
|
|
29674
|
-
|
|
29675
|
-
|
|
29676
|
-
|
|
29677
|
-
|
|
29678
|
-
|
|
30249
|
+
const deadlineAt = command.timeoutMs ? Date.now() + command.timeoutMs : null;
|
|
30250
|
+
let lastError;
|
|
30251
|
+
for (let attempt = 1; attempt <= maximumAttempts; attempt += 1) {
|
|
30252
|
+
try {
|
|
30253
|
+
throwIfCancelled(dependencies.signal);
|
|
30254
|
+
const remainingMs = remainingDownloadMs(deadlineAt);
|
|
30255
|
+
const attemptCommand = {
|
|
30256
|
+
...command,
|
|
30257
|
+
...remainingMs === void 0 ? {} : { timeoutMs: remainingMs }
|
|
30258
|
+
};
|
|
30259
|
+
const media = await resolveMediaForAttempt(config2, attemptCommand, dependencies);
|
|
30260
|
+
const file2 = await transferMedia(config2, media, outputTarget, attemptCommand, dependencies);
|
|
30261
|
+
return {
|
|
30262
|
+
exitCode: 0,
|
|
30263
|
+
output: {
|
|
30264
|
+
attempts: { completed: attempt, maximum: maximumAttempts },
|
|
30265
|
+
file: file2,
|
|
30266
|
+
format: "az8.canvas.media-download.v1",
|
|
30267
|
+
media: { coreNodeId: media.coreNodeId, mediaType: media.mediaType },
|
|
30268
|
+
projectId: command.projectId,
|
|
30269
|
+
source: command.source
|
|
30270
|
+
}
|
|
30271
|
+
};
|
|
30272
|
+
} catch (error51) {
|
|
30273
|
+
lastError = error51;
|
|
30274
|
+
const failure = normalizeDownloadError(error51);
|
|
30275
|
+
if (!failure.retryable || failure.code === "download-cancelled" || failure.code === "download-timed-out" || attempt === maximumAttempts) {
|
|
30276
|
+
return failureResult2(command, failure, outputTarget.absolutePath, attempt, maximumAttempts);
|
|
29679
30277
|
}
|
|
29680
|
-
|
|
29681
|
-
|
|
29682
|
-
|
|
30278
|
+
try {
|
|
30279
|
+
await waitForDownloadRetry(
|
|
30280
|
+
downloadRetryDelay(attempt, dependencies.random?.() ?? Math.random()),
|
|
30281
|
+
deadlineAt,
|
|
30282
|
+
dependencies
|
|
30283
|
+
);
|
|
30284
|
+
} catch (retryError) {
|
|
30285
|
+
return failureResult2(
|
|
30286
|
+
command,
|
|
30287
|
+
retryError,
|
|
30288
|
+
outputTarget.absolutePath,
|
|
30289
|
+
attempt,
|
|
30290
|
+
maximumAttempts
|
|
30291
|
+
);
|
|
30292
|
+
}
|
|
30293
|
+
}
|
|
29683
30294
|
}
|
|
30295
|
+
return failureResult2(
|
|
30296
|
+
command,
|
|
30297
|
+
lastError,
|
|
30298
|
+
outputTarget.absolutePath,
|
|
30299
|
+
maximumAttempts,
|
|
30300
|
+
maximumAttempts
|
|
30301
|
+
);
|
|
30302
|
+
}
|
|
30303
|
+
function downloadRetryDelay(attempt, random) {
|
|
30304
|
+
const boundedRandom = Number.isFinite(random) ? Math.max(0, Math.min(1, random)) : 0.5;
|
|
30305
|
+
const base = Math.min(250 * 2 ** (attempt - 1), 1e3);
|
|
30306
|
+
return Math.min(1e3, Math.round(base * (0.75 + boundedRandom * 0.5)));
|
|
29684
30307
|
}
|
|
29685
30308
|
function formatCanvasMediaDownloadResult(result3) {
|
|
29686
30309
|
return `${JSON.stringify(result3.output, null, 2)}
|
|
29687
30310
|
`;
|
|
29688
30311
|
}
|
|
29689
|
-
async function resolveMediaSource(client, command,
|
|
30312
|
+
async function resolveMediaSource(client, command, randomUUID5) {
|
|
29690
30313
|
let coreNodeId;
|
|
29691
30314
|
if (command.source.kind === "view-node") {
|
|
29692
30315
|
try {
|
|
@@ -29696,7 +30319,8 @@ async function resolveMediaSource(client, command, randomUUID4) {
|
|
|
29696
30319
|
"view-node-media-unavailable",
|
|
29697
30320
|
safeCanvasMessage(error51),
|
|
29698
30321
|
1,
|
|
29699
|
-
false
|
|
30322
|
+
false,
|
|
30323
|
+
{ cause: sanitizeDownloadCause(error51), phase: "source-resolution" }
|
|
29700
30324
|
);
|
|
29701
30325
|
}
|
|
29702
30326
|
} else {
|
|
@@ -29705,7 +30329,7 @@ async function resolveMediaSource(client, command, randomUUID4) {
|
|
|
29705
30329
|
const outcome = await client.executeOperation({
|
|
29706
30330
|
input: { coreNodeId },
|
|
29707
30331
|
name: "getCoreNode",
|
|
29708
|
-
requestId: `media-download-resolve-${
|
|
30332
|
+
requestId: `media-download-resolve-${randomUUID5?.() ?? crypto.randomUUID()}`,
|
|
29709
30333
|
timeoutMs: command.timeoutMs ?? DEFAULT_RESOLUTION_TIMEOUT_MS
|
|
29710
30334
|
});
|
|
29711
30335
|
if (outcome.receipt.status !== "succeeded") {
|
|
@@ -29714,7 +30338,8 @@ async function resolveMediaSource(client, command, randomUUID4) {
|
|
|
29714
30338
|
"core-node-resolution-failed",
|
|
29715
30339
|
outcome.receipt.error?.message ?? `Core Node ${coreNodeId} could not be resolved.`,
|
|
29716
30340
|
indeterminate ? 2 : 1,
|
|
29717
|
-
indeterminate
|
|
30341
|
+
indeterminate,
|
|
30342
|
+
{ phase: "core-node-resolution" }
|
|
29718
30343
|
);
|
|
29719
30344
|
}
|
|
29720
30345
|
const coreNode = parseCoreNode(outcome.receipt.result?.coreNode, coreNodeId);
|
|
@@ -29733,7 +30358,8 @@ function parseCoreNode(value, expectedId) {
|
|
|
29733
30358
|
"core-node-response-invalid",
|
|
29734
30359
|
`Core Node ${expectedId} returned an invalid record.`,
|
|
29735
30360
|
2,
|
|
29736
|
-
true
|
|
30361
|
+
true,
|
|
30362
|
+
{ phase: "core-node-resolution" }
|
|
29737
30363
|
);
|
|
29738
30364
|
}
|
|
29739
30365
|
const record2 = value;
|
|
@@ -29742,7 +30368,8 @@ function parseCoreNode(value, expectedId) {
|
|
|
29742
30368
|
"core-node-response-invalid",
|
|
29743
30369
|
`Core Node ${expectedId} returned an invalid record.`,
|
|
29744
30370
|
2,
|
|
29745
|
-
true
|
|
30371
|
+
true,
|
|
30372
|
+
{ phase: "core-node-resolution" }
|
|
29746
30373
|
);
|
|
29747
30374
|
}
|
|
29748
30375
|
return value;
|
|
@@ -29753,11 +30380,12 @@ async function prepareOutputTarget(requestedPath, overwrite, cwd) {
|
|
|
29753
30380
|
"invalid-output-path",
|
|
29754
30381
|
"Download output path must not be blank.",
|
|
29755
30382
|
1,
|
|
29756
|
-
false
|
|
30383
|
+
false,
|
|
30384
|
+
{ phase: "output-setup" }
|
|
29757
30385
|
);
|
|
29758
30386
|
}
|
|
29759
|
-
const absolutePath =
|
|
29760
|
-
const parentPath =
|
|
30387
|
+
const absolutePath = path7.resolve(cwd, requestedPath);
|
|
30388
|
+
const parentPath = path7.dirname(absolutePath);
|
|
29761
30389
|
let parent;
|
|
29762
30390
|
try {
|
|
29763
30391
|
parent = await stat(parentPath);
|
|
@@ -29766,7 +30394,8 @@ async function prepareOutputTarget(requestedPath, overwrite, cwd) {
|
|
|
29766
30394
|
"output-parent-unavailable",
|
|
29767
30395
|
"Download output parent directory does not exist or cannot be accessed.",
|
|
29768
30396
|
1,
|
|
29769
|
-
false
|
|
30397
|
+
false,
|
|
30398
|
+
{ phase: "output-setup" }
|
|
29770
30399
|
);
|
|
29771
30400
|
}
|
|
29772
30401
|
if (!parent.isDirectory()) {
|
|
@@ -29774,19 +30403,21 @@ async function prepareOutputTarget(requestedPath, overwrite, cwd) {
|
|
|
29774
30403
|
"output-parent-not-directory",
|
|
29775
30404
|
"Download output parent is not a directory.",
|
|
29776
30405
|
1,
|
|
29777
|
-
false
|
|
30406
|
+
false,
|
|
30407
|
+
{ phase: "output-setup" }
|
|
29778
30408
|
);
|
|
29779
30409
|
}
|
|
29780
30410
|
let existing;
|
|
29781
30411
|
try {
|
|
29782
|
-
existing = await
|
|
30412
|
+
existing = await lstat4(absolutePath);
|
|
29783
30413
|
} catch (error51) {
|
|
29784
30414
|
if (readFsCode2(error51) !== "ENOENT") {
|
|
29785
30415
|
throw new MediaDownloadError(
|
|
29786
30416
|
"output-target-unavailable",
|
|
29787
30417
|
"Download output target cannot be inspected.",
|
|
29788
30418
|
1,
|
|
29789
|
-
false
|
|
30419
|
+
false,
|
|
30420
|
+
{ phase: "output-setup" }
|
|
29790
30421
|
);
|
|
29791
30422
|
}
|
|
29792
30423
|
}
|
|
@@ -29795,7 +30426,8 @@ async function prepareOutputTarget(requestedPath, overwrite, cwd) {
|
|
|
29795
30426
|
"output-target-exists",
|
|
29796
30427
|
"Download output target already exists; pass --overwrite to replace a regular file.",
|
|
29797
30428
|
1,
|
|
29798
|
-
false
|
|
30429
|
+
false,
|
|
30430
|
+
{ phase: "output-setup" }
|
|
29799
30431
|
);
|
|
29800
30432
|
}
|
|
29801
30433
|
if (existing && (!existing.isFile() || existing.isSymbolicLink())) {
|
|
@@ -29803,7 +30435,8 @@ async function prepareOutputTarget(requestedPath, overwrite, cwd) {
|
|
|
29803
30435
|
"output-target-not-regular-file",
|
|
29804
30436
|
"Download output target must be a regular file and must not be a symbolic link.",
|
|
29805
30437
|
1,
|
|
29806
|
-
false
|
|
30438
|
+
false,
|
|
30439
|
+
{ phase: "output-setup" }
|
|
29807
30440
|
);
|
|
29808
30441
|
}
|
|
29809
30442
|
return { absolutePath, existed: Boolean(existing), parentPath };
|
|
@@ -29814,9 +30447,9 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29814
30447
|
let response;
|
|
29815
30448
|
try {
|
|
29816
30449
|
response = await config2.fetch(media.url, { redirect: "follow", signal: deadline.signal });
|
|
29817
|
-
} catch {
|
|
30450
|
+
} catch (error51) {
|
|
29818
30451
|
deadline.cleanup();
|
|
29819
|
-
throw transferFailure(deadline);
|
|
30452
|
+
throw transferFailure(deadline, error51);
|
|
29820
30453
|
}
|
|
29821
30454
|
if (!response.ok) {
|
|
29822
30455
|
deadline.cleanup();
|
|
@@ -29825,7 +30458,8 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29825
30458
|
"media-http-error",
|
|
29826
30459
|
`Media server returned HTTP ${response.status}.`,
|
|
29827
30460
|
retryable ? 2 : 1,
|
|
29828
|
-
retryable
|
|
30461
|
+
retryable,
|
|
30462
|
+
{ phase: "media-transfer" }
|
|
29829
30463
|
);
|
|
29830
30464
|
}
|
|
29831
30465
|
const contentType = normalizeContentType(response.headers.get("content-type"));
|
|
@@ -29835,8 +30469,9 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29835
30469
|
throw new MediaDownloadError(
|
|
29836
30470
|
"media-content-type-mismatch",
|
|
29837
30471
|
`Media response is ${headerFamily}, but Core Node ${media.coreNodeId} is ${media.mediaType}.`,
|
|
29838
|
-
|
|
29839
|
-
|
|
30472
|
+
1,
|
|
30473
|
+
false,
|
|
30474
|
+
{ phase: "media-verification" }
|
|
29840
30475
|
);
|
|
29841
30476
|
}
|
|
29842
30477
|
if (contentType === "text/html" || contentType === "application/json") {
|
|
@@ -29844,8 +30479,9 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29844
30479
|
throw new MediaDownloadError(
|
|
29845
30480
|
"media-content-type-mismatch",
|
|
29846
30481
|
"Media response returned a non-media document.",
|
|
29847
|
-
|
|
29848
|
-
|
|
30482
|
+
1,
|
|
30483
|
+
false,
|
|
30484
|
+
{ phase: "media-verification" }
|
|
29849
30485
|
);
|
|
29850
30486
|
}
|
|
29851
30487
|
const remoteContentLength = readContentLength(response);
|
|
@@ -29878,7 +30514,8 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29878
30514
|
"output-finalize-failed",
|
|
29879
30515
|
"Temporary download file could not be finalized.",
|
|
29880
30516
|
1,
|
|
29881
|
-
false
|
|
30517
|
+
false,
|
|
30518
|
+
{ phase: "output-finalize" }
|
|
29882
30519
|
);
|
|
29883
30520
|
}
|
|
29884
30521
|
let detected;
|
|
@@ -29889,7 +30526,8 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29889
30526
|
"media-verification-failed",
|
|
29890
30527
|
"Downloaded media could not be inspected safely.",
|
|
29891
30528
|
1,
|
|
29892
|
-
false
|
|
30529
|
+
false,
|
|
30530
|
+
{ phase: "media-verification" }
|
|
29893
30531
|
);
|
|
29894
30532
|
}
|
|
29895
30533
|
validateDownloadedMedia(media, contentType, detected);
|
|
@@ -29911,12 +30549,13 @@ async function transferMedia(config2, media, outputTarget, command, dependencies
|
|
|
29911
30549
|
} catch (error51) {
|
|
29912
30550
|
await temporary.handle.close().catch(() => void 0);
|
|
29913
30551
|
if (error51 instanceof MediaDownloadError) throw error51;
|
|
29914
|
-
if (deadline.signal.aborted) throw transferFailure(deadline);
|
|
30552
|
+
if (deadline.signal.aborted) throw transferFailure(deadline, error51);
|
|
29915
30553
|
throw new MediaDownloadError(
|
|
29916
30554
|
"media-download-internal-failed",
|
|
29917
30555
|
"Media download could not complete its local processing.",
|
|
29918
30556
|
2,
|
|
29919
|
-
true
|
|
30557
|
+
true,
|
|
30558
|
+
{ cause: sanitizeDownloadCause(error51), phase: "media-transfer" }
|
|
29920
30559
|
);
|
|
29921
30560
|
} finally {
|
|
29922
30561
|
deadline.cleanup();
|
|
@@ -29935,9 +30574,9 @@ async function detectFileTypeFromFileHeader(filePath) {
|
|
|
29935
30574
|
}
|
|
29936
30575
|
async function openTemporaryFile(outputTarget, identity) {
|
|
29937
30576
|
const safeIdentity = identity.replace(/[^a-z0-9-]/gi, "").slice(0, 64) || "download";
|
|
29938
|
-
const basename =
|
|
30577
|
+
const basename = path7.basename(outputTarget.absolutePath);
|
|
29939
30578
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
29940
|
-
const temporaryPath =
|
|
30579
|
+
const temporaryPath = path7.join(
|
|
29941
30580
|
outputTarget.parentPath,
|
|
29942
30581
|
`.${basename}.az8-${safeIdentity}-${attempt}.part`
|
|
29943
30582
|
);
|
|
@@ -29967,11 +30606,12 @@ async function streamResponseToFile(response, handle, deadline, expectedBytes) {
|
|
|
29967
30606
|
"media-response-body-missing",
|
|
29968
30607
|
"Media response has no readable body.",
|
|
29969
30608
|
2,
|
|
29970
|
-
true
|
|
30609
|
+
true,
|
|
30610
|
+
{ phase: "media-transfer" }
|
|
29971
30611
|
);
|
|
29972
30612
|
}
|
|
29973
30613
|
const reader = response.body.getReader();
|
|
29974
|
-
const hash2 =
|
|
30614
|
+
const hash2 = createHash4("sha256");
|
|
29975
30615
|
let bytes = 0;
|
|
29976
30616
|
try {
|
|
29977
30617
|
while (true) {
|
|
@@ -29985,16 +30625,17 @@ async function streamResponseToFile(response, handle, deadline, expectedBytes) {
|
|
|
29985
30625
|
}
|
|
29986
30626
|
} catch (error51) {
|
|
29987
30627
|
if (error51 instanceof MediaDownloadError) throw error51;
|
|
29988
|
-
if (deadline.signal.aborted) throw transferFailure(deadline);
|
|
30628
|
+
if (deadline.signal.aborted) throw transferFailure(deadline, error51);
|
|
29989
30629
|
if (readFsCode2(error51)) {
|
|
29990
30630
|
throw new MediaDownloadError(
|
|
29991
30631
|
"output-write-failed",
|
|
29992
30632
|
"Temporary download file could not be written completely.",
|
|
29993
30633
|
1,
|
|
29994
|
-
false
|
|
30634
|
+
false,
|
|
30635
|
+
{ cause: sanitizeDownloadCause(error51), phase: "output-write" }
|
|
29995
30636
|
);
|
|
29996
30637
|
}
|
|
29997
|
-
throw transferFailure(deadline);
|
|
30638
|
+
throw transferFailure(deadline, error51);
|
|
29998
30639
|
} finally {
|
|
29999
30640
|
reader.releaseLock();
|
|
30000
30641
|
}
|
|
@@ -30003,7 +30644,8 @@ async function streamResponseToFile(response, handle, deadline, expectedBytes) {
|
|
|
30003
30644
|
"media-content-length-mismatch",
|
|
30004
30645
|
`Media response declared ${expectedBytes} bytes but delivered ${bytes}.`,
|
|
30005
30646
|
2,
|
|
30006
|
-
true
|
|
30647
|
+
true,
|
|
30648
|
+
{ phase: "media-transfer" }
|
|
30007
30649
|
);
|
|
30008
30650
|
}
|
|
30009
30651
|
return { bytes, sha256: hash2.digest("hex") };
|
|
@@ -30017,7 +30659,8 @@ async function writeAll(handle, value) {
|
|
|
30017
30659
|
"output-write-stalled",
|
|
30018
30660
|
"Temporary download file stopped accepting data.",
|
|
30019
30661
|
1,
|
|
30020
|
-
false
|
|
30662
|
+
false,
|
|
30663
|
+
{ phase: "output-write" }
|
|
30021
30664
|
);
|
|
30022
30665
|
}
|
|
30023
30666
|
offset += bytesWritten;
|
|
@@ -30029,8 +30672,9 @@ function validateDownloadedMedia(media, contentType, detected) {
|
|
|
30029
30672
|
throw new MediaDownloadError(
|
|
30030
30673
|
"media-content-mismatch",
|
|
30031
30674
|
`Downloaded file is ${detectedFamily}, but Core Node ${media.coreNodeId} is ${media.mediaType}.`,
|
|
30032
|
-
|
|
30033
|
-
|
|
30675
|
+
1,
|
|
30676
|
+
false,
|
|
30677
|
+
{ phase: "media-verification" }
|
|
30034
30678
|
);
|
|
30035
30679
|
}
|
|
30036
30680
|
const headerMatches = readMediaFamily(contentType) === media.mediaType;
|
|
@@ -30039,15 +30683,16 @@ function validateDownloadedMedia(media, contentType, detected) {
|
|
|
30039
30683
|
throw new MediaDownloadError(
|
|
30040
30684
|
"media-content-unverified",
|
|
30041
30685
|
`Downloaded file could not be verified as ${media.mediaType} media.`,
|
|
30042
|
-
|
|
30043
|
-
|
|
30686
|
+
1,
|
|
30687
|
+
false,
|
|
30688
|
+
{ phase: "media-verification" }
|
|
30044
30689
|
);
|
|
30045
30690
|
}
|
|
30046
30691
|
}
|
|
30047
30692
|
async function commitTemporaryFile(temporaryPath, outputTarget, overwrite) {
|
|
30048
30693
|
try {
|
|
30049
30694
|
if (overwrite) {
|
|
30050
|
-
await
|
|
30695
|
+
await rename3(temporaryPath, outputTarget.absolutePath);
|
|
30051
30696
|
return;
|
|
30052
30697
|
}
|
|
30053
30698
|
await link(temporaryPath, outputTarget.absolutePath);
|
|
@@ -30058,14 +30703,16 @@ async function commitTemporaryFile(temporaryPath, outputTarget, overwrite) {
|
|
|
30058
30703
|
"output-target-exists",
|
|
30059
30704
|
"Download output target was created before the download could be committed.",
|
|
30060
30705
|
1,
|
|
30061
|
-
false
|
|
30706
|
+
false,
|
|
30707
|
+
{ phase: "output-commit" }
|
|
30062
30708
|
);
|
|
30063
30709
|
}
|
|
30064
30710
|
throw new MediaDownloadError(
|
|
30065
30711
|
"output-commit-failed",
|
|
30066
30712
|
"Verified media could not be committed to the output path.",
|
|
30067
30713
|
1,
|
|
30068
|
-
false
|
|
30714
|
+
false,
|
|
30715
|
+
{ cause: sanitizeDownloadCause(error51), phase: "output-commit" }
|
|
30069
30716
|
);
|
|
30070
30717
|
}
|
|
30071
30718
|
}
|
|
@@ -30089,18 +30736,29 @@ function createTransferSignal(external, timeoutMs) {
|
|
|
30089
30736
|
signal: controller.signal
|
|
30090
30737
|
};
|
|
30091
30738
|
}
|
|
30092
|
-
function transferFailure(deadline) {
|
|
30739
|
+
function transferFailure(deadline, cause) {
|
|
30093
30740
|
if (deadline.external?.aborted) {
|
|
30094
|
-
return new MediaDownloadError(
|
|
30741
|
+
return new MediaDownloadError(
|
|
30742
|
+
"download-cancelled",
|
|
30743
|
+
"Media download was cancelled.",
|
|
30744
|
+
130,
|
|
30745
|
+
true,
|
|
30746
|
+
{
|
|
30747
|
+
phase: "media-transfer"
|
|
30748
|
+
}
|
|
30749
|
+
);
|
|
30095
30750
|
}
|
|
30096
30751
|
if (deadline.isTimedOut()) {
|
|
30097
|
-
return new MediaDownloadError("download-timed-out", "Media download timed out.", 2, true
|
|
30752
|
+
return new MediaDownloadError("download-timed-out", "Media download timed out.", 2, true, {
|
|
30753
|
+
phase: "media-transfer"
|
|
30754
|
+
});
|
|
30098
30755
|
}
|
|
30099
30756
|
return new MediaDownloadError(
|
|
30100
30757
|
"media-network-failed",
|
|
30101
30758
|
"Media response could not be downloaded completely.",
|
|
30102
30759
|
2,
|
|
30103
|
-
true
|
|
30760
|
+
true,
|
|
30761
|
+
{ cause: sanitizeDownloadCause(cause), phase: "media-transfer" }
|
|
30104
30762
|
);
|
|
30105
30763
|
}
|
|
30106
30764
|
function throwIfCancelled(signal) {
|
|
@@ -30129,23 +30787,111 @@ function readMediaFamily(value) {
|
|
|
30129
30787
|
if (value?.startsWith("video/")) return "video";
|
|
30130
30788
|
return null;
|
|
30131
30789
|
}
|
|
30132
|
-
function failureResult2(command, error51, absolutePath) {
|
|
30133
|
-
const failure =
|
|
30790
|
+
function failureResult2(command, error51, absolutePath, attemptsCompleted = 1, maximumAttempts = 1) {
|
|
30791
|
+
const failure = normalizeDownloadError(error51);
|
|
30134
30792
|
return {
|
|
30135
30793
|
exitCode: failure.exitCode,
|
|
30136
30794
|
output: {
|
|
30137
30795
|
error: {
|
|
30138
30796
|
code: failure.code,
|
|
30139
30797
|
message: safeCanvasMessage(failure),
|
|
30140
|
-
|
|
30798
|
+
...failure.details.phase ? { phase: failure.details.phase } : {},
|
|
30799
|
+
retryable: failure.retryable,
|
|
30800
|
+
...failure.details.cause ? { cause: failure.details.cause } : {}
|
|
30141
30801
|
},
|
|
30142
30802
|
format: "az8.canvas.media-download.v1",
|
|
30143
|
-
|
|
30803
|
+
localState: {
|
|
30804
|
+
destinationCommitted: false,
|
|
30805
|
+
partialFileRetained: false
|
|
30806
|
+
},
|
|
30807
|
+
outputPath: absolutePath ?? path7.resolve(command.outputPath),
|
|
30144
30808
|
projectId: command.projectId,
|
|
30809
|
+
attempts: { completed: attemptsCompleted, maximum: maximumAttempts },
|
|
30810
|
+
remoteState: "unverified",
|
|
30145
30811
|
source: command.source
|
|
30146
30812
|
}
|
|
30147
30813
|
};
|
|
30148
30814
|
}
|
|
30815
|
+
async function resolveMediaForAttempt(config2, command, dependencies) {
|
|
30816
|
+
const client = dependencies.mediaDownloadClientFactory?.(config2, command.projectId) ?? new CanvasClient(config2, command.projectId);
|
|
30817
|
+
try {
|
|
30818
|
+
try {
|
|
30819
|
+
await client.connect(normalizeCanvasClientName(command.clientName));
|
|
30820
|
+
} catch (error51) {
|
|
30821
|
+
throw new MediaDownloadError(
|
|
30822
|
+
"canvas-connection-failed",
|
|
30823
|
+
"Unable to establish a ready Project Canvas context.",
|
|
30824
|
+
2,
|
|
30825
|
+
true,
|
|
30826
|
+
{ cause: sanitizeDownloadCause(error51), phase: "canvas-connect" }
|
|
30827
|
+
);
|
|
30828
|
+
}
|
|
30829
|
+
throwIfCancelled(dependencies.signal);
|
|
30830
|
+
return await resolveMediaSource(client, command, dependencies.randomUUID);
|
|
30831
|
+
} finally {
|
|
30832
|
+
client.close();
|
|
30833
|
+
}
|
|
30834
|
+
}
|
|
30835
|
+
function normalizeDownloadError(error51) {
|
|
30836
|
+
return error51 instanceof MediaDownloadError ? error51 : new MediaDownloadError("media-download-failed", safeCanvasMessage(error51), 2, true, {
|
|
30837
|
+
cause: sanitizeDownloadCause(error51),
|
|
30838
|
+
phase: "unknown"
|
|
30839
|
+
});
|
|
30840
|
+
}
|
|
30841
|
+
function remainingDownloadMs(deadlineAt) {
|
|
30842
|
+
if (deadlineAt === null) return void 0;
|
|
30843
|
+
const remaining = deadlineAt - Date.now();
|
|
30844
|
+
if (remaining < 1) {
|
|
30845
|
+
throw new MediaDownloadError("download-timed-out", "Media download timed out.", 2, true, {
|
|
30846
|
+
phase: "retry-wait"
|
|
30847
|
+
});
|
|
30848
|
+
}
|
|
30849
|
+
return remaining;
|
|
30850
|
+
}
|
|
30851
|
+
async function waitForDownloadRetry(delayMs, deadlineAt, dependencies) {
|
|
30852
|
+
const remaining = remainingDownloadMs(deadlineAt);
|
|
30853
|
+
if (remaining !== void 0 && remaining <= delayMs) {
|
|
30854
|
+
throw new MediaDownloadError("download-timed-out", "Media download timed out.", 2, true, {
|
|
30855
|
+
phase: "retry-wait"
|
|
30856
|
+
});
|
|
30857
|
+
}
|
|
30858
|
+
await (dependencies.sleep ?? abortableSleep)(delayMs, dependencies.signal);
|
|
30859
|
+
throwIfCancelled(dependencies.signal);
|
|
30860
|
+
}
|
|
30861
|
+
async function abortableSleep(delayMs, signal) {
|
|
30862
|
+
if (signal?.aborted) return;
|
|
30863
|
+
await new Promise((resolve) => {
|
|
30864
|
+
const timeout = setTimeout(done, delayMs);
|
|
30865
|
+
const onAbort = () => done();
|
|
30866
|
+
function done() {
|
|
30867
|
+
clearTimeout(timeout);
|
|
30868
|
+
signal?.removeEventListener("abort", onAbort);
|
|
30869
|
+
resolve();
|
|
30870
|
+
}
|
|
30871
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
30872
|
+
});
|
|
30873
|
+
}
|
|
30874
|
+
function sanitizeDownloadCause(error51) {
|
|
30875
|
+
if (!error51 || typeof error51 !== "object") return void 0;
|
|
30876
|
+
const record2 = error51;
|
|
30877
|
+
const cause = record2.cause && typeof record2.cause === "object" ? record2.cause : record2;
|
|
30878
|
+
const message = cause instanceof Error ? cause.message : typeof cause.message === "string" ? cause.message : error51 instanceof Error ? error51.message : void 0;
|
|
30879
|
+
const code = typeof cause.code === "string" || typeof cause.code === "number" ? String(cause.code) : void 0;
|
|
30880
|
+
const closeCode = typeof cause.closeCode === "number" ? cause.closeCode : typeof cause.websocketCloseCode === "number" ? cause.websocketCloseCode : void 0;
|
|
30881
|
+
const closeReason = typeof cause.closeReason === "string" ? cause.closeReason : typeof cause.websocketCloseReason === "string" ? cause.websocketCloseReason : void 0;
|
|
30882
|
+
const sanitizedMessage = message ? sanitizeTransportDetail(message) : void 0;
|
|
30883
|
+
const sanitizedReason = closeReason ? sanitizeTransportDetail(closeReason) : void 0;
|
|
30884
|
+
if (!code && !closeCode && !sanitizedMessage && !sanitizedReason) return void 0;
|
|
30885
|
+
return {
|
|
30886
|
+
...code ? { code } : {},
|
|
30887
|
+
...sanitizedMessage ? { message: sanitizedMessage } : {},
|
|
30888
|
+
...closeCode ? { websocketCloseCode: closeCode } : {},
|
|
30889
|
+
...sanitizedReason ? { websocketCloseReason: sanitizedReason } : {}
|
|
30890
|
+
};
|
|
30891
|
+
}
|
|
30892
|
+
function sanitizeTransportDetail(value) {
|
|
30893
|
+
return value.replace(/token=[^\s;&]+/gi, "token=[REDACTED]").replace(/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[REDACTED]").replace(/(?:https?|wss?):\/\/[^\s]+/gi, "[REDACTED_URL]");
|
|
30894
|
+
}
|
|
30149
30895
|
function readFsCode2(error51) {
|
|
30150
30896
|
return typeof error51 === "object" && error51 !== null && "code" in error51 ? String(error51.code) : void 0;
|
|
30151
30897
|
}
|
|
@@ -30222,8 +30968,8 @@ function canvasOneShotSetupError(kind, projectId, capability, error51) {
|
|
|
30222
30968
|
}
|
|
30223
30969
|
|
|
30224
30970
|
// src/commands/canvas.ts
|
|
30225
|
-
import { randomUUID as
|
|
30226
|
-
import
|
|
30971
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
30972
|
+
import path8 from "node:path";
|
|
30227
30973
|
|
|
30228
30974
|
// src/integrations/snapshot-reader.ts
|
|
30229
30975
|
function createAz8StudioSnapshotReader(config2) {
|
|
@@ -31044,10 +31790,10 @@ function mergeDefs(...defs) {
|
|
|
31044
31790
|
function cloneDef(schema) {
|
|
31045
31791
|
return mergeDefs(schema._zod.def);
|
|
31046
31792
|
}
|
|
31047
|
-
function getElementAtPath(obj,
|
|
31048
|
-
if (!
|
|
31793
|
+
function getElementAtPath(obj, path10) {
|
|
31794
|
+
if (!path10)
|
|
31049
31795
|
return obj;
|
|
31050
|
-
return
|
|
31796
|
+
return path10.reduce((acc, key) => acc?.[key], obj);
|
|
31051
31797
|
}
|
|
31052
31798
|
function promiseAllObject(promisesObj) {
|
|
31053
31799
|
const keys2 = Object.keys(promisesObj);
|
|
@@ -31456,11 +32202,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
31456
32202
|
}
|
|
31457
32203
|
return false;
|
|
31458
32204
|
}
|
|
31459
|
-
function prefixIssues(
|
|
32205
|
+
function prefixIssues(path10, issues) {
|
|
31460
32206
|
return issues.map((iss) => {
|
|
31461
32207
|
var _a3;
|
|
31462
32208
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
31463
|
-
iss.path.unshift(
|
|
32209
|
+
iss.path.unshift(path10);
|
|
31464
32210
|
return iss;
|
|
31465
32211
|
});
|
|
31466
32212
|
}
|
|
@@ -31607,16 +32353,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
31607
32353
|
}
|
|
31608
32354
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
31609
32355
|
const fieldErrors = { _errors: [] };
|
|
31610
|
-
const processError = (error52,
|
|
32356
|
+
const processError = (error52, path10 = []) => {
|
|
31611
32357
|
for (const issue2 of error52.issues) {
|
|
31612
32358
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
31613
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
32359
|
+
issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
|
|
31614
32360
|
} else if (issue2.code === "invalid_key") {
|
|
31615
|
-
processError({ issues: issue2.issues }, [...
|
|
32361
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
31616
32362
|
} else if (issue2.code === "invalid_element") {
|
|
31617
|
-
processError({ issues: issue2.issues }, [...
|
|
32363
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
31618
32364
|
} else {
|
|
31619
|
-
const fullpath = [...
|
|
32365
|
+
const fullpath = [...path10, ...issue2.path];
|
|
31620
32366
|
if (fullpath.length === 0) {
|
|
31621
32367
|
fieldErrors._errors.push(mapper(issue2));
|
|
31622
32368
|
} else {
|
|
@@ -31643,17 +32389,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
31643
32389
|
}
|
|
31644
32390
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
31645
32391
|
const result3 = { errors: [] };
|
|
31646
|
-
const processError = (error52,
|
|
32392
|
+
const processError = (error52, path10 = []) => {
|
|
31647
32393
|
var _a3, _b;
|
|
31648
32394
|
for (const issue2 of error52.issues) {
|
|
31649
32395
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
31650
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
32396
|
+
issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
|
|
31651
32397
|
} else if (issue2.code === "invalid_key") {
|
|
31652
|
-
processError({ issues: issue2.issues }, [...
|
|
32398
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
31653
32399
|
} else if (issue2.code === "invalid_element") {
|
|
31654
|
-
processError({ issues: issue2.issues }, [...
|
|
32400
|
+
processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
|
|
31655
32401
|
} else {
|
|
31656
|
-
const fullpath = [...
|
|
32402
|
+
const fullpath = [...path10, ...issue2.path];
|
|
31657
32403
|
if (fullpath.length === 0) {
|
|
31658
32404
|
result3.errors.push(mapper(issue2));
|
|
31659
32405
|
continue;
|
|
@@ -31685,8 +32431,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
31685
32431
|
}
|
|
31686
32432
|
function toDotPath(_path) {
|
|
31687
32433
|
const segs = [];
|
|
31688
|
-
const
|
|
31689
|
-
for (const seg of
|
|
32434
|
+
const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
32435
|
+
for (const seg of path10) {
|
|
31690
32436
|
if (typeof seg === "number")
|
|
31691
32437
|
segs.push(`[${seg}]`);
|
|
31692
32438
|
else if (typeof seg === "symbol")
|
|
@@ -44378,13 +45124,13 @@ function resolveRef(ref, ctx) {
|
|
|
44378
45124
|
if (!ref.startsWith("#")) {
|
|
44379
45125
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
44380
45126
|
}
|
|
44381
|
-
const
|
|
44382
|
-
if (
|
|
45127
|
+
const path10 = ref.slice(1).split("/").filter(Boolean);
|
|
45128
|
+
if (path10.length === 0) {
|
|
44383
45129
|
return ctx.rootSchema;
|
|
44384
45130
|
}
|
|
44385
45131
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
44386
|
-
if (
|
|
44387
|
-
const key =
|
|
45132
|
+
if (path10[0] === defsKey) {
|
|
45133
|
+
const key = path10[1];
|
|
44388
45134
|
if (!key || !ctx.defs[key]) {
|
|
44389
45135
|
throw new Error(`Reference not found: ${ref}`);
|
|
44390
45136
|
}
|
|
@@ -44954,7 +45700,7 @@ function registerCanvasCommands(program2, dependencies, setResult) {
|
|
|
44954
45700
|
return "invalid-option";
|
|
44955
45701
|
});
|
|
44956
45702
|
const config2 = await resolveCliConfig(readConfigOptions(command), dependencies);
|
|
44957
|
-
const requestId = options.requestId ?? dependencies.randomUUID?.() ??
|
|
45703
|
+
const requestId = options.requestId ?? dependencies.randomUUID?.() ?? randomUUID3();
|
|
44958
45704
|
const result3 = await runCanvasOneShot(
|
|
44959
45705
|
config2,
|
|
44960
45706
|
{
|
|
@@ -44963,7 +45709,7 @@ function registerCanvasCommands(program2, dependencies, setResult) {
|
|
|
44963
45709
|
idempotencyKey: options.idempotencyKey,
|
|
44964
45710
|
...options.name ? { name: options.name } : {},
|
|
44965
45711
|
...options.positionX !== void 0 && options.positionY !== void 0 ? { position: { x: options.positionX, y: options.positionY } } : {},
|
|
44966
|
-
source:
|
|
45712
|
+
source: path8.resolve(dependencies.cwd ?? process.cwd(), options.file)
|
|
44967
45713
|
},
|
|
44968
45714
|
kind: "operation",
|
|
44969
45715
|
name: "uploadMedia",
|
|
@@ -45039,7 +45785,7 @@ function registerCanvasCommands(program2, dependencies, setResult) {
|
|
|
45039
45785
|
(issue2) => issue2.path[0] === "input" ? "invalid-input-source" : "invalid-option"
|
|
45040
45786
|
);
|
|
45041
45787
|
const config2 = await resolveCliConfig(readConfigOptions(command), dependencies);
|
|
45042
|
-
const requestId = options.requestId ?? dependencies.randomUUID?.() ??
|
|
45788
|
+
const requestId = options.requestId ?? dependencies.randomUUID?.() ?? randomUUID3();
|
|
45043
45789
|
const result3 = await runCanvasOneShot(
|
|
45044
45790
|
config2,
|
|
45045
45791
|
{
|
|
@@ -45064,7 +45810,7 @@ function registerCanvasCommands(program2, dependencies, setResult) {
|
|
|
45064
45810
|
// package.json
|
|
45065
45811
|
var package_default = {
|
|
45066
45812
|
name: "@everfir/az8-cli",
|
|
45067
|
-
version: "0.3.0
|
|
45813
|
+
version: "0.3.0",
|
|
45068
45814
|
description: "Semantic Project Canvas client for AZ8 Studio agents.",
|
|
45069
45815
|
license: "UNLICENSED",
|
|
45070
45816
|
type: "module",
|
|
@@ -45080,7 +45826,7 @@ var package_default = {
|
|
|
45080
45826
|
main: "./dist/main.js",
|
|
45081
45827
|
publishConfig: {
|
|
45082
45828
|
access: "public",
|
|
45083
|
-
tag: "
|
|
45829
|
+
tag: "latest"
|
|
45084
45830
|
},
|
|
45085
45831
|
scripts: {
|
|
45086
45832
|
build: `pnpm build:dependencies && rm -rf dist && esbuild src/main.ts --bundle --platform=node --format=esm --target=node22.12 --banner:js='import { createRequire } from "node:module"; const require = createRequire(import.meta.url);' --outfile=dist/main.js`,
|
|
@@ -45131,7 +45877,7 @@ function readAz8CliVersion() {
|
|
|
45131
45877
|
}
|
|
45132
45878
|
|
|
45133
45879
|
// src/guide/agent-guide.ts
|
|
45134
|
-
import { readFile as
|
|
45880
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
45135
45881
|
var AGENT_GUIDE_URLS = [
|
|
45136
45882
|
new URL("../skills/az8-cli/SKILL.md", import.meta.url),
|
|
45137
45883
|
new URL("../../skills/az8-cli/SKILL.md", import.meta.url)
|
|
@@ -45164,7 +45910,7 @@ async function renderAgentGuide(options) {
|
|
|
45164
45910
|
async function readPackagedGuide() {
|
|
45165
45911
|
for (const candidate of AGENT_GUIDE_URLS) {
|
|
45166
45912
|
try {
|
|
45167
|
-
return await
|
|
45913
|
+
return await readFile5(candidate, "utf8");
|
|
45168
45914
|
} catch (error51) {
|
|
45169
45915
|
if (error51.code !== "ENOENT") throw error51;
|
|
45170
45916
|
}
|
|
@@ -45276,11 +46022,11 @@ async function withProjectClient(command, dependencies, setResult, action) {
|
|
|
45276
46022
|
}
|
|
45277
46023
|
|
|
45278
46024
|
// src/commands/session.ts
|
|
45279
|
-
import { randomUUID as
|
|
46025
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
45280
46026
|
|
|
45281
46027
|
// src/agent-session/manager.ts
|
|
45282
46028
|
import { spawn } from "node:child_process";
|
|
45283
|
-
import
|
|
46029
|
+
import path9 from "node:path";
|
|
45284
46030
|
var AgentSessionManager = class {
|
|
45285
46031
|
constructor(options = {}) {
|
|
45286
46032
|
this.options = options;
|
|
@@ -45308,7 +46054,7 @@ var AgentSessionManager = class {
|
|
|
45308
46054
|
const descriptorPath = this.store.descriptorPath(sessionId);
|
|
45309
46055
|
const config2 = {
|
|
45310
46056
|
...input.config,
|
|
45311
|
-
...input.config.envFile ? { envFile:
|
|
46057
|
+
...input.config.envFile ? { envFile: path9.resolve(this.store.cwd, input.config.envFile) } : {}
|
|
45312
46058
|
};
|
|
45313
46059
|
const descriptor2 = {
|
|
45314
46060
|
clientName,
|
|
@@ -45427,7 +46173,8 @@ var AgentSessionManager = class {
|
|
|
45427
46173
|
descriptor2.socketPath,
|
|
45428
46174
|
request,
|
|
45429
46175
|
options.timeoutMs ?? 5e3,
|
|
45430
|
-
options.signal
|
|
46176
|
+
options.signal,
|
|
46177
|
+
options.onProgress
|
|
45431
46178
|
).catch((error51) => {
|
|
45432
46179
|
if (isRemoteFailure(error51)) throw error51;
|
|
45433
46180
|
throw managerError(
|
|
@@ -45786,7 +46533,7 @@ function registerSessionCommands(program2, dependencies, setResult) {
|
|
|
45786
46533
|
...recordOptions(rawOptions),
|
|
45787
46534
|
session: readSessionOption(command)
|
|
45788
46535
|
});
|
|
45789
|
-
const requestId = options.requestId ?? dependencies.randomUUID?.() ??
|
|
46536
|
+
const requestId = options.requestId ?? dependencies.randomUUID?.() ?? randomUUID4();
|
|
45790
46537
|
const { descriptor: descriptor2, value } = await manager.call(
|
|
45791
46538
|
{
|
|
45792
46539
|
input: await readCanvasOneShotInputOptions(options, dependencies),
|
|
@@ -45795,7 +46542,11 @@ function registerSessionCommands(program2, dependencies, setResult) {
|
|
|
45795
46542
|
requestId,
|
|
45796
46543
|
...options.timeoutMs ? { timeoutMs: options.timeoutMs } : {}
|
|
45797
46544
|
},
|
|
45798
|
-
{
|
|
46545
|
+
{
|
|
46546
|
+
onProgress: (progress) => dependencies.onProgress?.({ ...progress, requestId }),
|
|
46547
|
+
sessionId: options.session,
|
|
46548
|
+
timeoutMs: (options.timeoutMs ?? 15e3) + 5e3
|
|
46549
|
+
}
|
|
45799
46550
|
);
|
|
45800
46551
|
const receipt = readOperationReceipt(value);
|
|
45801
46552
|
const exitCode = receipt.status === "succeeded" ? 0 : receipt.error?.outcome === "indeterminate" ? 2 : 1;
|
|
@@ -45862,7 +46613,7 @@ function publicDescriptor(descriptor2) {
|
|
|
45862
46613
|
};
|
|
45863
46614
|
}
|
|
45864
46615
|
function requireWatchDelivery(value) {
|
|
45865
|
-
if (!("result" in value) || !
|
|
46616
|
+
if (!("result" in value) || !isRecord6(value.result)) {
|
|
45866
46617
|
throw new Error("Agent Session returned an invalid Watch delivery.");
|
|
45867
46618
|
}
|
|
45868
46619
|
return value;
|
|
@@ -45877,7 +46628,7 @@ function readCanvasSummary(value) {
|
|
|
45877
46628
|
return "canvas" in value ? value.canvas : value;
|
|
45878
46629
|
}
|
|
45879
46630
|
function readOperationReceipt(value) {
|
|
45880
|
-
if (!("receipt" in value) || !
|
|
46631
|
+
if (!("receipt" in value) || !isRecord6(value.receipt)) {
|
|
45881
46632
|
throw new Error("Agent Session returned an invalid Operation Receipt.");
|
|
45882
46633
|
}
|
|
45883
46634
|
return value.receipt;
|
|
@@ -45900,11 +46651,11 @@ function sessionError(error51) {
|
|
|
45900
46651
|
`
|
|
45901
46652
|
};
|
|
45902
46653
|
}
|
|
45903
|
-
function
|
|
46654
|
+
function isRecord6(value) {
|
|
45904
46655
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45905
46656
|
}
|
|
45906
46657
|
function recordOptions(value) {
|
|
45907
|
-
return
|
|
46658
|
+
return isRecord6(value) ? value : {};
|
|
45908
46659
|
}
|
|
45909
46660
|
|
|
45910
46661
|
// src/cli/program.ts
|
|
@@ -45999,6 +46750,12 @@ process.once("SIGINT", abortOnSignal);
|
|
|
45999
46750
|
process.once("SIGTERM", abortOnSignal);
|
|
46000
46751
|
try {
|
|
46001
46752
|
const result3 = await runAz8Cli(process.argv.slice(2), {
|
|
46753
|
+
onProgress(progress) {
|
|
46754
|
+
process.stderr.write(
|
|
46755
|
+
`${JSON.stringify({ format: "az8.operation-progress.v1", ...progress })}
|
|
46756
|
+
`
|
|
46757
|
+
);
|
|
46758
|
+
},
|
|
46002
46759
|
persistentCanvas: runPersistentCanvas,
|
|
46003
46760
|
signal: abortController.signal
|
|
46004
46761
|
});
|