fluncle 0.135.0 → 0.136.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/bin/fluncle.mjs +368 -18
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -561,7 +561,7 @@ function parseVersion(version) {
|
|
|
561
561
|
var currentVersion;
|
|
562
562
|
var init_version = __esm(() => {
|
|
563
563
|
init_output();
|
|
564
|
-
currentVersion = "0.
|
|
564
|
+
currentVersion = "0.136.0".trim() ? "0.136.0".trim() : "0.1.0";
|
|
565
565
|
});
|
|
566
566
|
|
|
567
567
|
// src/update-notifier.ts
|
|
@@ -2189,7 +2189,7 @@ function parseVersion2(version) {
|
|
|
2189
2189
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2190
2190
|
var init_version2 = __esm(() => {
|
|
2191
2191
|
init_output();
|
|
2192
|
-
currentVersion2 = "0.
|
|
2192
|
+
currentVersion2 = "0.136.0".trim() ? "0.136.0".trim() : "0.1.0";
|
|
2193
2193
|
});
|
|
2194
2194
|
|
|
2195
2195
|
// ../../packages/registry/src/index.ts
|
|
@@ -3443,6 +3443,9 @@ async function trackObserveCommand(idOrLogId, options) {
|
|
|
3443
3443
|
if (options.durationTargetSec !== undefined) {
|
|
3444
3444
|
body.durationTargetSec = options.durationTargetSec;
|
|
3445
3445
|
}
|
|
3446
|
+
if (typeof options.promptVersion === "number") {
|
|
3447
|
+
body.promptVersion = options.promptVersion;
|
|
3448
|
+
}
|
|
3446
3449
|
if (options.contextNote !== undefined) {
|
|
3447
3450
|
body.contextNote = options.contextNote;
|
|
3448
3451
|
}
|
|
@@ -3466,6 +3469,9 @@ async function trackNoteCommand(idOrLogId, options) {
|
|
|
3466
3469
|
if (options.dryRun) {
|
|
3467
3470
|
body.dryRun = true;
|
|
3468
3471
|
}
|
|
3472
|
+
if (typeof options.promptVersion === "number") {
|
|
3473
|
+
body.promptVersion = options.promptVersion;
|
|
3474
|
+
}
|
|
3469
3475
|
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
|
|
3470
3476
|
}
|
|
3471
3477
|
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS, RERENDER_CONTRACT_FIELDS, RERENDER_ADVISORY_FIELDS, FOOTAGE_FIELDS, PLATE_FIELDS, NON_FILE_OPTIONS;
|
|
@@ -5018,6 +5024,9 @@ function buildBody2(options, { requireContent }) {
|
|
|
5018
5024
|
} else if (requireContent) {
|
|
5019
5025
|
throw new CliError2("missing_content", "A draft needs the structured content payload via --content-file <edition.json>");
|
|
5020
5026
|
}
|
|
5027
|
+
if (requireContent && typeof options.promptVersion === "number") {
|
|
5028
|
+
body.promptVersion = options.promptVersion;
|
|
5029
|
+
}
|
|
5021
5030
|
if (options.subject !== undefined) {
|
|
5022
5031
|
body.subject = options.subject;
|
|
5023
5032
|
}
|
|
@@ -5095,6 +5104,7 @@ function requireTitle(options) {
|
|
|
5095
5104
|
async function logbookCreateCommand(sector, options) {
|
|
5096
5105
|
return adminApiPost(`/api/admin/logbook/${encodeURIComponent(sector)}`, {
|
|
5097
5106
|
body: resolveBody(options),
|
|
5107
|
+
...typeof options.promptVersion === "number" ? { promptVersion: options.promptVersion } : {},
|
|
5098
5108
|
title: requireTitle(options)
|
|
5099
5109
|
});
|
|
5100
5110
|
}
|
|
@@ -5109,6 +5119,193 @@ var init_admin_logbook = __esm(() => {
|
|
|
5109
5119
|
init_output();
|
|
5110
5120
|
});
|
|
5111
5121
|
|
|
5122
|
+
// src/commands/admin-prompts.ts
|
|
5123
|
+
var exports_admin_prompts = {};
|
|
5124
|
+
__export(exports_admin_prompts, {
|
|
5125
|
+
renderDiff: () => renderDiff,
|
|
5126
|
+
promptsListCommand: () => promptsListCommand,
|
|
5127
|
+
promptUpdateCommand: () => promptUpdateCommand,
|
|
5128
|
+
promptRows: () => promptRows,
|
|
5129
|
+
promptRollbackCommand: () => promptRollbackCommand,
|
|
5130
|
+
promptResetCommand: () => promptResetCommand,
|
|
5131
|
+
promptGetCommand: () => promptGetCommand,
|
|
5132
|
+
promptDiffCommand: () => promptDiffCommand,
|
|
5133
|
+
promptDetailCommand: () => promptDetailCommand,
|
|
5134
|
+
parseVersion: () => parseVersion3,
|
|
5135
|
+
parseAgainst: () => parseAgainst,
|
|
5136
|
+
historyRows: () => historyRows,
|
|
5137
|
+
diffLines: () => diffLines,
|
|
5138
|
+
bodyLines: () => bodyLines
|
|
5139
|
+
});
|
|
5140
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
|
|
5141
|
+
async function promptsListCommand() {
|
|
5142
|
+
const response = await adminApiGet("/api/admin/prompts");
|
|
5143
|
+
return response.prompts;
|
|
5144
|
+
}
|
|
5145
|
+
async function promptGetCommand(slug) {
|
|
5146
|
+
return adminApiGet(`/api/admin/prompts/${encodeURIComponent(slug)}`);
|
|
5147
|
+
}
|
|
5148
|
+
async function promptDetailCommand(slug) {
|
|
5149
|
+
const prompts = await promptsListCommand();
|
|
5150
|
+
const detail = prompts.find((prompt) => prompt.slug === slug);
|
|
5151
|
+
if (!detail) {
|
|
5152
|
+
throw new CliError2("unknown_prompt", `No prompt goes by "${slug}". The registered ones: ${prompts.map((prompt) => prompt.slug).join(", ")}`);
|
|
5153
|
+
}
|
|
5154
|
+
return detail;
|
|
5155
|
+
}
|
|
5156
|
+
function resolveBody2(options) {
|
|
5157
|
+
if (options.bodyFile === undefined) {
|
|
5158
|
+
throw new CliError2("missing_body", "An edit needs a body via --body-file <prompt.txt>. Start from `fluncle admin prompts get <slug> --json | jq -r .body`.");
|
|
5159
|
+
}
|
|
5160
|
+
if (!existsSync6(options.bodyFile)) {
|
|
5161
|
+
throw new CliError2("file_not_found", `Body file not found: ${options.bodyFile}`);
|
|
5162
|
+
}
|
|
5163
|
+
const body = readFileSync6(options.bodyFile, "utf-8");
|
|
5164
|
+
if (body.trim().length === 0) {
|
|
5165
|
+
throw new CliError2("empty_body", "A prompt body cannot be empty. Nothing was appended.");
|
|
5166
|
+
}
|
|
5167
|
+
return body;
|
|
5168
|
+
}
|
|
5169
|
+
async function promptUpdateCommand(slug, options) {
|
|
5170
|
+
const body = resolveBody2(options);
|
|
5171
|
+
const note = options.note?.trim();
|
|
5172
|
+
const response = await adminApiPost(`/api/admin/prompts/${encodeURIComponent(slug)}`, note ? { body, note } : { body });
|
|
5173
|
+
return { slug, version: response.version };
|
|
5174
|
+
}
|
|
5175
|
+
async function promptRollbackCommand(slug, version) {
|
|
5176
|
+
const detail = await promptDetailCommand(slug);
|
|
5177
|
+
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
5178
|
+
if (!target) {
|
|
5179
|
+
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
5180
|
+
throw new CliError2("unknown_version", known.length > 0 ? `${slug} has no v${version}. On file: ${known}. For the repo's baked default, run \`fluncle admin prompts reset ${slug}\`.` : `${slug} has no history yet: the repo's baked default is what runs. There is nothing to roll back to.`);
|
|
5181
|
+
}
|
|
5182
|
+
return restore(detail, { body: target.body, from: version, note: `rolled back to v${version}` });
|
|
5183
|
+
}
|
|
5184
|
+
async function promptResetCommand(slug) {
|
|
5185
|
+
const detail = await promptDetailCommand(slug);
|
|
5186
|
+
return restore(detail, {
|
|
5187
|
+
body: detail.defaultBody,
|
|
5188
|
+
from: 0,
|
|
5189
|
+
note: "reset to the repo's baked default"
|
|
5190
|
+
});
|
|
5191
|
+
}
|
|
5192
|
+
async function restore(detail, input) {
|
|
5193
|
+
if (input.body.trim() === detail.activeBody.trim()) {
|
|
5194
|
+
return { from: input.from, skipped: true, slug: detail.slug, version: detail.activeVersion };
|
|
5195
|
+
}
|
|
5196
|
+
const response = await adminApiPost(`/api/admin/prompts/${encodeURIComponent(detail.slug)}`, { body: input.body, note: input.note });
|
|
5197
|
+
return { from: input.from, skipped: false, slug: detail.slug, version: response.version };
|
|
5198
|
+
}
|
|
5199
|
+
function parseAgainst(value) {
|
|
5200
|
+
if (value === undefined || value.trim().toLowerCase() === "default") {
|
|
5201
|
+
return { kind: "default" };
|
|
5202
|
+
}
|
|
5203
|
+
const version = parseVersion3(value);
|
|
5204
|
+
if (version === undefined) {
|
|
5205
|
+
throw new CliError2("invalid_against", `--against takes a version (3, or v3) or the word default. Got "${value}".`);
|
|
5206
|
+
}
|
|
5207
|
+
return { kind: "version", version };
|
|
5208
|
+
}
|
|
5209
|
+
function parseVersion3(value) {
|
|
5210
|
+
const digits = /^v?(\d+)$/.exec(value.trim());
|
|
5211
|
+
const parsed = digits?.[1];
|
|
5212
|
+
if (parsed === undefined) {
|
|
5213
|
+
return;
|
|
5214
|
+
}
|
|
5215
|
+
const version = Number.parseInt(parsed, 10);
|
|
5216
|
+
return Number.isFinite(version) && version > 0 ? version : undefined;
|
|
5217
|
+
}
|
|
5218
|
+
function bodyLines(body) {
|
|
5219
|
+
return body.replace(/\r\n/g, `
|
|
5220
|
+
`).replace(/\n+$/, "").split(`
|
|
5221
|
+
`);
|
|
5222
|
+
}
|
|
5223
|
+
function diffLines(before, after) {
|
|
5224
|
+
const rows = before.length;
|
|
5225
|
+
const cols = after.length;
|
|
5226
|
+
const width = cols + 1;
|
|
5227
|
+
const lengths = new Int32Array((rows + 1) * width);
|
|
5228
|
+
const lcs = (row2, col2) => lengths[row2 * width + col2] ?? 0;
|
|
5229
|
+
for (let row2 = rows - 1;row2 >= 0; row2 -= 1) {
|
|
5230
|
+
for (let col2 = cols - 1;col2 >= 0; col2 -= 1) {
|
|
5231
|
+
lengths[row2 * width + col2] = before[row2] === after[col2] ? lcs(row2 + 1, col2 + 1) + 1 : Math.max(lcs(row2 + 1, col2), lcs(row2, col2 + 1));
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
const lines = [];
|
|
5235
|
+
let row = 0;
|
|
5236
|
+
let col = 0;
|
|
5237
|
+
while (row < rows && col < cols) {
|
|
5238
|
+
if (before[row] === after[col]) {
|
|
5239
|
+
lines.push({ kind: "context", text: before[row] ?? "" });
|
|
5240
|
+
row += 1;
|
|
5241
|
+
col += 1;
|
|
5242
|
+
continue;
|
|
5243
|
+
}
|
|
5244
|
+
if (lcs(row + 1, col) >= lcs(row, col + 1)) {
|
|
5245
|
+
lines.push({ kind: "remove", text: before[row] ?? "" });
|
|
5246
|
+
row += 1;
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
lines.push({ kind: "add", text: after[col] ?? "" });
|
|
5250
|
+
col += 1;
|
|
5251
|
+
}
|
|
5252
|
+
while (row < rows) {
|
|
5253
|
+
lines.push({ kind: "remove", text: before[row] ?? "" });
|
|
5254
|
+
row += 1;
|
|
5255
|
+
}
|
|
5256
|
+
while (col < cols) {
|
|
5257
|
+
lines.push({ kind: "add", text: after[col] ?? "" });
|
|
5258
|
+
col += 1;
|
|
5259
|
+
}
|
|
5260
|
+
return lines;
|
|
5261
|
+
}
|
|
5262
|
+
function renderDiff(lines) {
|
|
5263
|
+
return lines.map((line) => {
|
|
5264
|
+
const marker = line.kind === "add" ? "+" : line.kind === "remove" ? "-" : " ";
|
|
5265
|
+
return `${marker} ${line.text}`;
|
|
5266
|
+
});
|
|
5267
|
+
}
|
|
5268
|
+
async function promptDiffCommand(slug, against) {
|
|
5269
|
+
const detail = await promptDetailCommand(slug);
|
|
5270
|
+
const from = against.kind === "default" ? { body: detail.defaultBody, label: "the repo's baked default", version: 0 } : resolveAgainstVersion(detail, against.version);
|
|
5271
|
+
const lines = diffLines(bodyLines(from.body), bodyLines(detail.activeBody));
|
|
5272
|
+
return {
|
|
5273
|
+
added: lines.filter((line) => line.kind === "add").length,
|
|
5274
|
+
against: { label: from.label, version: from.version },
|
|
5275
|
+
lines,
|
|
5276
|
+
live: { source: detail.source, version: detail.activeVersion },
|
|
5277
|
+
removed: lines.filter((line) => line.kind === "remove").length,
|
|
5278
|
+
slug: detail.slug
|
|
5279
|
+
};
|
|
5280
|
+
}
|
|
5281
|
+
function resolveAgainstVersion(detail, version) {
|
|
5282
|
+
const target = detail.versions.find((candidate) => candidate.version === version);
|
|
5283
|
+
if (!target) {
|
|
5284
|
+
const known = detail.versions.map((candidate) => `v${candidate.version}`).join(", ");
|
|
5285
|
+
throw new CliError2("unknown_version", known.length > 0 ? `${detail.slug} has no v${version}. On file: ${known}.` : `${detail.slug} has no history yet. Diff against the repo's default instead: drop --against.`);
|
|
5286
|
+
}
|
|
5287
|
+
return { body: target.body, label: `v${version}`, version };
|
|
5288
|
+
}
|
|
5289
|
+
function promptRows(prompts) {
|
|
5290
|
+
const slugWidth = prompts.reduce((width, prompt) => Math.max(width, prompt.slug.length), 0);
|
|
5291
|
+
const surfaceWidth = prompts.reduce((width, prompt) => Math.max(width, prompt.surface.length), 0);
|
|
5292
|
+
return prompts.map((prompt) => {
|
|
5293
|
+
const live = prompt.source === "override" ? `v${prompt.activeVersion}` : "default";
|
|
5294
|
+
return `${prompt.slug.padEnd(slugWidth)} ${prompt.surface.padEnd(surfaceWidth)} ${live.padEnd(7)} ${prompt.title}`;
|
|
5295
|
+
});
|
|
5296
|
+
}
|
|
5297
|
+
function historyRows(versions) {
|
|
5298
|
+
return versions.map((version) => {
|
|
5299
|
+
const when = version.createdAt.slice(0, 10);
|
|
5300
|
+
const note = version.note?.trim();
|
|
5301
|
+
return `v${version.version} ${when} ${version.createdBy.padEnd(8)} ${note && note.length > 0 ? note : "(no note)"}`;
|
|
5302
|
+
});
|
|
5303
|
+
}
|
|
5304
|
+
var init_admin_prompts = __esm(() => {
|
|
5305
|
+
init_api();
|
|
5306
|
+
init_output();
|
|
5307
|
+
});
|
|
5308
|
+
|
|
5112
5309
|
// src/commands/add.ts
|
|
5113
5310
|
async function addCommand2(spotifyUrl, options) {
|
|
5114
5311
|
const result = await adminApiPost("/api/admin/tracks", {
|
|
@@ -5197,7 +5394,10 @@ async function approveSubmissionCommand(submissionId, options = {}) {
|
|
|
5197
5394
|
console.log(`Approved ${formatTrackLine(submission)}.`);
|
|
5198
5395
|
}
|
|
5199
5396
|
async function triageSubmissionCommand(submissionId, verdict, options = {}) {
|
|
5200
|
-
const response = await adminApiPost(`/api/admin/submissions/${encodeURIComponent(submissionId)}/triage`, {
|
|
5397
|
+
const response = await adminApiPost(`/api/admin/submissions/${encodeURIComponent(submissionId)}/triage`, {
|
|
5398
|
+
...typeof options.promptVersion === "number" ? { promptVersion: options.promptVersion } : {},
|
|
5399
|
+
verdict
|
|
5400
|
+
});
|
|
5201
5401
|
if (options.json) {
|
|
5202
5402
|
printJson2({ ok: true, submission: response.submission });
|
|
5203
5403
|
return;
|
|
@@ -5845,7 +6045,7 @@ var init_format2 = __esm(() => {
|
|
|
5845
6045
|
});
|
|
5846
6046
|
|
|
5847
6047
|
// src/cli.ts
|
|
5848
|
-
import { existsSync as
|
|
6048
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
5849
6049
|
import path2 from "path";
|
|
5850
6050
|
|
|
5851
6051
|
// ../../node_modules/commander/lib/error.js
|
|
@@ -8210,7 +8410,7 @@ function addAdminCommands(program2) {
|
|
|
8210
8410
|
const { previewArchiveUploadCommand: previewArchiveUploadCommand2 } = await Promise.resolve().then(() => (init_preview_archive(), exports_preview_archive));
|
|
8211
8411
|
await runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCommand2);
|
|
8212
8412
|
});
|
|
8213
|
-
adminTrack.command("observe").description("Render Fluncle's spoken field observation for a track (Cartesia, Worker-side)").argument("[idOrLogId]").option("--queue", "Show the observe worklist (notes but no observation yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated observation script (the spoken text)").option("--script-file <file>", "Read the observation script from a file (e.g. observation.txt)").option("--voice-id <id>", "Override the configured Cartesia voice id").option("--duration-ms <ms>", "Probed audio duration in ms (else derived from word timestamps)").option("--duration-target-sec <sec>", "Target observation length in seconds (20\u201345)").option("--context-note <text>", "Pre-fetched factual context (else the Worker firecrawls)").option("--force", "Re-render even if an observation already exists (voice re-tune / fix)", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8413
|
+
adminTrack.command("observe").description("Render Fluncle's spoken field observation for a track (Cartesia, Worker-side)").argument("[idOrLogId]").option("--queue", "Show the observe worklist (notes but no observation yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated observation script (the spoken text)").option("--script-file <file>", "Read the observation script from a file (e.g. observation.txt)").option("--voice-id <id>", "Override the configured Cartesia voice id").option("--duration-ms <ms>", "Probed audio duration in ms (else derived from word timestamps)").option("--duration-target-sec <sec>", "Target observation length in seconds (20\u201345)").option("--context-note <text>", "Pre-fetched factual context (else the Worker firecrawls)").option("--prompt-version <n>", "The prompt-registry version that authored this (the sweep sends it; it is the artifact's provenance)").option("--force", "Re-render even if an observation already exists (voice re-tune / fix)", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8214
8414
|
if (options.queue) {
|
|
8215
8415
|
const { observeQueueCommand: observeQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8216
8416
|
await runAdminObserveQueue(options, observeQueueCommand2);
|
|
@@ -8228,7 +8428,7 @@ function addAdminCommands(program2) {
|
|
|
8228
8428
|
const { trackContextCommand: trackContextCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
8229
8429
|
await runTrackContext(idOrLogId, options, trackContextCommand2);
|
|
8230
8430
|
});
|
|
8231
|
-
adminTrack.command("note").description("Author the editorial note for a finding (fills an empty note only)").argument("[idOrLogId]").option("--queue", "Show the note worklist (context'd findings with no note yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated editorial note").option("--script-file <file>", "Read the editorial note from a file").option("--dry-run", "Run the voice + echo gates and report the verdict without storing anything", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8431
|
+
adminTrack.command("note").description("Author the editorial note for a finding (fills an empty note only)").argument("[idOrLogId]").option("--queue", "Show the note worklist (context'd findings with no note yet), oldest first", false).option("--limit <limit>", "Number of findings to show with --queue", "10").option("--script <text>", "The voice-gated editorial note").option("--script-file <file>", "Read the editorial note from a file").option("--prompt-version <n>", "The prompt-registry version that authored the note (the sweep sends this; it is the note's provenance)").option("--dry-run", "Run the voice + echo gates and report the verdict without storing anything", false).option("--json", "Print JSON", false).allowExcessArguments().action(async (idOrLogId, options) => {
|
|
8232
8432
|
if (options.queue) {
|
|
8233
8433
|
const { noteQueueCommand: noteQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8234
8434
|
await runAdminNoteQueue(options, noteQueueCommand2);
|
|
@@ -8361,9 +8561,9 @@ function addAdminCommands(program2) {
|
|
|
8361
8561
|
adminNewsletter.action(() => {
|
|
8362
8562
|
adminNewsletter.outputHelp();
|
|
8363
8563
|
});
|
|
8364
|
-
adminNewsletter.command("draft").description("Persist a newsletter edition draft (the agent authors it, you send it)").option("--content-file <file>", "Structured edition content payload (JSON)").option("--subject <text>", "Email subject line").option("--window-since <date>", "Discovery-window start (ISO)").option("--window-until <date>", "Discovery-window end (ISO)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8564
|
+
adminNewsletter.command("draft").description("Persist a newsletter edition draft (the agent authors it, you send it)").option("--content-file <file>", "Structured edition content payload (JSON)").option("--subject <text>", "Email subject line").option("--window-since <date>", "Discovery-window start (ISO)").option("--window-until <date>", "Discovery-window end (ISO)").option("--prompt-version <n>", "The prompt-registry version that authored this (the sweep sends it; it is the edition's provenance)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8365
8565
|
const { newsletterDraftCommand: newsletterDraftCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
8366
|
-
await runNewsletterDraft(options, newsletterDraftCommand2);
|
|
8566
|
+
await runNewsletterDraft({ ...options, promptVersion: parsePromptVersion(options.promptVersion) }, newsletterDraftCommand2);
|
|
8367
8567
|
});
|
|
8368
8568
|
adminNewsletter.command("update").description("Update a draft edition's payload, subject, or window").argument("[id]").option("--content-file <file>", "Structured edition content payload (JSON)").option("--subject <text>", "Email subject line").option("--window-since <date>", "Discovery-window start (ISO)").option("--window-until <date>", "Discovery-window end (ISO)").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
8369
8569
|
const { newsletterUpdateCommand: newsletterUpdateCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
@@ -8389,7 +8589,7 @@ function addAdminCommands(program2) {
|
|
|
8389
8589
|
const { logbookGapsCommand: logbookGapsCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8390
8590
|
await runLogbookGaps(options, logbookGapsCommand2);
|
|
8391
8591
|
});
|
|
8392
|
-
adminLogbook.command("create").description("Author a sector-day's entry (fills an empty sector only)").argument("[sector]").option("--title <text>", "The entry title").option("--body <text>", "The entry body (markdown; [[logId]] figure tokens)").option("--body-file <file>", "Read the body from a file (the sweep's path)").option("--json", "Print JSON", false).allowExcessArguments().action(async (sector, options) => {
|
|
8592
|
+
adminLogbook.command("create").description("Author a sector-day's entry (fills an empty sector only)").argument("[sector]").option("--title <text>", "The entry title").option("--body <text>", "The entry body (markdown; [[logId]] figure tokens)").option("--body-file <file>", "Read the body from a file (the sweep's path)").option("--prompt-version <n>", "The prompt-registry version that authored this (the sweep sends it; it is the artifact's provenance)").option("--json", "Print JSON", false).allowExcessArguments().action(async (sector, options) => {
|
|
8393
8593
|
const { logbookCreateCommand: logbookCreateCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8394
8594
|
await runLogbookWrite(sector, options, logbookCreateCommand2);
|
|
8395
8595
|
});
|
|
@@ -8397,6 +8597,38 @@ function addAdminCommands(program2) {
|
|
|
8397
8597
|
const { logbookUpdateCommand: logbookUpdateCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8398
8598
|
await runLogbookWrite(sector, options, logbookUpdateCommand2);
|
|
8399
8599
|
});
|
|
8600
|
+
const adminPrompts = configureCommand(admin.command("prompts").description("The prompt registry: what Fluncle tells the models"));
|
|
8601
|
+
adminPrompts.action(() => {
|
|
8602
|
+
adminPrompts.outputHelp();
|
|
8603
|
+
});
|
|
8604
|
+
adminPrompts.command("list").description("Every prompt: where it runs, and whether the repo default or an edit is live").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
8605
|
+
const { promptsListCommand: promptsListCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8606
|
+
await runPromptsList(options, promptsListCommand2);
|
|
8607
|
+
});
|
|
8608
|
+
adminPrompts.command("get").description("The body running right now, with its version and source").argument("[slug]").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
8609
|
+
const { promptGetCommand: promptGetCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8610
|
+
await runPromptGet(slug, options, promptGetCommand2);
|
|
8611
|
+
});
|
|
8612
|
+
adminPrompts.command("history").description("Every version of a prompt, newest first: when, who, and the why").argument("[slug]").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
8613
|
+
const { promptDetailCommand: promptDetailCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8614
|
+
await runPromptHistory(slug, options, promptDetailCommand2);
|
|
8615
|
+
});
|
|
8616
|
+
adminPrompts.command("diff").description("Line diff: the live body against the repo default, or against a version").argument("[slug]").option("--against <version>", "A version (3, or v3) or the word default", "default").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
8617
|
+
const { parseAgainst: parseAgainst2, promptDiffCommand: promptDiffCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8618
|
+
await runPromptDiff(slug, options, { parseAgainst: parseAgainst2, promptDiffCommand: promptDiffCommand2 });
|
|
8619
|
+
});
|
|
8620
|
+
adminPrompts.command("update").description("Append an edited body as a new version. OPERATOR only").argument("[slug]").option("--body-file <file>", "Read the new prompt body from a file").option("--note <text>", 'The why, for the history ("shortened the neighbour block")').option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
8621
|
+
const { promptUpdateCommand: promptUpdateCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8622
|
+
await runPromptUpdate(slug, options, promptUpdateCommand2);
|
|
8623
|
+
});
|
|
8624
|
+
adminPrompts.command("rollback").description("Put an old version's body back, as a new version. OPERATOR only").argument("[slug]").argument("[version]").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, version, options) => {
|
|
8625
|
+
const { parseVersion: parseVersion4, promptRollbackCommand: promptRollbackCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8626
|
+
await runPromptRollback(slug, version, options, { parseVersion: parseVersion4, promptRollbackCommand: promptRollbackCommand2 });
|
|
8627
|
+
});
|
|
8628
|
+
adminPrompts.command("reset").description("Put the repo's baked default back, as a new version. OPERATOR only").argument("[slug]").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
8629
|
+
const { promptResetCommand: promptResetCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8630
|
+
await runPromptReset(slug, options, promptResetCommand2);
|
|
8631
|
+
});
|
|
8400
8632
|
const submissions = configureCommand(admin.command("submissions").description("Review listener submissions"));
|
|
8401
8633
|
submissions.option("--json", "Print JSON", false).action(async (options) => {
|
|
8402
8634
|
const { listSubmissionsCommand: listSubmissionsCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
@@ -8423,16 +8655,19 @@ function addAdminCommands(program2) {
|
|
|
8423
8655
|
const { approveSubmissionCommand: approveSubmissionCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
8424
8656
|
await approveSubmissionCommand2(submissionId, options);
|
|
8425
8657
|
});
|
|
8426
|
-
submissions.command("triage").description("Write the pre-chew triage verdict onto a pending submission").argument("[submissionId]").option("--verdict <text>", "The triage verdict one-liner").option("--verdict-file <file>", "Read the verdict from a file").option("--json", "Print JSON", false).action(async (submissionId, options) => {
|
|
8658
|
+
submissions.command("triage").description("Write the pre-chew triage verdict onto a pending submission").argument("[submissionId]").option("--verdict <text>", "The triage verdict one-liner").option("--verdict-file <file>", "Read the verdict from a file").option("--prompt-version <n>", "The prompt-registry version that authored this (the sweep sends it; it is the artifact's provenance)").option("--json", "Print JSON", false).action(async (submissionId, options) => {
|
|
8427
8659
|
if (!submissionId) {
|
|
8428
8660
|
throw new Error("Missing submission id for: triage");
|
|
8429
8661
|
}
|
|
8430
|
-
const verdict = options.verdictFile ?
|
|
8662
|
+
const verdict = options.verdictFile ? readFileSync7(options.verdictFile, "utf8") : options.verdict;
|
|
8431
8663
|
if (!verdict || !verdict.trim()) {
|
|
8432
8664
|
throw new Error("Usage: fluncle admin submissions triage <submissionId> (--verdict <text> | --verdict-file <file>) [--json]");
|
|
8433
8665
|
}
|
|
8434
8666
|
const { triageSubmissionCommand: triageSubmissionCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
8435
|
-
await triageSubmissionCommand2(submissionId, verdict, {
|
|
8667
|
+
await triageSubmissionCommand2(submissionId, verdict, {
|
|
8668
|
+
json: options.json,
|
|
8669
|
+
promptVersion: parsePromptVersion(options.promptVersion)
|
|
8670
|
+
});
|
|
8436
8671
|
});
|
|
8437
8672
|
const auth = configureCommand(admin.command("auth").description("Authentication commands"));
|
|
8438
8673
|
auth.command("spotify").description("Authorize Spotify access").action(async () => {
|
|
@@ -8564,7 +8799,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
8564
8799
|
console.log(` mime: ${result.mime}`);
|
|
8565
8800
|
}
|
|
8566
8801
|
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
8567
|
-
const script = options.scriptFile ?
|
|
8802
|
+
const script = options.scriptFile ? readFileSync7(options.scriptFile, "utf8") : options.script;
|
|
8568
8803
|
if (!idOrLogId || !script || !script.trim()) {
|
|
8569
8804
|
throw new Error("Usage: fluncle admin tracks observe <track_id|log_id> (--script <text> | --script-file <file>) [--voice-id <id>] [--duration-ms <ms>] [--context-note <text>] [--json]");
|
|
8570
8805
|
}
|
|
@@ -8581,6 +8816,7 @@ async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
|
8581
8816
|
durationMs,
|
|
8582
8817
|
durationTargetSec,
|
|
8583
8818
|
force: options.force,
|
|
8819
|
+
promptVersion: parsePromptVersion(options.promptVersion),
|
|
8584
8820
|
script: script.trim(),
|
|
8585
8821
|
voiceId: options.voiceId
|
|
8586
8822
|
});
|
|
@@ -8619,14 +8855,22 @@ async function runTrackContext(idOrLogId, options, trackContextCommand2) {
|
|
|
8619
8855
|
console.log(` sources: ${result.sources.join(", ")}`);
|
|
8620
8856
|
}
|
|
8621
8857
|
}
|
|
8858
|
+
function parsePromptVersion(raw) {
|
|
8859
|
+
if (raw === undefined) {
|
|
8860
|
+
return;
|
|
8861
|
+
}
|
|
8862
|
+
const parsed = Number(raw);
|
|
8863
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
8864
|
+
}
|
|
8622
8865
|
async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
|
|
8623
|
-
const note = options.scriptFile ?
|
|
8866
|
+
const note = options.scriptFile ? readFileSync7(options.scriptFile, "utf8") : options.script;
|
|
8624
8867
|
if (!idOrLogId || !note || !note.trim()) {
|
|
8625
8868
|
throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--dry-run] [--json]");
|
|
8626
8869
|
}
|
|
8627
8870
|
const result = await trackNoteCommand2(idOrLogId, {
|
|
8628
8871
|
dryRun: options.dryRun,
|
|
8629
|
-
note: note.trim()
|
|
8872
|
+
note: note.trim(),
|
|
8873
|
+
promptVersion: parsePromptVersion(options.promptVersion)
|
|
8630
8874
|
});
|
|
8631
8875
|
if (options.json) {
|
|
8632
8876
|
printJson(result);
|
|
@@ -9059,7 +9303,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
|
9059
9303
|
return;
|
|
9060
9304
|
}
|
|
9061
9305
|
const candidate = path2.join(dir, name);
|
|
9062
|
-
return
|
|
9306
|
+
return existsSync7(candidate) ? candidate : undefined;
|
|
9063
9307
|
};
|
|
9064
9308
|
const resolveFile = (explicit, name) => {
|
|
9065
9309
|
if (explicit) {
|
|
@@ -9271,7 +9515,7 @@ async function runTrackUpdate(trackId, options, trackUpdateCommand3) {
|
|
|
9271
9515
|
if (options.analyzedFrom !== undefined && options.analyzedFrom !== "full" && options.analyzedFrom !== "preview") {
|
|
9272
9516
|
throw new Error(`Invalid --analyzed-from: ${options.analyzedFrom} (expected full or preview)`);
|
|
9273
9517
|
}
|
|
9274
|
-
const embeddingRaw = options.embeddingFile ?
|
|
9518
|
+
const embeddingRaw = options.embeddingFile ? readFileSync7(options.embeddingFile, "utf8") : options.embedding;
|
|
9275
9519
|
const embedding = parseEmbeddingArg(embeddingRaw);
|
|
9276
9520
|
const result = await trackUpdateCommand3(trackId, {
|
|
9277
9521
|
analyzedAt: options.analyzedAt,
|
|
@@ -9644,6 +9888,7 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
9644
9888
|
const result = await writeCommand(sector, {
|
|
9645
9889
|
body: options.body,
|
|
9646
9890
|
bodyFile: options.bodyFile,
|
|
9891
|
+
promptVersion: parsePromptVersion(options.promptVersion),
|
|
9647
9892
|
title: options.title
|
|
9648
9893
|
});
|
|
9649
9894
|
if (options.json) {
|
|
@@ -9653,6 +9898,109 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
9653
9898
|
const skipped = "skipped" in result && result.skipped;
|
|
9654
9899
|
console.log(skipped ? `sector ${result.entry.sector}: an entry already stands \u2014 no-op (${result.entry.generatedBy})` : `sector ${result.entry.sector}: ${result.entry.title}`);
|
|
9655
9900
|
}
|
|
9901
|
+
function requirePromptSlug(slug) {
|
|
9902
|
+
if (!slug) {
|
|
9903
|
+
throw new Error("Missing prompt slug. `fluncle admin prompts list` names them all.");
|
|
9904
|
+
}
|
|
9905
|
+
return slug;
|
|
9906
|
+
}
|
|
9907
|
+
async function runPromptsList(options, promptsListCommand2) {
|
|
9908
|
+
const prompts = await promptsListCommand2();
|
|
9909
|
+
if (options.json) {
|
|
9910
|
+
printJson({ ok: true, prompts });
|
|
9911
|
+
return;
|
|
9912
|
+
}
|
|
9913
|
+
const { promptRows: promptRows2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
9914
|
+
for (const row of promptRows2(prompts)) {
|
|
9915
|
+
console.log(row);
|
|
9916
|
+
}
|
|
9917
|
+
}
|
|
9918
|
+
async function runPromptGet(slug, options, promptGetCommand2) {
|
|
9919
|
+
const resolved = await promptGetCommand2(requirePromptSlug(slug));
|
|
9920
|
+
if (options.json) {
|
|
9921
|
+
printJson(resolved);
|
|
9922
|
+
return;
|
|
9923
|
+
}
|
|
9924
|
+
const live = resolved.source === "override" ? `v${resolved.version}, an operator edit` : "the repo's baked default (v0)";
|
|
9925
|
+
console.log(`${resolved.slug}: ${live}`);
|
|
9926
|
+
console.log("");
|
|
9927
|
+
console.log(resolved.body);
|
|
9928
|
+
}
|
|
9929
|
+
async function runPromptHistory(slug, options, promptDetailCommand2) {
|
|
9930
|
+
const detail = await promptDetailCommand2(requirePromptSlug(slug));
|
|
9931
|
+
if (options.json) {
|
|
9932
|
+
printJson({
|
|
9933
|
+
activeVersion: detail.activeVersion,
|
|
9934
|
+
ok: true,
|
|
9935
|
+
slug: detail.slug,
|
|
9936
|
+
source: detail.source,
|
|
9937
|
+
versions: detail.versions
|
|
9938
|
+
});
|
|
9939
|
+
return;
|
|
9940
|
+
}
|
|
9941
|
+
if (detail.versions.length === 0) {
|
|
9942
|
+
console.log(`${detail.slug}: never edited. The repo's baked default is what runs.`);
|
|
9943
|
+
return;
|
|
9944
|
+
}
|
|
9945
|
+
const { historyRows: historyRows2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
9946
|
+
for (const row of historyRows2(detail.versions)) {
|
|
9947
|
+
console.log(row);
|
|
9948
|
+
}
|
|
9949
|
+
}
|
|
9950
|
+
async function runPromptDiff(slug, options, commands) {
|
|
9951
|
+
const against = commands.parseAgainst(options.against);
|
|
9952
|
+
const result = await commands.promptDiffCommand(requirePromptSlug(slug), against);
|
|
9953
|
+
if (options.json) {
|
|
9954
|
+
printJson({ ok: true, ...result });
|
|
9955
|
+
return;
|
|
9956
|
+
}
|
|
9957
|
+
const live = result.live.source === "override" ? `v${result.live.version}` : "the repo's baked default";
|
|
9958
|
+
if (result.added === 0 && result.removed === 0) {
|
|
9959
|
+
console.log(`${result.slug}: ${live} and ${result.against.label} are the same body.`);
|
|
9960
|
+
return;
|
|
9961
|
+
}
|
|
9962
|
+
const { renderDiff: renderDiff2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
9963
|
+
console.log(`${result.slug}: ${result.against.label} (-) against ${live} (+)`);
|
|
9964
|
+
for (const line of renderDiff2(result.lines)) {
|
|
9965
|
+
console.log(line);
|
|
9966
|
+
}
|
|
9967
|
+
console.log(`${result.added} added, ${result.removed} removed.`);
|
|
9968
|
+
}
|
|
9969
|
+
async function runPromptUpdate(slug, options, promptUpdateCommand2) {
|
|
9970
|
+
const result = await promptUpdateCommand2(requirePromptSlug(slug), {
|
|
9971
|
+
bodyFile: options.bodyFile,
|
|
9972
|
+
note: options.note
|
|
9973
|
+
});
|
|
9974
|
+
if (options.json) {
|
|
9975
|
+
printJson({ ok: true, ...result });
|
|
9976
|
+
return;
|
|
9977
|
+
}
|
|
9978
|
+
console.log(`${result.slug}: v${result.version} is live. Nothing to deploy.`);
|
|
9979
|
+
}
|
|
9980
|
+
async function runPromptRollback(slug, version, options, commands) {
|
|
9981
|
+
const promptSlug = requirePromptSlug(slug);
|
|
9982
|
+
if (!version) {
|
|
9983
|
+
throw new Error(`Missing version. \`fluncle admin prompts history ${promptSlug}\` lists what you can go back to.`);
|
|
9984
|
+
}
|
|
9985
|
+
const parsed = commands.parseVersion(version);
|
|
9986
|
+
if (parsed === undefined) {
|
|
9987
|
+
throw new Error(`A version reads as 3 or v3. Got "${version}".`);
|
|
9988
|
+
}
|
|
9989
|
+
const result = await commands.promptRollbackCommand(promptSlug, parsed);
|
|
9990
|
+
if (options.json) {
|
|
9991
|
+
printJson({ ok: true, ...result });
|
|
9992
|
+
return;
|
|
9993
|
+
}
|
|
9994
|
+
console.log(result.skipped ? `${result.slug}: v${result.from} is already the body running. Nothing appended.` : `${result.slug}: back on v${result.from}'s body, live as v${result.version}.`);
|
|
9995
|
+
}
|
|
9996
|
+
async function runPromptReset(slug, options, promptResetCommand2) {
|
|
9997
|
+
const result = await promptResetCommand2(requirePromptSlug(slug));
|
|
9998
|
+
if (options.json) {
|
|
9999
|
+
printJson({ ok: true, ...result });
|
|
10000
|
+
return;
|
|
10001
|
+
}
|
|
10002
|
+
console.log(result.skipped ? `${result.slug}: already running the repo's baked default. Nothing appended.` : `${result.slug}: back on the repo's baked default, live as v${result.version}.`);
|
|
10003
|
+
}
|
|
9656
10004
|
async function runAdd(spotifyUrl, options, addCommand3) {
|
|
9657
10005
|
if (!spotifyUrl) {
|
|
9658
10006
|
throw new Error("Missing Spotify track URL");
|
|
@@ -9858,7 +10206,7 @@ async function runGalaxyEmbeddings(options, galaxyEmbeddingsCommand2) {
|
|
|
9858
10206
|
console.log(`${result.embeddings.length} embedding(s)${result.nextCursor ? ` \xB7 nextCursor: ${result.nextCursor}` : " \xB7 end of corpus"}`);
|
|
9859
10207
|
}
|
|
9860
10208
|
async function runGalaxyMapWrite(options, galaxyMapWriteCommand2) {
|
|
9861
|
-
const raw = JSON.parse(
|
|
10209
|
+
const raw = JSON.parse(readFileSync7(options.file, "utf8"));
|
|
9862
10210
|
const clusters = Array.isArray(raw) || raw === null ? raw : raw.clusters;
|
|
9863
10211
|
if (!Array.isArray(clusters)) {
|
|
9864
10212
|
throw new Error("Invalid --file: expected { clusters: [...] } or a JSON array of cluster rows");
|
|
@@ -10400,6 +10748,7 @@ function normalizeCommanderError(error) {
|
|
|
10400
10748
|
return new Error(message);
|
|
10401
10749
|
}
|
|
10402
10750
|
var stringOptions = new Set([
|
|
10751
|
+
"--against",
|
|
10403
10752
|
"--analyzed-at",
|
|
10404
10753
|
"--analyzed-from",
|
|
10405
10754
|
"--at",
|
|
@@ -10451,6 +10800,7 @@ var stringOptions = new Set([
|
|
|
10451
10800
|
"--plate-background",
|
|
10452
10801
|
"--platform",
|
|
10453
10802
|
"--poster",
|
|
10803
|
+
"--prompt-version",
|
|
10454
10804
|
"--props",
|
|
10455
10805
|
"--query",
|
|
10456
10806
|
"--reasoning",
|
package/package.json
CHANGED