@vm0/cli 9.161.7 → 9.161.9
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/{chunk-P3SAJ3Q2.js → chunk-JXO3PHAE.js} +2021 -987
- package/{chunk-P3SAJ3Q2.js.map → chunk-JXO3PHAE.js.map} +1 -1
- package/index.js +9 -9
- package/package.json +1 -1
- package/zero.js +883 -33
- package/zero.js.map +1 -1
package/zero.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
connectorTypeSchema,
|
|
22
22
|
createComputerUseReadCommand,
|
|
23
23
|
createComputerUseWriteCommand,
|
|
24
|
+
createGithubLabelListener,
|
|
24
25
|
createLocalBrowserReadCommand,
|
|
25
26
|
createLocalBrowserWriteCommand,
|
|
26
27
|
createSkill,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
createZeroRun,
|
|
30
31
|
decodeCliTokenPayload,
|
|
31
32
|
decodeZeroTokenPayload,
|
|
33
|
+
deleteGithubLabelListener,
|
|
32
34
|
deleteLocalBrowserHost,
|
|
33
35
|
deleteSkill,
|
|
34
36
|
deleteZeroAgent,
|
|
@@ -64,6 +66,7 @@ import {
|
|
|
64
66
|
getConnectorGenerationTypes,
|
|
65
67
|
getConnectorTypeForSecretName,
|
|
66
68
|
getDefaultAuthMethod,
|
|
69
|
+
getGithubInstallation,
|
|
67
70
|
getLocalBrowserReadCommand,
|
|
68
71
|
getScopeDiff,
|
|
69
72
|
getSecretsForAuthMethod,
|
|
@@ -139,6 +142,7 @@ import {
|
|
|
139
142
|
source_default,
|
|
140
143
|
submitDeveloperSupport,
|
|
141
144
|
switchZeroOrg,
|
|
145
|
+
updateGithubLabelListener,
|
|
142
146
|
updateSkill,
|
|
143
147
|
updateZeroAgent,
|
|
144
148
|
updateZeroAgentInstructions,
|
|
@@ -150,7 +154,7 @@ import {
|
|
|
150
154
|
zeroAgentCustomSkillNameSchema,
|
|
151
155
|
zeroLocalAgentCommand,
|
|
152
156
|
zeroTokenAllowsFeatureSwitch
|
|
153
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-JXO3PHAE.js";
|
|
154
158
|
import {
|
|
155
159
|
__commonJS,
|
|
156
160
|
__require,
|
|
@@ -32432,6 +32436,160 @@ Notes:
|
|
|
32432
32436
|
)
|
|
32433
32437
|
);
|
|
32434
32438
|
|
|
32439
|
+
// src/commands/zero/github/label-listener/index.ts
|
|
32440
|
+
init_esm_shims();
|
|
32441
|
+
function parseTriggerMode(value) {
|
|
32442
|
+
if (value === "created_by_me" || value === "anyone") {
|
|
32443
|
+
return value;
|
|
32444
|
+
}
|
|
32445
|
+
throw new Error("trigger-mode must be one of: created_by_me, anyone");
|
|
32446
|
+
}
|
|
32447
|
+
function enabledLabel(listener) {
|
|
32448
|
+
return listener.enabled ? source_default.green("yes") : source_default.dim("no");
|
|
32449
|
+
}
|
|
32450
|
+
function manageableLabel(listener) {
|
|
32451
|
+
return listener.canManage ? source_default.green("yes") : source_default.dim("no");
|
|
32452
|
+
}
|
|
32453
|
+
function printListeners(listeners) {
|
|
32454
|
+
if (listeners.length === 0) {
|
|
32455
|
+
console.log(source_default.dim("No GitHub label listeners found"));
|
|
32456
|
+
return;
|
|
32457
|
+
}
|
|
32458
|
+
const idWidth = Math.max(
|
|
32459
|
+
2,
|
|
32460
|
+
...listeners.map((listener) => {
|
|
32461
|
+
return listener.id.length;
|
|
32462
|
+
})
|
|
32463
|
+
);
|
|
32464
|
+
const labelWidth = Math.max(
|
|
32465
|
+
5,
|
|
32466
|
+
...listeners.map((listener) => {
|
|
32467
|
+
return listener.labelName.length;
|
|
32468
|
+
})
|
|
32469
|
+
);
|
|
32470
|
+
const agentWidth = Math.max(
|
|
32471
|
+
5,
|
|
32472
|
+
...listeners.map((listener) => {
|
|
32473
|
+
return (listener.agent?.name ?? "-").length;
|
|
32474
|
+
})
|
|
32475
|
+
);
|
|
32476
|
+
console.log(
|
|
32477
|
+
source_default.dim(
|
|
32478
|
+
[
|
|
32479
|
+
"ID".padEnd(idWidth),
|
|
32480
|
+
"LABEL".padEnd(labelWidth),
|
|
32481
|
+
"AGENT".padEnd(agentWidth),
|
|
32482
|
+
"TRIGGER".padEnd(13),
|
|
32483
|
+
"ENABLED",
|
|
32484
|
+
"CAN MANAGE"
|
|
32485
|
+
].join(" ")
|
|
32486
|
+
)
|
|
32487
|
+
);
|
|
32488
|
+
for (const listener of listeners) {
|
|
32489
|
+
console.log(
|
|
32490
|
+
[
|
|
32491
|
+
listener.id.padEnd(idWidth),
|
|
32492
|
+
listener.labelName.padEnd(labelWidth),
|
|
32493
|
+
(listener.agent?.name ?? "-").padEnd(agentWidth),
|
|
32494
|
+
listener.triggerMode.padEnd(13),
|
|
32495
|
+
enabledLabel(listener).padEnd(7),
|
|
32496
|
+
manageableLabel(listener)
|
|
32497
|
+
].join(" ")
|
|
32498
|
+
);
|
|
32499
|
+
}
|
|
32500
|
+
}
|
|
32501
|
+
var listCommand9 = new Command().name("list").alias("ls").description("List GitHub label listeners for the active organization").option("--json", "Print raw JSON").action(
|
|
32502
|
+
withErrorHandler(async (options) => {
|
|
32503
|
+
const installation = await getGithubInstallation();
|
|
32504
|
+
if (options.json) {
|
|
32505
|
+
console.log(JSON.stringify(installation.labelListeners));
|
|
32506
|
+
return;
|
|
32507
|
+
}
|
|
32508
|
+
printListeners(installation.labelListeners);
|
|
32509
|
+
})
|
|
32510
|
+
);
|
|
32511
|
+
var createCommand2 = new Command().name("create").description("Create a GitHub label listener").requiredOption("--label <name>", "GitHub label name to watch").requiredOption(
|
|
32512
|
+
"--agent-id <id>",
|
|
32513
|
+
"Agent ID to run when the label is applied"
|
|
32514
|
+
).requiredOption("--prompt <text>", "Prompt to pass to the agent").option(
|
|
32515
|
+
"--trigger-mode <mode>",
|
|
32516
|
+
"Who can trigger the listener: anyone | created_by_me",
|
|
32517
|
+
"anyone"
|
|
32518
|
+
).option("--disabled", "Create the listener disabled").option("--json", "Print raw JSON").action(
|
|
32519
|
+
withErrorHandler(
|
|
32520
|
+
async (options) => {
|
|
32521
|
+
const result = await createGithubLabelListener({
|
|
32522
|
+
labelName: options.label,
|
|
32523
|
+
agentId: options.agentId,
|
|
32524
|
+
prompt: options.prompt,
|
|
32525
|
+
triggerMode: parseTriggerMode(options.triggerMode),
|
|
32526
|
+
enabled: options.disabled ? false : void 0
|
|
32527
|
+
});
|
|
32528
|
+
if (options.json) {
|
|
32529
|
+
console.log(JSON.stringify(result.listener));
|
|
32530
|
+
return;
|
|
32531
|
+
}
|
|
32532
|
+
console.log(`Created GitHub label listener ${result.listener.id}`);
|
|
32533
|
+
}
|
|
32534
|
+
)
|
|
32535
|
+
);
|
|
32536
|
+
var updateCommand = new Command().name("update").alias("edit").description("Update a GitHub label listener").argument("<listener-id>", "GitHub label listener ID").option("--label <name>", "New GitHub label name").option("--agent-id <id>", "New agent ID").option("--prompt <text>", "New prompt").option(
|
|
32537
|
+
"--trigger-mode <mode>",
|
|
32538
|
+
"Who can trigger the listener: anyone | created_by_me"
|
|
32539
|
+
).option("--enable", "Enable the listener").option("--disable", "Disable the listener").option("--json", "Print raw JSON").action(
|
|
32540
|
+
withErrorHandler(
|
|
32541
|
+
async (listenerId, options) => {
|
|
32542
|
+
if (options.enable && options.disable) {
|
|
32543
|
+
throw new Error("Use only one of --enable or --disable");
|
|
32544
|
+
}
|
|
32545
|
+
const body = {};
|
|
32546
|
+
if (options.label !== void 0) body.labelName = options.label;
|
|
32547
|
+
if (options.agentId !== void 0) body.agentId = options.agentId;
|
|
32548
|
+
if (options.prompt !== void 0) body.prompt = options.prompt;
|
|
32549
|
+
if (options.triggerMode !== void 0) {
|
|
32550
|
+
body.triggerMode = parseTriggerMode(options.triggerMode);
|
|
32551
|
+
}
|
|
32552
|
+
if (options.enable) body.enabled = true;
|
|
32553
|
+
if (options.disable) body.enabled = false;
|
|
32554
|
+
if (Object.keys(body).length === 0) {
|
|
32555
|
+
throw new Error(
|
|
32556
|
+
"Provide at least one change: --label, --agent-id, --prompt, --trigger-mode, --enable, or --disable"
|
|
32557
|
+
);
|
|
32558
|
+
}
|
|
32559
|
+
const result = await updateGithubLabelListener(listenerId, body);
|
|
32560
|
+
if (options.json) {
|
|
32561
|
+
console.log(JSON.stringify(result.listener));
|
|
32562
|
+
return;
|
|
32563
|
+
}
|
|
32564
|
+
console.log(`Updated GitHub label listener ${result.listener.id}`);
|
|
32565
|
+
}
|
|
32566
|
+
)
|
|
32567
|
+
);
|
|
32568
|
+
var deleteCommand5 = new Command().name("delete").alias("rm").description("Delete a GitHub label listener").argument("<listener-id>", "GitHub label listener ID").option("--json", "Print raw JSON").action(
|
|
32569
|
+
withErrorHandler(
|
|
32570
|
+
async (listenerId, options) => {
|
|
32571
|
+
const result = await deleteGithubLabelListener(listenerId);
|
|
32572
|
+
if (options.json) {
|
|
32573
|
+
console.log(JSON.stringify(result));
|
|
32574
|
+
return;
|
|
32575
|
+
}
|
|
32576
|
+
console.log(`Deleted GitHub label listener ${listenerId}`);
|
|
32577
|
+
}
|
|
32578
|
+
)
|
|
32579
|
+
);
|
|
32580
|
+
var labelListenerCommand = new Command().name("label-listener").alias("label-listeners").alias("labels").description("Manage GitHub label listeners").addCommand(listCommand9).addCommand(createCommand2).addCommand(updateCommand).addCommand(deleteCommand5).addHelpText(
|
|
32581
|
+
"after",
|
|
32582
|
+
`
|
|
32583
|
+
Examples:
|
|
32584
|
+
List listeners: zero github label-listener list
|
|
32585
|
+
Create listener: zero github label-listener create --label zero --agent-id <agent-id> --prompt "Handle this issue"
|
|
32586
|
+
Edit listener: zero github label-listener update <listener-id> --disable
|
|
32587
|
+
Delete listener: zero github label-listener delete <listener-id>
|
|
32588
|
+
|
|
32589
|
+
Notes:
|
|
32590
|
+
- Updating or deleting a listener is allowed only for the listener owner or an org admin.`
|
|
32591
|
+
);
|
|
32592
|
+
|
|
32435
32593
|
// src/commands/zero/github/upload-file.ts
|
|
32436
32594
|
init_esm_shims();
|
|
32437
32595
|
import { readFileSync as readFileSync5, statSync } from "fs";
|
|
@@ -32531,12 +32689,13 @@ Notes:
|
|
|
32531
32689
|
);
|
|
32532
32690
|
|
|
32533
32691
|
// src/commands/zero/github/index.ts
|
|
32534
|
-
var zeroGithubCommand = new Command().name("github").description("
|
|
32692
|
+
var zeroGithubCommand = new Command().name("github").description("Manage GitHub integration files and label listeners").addCommand(downloadFileCommand).addCommand(labelListenerCommand).addCommand(uploadFileCommand).addHelpText(
|
|
32535
32693
|
"after",
|
|
32536
32694
|
`
|
|
32537
32695
|
Examples:
|
|
32538
32696
|
Upload a file: zero github upload-file -f /tmp/report.pdf -r vm0-ai/vm0 -i 42
|
|
32539
|
-
Download a file: zero github download-file https://github.com/user-attachments/assets/abc123 -o /tmp/out.png
|
|
32697
|
+
Download a file: zero github download-file https://github.com/user-attachments/assets/abc123 -o /tmp/out.png
|
|
32698
|
+
List labels: zero github label-listener list`
|
|
32540
32699
|
);
|
|
32541
32700
|
|
|
32542
32701
|
// src/commands/zero/slack/index.ts
|
|
@@ -32748,7 +32907,7 @@ function statusLabel(bot) {
|
|
|
32748
32907
|
if (bot.tokenStatus === "invalid") return source_default.red("invalid");
|
|
32749
32908
|
return source_default.yellow("unknown");
|
|
32750
32909
|
}
|
|
32751
|
-
var
|
|
32910
|
+
var listCommand10 = new Command().name("list").alias("ls").description("List Telegram bots available in the active organization").addHelpText(
|
|
32752
32911
|
"after",
|
|
32753
32912
|
`
|
|
32754
32913
|
Examples:
|
|
@@ -32807,7 +32966,7 @@ Notes:
|
|
|
32807
32966
|
);
|
|
32808
32967
|
|
|
32809
32968
|
// src/commands/zero/telegram/bot/index.ts
|
|
32810
|
-
var zeroTelegramBotCommand = new Command().name("bot").description("Inspect Telegram bots").addCommand(
|
|
32969
|
+
var zeroTelegramBotCommand = new Command().name("bot").description("Inspect Telegram bots").addCommand(listCommand10).addHelpText(
|
|
32811
32970
|
"after",
|
|
32812
32971
|
`
|
|
32813
32972
|
Examples:
|
|
@@ -33221,7 +33380,7 @@ function truncateValue2(value, maxLength = 60) {
|
|
|
33221
33380
|
}
|
|
33222
33381
|
return value.slice(0, maxLength - 15) + "... [truncated]";
|
|
33223
33382
|
}
|
|
33224
|
-
var
|
|
33383
|
+
var listCommand11 = new Command().name("list").alias("ls").description("List all variables").action(
|
|
33225
33384
|
withErrorHandler(async () => {
|
|
33226
33385
|
const result = await listZeroVariables();
|
|
33227
33386
|
if (result.variables.length === 0) {
|
|
@@ -33277,7 +33436,7 @@ var setCommand5 = new Command().name("set").description("Create or update a vari
|
|
|
33277
33436
|
|
|
33278
33437
|
// src/commands/zero/variable/delete.ts
|
|
33279
33438
|
init_esm_shims();
|
|
33280
|
-
var
|
|
33439
|
+
var deleteCommand6 = new Command().name("delete").description("Delete a variable").argument("<name>", "Variable name to delete").option("-y, --yes", "Skip confirmation prompt").action(
|
|
33281
33440
|
withErrorHandler(async (name, options) => {
|
|
33282
33441
|
if (!options.yes) {
|
|
33283
33442
|
if (!isInteractive()) {
|
|
@@ -33298,7 +33457,7 @@ var deleteCommand5 = new Command().name("delete").description("Delete a variable
|
|
|
33298
33457
|
);
|
|
33299
33458
|
|
|
33300
33459
|
// src/commands/zero/variable/index.ts
|
|
33301
|
-
var zeroVariableCommand = new Command().name("variable").description("Read or write non-sensitive configuration values").addCommand(
|
|
33460
|
+
var zeroVariableCommand = new Command().name("variable").description("Read or write non-sensitive configuration values").addCommand(listCommand11).addCommand(setCommand5).addCommand(deleteCommand6);
|
|
33302
33461
|
|
|
33303
33462
|
// src/commands/zero/whoami.ts
|
|
33304
33463
|
init_esm_shims();
|
|
@@ -33487,7 +33646,7 @@ function readSkillDirectory(dirPath) {
|
|
|
33487
33646
|
}
|
|
33488
33647
|
|
|
33489
33648
|
// src/commands/zero/skill/create.ts
|
|
33490
|
-
var
|
|
33649
|
+
var createCommand3 = new Command().name("create").description("Create a custom skill in the organization").argument("<name>", "Skill name (lowercase alphanumeric with hyphens)").requiredOption("--dir <path>", "Path to directory containing SKILL.md").option("--display-name <name>", "Skill display name").option("--description <text>", "Skill description").addHelpText(
|
|
33491
33650
|
"after",
|
|
33492
33651
|
`
|
|
33493
33652
|
Examples:
|
|
@@ -33577,7 +33736,7 @@ Examples:
|
|
|
33577
33736
|
|
|
33578
33737
|
// src/commands/zero/skill/list.ts
|
|
33579
33738
|
init_esm_shims();
|
|
33580
|
-
var
|
|
33739
|
+
var listCommand12 = new Command().name("list").alias("ls").description("List custom skills in the organization").addHelpText(
|
|
33581
33740
|
"after",
|
|
33582
33741
|
`
|
|
33583
33742
|
Examples:
|
|
@@ -33623,7 +33782,7 @@ Examples:
|
|
|
33623
33782
|
|
|
33624
33783
|
// src/commands/zero/skill/delete.ts
|
|
33625
33784
|
init_esm_shims();
|
|
33626
|
-
var
|
|
33785
|
+
var deleteCommand7 = new Command().name("delete").alias("rm").description("Delete a custom skill from the organization").argument("<name>", "Skill name").option("-y, --yes", "Skip confirmation prompt").addHelpText(
|
|
33627
33786
|
"after",
|
|
33628
33787
|
`
|
|
33629
33788
|
Examples:
|
|
@@ -33655,7 +33814,7 @@ Notes:
|
|
|
33655
33814
|
);
|
|
33656
33815
|
|
|
33657
33816
|
// src/commands/zero/skill/index.ts
|
|
33658
|
-
var zeroSkillCommand = new Command("skill").description("Manage custom skills").addCommand(
|
|
33817
|
+
var zeroSkillCommand = new Command("skill").description("Manage custom skills").addCommand(createCommand3).addCommand(editCommand2).addCommand(viewCommand2).addCommand(listCommand12).addCommand(deleteCommand7).addHelpText(
|
|
33659
33818
|
"after",
|
|
33660
33819
|
`
|
|
33661
33820
|
Examples:
|
|
@@ -33696,7 +33855,7 @@ function formatStatus(status) {
|
|
|
33696
33855
|
function formatTime(iso) {
|
|
33697
33856
|
return new Date(iso).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
33698
33857
|
}
|
|
33699
|
-
var
|
|
33858
|
+
var listCommand13 = new Command().name("list").alias("ls").description("List agent run logs").option("--agent <id>", "Filter by Zero agent ID").option(
|
|
33700
33859
|
"--status <status>",
|
|
33701
33860
|
"Filter by status (queued|pending|running|completed|failed|timeout|cancelled)"
|
|
33702
33861
|
).option(
|
|
@@ -33959,7 +34118,7 @@ async function showAgentEvents(runId, options) {
|
|
|
33959
34118
|
renderer.render(parsed);
|
|
33960
34119
|
}
|
|
33961
34120
|
}
|
|
33962
|
-
var zeroLogsCommand = new Command().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to view agent events for").addCommand(
|
|
34121
|
+
var zeroLogsCommand = new Command().name("logs").description("View and search agent run logs").argument("[runId]", "Run ID to view agent events for").addCommand(listCommand13).addCommand(searchCommand2).option(
|
|
33963
34122
|
"--since <time>",
|
|
33964
34123
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z)"
|
|
33965
34124
|
).option("--tail <n>", "Show last N entries (default: 5)").option("--head <n>", "Show first N entries").option("--all", "Fetch all log entries").addHelpText(
|
|
@@ -34165,13 +34324,13 @@ var zeroSearchCommand = new Command().name("search").description("Search logs, c
|
|
|
34165
34324
|
if (sources.length > 1) {
|
|
34166
34325
|
throw new Error("Only one --source is allowed.");
|
|
34167
34326
|
}
|
|
34168
|
-
const
|
|
34169
|
-
if (!SUPPORTED_SOURCES.includes(
|
|
34327
|
+
const source2 = sources[0];
|
|
34328
|
+
if (!SUPPORTED_SOURCES.includes(source2)) {
|
|
34170
34329
|
throw new Error(
|
|
34171
|
-
`Unknown --source "${
|
|
34330
|
+
`Unknown --source "${source2}". Expected one of: ${SUPPORTED_SOURCES.join(", ")}`
|
|
34172
34331
|
);
|
|
34173
34332
|
}
|
|
34174
|
-
switch (
|
|
34333
|
+
switch (source2) {
|
|
34175
34334
|
case "logs":
|
|
34176
34335
|
await runLogsSource(query, options);
|
|
34177
34336
|
return;
|
|
@@ -34745,6 +34904,457 @@ init_esm_shims();
|
|
|
34745
34904
|
// src/commands/zero/shared/presentation-generate.ts
|
|
34746
34905
|
init_esm_shims();
|
|
34747
34906
|
import { readFileSync as readFileSync14 } from "fs";
|
|
34907
|
+
|
|
34908
|
+
// src/commands/zero/shared/html-artifact-authoring.ts
|
|
34909
|
+
init_esm_shims();
|
|
34910
|
+
|
|
34911
|
+
// src/commands/zero/shared/open-design-registry.ts
|
|
34912
|
+
init_esm_shims();
|
|
34913
|
+
var OPEN_DESIGN_REPO = "vm0-ai/open-design";
|
|
34914
|
+
var OPEN_DESIGN_COMMIT = "d021b04720ace133f1d6133d1487326f5fc28f07";
|
|
34915
|
+
var OPEN_DESIGN_REGISTRY_VERSION = `${OPEN_DESIGN_REPO}@${OPEN_DESIGN_COMMIT}`;
|
|
34916
|
+
function source(path) {
|
|
34917
|
+
return {
|
|
34918
|
+
repo: OPEN_DESIGN_REPO,
|
|
34919
|
+
commit: OPEN_DESIGN_COMMIT,
|
|
34920
|
+
path
|
|
34921
|
+
};
|
|
34922
|
+
}
|
|
34923
|
+
var OPEN_DESIGN_REGISTRY = [
|
|
34924
|
+
{
|
|
34925
|
+
id: "od:skill:data-report",
|
|
34926
|
+
kind: "skill",
|
|
34927
|
+
name: "Data Report",
|
|
34928
|
+
description: "Turns source-backed data, rankings, metrics, or lists into a concise analytical report.",
|
|
34929
|
+
source: source("skills/data-report/SKILL.md"),
|
|
34930
|
+
targets: ["presentation", "website", "dashboard", "report", "docs"],
|
|
34931
|
+
tags: ["analysis", "data", "report", "ranking", "sources", "table"],
|
|
34932
|
+
triggers: ["report", "top 10", "ranking", "metrics", "analysis"],
|
|
34933
|
+
bestFor: ["source-backed reports", "ranked lists", "data summaries"],
|
|
34934
|
+
status: "curated",
|
|
34935
|
+
priority: 40
|
|
34936
|
+
},
|
|
34937
|
+
{
|
|
34938
|
+
id: "od:skill:article-magazine",
|
|
34939
|
+
kind: "skill",
|
|
34940
|
+
name: "Article Magazine",
|
|
34941
|
+
description: "Shapes research or editorial material into a magazine-like narrative with strong hierarchy.",
|
|
34942
|
+
source: source("skills/article-magazine/SKILL.md"),
|
|
34943
|
+
targets: ["presentation", "website", "poster", "report", "docs"],
|
|
34944
|
+
tags: ["editorial", "magazine", "article", "narrative", "research"],
|
|
34945
|
+
triggers: ["magazine", "editorial", "story", "essay", "briefing"],
|
|
34946
|
+
bestFor: [
|
|
34947
|
+
"editorial reports",
|
|
34948
|
+
"narrative explainers",
|
|
34949
|
+
"research synthesis"
|
|
34950
|
+
],
|
|
34951
|
+
status: "curated",
|
|
34952
|
+
priority: 28
|
|
34953
|
+
},
|
|
34954
|
+
{
|
|
34955
|
+
id: "od:skill:design-brief",
|
|
34956
|
+
kind: "skill",
|
|
34957
|
+
name: "Design Brief",
|
|
34958
|
+
description: "Converts a product, brand, or feature request into a structured design brief.",
|
|
34959
|
+
source: source("skills/design-brief/SKILL.md"),
|
|
34960
|
+
targets: ["presentation", "website", "mobile-app", "docs"],
|
|
34961
|
+
tags: ["design", "brief", "product", "brand", "requirements"],
|
|
34962
|
+
triggers: ["design brief", "brand", "product direction", "requirements"],
|
|
34963
|
+
bestFor: ["product design briefs", "brand-driven websites"],
|
|
34964
|
+
status: "curated",
|
|
34965
|
+
priority: 16
|
|
34966
|
+
},
|
|
34967
|
+
{
|
|
34968
|
+
id: "od:template:dashboard",
|
|
34969
|
+
kind: "template",
|
|
34970
|
+
name: "Dashboard",
|
|
34971
|
+
description: "Dense operational dashboard layout for KPIs, lists, filters, and repeated scanning.",
|
|
34972
|
+
source: source("design-templates/dashboard"),
|
|
34973
|
+
targets: ["website", "dashboard", "report"],
|
|
34974
|
+
tags: ["dashboard", "analytics", "kpi", "metrics", "operations", "table"],
|
|
34975
|
+
triggers: ["dashboard", "analytics", "monitoring", "metrics", "ops"],
|
|
34976
|
+
bestFor: ["metric-heavy pages", "status surfaces", "operational summaries"],
|
|
34977
|
+
compatibleWith: ["od:skill:data-report", "od:design-system:dashboard"],
|
|
34978
|
+
status: "curated",
|
|
34979
|
+
priority: 36
|
|
34980
|
+
},
|
|
34981
|
+
{
|
|
34982
|
+
id: "od:template:finance-report",
|
|
34983
|
+
kind: "template",
|
|
34984
|
+
name: "Finance Report",
|
|
34985
|
+
description: "Executive report layout with tables, callouts, trend blocks, and source notes.",
|
|
34986
|
+
source: source("design-templates/finance-report"),
|
|
34987
|
+
targets: ["presentation", "website", "report"],
|
|
34988
|
+
tags: ["report", "finance", "executive", "table", "analysis", "sources"],
|
|
34989
|
+
triggers: ["report", "brief", "analysis", "top 10", "finance"],
|
|
34990
|
+
bestFor: ["source-backed reports", "executive summaries", "ranked lists"],
|
|
34991
|
+
compatibleWith: ["od:skill:data-report", "od:design-system:dashboard"],
|
|
34992
|
+
status: "curated",
|
|
34993
|
+
priority: 34
|
|
34994
|
+
},
|
|
34995
|
+
{
|
|
34996
|
+
id: "od:template:docs-page",
|
|
34997
|
+
kind: "template",
|
|
34998
|
+
name: "Docs Page",
|
|
34999
|
+
description: "Documentation-style page layout for structured explanations, navigation, and examples.",
|
|
35000
|
+
source: source("design-templates/docs-page"),
|
|
35001
|
+
targets: ["website", "docs", "report"],
|
|
35002
|
+
tags: ["docs", "explanation", "guide", "structured", "reference"],
|
|
35003
|
+
triggers: ["docs", "documentation", "guide", "explain", "how to"],
|
|
35004
|
+
bestFor: ["technical explainers", "product docs", "implementation notes"],
|
|
35005
|
+
compatibleWith: ["od:skill:design-brief", "od:design-system:mono"],
|
|
35006
|
+
status: "curated",
|
|
35007
|
+
priority: 26
|
|
35008
|
+
},
|
|
35009
|
+
{
|
|
35010
|
+
id: "od:template:html-ppt-graphify-dark-graph",
|
|
35011
|
+
kind: "template",
|
|
35012
|
+
name: "Graphify Dark Graph",
|
|
35013
|
+
description: "Dark graph-heavy HTML presentation template for data stories and technical briefings.",
|
|
35014
|
+
source: source("design-templates/html-ppt-graphify-dark-graph"),
|
|
35015
|
+
targets: ["presentation", "report"],
|
|
35016
|
+
tags: ["presentation", "dark", "graph", "data", "technical", "metrics"],
|
|
35017
|
+
triggers: ["deck", "presentation", "graph", "dark", "data story"],
|
|
35018
|
+
bestFor: ["data presentations", "technical executive briefings"],
|
|
35019
|
+
compatibleWith: [
|
|
35020
|
+
"od:skill:data-report",
|
|
35021
|
+
"od:design-system:trading-terminal"
|
|
35022
|
+
],
|
|
35023
|
+
status: "curated",
|
|
35024
|
+
priority: 32
|
|
35025
|
+
},
|
|
35026
|
+
{
|
|
35027
|
+
id: "od:template:html-ppt-zhangzara-retro-zine",
|
|
35028
|
+
kind: "template",
|
|
35029
|
+
name: "Zhangzara Retro Zine",
|
|
35030
|
+
description: "Expressive retro editorial HTML presentation template with zine-like composition.",
|
|
35031
|
+
source: source("design-templates/html-ppt-zhangzara-retro-zine"),
|
|
35032
|
+
targets: ["presentation", "poster", "report"],
|
|
35033
|
+
tags: ["presentation", "retro", "zine", "editorial", "expressive"],
|
|
35034
|
+
triggers: ["retro", "zine", "editorial", "magazine", "bold"],
|
|
35035
|
+
bestFor: [
|
|
35036
|
+
"editorial decks",
|
|
35037
|
+
"culture reports",
|
|
35038
|
+
"visually distinctive summaries"
|
|
35039
|
+
],
|
|
35040
|
+
compatibleWith: [
|
|
35041
|
+
"od:skill:article-magazine",
|
|
35042
|
+
"od:design-system:warm-editorial"
|
|
35043
|
+
],
|
|
35044
|
+
status: "curated",
|
|
35045
|
+
priority: 30
|
|
35046
|
+
},
|
|
35047
|
+
{
|
|
35048
|
+
id: "od:template:weekly-update",
|
|
35049
|
+
kind: "template",
|
|
35050
|
+
name: "Weekly Update",
|
|
35051
|
+
description: "Compact update deck/page structure for highlights, risks, next steps, and metrics.",
|
|
35052
|
+
source: source("design-templates/weekly-update"),
|
|
35053
|
+
targets: ["presentation", "report", "docs"],
|
|
35054
|
+
tags: ["update", "status", "briefing", "report", "metrics"],
|
|
35055
|
+
triggers: ["weekly", "status", "update", "briefing"],
|
|
35056
|
+
bestFor: ["team updates", "status reports", "progress summaries"],
|
|
35057
|
+
compatibleWith: ["od:skill:data-report", "od:design-system:dashboard"],
|
|
35058
|
+
status: "curated",
|
|
35059
|
+
priority: 24
|
|
35060
|
+
},
|
|
35061
|
+
{
|
|
35062
|
+
id: "od:template:web-prototype-taste-editorial",
|
|
35063
|
+
kind: "template",
|
|
35064
|
+
name: "Taste Editorial Web Prototype",
|
|
35065
|
+
description: "Editorial website prototype direction with image-led sections and strong copy hierarchy.",
|
|
35066
|
+
source: source("design-templates/web-prototype-taste-editorial"),
|
|
35067
|
+
targets: ["website", "poster"],
|
|
35068
|
+
tags: ["website", "editorial", "brand", "visual", "prototype"],
|
|
35069
|
+
triggers: ["landing", "site", "brand", "editorial", "launch"],
|
|
35070
|
+
bestFor: ["brand websites", "launch pages", "editorial product pages"],
|
|
35071
|
+
compatibleWith: ["od:skill:article-magazine", "od:design-system:editorial"],
|
|
35072
|
+
status: "curated",
|
|
35073
|
+
priority: 30
|
|
35074
|
+
},
|
|
35075
|
+
{
|
|
35076
|
+
id: "od:design-system:dashboard",
|
|
35077
|
+
kind: "design-system",
|
|
35078
|
+
name: "Dashboard",
|
|
35079
|
+
description: "Quiet, dense interface system for dashboards, tables, filters, and repeat workflows.",
|
|
35080
|
+
source: source("design-systems/dashboard"),
|
|
35081
|
+
targets: ["website", "dashboard", "report"],
|
|
35082
|
+
tags: ["dashboard", "neutral", "dense", "table", "operations", "charts"],
|
|
35083
|
+
triggers: ["dashboard", "analytics", "metrics", "ops", "report"],
|
|
35084
|
+
bestFor: ["operational UIs", "data reports", "admin surfaces"],
|
|
35085
|
+
status: "curated",
|
|
35086
|
+
priority: 36
|
|
35087
|
+
},
|
|
35088
|
+
{
|
|
35089
|
+
id: "od:design-system:trading-terminal",
|
|
35090
|
+
kind: "design-system",
|
|
35091
|
+
name: "Trading Terminal",
|
|
35092
|
+
description: "Dark dense market-terminal aesthetic for charts, feeds, tables, and high information density.",
|
|
35093
|
+
source: source("design-systems/trading-terminal"),
|
|
35094
|
+
targets: ["presentation", "website", "dashboard", "report"],
|
|
35095
|
+
tags: ["dark", "terminal", "finance", "data", "charts", "dense"],
|
|
35096
|
+
triggers: ["dark", "terminal", "trading", "chart", "graph"],
|
|
35097
|
+
bestFor: ["dark analytical reports", "graph-heavy dashboards"],
|
|
35098
|
+
status: "curated",
|
|
35099
|
+
priority: 32
|
|
35100
|
+
},
|
|
35101
|
+
{
|
|
35102
|
+
id: "od:design-system:warm-editorial",
|
|
35103
|
+
kind: "design-system",
|
|
35104
|
+
name: "Warm Editorial",
|
|
35105
|
+
description: "Warm editorial design system for readable narrative pages, zines, and reports.",
|
|
35106
|
+
source: source("design-systems/warm-editorial"),
|
|
35107
|
+
targets: ["presentation", "website", "poster", "report", "docs"],
|
|
35108
|
+
tags: ["warm", "editorial", "magazine", "narrative", "readable"],
|
|
35109
|
+
triggers: ["editorial", "magazine", "zine", "warm", "story"],
|
|
35110
|
+
bestFor: ["narrative reports", "editorial decks", "long-form pages"],
|
|
35111
|
+
status: "curated",
|
|
35112
|
+
priority: 30
|
|
35113
|
+
},
|
|
35114
|
+
{
|
|
35115
|
+
id: "od:design-system:editorial",
|
|
35116
|
+
kind: "design-system",
|
|
35117
|
+
name: "Editorial",
|
|
35118
|
+
description: "Clean editorial design system with strong typography, media framing, and section rhythm.",
|
|
35119
|
+
source: source("design-systems/editorial"),
|
|
35120
|
+
targets: ["presentation", "website", "poster", "report", "docs"],
|
|
35121
|
+
tags: ["editorial", "typography", "media", "brand", "article"],
|
|
35122
|
+
triggers: ["editorial", "article", "brand", "landing", "magazine"],
|
|
35123
|
+
bestFor: ["brand sites", "article-style reports", "visual narratives"],
|
|
35124
|
+
status: "curated",
|
|
35125
|
+
priority: 28
|
|
35126
|
+
},
|
|
35127
|
+
{
|
|
35128
|
+
id: "od:design-system:mono",
|
|
35129
|
+
kind: "design-system",
|
|
35130
|
+
name: "Mono",
|
|
35131
|
+
description: "Minimal monospace-oriented system for documentation, technical pages, and precise reports.",
|
|
35132
|
+
source: source("design-systems/mono"),
|
|
35133
|
+
targets: ["website", "docs", "report"],
|
|
35134
|
+
tags: ["mono", "docs", "technical", "minimal", "structured"],
|
|
35135
|
+
triggers: ["docs", "technical", "reference", "minimal", "api"],
|
|
35136
|
+
bestFor: ["technical documentation", "implementation reports"],
|
|
35137
|
+
status: "curated",
|
|
35138
|
+
priority: 20
|
|
35139
|
+
}
|
|
35140
|
+
];
|
|
35141
|
+
function normalizeText(value) {
|
|
35142
|
+
return value.toLowerCase();
|
|
35143
|
+
}
|
|
35144
|
+
function tokenize(value) {
|
|
35145
|
+
return normalizeText(value).split(/[^a-z0-9]+/u).filter((token) => {
|
|
35146
|
+
return token.length >= 2;
|
|
35147
|
+
});
|
|
35148
|
+
}
|
|
35149
|
+
function phraseScore(values, prompt, weight) {
|
|
35150
|
+
if (!values) {
|
|
35151
|
+
return 0;
|
|
35152
|
+
}
|
|
35153
|
+
return values.reduce((score, value) => {
|
|
35154
|
+
return prompt.includes(normalizeText(value)) ? score + weight : score;
|
|
35155
|
+
}, 0);
|
|
35156
|
+
}
|
|
35157
|
+
function tokenScore(values, promptTokens, weight) {
|
|
35158
|
+
if (!values) {
|
|
35159
|
+
return 0;
|
|
35160
|
+
}
|
|
35161
|
+
return values.reduce((score, value) => {
|
|
35162
|
+
const matches = tokenize(value).filter((token) => {
|
|
35163
|
+
return promptTokens.has(token);
|
|
35164
|
+
});
|
|
35165
|
+
return score + matches.length * weight;
|
|
35166
|
+
}, 0);
|
|
35167
|
+
}
|
|
35168
|
+
function scoreEntry(entry, target, prompt) {
|
|
35169
|
+
const normalizedPrompt = normalizeText(prompt);
|
|
35170
|
+
const promptTokens = new Set(tokenize(prompt));
|
|
35171
|
+
const targetScore = entry.targets.includes(target) ? 100 : 0;
|
|
35172
|
+
const curationScore = entry.status === "curated" ? 20 : entry.status === "experimental" ? -20 : -1e3;
|
|
35173
|
+
return targetScore + curationScore + (entry.priority ?? 0) + phraseScore(entry.triggers, normalizedPrompt, 40) + phraseScore(entry.bestFor, normalizedPrompt, 15) + tokenScore(entry.tags, promptTokens, 10) + tokenScore(entry.description.split(" "), promptTokens, 2);
|
|
35174
|
+
}
|
|
35175
|
+
function selectByKind(kind, target, prompt, limit) {
|
|
35176
|
+
return OPEN_DESIGN_REGISTRY.filter((entry) => {
|
|
35177
|
+
return entry.kind === kind && entry.status !== "hidden";
|
|
35178
|
+
}).map((entry) => {
|
|
35179
|
+
return { entry, score: scoreEntry(entry, target, prompt) };
|
|
35180
|
+
}).filter(({ score }) => {
|
|
35181
|
+
return score > 0;
|
|
35182
|
+
}).sort((left, right) => {
|
|
35183
|
+
if (right.score !== left.score) {
|
|
35184
|
+
return right.score - left.score;
|
|
35185
|
+
}
|
|
35186
|
+
return left.entry.id.localeCompare(right.entry.id);
|
|
35187
|
+
}).slice(0, limit).map(({ entry }) => {
|
|
35188
|
+
return entry;
|
|
35189
|
+
});
|
|
35190
|
+
}
|
|
35191
|
+
function selectOpenDesignCandidates(options) {
|
|
35192
|
+
const limitPerKind = options.limitPerKind ?? 8;
|
|
35193
|
+
return {
|
|
35194
|
+
registryVersion: OPEN_DESIGN_REGISTRY_VERSION,
|
|
35195
|
+
source: {
|
|
35196
|
+
repo: OPEN_DESIGN_REPO,
|
|
35197
|
+
commit: OPEN_DESIGN_COMMIT
|
|
35198
|
+
},
|
|
35199
|
+
candidates: {
|
|
35200
|
+
skills: selectByKind(
|
|
35201
|
+
"skill",
|
|
35202
|
+
options.target,
|
|
35203
|
+
options.prompt,
|
|
35204
|
+
limitPerKind
|
|
35205
|
+
),
|
|
35206
|
+
templates: selectByKind(
|
|
35207
|
+
"template",
|
|
35208
|
+
options.target,
|
|
35209
|
+
options.prompt,
|
|
35210
|
+
limitPerKind
|
|
35211
|
+
),
|
|
35212
|
+
designSystems: selectByKind(
|
|
35213
|
+
"design-system",
|
|
35214
|
+
options.target,
|
|
35215
|
+
options.prompt,
|
|
35216
|
+
limitPerKind
|
|
35217
|
+
)
|
|
35218
|
+
}
|
|
35219
|
+
};
|
|
35220
|
+
}
|
|
35221
|
+
|
|
35222
|
+
// src/commands/zero/shared/html-artifact-authoring.ts
|
|
35223
|
+
function slugify(value) {
|
|
35224
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").replace(/-{2,}/gu, "-").slice(0, 48).replace(/-+$/u, "");
|
|
35225
|
+
return slug.length >= 3 ? slug : "html-artifact";
|
|
35226
|
+
}
|
|
35227
|
+
function titleForKind(kind) {
|
|
35228
|
+
const titles = {
|
|
35229
|
+
presentation: "HTML presentation",
|
|
35230
|
+
website: "hosted website",
|
|
35231
|
+
dashboard: "dashboard",
|
|
35232
|
+
"mobile-app": "mobile app prototype",
|
|
35233
|
+
poster: "poster",
|
|
35234
|
+
"intro-video": "intro video storyboard",
|
|
35235
|
+
report: "report",
|
|
35236
|
+
docs: "documentation site"
|
|
35237
|
+
};
|
|
35238
|
+
return titles[kind];
|
|
35239
|
+
}
|
|
35240
|
+
function outputDirForSite(site) {
|
|
35241
|
+
return `./opendesign/mockups/${site}`;
|
|
35242
|
+
}
|
|
35243
|
+
function createHtmlArtifactAuthoringPacket(options) {
|
|
35244
|
+
const site = options.site ?? slugify(options.slugSource ?? options.prompt);
|
|
35245
|
+
const outputDir = outputDirForSite(site);
|
|
35246
|
+
const hostCommand = `zero host ${outputDir} --site ${site}${options.kind === "website" ? " --spa" : ""}`;
|
|
35247
|
+
const title = titleForKind(options.kind);
|
|
35248
|
+
const candidateSlice = selectOpenDesignCandidates({
|
|
35249
|
+
target: options.kind,
|
|
35250
|
+
prompt: [
|
|
35251
|
+
options.prompt,
|
|
35252
|
+
options.slugSource ?? "",
|
|
35253
|
+
...options.details,
|
|
35254
|
+
...options.artifactRules
|
|
35255
|
+
].join("\n")
|
|
35256
|
+
});
|
|
35257
|
+
const selectionSchema = {
|
|
35258
|
+
skills: "string[]",
|
|
35259
|
+
template: "string",
|
|
35260
|
+
designSystem: "string | null",
|
|
35261
|
+
rationale: "string"
|
|
35262
|
+
};
|
|
35263
|
+
const instructions = [
|
|
35264
|
+
`# Zero built-in generate ${options.kind}`,
|
|
35265
|
+
"",
|
|
35266
|
+
"This is an Open Design resource-selection packet for the current agent.",
|
|
35267
|
+
`Zero is not generating this ${title} on the server. You select resources, resolve them, and author the artifact.`,
|
|
35268
|
+
"",
|
|
35269
|
+
"## User Prompt",
|
|
35270
|
+
options.prompt,
|
|
35271
|
+
"",
|
|
35272
|
+
"## Stage 1: Resource Selection",
|
|
35273
|
+
"- Choose the Open Design resources from the bundled registry slice below.",
|
|
35274
|
+
"- Select one template, one or more skills, and zero or one design system.",
|
|
35275
|
+
"- Choose only IDs present in this packet; do not invent registry IDs.",
|
|
35276
|
+
"- Prefer compatible resources, but the user prompt is the highest-priority signal.",
|
|
35277
|
+
"- Treat the selection JSON as internal working state, then continue to authoring.",
|
|
35278
|
+
"",
|
|
35279
|
+
"## Selection Output Schema",
|
|
35280
|
+
"```json",
|
|
35281
|
+
JSON.stringify(selectionSchema, null, 2),
|
|
35282
|
+
"```",
|
|
35283
|
+
"",
|
|
35284
|
+
"## Candidate Registry Slice",
|
|
35285
|
+
`Registry: \`${candidateSlice.registryVersion}\``,
|
|
35286
|
+
"",
|
|
35287
|
+
"```json",
|
|
35288
|
+
JSON.stringify(candidateSlice.candidates, null, 2),
|
|
35289
|
+
"```",
|
|
35290
|
+
"",
|
|
35291
|
+
"## Stage 2: Resolve Selected Resources",
|
|
35292
|
+
"- For every selected resource, fetch or read the referenced Open Design source before authoring.",
|
|
35293
|
+
"- Source refs are pinned as `repo@commit:path`; use the commit in the packet for reproducibility.",
|
|
35294
|
+
"- For directory refs, inspect the most relevant files such as `SKILL.md`, `DESIGN.md`, `README.md`, tokens, examples, and templates.",
|
|
35295
|
+
"- If a source file cannot be fetched, state that limitation and fall back to the registry metadata for that resource.",
|
|
35296
|
+
"",
|
|
35297
|
+
"## Stage 3: Author Artifact",
|
|
35298
|
+
`Author a production-quality ${title} as a static HTML artifact using the selected Open Design resources.`,
|
|
35299
|
+
"",
|
|
35300
|
+
"## Output Contract",
|
|
35301
|
+
`- Write the artifact under \`${outputDir}/\`.`,
|
|
35302
|
+
`- The entry file must be \`${outputDir}/index.html\`.`,
|
|
35303
|
+
"- Keep every local asset inside the same output directory.",
|
|
35304
|
+
"- Do not reference files from another project path.",
|
|
35305
|
+
"- Use descriptive filenames and canonical HTML: close non-void tags and double-quote attributes.",
|
|
35306
|
+
"- Prefer a single self-contained HTML file unless the artifact genuinely needs separate assets.",
|
|
35307
|
+
"",
|
|
35308
|
+
"## Requested Parameters",
|
|
35309
|
+
...options.details.map((detail) => {
|
|
35310
|
+
return `- ${detail}`;
|
|
35311
|
+
}),
|
|
35312
|
+
"",
|
|
35313
|
+
"## Open Design Authoring Rules",
|
|
35314
|
+
"- Let the selected template define structure, the selected design system define visual language, and the selected skills define process.",
|
|
35315
|
+
"- Read the local codebase, brand assets, and existing design systems when the prompt depends on this repository.",
|
|
35316
|
+
"- Avoid generic AI design defaults: no stock SaaS gradients, no emoji-as-icons, no filler stats, no decorative chrome that does not help the artifact.",
|
|
35317
|
+
"- Build the actual artifact first, not a marketing explanation of the artifact.",
|
|
35318
|
+
"- Make controls and interactions real when they are visible.",
|
|
35319
|
+
"- Keep text readable at desktop and mobile preview sizes.",
|
|
35320
|
+
...options.artifactRules.map((rule) => {
|
|
35321
|
+
return `- ${rule}`;
|
|
35322
|
+
}),
|
|
35323
|
+
"",
|
|
35324
|
+
"## Verification",
|
|
35325
|
+
"- Open the HTML locally and verify it is nonblank.",
|
|
35326
|
+
"- Check that keyboard/click interactions work when present.",
|
|
35327
|
+
"- Check that text does not overflow or overlap at desktop and mobile viewport sizes.",
|
|
35328
|
+
"- Run the final hosting command only after the artifact looks correct.",
|
|
35329
|
+
"",
|
|
35330
|
+
"## Publish",
|
|
35331
|
+
`When everything is OK, publish it with:`,
|
|
35332
|
+
"",
|
|
35333
|
+
"```bash",
|
|
35334
|
+
hostCommand,
|
|
35335
|
+
"```"
|
|
35336
|
+
].join("\n");
|
|
35337
|
+
return {
|
|
35338
|
+
type: "open-design-resource-selection",
|
|
35339
|
+
kind: options.kind,
|
|
35340
|
+
prompt: options.prompt,
|
|
35341
|
+
registryVersion: candidateSlice.registryVersion,
|
|
35342
|
+
selection: {
|
|
35343
|
+
candidates: candidateSlice.candidates,
|
|
35344
|
+
outputSchema: selectionSchema
|
|
35345
|
+
},
|
|
35346
|
+
authoring: {
|
|
35347
|
+
details: options.details,
|
|
35348
|
+
artifactRules: options.artifactRules
|
|
35349
|
+
},
|
|
35350
|
+
outputDir,
|
|
35351
|
+
site,
|
|
35352
|
+
hostCommand,
|
|
35353
|
+
instructions
|
|
35354
|
+
};
|
|
35355
|
+
}
|
|
35356
|
+
|
|
35357
|
+
// src/commands/zero/shared/presentation-generate.ts
|
|
34748
35358
|
var PRESENTATION_MAX_IMAGES = 8;
|
|
34749
35359
|
function parseSlideCount(value) {
|
|
34750
35360
|
const slideCount = Number(value);
|
|
@@ -34782,7 +35392,7 @@ function readPrompt2(options, usageCommand) {
|
|
|
34782
35392
|
});
|
|
34783
35393
|
}
|
|
34784
35394
|
function createPresentationGenerateCommand(config) {
|
|
34785
|
-
return new Command().name(config.name).description("Generate
|
|
35395
|
+
return new Command().name(config.name).description("Generate an HTML presentation from a prompt").option(
|
|
34786
35396
|
"--prompt <text>",
|
|
34787
35397
|
"Presentation prompt; can also be piped via stdin"
|
|
34788
35398
|
).option("--style <style>", "Style: editorial or swiss", "editorial").option("--slides <count>", "Slide count: 4-20", parseSlideCount, 8).option(
|
|
@@ -34803,15 +35413,44 @@ Examples:
|
|
|
34803
35413
|
${config.examples}
|
|
34804
35414
|
|
|
34805
35415
|
Output:
|
|
34806
|
-
Prints the generated /f/ HTML presentation URL and metadata
|
|
35416
|
+
Prints the generated /f/ HTML presentation URL and metadata. With openDesignGenerate enabled, prints an Open Design registry-selection packet for the current agent instead.
|
|
34807
35417
|
|
|
34808
35418
|
Notes:
|
|
34809
|
-
- Authenticates via ZERO_TOKEN
|
|
34810
|
-
-
|
|
34811
|
-
-
|
|
35419
|
+
- Authenticates via ZERO_TOKEN
|
|
35420
|
+
- Default path charges org credits after successful presentation generation
|
|
35421
|
+
- OpenDesign path is gated by the openDesignGenerate feature switch`
|
|
34812
35422
|
).action(
|
|
34813
35423
|
withErrorHandler(async (options) => {
|
|
34814
35424
|
const prompt = readPrompt2(options, config.usageCommand);
|
|
35425
|
+
if (zeroTokenAllowsFeatureSwitch("openDesignGenerate" /* OpenDesignGenerate */)) {
|
|
35426
|
+
const packet = createHtmlArtifactAuthoringPacket({
|
|
35427
|
+
kind: "presentation",
|
|
35428
|
+
prompt,
|
|
35429
|
+
slugSource: options.title,
|
|
35430
|
+
details: [
|
|
35431
|
+
`Style: ${options.style}`,
|
|
35432
|
+
`Slide count: ${options.slides}`,
|
|
35433
|
+
`Suggested generated visual count: ${options.images}`,
|
|
35434
|
+
`Image model preference if visuals are generated separately: ${options.imageModel ?? "default"}`,
|
|
35435
|
+
`Theme: ${options.theme ?? "agent decides from style"}`,
|
|
35436
|
+
`Audience: ${options.audience ?? "not specified"}`,
|
|
35437
|
+
`Requested deck title: ${options.title ?? "not specified"}`
|
|
35438
|
+
],
|
|
35439
|
+
artifactRules: [
|
|
35440
|
+
"Think like a presentation designer, not a web page designer.",
|
|
35441
|
+
"Use a fixed 1920x1080 slide canvas and scale it uniformly for smaller viewports.",
|
|
35442
|
+
"Use one section per slide and keep repeated elements in consistent positions.",
|
|
35443
|
+
"Make keyboard navigation work with ArrowLeft, ArrowRight, Home, and End.",
|
|
35444
|
+
"Keep slide text readable from across a room; avoid memo-like walls of text."
|
|
35445
|
+
]
|
|
35446
|
+
});
|
|
35447
|
+
if (options.json) {
|
|
35448
|
+
console.log(JSON.stringify(packet));
|
|
35449
|
+
return;
|
|
35450
|
+
}
|
|
35451
|
+
console.log(packet.instructions);
|
|
35452
|
+
return;
|
|
35453
|
+
}
|
|
34815
35454
|
const result = await generateWebPresentation({
|
|
34816
35455
|
prompt,
|
|
34817
35456
|
style: options.style,
|
|
@@ -34860,6 +35499,22 @@ init_esm_shims();
|
|
|
34860
35499
|
// src/commands/zero/shared/video-generate.ts
|
|
34861
35500
|
init_esm_shims();
|
|
34862
35501
|
import { readFileSync as readFileSync15 } from "fs";
|
|
35502
|
+
var FRAME_ASPECT_RATIO_TOLERANCE = 0.02;
|
|
35503
|
+
var JPEG_START_OF_FRAME_MARKERS = /* @__PURE__ */ new Set([
|
|
35504
|
+
192,
|
|
35505
|
+
193,
|
|
35506
|
+
194,
|
|
35507
|
+
195,
|
|
35508
|
+
197,
|
|
35509
|
+
198,
|
|
35510
|
+
199,
|
|
35511
|
+
201,
|
|
35512
|
+
202,
|
|
35513
|
+
203,
|
|
35514
|
+
205,
|
|
35515
|
+
206,
|
|
35516
|
+
207
|
|
35517
|
+
]);
|
|
34863
35518
|
function parseSeed2(value) {
|
|
34864
35519
|
const seed = Number(value);
|
|
34865
35520
|
if (!Number.isInteger(seed) || seed < 0 || !Number.isSafeInteger(seed)) {
|
|
@@ -34870,6 +35525,173 @@ function parseSeed2(value) {
|
|
|
34870
35525
|
function collectUrl(value, previous = []) {
|
|
34871
35526
|
return [...previous, value];
|
|
34872
35527
|
}
|
|
35528
|
+
function parseAspectRatio(value) {
|
|
35529
|
+
const [widthText, heightText] = value.split(":");
|
|
35530
|
+
const width = Number(widthText);
|
|
35531
|
+
const height = Number(heightText);
|
|
35532
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
35533
|
+
throw new Error(`Invalid --aspect-ratio "${value}"`);
|
|
35534
|
+
}
|
|
35535
|
+
return { width, height };
|
|
35536
|
+
}
|
|
35537
|
+
function readPngDimensions(buffer) {
|
|
35538
|
+
if (buffer.length < 24 || buffer.toString("latin1", 0, 8) !== "\x89PNG\r\n\n") {
|
|
35539
|
+
return void 0;
|
|
35540
|
+
}
|
|
35541
|
+
return {
|
|
35542
|
+
width: buffer.readUInt32BE(16),
|
|
35543
|
+
height: buffer.readUInt32BE(20)
|
|
35544
|
+
};
|
|
35545
|
+
}
|
|
35546
|
+
function readGifDimensions(buffer) {
|
|
35547
|
+
if (buffer.length < 10 || !buffer.toString("latin1", 0, 6).startsWith("GIF")) {
|
|
35548
|
+
return void 0;
|
|
35549
|
+
}
|
|
35550
|
+
return {
|
|
35551
|
+
width: buffer.readUInt16LE(6),
|
|
35552
|
+
height: buffer.readUInt16LE(8)
|
|
35553
|
+
};
|
|
35554
|
+
}
|
|
35555
|
+
function readJpegDimensions(buffer) {
|
|
35556
|
+
if (buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
|
|
35557
|
+
return void 0;
|
|
35558
|
+
}
|
|
35559
|
+
let offset = 2;
|
|
35560
|
+
while (offset + 9 < buffer.length) {
|
|
35561
|
+
if (buffer[offset] !== 255) {
|
|
35562
|
+
offset += 1;
|
|
35563
|
+
continue;
|
|
35564
|
+
}
|
|
35565
|
+
const marker = buffer[offset + 1];
|
|
35566
|
+
if (marker === 217 || marker === 218) {
|
|
35567
|
+
break;
|
|
35568
|
+
}
|
|
35569
|
+
const segmentLength = buffer.readUInt16BE(offset + 2);
|
|
35570
|
+
if (segmentLength < 2 || offset + 2 + segmentLength > buffer.length) {
|
|
35571
|
+
break;
|
|
35572
|
+
}
|
|
35573
|
+
if (JPEG_START_OF_FRAME_MARKERS.has(marker)) {
|
|
35574
|
+
return {
|
|
35575
|
+
height: buffer.readUInt16BE(offset + 5),
|
|
35576
|
+
width: buffer.readUInt16BE(offset + 7)
|
|
35577
|
+
};
|
|
35578
|
+
}
|
|
35579
|
+
offset += 2 + segmentLength;
|
|
35580
|
+
}
|
|
35581
|
+
return void 0;
|
|
35582
|
+
}
|
|
35583
|
+
function readUnsigned24LE(buffer, offset) {
|
|
35584
|
+
return buffer.readUInt8(offset) + (buffer.readUInt8(offset + 1) << 8) + (buffer.readUInt8(offset + 2) << 16);
|
|
35585
|
+
}
|
|
35586
|
+
function readWebpDimensions(buffer) {
|
|
35587
|
+
if (buffer.length < 30 || buffer.toString("ascii", 0, 4) !== "RIFF" || buffer.toString("ascii", 8, 12) !== "WEBP") {
|
|
35588
|
+
return void 0;
|
|
35589
|
+
}
|
|
35590
|
+
let offset = 12;
|
|
35591
|
+
while (offset + 8 <= buffer.length) {
|
|
35592
|
+
const chunkType = buffer.toString("ascii", offset, offset + 4);
|
|
35593
|
+
const chunkSize = buffer.readUInt32LE(offset + 4);
|
|
35594
|
+
const payloadOffset = offset + 8;
|
|
35595
|
+
if (payloadOffset + chunkSize > buffer.length) {
|
|
35596
|
+
break;
|
|
35597
|
+
}
|
|
35598
|
+
if (chunkType === "VP8X" && chunkSize >= 10) {
|
|
35599
|
+
return {
|
|
35600
|
+
width: readUnsigned24LE(buffer, payloadOffset + 4) + 1,
|
|
35601
|
+
height: readUnsigned24LE(buffer, payloadOffset + 7) + 1
|
|
35602
|
+
};
|
|
35603
|
+
}
|
|
35604
|
+
if (chunkType === "VP8L" && chunkSize >= 5 && buffer[payloadOffset] === 47) {
|
|
35605
|
+
const byte1 = buffer.readUInt8(payloadOffset + 1);
|
|
35606
|
+
const byte2 = buffer.readUInt8(payloadOffset + 2);
|
|
35607
|
+
const byte3 = buffer.readUInt8(payloadOffset + 3);
|
|
35608
|
+
const byte4 = buffer.readUInt8(payloadOffset + 4);
|
|
35609
|
+
return {
|
|
35610
|
+
width: 1 + byte1 + ((byte2 & 63) << 8),
|
|
35611
|
+
height: 1 + ((byte2 & 192) >> 6) + (byte3 << 2) + ((byte4 & 15) << 10)
|
|
35612
|
+
};
|
|
35613
|
+
}
|
|
35614
|
+
if (chunkType === "VP8 " && chunkSize >= 10 && buffer[payloadOffset + 3] === 157 && buffer[payloadOffset + 4] === 1 && buffer[payloadOffset + 5] === 42) {
|
|
35615
|
+
return {
|
|
35616
|
+
width: buffer.readUInt16LE(payloadOffset + 6) & 16383,
|
|
35617
|
+
height: buffer.readUInt16LE(payloadOffset + 8) & 16383
|
|
35618
|
+
};
|
|
35619
|
+
}
|
|
35620
|
+
offset = payloadOffset + chunkSize + chunkSize % 2;
|
|
35621
|
+
}
|
|
35622
|
+
return void 0;
|
|
35623
|
+
}
|
|
35624
|
+
function readImageDimensions(buffer) {
|
|
35625
|
+
return readPngDimensions(buffer) ?? readJpegDimensions(buffer) ?? readWebpDimensions(buffer) ?? readGifDimensions(buffer);
|
|
35626
|
+
}
|
|
35627
|
+
function formatDimensionsAsRatio({ width, height }) {
|
|
35628
|
+
const divisor = greatestCommonDivisor(width, height);
|
|
35629
|
+
return `${width / divisor}:${height / divisor}`;
|
|
35630
|
+
}
|
|
35631
|
+
function greatestCommonDivisor(left, right) {
|
|
35632
|
+
let a = Math.abs(left);
|
|
35633
|
+
let b = Math.abs(right);
|
|
35634
|
+
while (b !== 0) {
|
|
35635
|
+
const remainder = a % b;
|
|
35636
|
+
a = b;
|
|
35637
|
+
b = remainder;
|
|
35638
|
+
}
|
|
35639
|
+
return a || 1;
|
|
35640
|
+
}
|
|
35641
|
+
function hasMatchingAspectRatio(actual, expected) {
|
|
35642
|
+
const actualRatio = actual.width / actual.height;
|
|
35643
|
+
const expectedRatio = expected.width / expected.height;
|
|
35644
|
+
return Math.abs(actualRatio - expectedRatio) / expectedRatio <= FRAME_ASPECT_RATIO_TOLERANCE;
|
|
35645
|
+
}
|
|
35646
|
+
async function fetchImageDimensions(optionName, imageUrl) {
|
|
35647
|
+
let url;
|
|
35648
|
+
try {
|
|
35649
|
+
url = new URL(imageUrl);
|
|
35650
|
+
} catch {
|
|
35651
|
+
throw new Error(`${optionName} must be an absolute URL`);
|
|
35652
|
+
}
|
|
35653
|
+
const response = await fetch(url);
|
|
35654
|
+
if (!response.ok) {
|
|
35655
|
+
throw new Error(
|
|
35656
|
+
`Could not validate ${optionName}: failed to fetch image (HTTP ${response.status})`
|
|
35657
|
+
);
|
|
35658
|
+
}
|
|
35659
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
35660
|
+
const dimensions = readImageDimensions(buffer);
|
|
35661
|
+
if (!dimensions) {
|
|
35662
|
+
throw new Error(
|
|
35663
|
+
`Could not validate ${optionName}: unsupported image format or missing dimensions`
|
|
35664
|
+
);
|
|
35665
|
+
}
|
|
35666
|
+
return dimensions;
|
|
35667
|
+
}
|
|
35668
|
+
async function validateFrameImageAspectRatio(optionName, imageUrl, aspectRatio) {
|
|
35669
|
+
if (!imageUrl) {
|
|
35670
|
+
return;
|
|
35671
|
+
}
|
|
35672
|
+
const expected = parseAspectRatio(aspectRatio);
|
|
35673
|
+
const actual = await fetchImageDimensions(optionName, imageUrl);
|
|
35674
|
+
if (hasMatchingAspectRatio(actual, expected)) {
|
|
35675
|
+
return;
|
|
35676
|
+
}
|
|
35677
|
+
throw new Error(
|
|
35678
|
+
`${optionName} has aspect ratio ${formatDimensionsAsRatio(actual)} (${actual.width}x${actual.height}), but --aspect-ratio is ${aspectRatio}. Use --aspect-ratio ${formatDimensionsAsRatio(actual)} or provide a frame image with ${aspectRatio} dimensions.`
|
|
35679
|
+
);
|
|
35680
|
+
}
|
|
35681
|
+
async function validateVideoOptions(options) {
|
|
35682
|
+
await Promise.all([
|
|
35683
|
+
validateFrameImageAspectRatio(
|
|
35684
|
+
"--first-frame-image-url",
|
|
35685
|
+
options.firstFrameImageUrl,
|
|
35686
|
+
options.aspectRatio
|
|
35687
|
+
),
|
|
35688
|
+
validateFrameImageAspectRatio(
|
|
35689
|
+
"--last-frame-image-url",
|
|
35690
|
+
options.lastFrameImageUrl,
|
|
35691
|
+
options.aspectRatio
|
|
35692
|
+
)
|
|
35693
|
+
]);
|
|
35694
|
+
}
|
|
34873
35695
|
function readPrompt3(options, usageCommand) {
|
|
34874
35696
|
if (options.prompt?.trim()) {
|
|
34875
35697
|
return options.prompt.trim();
|
|
@@ -34941,6 +35763,7 @@ Models:
|
|
|
34941
35763
|
).action(
|
|
34942
35764
|
withErrorHandler(async (options) => {
|
|
34943
35765
|
const prompt = readPrompt3(options, config.usageCommand);
|
|
35766
|
+
await validateVideoOptions(options);
|
|
34944
35767
|
const result = await generateWebVideo({
|
|
34945
35768
|
prompt,
|
|
34946
35769
|
model: options.model,
|
|
@@ -36066,7 +36889,7 @@ function formatBytes(bytes) {
|
|
|
36066
36889
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
36067
36890
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
36068
36891
|
}
|
|
36069
|
-
var websiteCommand = new Command().name("website").description("Generate
|
|
36892
|
+
var websiteCommand = new Command().name("website").description("Generate a hosted website from a prompt").option("--prompt <text>", "Website prompt; can also be piped via stdin").option(
|
|
36070
36893
|
"--template <template>",
|
|
36071
36894
|
"Template: auto, launch, or profile",
|
|
36072
36895
|
parseTemplate,
|
|
@@ -36089,15 +36912,42 @@ Examples:
|
|
|
36089
36912
|
Pipe prompt: cat brief.txt | zero built-in generate website
|
|
36090
36913
|
|
|
36091
36914
|
Output:
|
|
36092
|
-
|
|
36915
|
+
Generates and publishes a hosted website. With openDesignGenerate enabled, prints an Open Design registry-selection packet for the current agent instead.
|
|
36093
36916
|
|
|
36094
36917
|
Notes:
|
|
36095
|
-
- Authenticates via ZERO_TOKEN
|
|
36096
|
-
-
|
|
36097
|
-
-
|
|
36918
|
+
- Authenticates via ZERO_TOKEN
|
|
36919
|
+
- Default path charges org credits for model-generated website content
|
|
36920
|
+
- OpenDesign path is gated by the openDesignGenerate feature switch`
|
|
36098
36921
|
).action(
|
|
36099
36922
|
withErrorHandler(async (options) => {
|
|
36100
36923
|
const prompt = readPrompt4(options);
|
|
36924
|
+
if (zeroTokenAllowsFeatureSwitch("openDesignGenerate" /* OpenDesignGenerate */)) {
|
|
36925
|
+
const packet = createHtmlArtifactAuthoringPacket({
|
|
36926
|
+
kind: "website",
|
|
36927
|
+
prompt,
|
|
36928
|
+
slugSource: options.title,
|
|
36929
|
+
site: options.site,
|
|
36930
|
+
details: [
|
|
36931
|
+
`Template direction: ${options.template}`,
|
|
36932
|
+
`Suggested generated visual count: ${options.images}`,
|
|
36933
|
+
`Image model preference if visuals are generated separately: ${options.imageModel ?? "default"}`,
|
|
36934
|
+
`Requested title/site name: ${options.title ?? "not specified"}`,
|
|
36935
|
+
`Audience: ${options.audience ?? "not specified"}`
|
|
36936
|
+
],
|
|
36937
|
+
artifactRules: [
|
|
36938
|
+
"Build the usable website as the first screen; do not output a landing-page plan.",
|
|
36939
|
+
"If it is a marketing site, make the product or offer visible in the first viewport.",
|
|
36940
|
+
"For app or tool surfaces, prioritize dense, scannable, task-focused UI over decorative sections.",
|
|
36941
|
+
"Use responsive HTML/CSS and verify the page works at mobile and desktop widths."
|
|
36942
|
+
]
|
|
36943
|
+
});
|
|
36944
|
+
if (options.json) {
|
|
36945
|
+
console.log(JSON.stringify(packet));
|
|
36946
|
+
return;
|
|
36947
|
+
}
|
|
36948
|
+
console.log(packet.instructions);
|
|
36949
|
+
return;
|
|
36950
|
+
}
|
|
36101
36951
|
if (!options.json) {
|
|
36102
36952
|
console.log(source_default.dim("Generating website content..."));
|
|
36103
36953
|
}
|
|
@@ -36974,7 +37824,7 @@ function getModelSwitchGuidance(integration = getCurrentIntegration()) {
|
|
|
36974
37824
|
}
|
|
36975
37825
|
return "Open https://app.vm0.ai and switch models from the model selector next to the input box.";
|
|
36976
37826
|
}
|
|
36977
|
-
var
|
|
37827
|
+
var listCommand14 = new Command().name("list").alias("ls").description("List models allowed by the current organization").action(
|
|
36978
37828
|
withErrorHandler(async () => {
|
|
36979
37829
|
const result = await listZeroModelPolicies();
|
|
36980
37830
|
if (result.policies.length === 0) {
|
|
@@ -37010,7 +37860,7 @@ var listCommand13 = new Command().name("list").alias("ls").description("List mod
|
|
|
37010
37860
|
var switchCommand = new Command().name("switch").description("Show how to switch models in the current environment").action(() => {
|
|
37011
37861
|
console.log(getModelSwitchGuidance());
|
|
37012
37862
|
});
|
|
37013
|
-
var zeroModelCommand = new Command().name("model").description("List available models and model-switching guidance").addCommand(
|
|
37863
|
+
var zeroModelCommand = new Command().name("model").description("List available models and model-switching guidance").addCommand(listCommand14).addCommand(switchCommand);
|
|
37014
37864
|
|
|
37015
37865
|
// src/commands/zero/model-provider/index.ts
|
|
37016
37866
|
init_esm_shims();
|
|
@@ -37021,7 +37871,7 @@ var MODEL_PROVIDER_SET_GUIDANCE = [
|
|
|
37021
37871
|
"",
|
|
37022
37872
|
"If an organization admin sets a model provider to subscription, members must use the bottom-left user menu, choose Preferences / Personal Models, and connect their personal subscription."
|
|
37023
37873
|
].join("\n");
|
|
37024
|
-
var
|
|
37874
|
+
var listCommand15 = new Command().name("list").alias("ls").description(
|
|
37025
37875
|
"List provider routing for each model allowed by the organization"
|
|
37026
37876
|
).action(
|
|
37027
37877
|
withErrorHandler(async () => {
|
|
@@ -37056,7 +37906,7 @@ var setCommand6 = new Command().name("set").description("Show where to adjust mo
|
|
|
37056
37906
|
${MODEL_PROVIDER_SET_GUIDANCE}`).action(() => {
|
|
37057
37907
|
console.log(MODEL_PROVIDER_SET_GUIDANCE);
|
|
37058
37908
|
});
|
|
37059
|
-
var zeroModelProviderCommand = new Command().name("model-provider").description("Inspect model provider routing").addCommand(
|
|
37909
|
+
var zeroModelProviderCommand = new Command().name("model-provider").description("Inspect model provider routing").addCommand(listCommand15).addCommand(setCommand6);
|
|
37060
37910
|
|
|
37061
37911
|
// src/zero.ts
|
|
37062
37912
|
var COMMAND_CAPABILITY_MAP = {
|
|
@@ -37177,7 +38027,7 @@ function registerZeroCommands(prog, commands) {
|
|
|
37177
38027
|
var program = new Command();
|
|
37178
38028
|
program.name("zero").description(
|
|
37179
38029
|
"Zero CLI \u2014 interact with the zero platform from inside the sandbox"
|
|
37180
|
-
).version("9.161.
|
|
38030
|
+
).version("9.161.9").addHelpText("after", () => {
|
|
37181
38031
|
return buildZeroHelpText();
|
|
37182
38032
|
});
|
|
37183
38033
|
if (process.argv[1]?.endsWith("zero.js") || process.argv[1]?.endsWith("zero.ts") || process.argv[1]?.endsWith("zero")) {
|