fluncle 0.135.0 → 0.137.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 +447 -20
- 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.137.0".trim() ? "0.137.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.137.0".trim() ? "0.137.0".trim() : "0.1.0";
|
|
2193
2193
|
});
|
|
2194
2194
|
|
|
2195
2195
|
// ../../packages/registry/src/index.ts
|
|
@@ -2247,11 +2247,11 @@ var init_src = __esm(() => {
|
|
|
2247
2247
|
},
|
|
2248
2248
|
{
|
|
2249
2249
|
exposedContent: [
|
|
2250
|
-
"the
|
|
2250
|
+
"the free mixing tool — name artists you like, and Fluncle ranks what mixes in clean next from the whole archive; chain a set and share it as a link"
|
|
2251
2251
|
],
|
|
2252
2252
|
kind: "web_route",
|
|
2253
2253
|
name: "web.mix",
|
|
2254
|
-
operatorNotes: "
|
|
2254
|
+
operatorNotes: "PUBLIC-CAPABLE, gated by a SELF-LIFTING DEPTH MEASUREMENT (not admin auth). The old ~250-finding / admin gate is gone: `/mix` now measures the live archive on every load (`getMixChainDepth` — can the median track reach a full set + rail by a named harmonic move?) and opens to the world on its own the day the catalogue lands enough keyed depth. Until then a stranger is redirected home and the operator still gets in to dogfood. This entry stays `pending` (dark to the dev-row, llms.txt, the sitemap, /status) ONLY so we do not advertise a URL that still redirects — the flip is: confirm the depth gate has opened in prod, remove `pending`, announce. The web weight is pre-set, so the flip needs no other change. No probeConfig — a closed gate 302s a bare GET, which would read as a false 'down'.",
|
|
2255
2255
|
pending: true,
|
|
2256
2256
|
route: "/mix",
|
|
2257
2257
|
url: `${SITE}/mix`,
|
|
@@ -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;
|
|
@@ -5546,6 +5746,22 @@ var init_admin_artists = __esm(() => {
|
|
|
5546
5746
|
init_api();
|
|
5547
5747
|
});
|
|
5548
5748
|
|
|
5749
|
+
// src/commands/admin-labels.ts
|
|
5750
|
+
var exports_admin_labels = {};
|
|
5751
|
+
__export(exports_admin_labels, {
|
|
5752
|
+
backfillLabelImagesCommand: () => backfillLabelImagesCommand
|
|
5753
|
+
});
|
|
5754
|
+
async function backfillLabelImagesCommand(limit, dryRun, cursor) {
|
|
5755
|
+
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
5756
|
+
if (cursor) {
|
|
5757
|
+
params.set("cursor", cursor);
|
|
5758
|
+
}
|
|
5759
|
+
return adminApiPost(`/api/admin/backfill/label-images?${params.toString()}`);
|
|
5760
|
+
}
|
|
5761
|
+
var init_admin_labels = __esm(() => {
|
|
5762
|
+
init_api();
|
|
5763
|
+
});
|
|
5764
|
+
|
|
5549
5765
|
// src/commands/preview-migration.ts
|
|
5550
5766
|
var exports_preview_migration = {};
|
|
5551
5767
|
__export(exports_preview_migration, {
|
|
@@ -5845,7 +6061,7 @@ var init_format2 = __esm(() => {
|
|
|
5845
6061
|
});
|
|
5846
6062
|
|
|
5847
6063
|
// src/cli.ts
|
|
5848
|
-
import { existsSync as
|
|
6064
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
5849
6065
|
import path2 from "path";
|
|
5850
6066
|
|
|
5851
6067
|
// ../../node_modules/commander/lib/error.js
|
|
@@ -8210,7 +8426,7 @@ function addAdminCommands(program2) {
|
|
|
8210
8426
|
const { previewArchiveUploadCommand: previewArchiveUploadCommand2 } = await Promise.resolve().then(() => (init_preview_archive(), exports_preview_archive));
|
|
8211
8427
|
await runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCommand2);
|
|
8212
8428
|
});
|
|
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) => {
|
|
8429
|
+
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
8430
|
if (options.queue) {
|
|
8215
8431
|
const { observeQueueCommand: observeQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8216
8432
|
await runAdminObserveQueue(options, observeQueueCommand2);
|
|
@@ -8228,7 +8444,7 @@ function addAdminCommands(program2) {
|
|
|
8228
8444
|
const { trackContextCommand: trackContextCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
|
|
8229
8445
|
await runTrackContext(idOrLogId, options, trackContextCommand2);
|
|
8230
8446
|
});
|
|
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) => {
|
|
8447
|
+
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
8448
|
if (options.queue) {
|
|
8233
8449
|
const { noteQueueCommand: noteQueueCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8234
8450
|
await runAdminNoteQueue(options, noteQueueCommand2);
|
|
@@ -8361,9 +8577,9 @@ function addAdminCommands(program2) {
|
|
|
8361
8577
|
adminNewsletter.action(() => {
|
|
8362
8578
|
adminNewsletter.outputHelp();
|
|
8363
8579
|
});
|
|
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) => {
|
|
8580
|
+
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
8581
|
const { newsletterDraftCommand: newsletterDraftCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
8366
|
-
await runNewsletterDraft(options, newsletterDraftCommand2);
|
|
8582
|
+
await runNewsletterDraft({ ...options, promptVersion: parsePromptVersion(options.promptVersion) }, newsletterDraftCommand2);
|
|
8367
8583
|
});
|
|
8368
8584
|
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
8585
|
const { newsletterUpdateCommand: newsletterUpdateCommand2 } = await Promise.resolve().then(() => (init_newsletter(), exports_newsletter));
|
|
@@ -8389,7 +8605,7 @@ function addAdminCommands(program2) {
|
|
|
8389
8605
|
const { logbookGapsCommand: logbookGapsCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8390
8606
|
await runLogbookGaps(options, logbookGapsCommand2);
|
|
8391
8607
|
});
|
|
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) => {
|
|
8608
|
+
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
8609
|
const { logbookCreateCommand: logbookCreateCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8394
8610
|
await runLogbookWrite(sector, options, logbookCreateCommand2);
|
|
8395
8611
|
});
|
|
@@ -8397,6 +8613,38 @@ function addAdminCommands(program2) {
|
|
|
8397
8613
|
const { logbookUpdateCommand: logbookUpdateCommand2 } = await Promise.resolve().then(() => (init_admin_logbook(), exports_admin_logbook));
|
|
8398
8614
|
await runLogbookWrite(sector, options, logbookUpdateCommand2);
|
|
8399
8615
|
});
|
|
8616
|
+
const adminPrompts = configureCommand(admin.command("prompts").description("The prompt registry: what Fluncle tells the models"));
|
|
8617
|
+
adminPrompts.action(() => {
|
|
8618
|
+
adminPrompts.outputHelp();
|
|
8619
|
+
});
|
|
8620
|
+
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) => {
|
|
8621
|
+
const { promptsListCommand: promptsListCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8622
|
+
await runPromptsList(options, promptsListCommand2);
|
|
8623
|
+
});
|
|
8624
|
+
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) => {
|
|
8625
|
+
const { promptGetCommand: promptGetCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8626
|
+
await runPromptGet(slug, options, promptGetCommand2);
|
|
8627
|
+
});
|
|
8628
|
+
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) => {
|
|
8629
|
+
const { promptDetailCommand: promptDetailCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8630
|
+
await runPromptHistory(slug, options, promptDetailCommand2);
|
|
8631
|
+
});
|
|
8632
|
+
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) => {
|
|
8633
|
+
const { parseAgainst: parseAgainst2, promptDiffCommand: promptDiffCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8634
|
+
await runPromptDiff(slug, options, { parseAgainst: parseAgainst2, promptDiffCommand: promptDiffCommand2 });
|
|
8635
|
+
});
|
|
8636
|
+
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) => {
|
|
8637
|
+
const { promptUpdateCommand: promptUpdateCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8638
|
+
await runPromptUpdate(slug, options, promptUpdateCommand2);
|
|
8639
|
+
});
|
|
8640
|
+
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) => {
|
|
8641
|
+
const { parseVersion: parseVersion4, promptRollbackCommand: promptRollbackCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8642
|
+
await runPromptRollback(slug, version, options, { parseVersion: parseVersion4, promptRollbackCommand: promptRollbackCommand2 });
|
|
8643
|
+
});
|
|
8644
|
+
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) => {
|
|
8645
|
+
const { promptResetCommand: promptResetCommand2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
8646
|
+
await runPromptReset(slug, options, promptResetCommand2);
|
|
8647
|
+
});
|
|
8400
8648
|
const submissions = configureCommand(admin.command("submissions").description("Review listener submissions"));
|
|
8401
8649
|
submissions.option("--json", "Print JSON", false).action(async (options) => {
|
|
8402
8650
|
const { listSubmissionsCommand: listSubmissionsCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
@@ -8423,16 +8671,19 @@ function addAdminCommands(program2) {
|
|
|
8423
8671
|
const { approveSubmissionCommand: approveSubmissionCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
8424
8672
|
await approveSubmissionCommand2(submissionId, options);
|
|
8425
8673
|
});
|
|
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) => {
|
|
8674
|
+
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
8675
|
if (!submissionId) {
|
|
8428
8676
|
throw new Error("Missing submission id for: triage");
|
|
8429
8677
|
}
|
|
8430
|
-
const verdict = options.verdictFile ?
|
|
8678
|
+
const verdict = options.verdictFile ? readFileSync7(options.verdictFile, "utf8") : options.verdict;
|
|
8431
8679
|
if (!verdict || !verdict.trim()) {
|
|
8432
8680
|
throw new Error("Usage: fluncle admin submissions triage <submissionId> (--verdict <text> | --verdict-file <file>) [--json]");
|
|
8433
8681
|
}
|
|
8434
8682
|
const { triageSubmissionCommand: triageSubmissionCommand2 } = await Promise.resolve().then(() => (init_submissions(), exports_submissions));
|
|
8435
|
-
await triageSubmissionCommand2(submissionId, verdict, {
|
|
8683
|
+
await triageSubmissionCommand2(submissionId, verdict, {
|
|
8684
|
+
json: options.json,
|
|
8685
|
+
promptVersion: parsePromptVersion(options.promptVersion)
|
|
8686
|
+
});
|
|
8436
8687
|
});
|
|
8437
8688
|
const auth = configureCommand(admin.command("auth").description("Authentication commands"));
|
|
8438
8689
|
auth.command("spotify").description("Authorize Spotify access").action(async () => {
|
|
@@ -8527,6 +8778,10 @@ function addAdminCommands(program2) {
|
|
|
8527
8778
|
const { backfillArtistImagesCommand: backfillArtistImagesCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
8528
8779
|
await runBackfillArtistImages(options, backfillArtistImagesCommand2);
|
|
8529
8780
|
});
|
|
8781
|
+
backfill.command("label-images").description("Resolve label logos (Discogs \u2192 Wikidata) into R2 for existing labels").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max labels to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
8782
|
+
const { backfillLabelImagesCommand: backfillLabelImagesCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
8783
|
+
await runBackfillLabelImages(options, backfillLabelImagesCommand2);
|
|
8784
|
+
});
|
|
8530
8785
|
artists.command("resolve").description("Resolve an artist's social identity (MB url-rels + Firecrawl gap-fill)").argument("[artistId]").option("--queue", "Show the resolve worklist (artists awaiting resolution), oldest first", false).option("--limit <limit>", "Number of artists to show with --queue", "50").option("--json", "Print JSON", false).allowExcessArguments().action(async (artistId, options) => {
|
|
8531
8786
|
if (options.queue) {
|
|
8532
8787
|
const { listArtistsCommand: listArtistsCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
@@ -8564,7 +8819,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
8564
8819
|
console.log(` mime: ${result.mime}`);
|
|
8565
8820
|
}
|
|
8566
8821
|
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
8567
|
-
const script = options.scriptFile ?
|
|
8822
|
+
const script = options.scriptFile ? readFileSync7(options.scriptFile, "utf8") : options.script;
|
|
8568
8823
|
if (!idOrLogId || !script || !script.trim()) {
|
|
8569
8824
|
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
8825
|
}
|
|
@@ -8581,6 +8836,7 @@ async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
|
8581
8836
|
durationMs,
|
|
8582
8837
|
durationTargetSec,
|
|
8583
8838
|
force: options.force,
|
|
8839
|
+
promptVersion: parsePromptVersion(options.promptVersion),
|
|
8584
8840
|
script: script.trim(),
|
|
8585
8841
|
voiceId: options.voiceId
|
|
8586
8842
|
});
|
|
@@ -8619,14 +8875,22 @@ async function runTrackContext(idOrLogId, options, trackContextCommand2) {
|
|
|
8619
8875
|
console.log(` sources: ${result.sources.join(", ")}`);
|
|
8620
8876
|
}
|
|
8621
8877
|
}
|
|
8878
|
+
function parsePromptVersion(raw) {
|
|
8879
|
+
if (raw === undefined) {
|
|
8880
|
+
return;
|
|
8881
|
+
}
|
|
8882
|
+
const parsed = Number(raw);
|
|
8883
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : undefined;
|
|
8884
|
+
}
|
|
8622
8885
|
async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
|
|
8623
|
-
const note = options.scriptFile ?
|
|
8886
|
+
const note = options.scriptFile ? readFileSync7(options.scriptFile, "utf8") : options.script;
|
|
8624
8887
|
if (!idOrLogId || !note || !note.trim()) {
|
|
8625
8888
|
throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--dry-run] [--json]");
|
|
8626
8889
|
}
|
|
8627
8890
|
const result = await trackNoteCommand2(idOrLogId, {
|
|
8628
8891
|
dryRun: options.dryRun,
|
|
8629
|
-
note: note.trim()
|
|
8892
|
+
note: note.trim(),
|
|
8893
|
+
promptVersion: parsePromptVersion(options.promptVersion)
|
|
8630
8894
|
});
|
|
8631
8895
|
if (options.json) {
|
|
8632
8896
|
printJson(result);
|
|
@@ -9009,6 +9273,63 @@ async function runBackfillArtistImages(options, backfillArtistImagesCommand2) {
|
|
|
9009
9273
|
process.exitCode = 1;
|
|
9010
9274
|
}
|
|
9011
9275
|
}
|
|
9276
|
+
async function runBackfillLabelImages(options, backfillLabelImagesCommand2) {
|
|
9277
|
+
const limit = parseListLimit(options.limit);
|
|
9278
|
+
const resolved = [];
|
|
9279
|
+
const none = [];
|
|
9280
|
+
const failed = [];
|
|
9281
|
+
let cursor;
|
|
9282
|
+
let dryRun = options.dryRun;
|
|
9283
|
+
let throttled = false;
|
|
9284
|
+
while (resolved.length + none.length + failed.length < limit) {
|
|
9285
|
+
const remaining = limit - (resolved.length + none.length + failed.length);
|
|
9286
|
+
const result = await backfillLabelImagesCommand2(remaining, options.dryRun, cursor);
|
|
9287
|
+
dryRun = result.dryRun;
|
|
9288
|
+
resolved.push(...result.resolved);
|
|
9289
|
+
none.push(...result.none);
|
|
9290
|
+
failed.push(...result.failed);
|
|
9291
|
+
if (!options.json) {
|
|
9292
|
+
const verb2 = result.dryRun ? "would resolve" : "resolved";
|
|
9293
|
+
console.log(` \u2026${verb2} ${result.resolvedCount}; ${result.noneCount} without an image; ${result.failedCount} failed`);
|
|
9294
|
+
}
|
|
9295
|
+
if (result.rateLimited) {
|
|
9296
|
+
throttled = true;
|
|
9297
|
+
break;
|
|
9298
|
+
}
|
|
9299
|
+
if (result.nextCursor === null) {
|
|
9300
|
+
break;
|
|
9301
|
+
}
|
|
9302
|
+
cursor = result.nextCursor;
|
|
9303
|
+
}
|
|
9304
|
+
if (options.json) {
|
|
9305
|
+
printJson({
|
|
9306
|
+
dryRun,
|
|
9307
|
+
failed,
|
|
9308
|
+
failedCount: failed.length,
|
|
9309
|
+
none,
|
|
9310
|
+
noneCount: none.length,
|
|
9311
|
+
ok: true,
|
|
9312
|
+
rateLimited: throttled,
|
|
9313
|
+
resolved,
|
|
9314
|
+
resolvedCount: resolved.length
|
|
9315
|
+
});
|
|
9316
|
+
if (failed.length > 0) {
|
|
9317
|
+
process.exitCode = 1;
|
|
9318
|
+
}
|
|
9319
|
+
return;
|
|
9320
|
+
}
|
|
9321
|
+
const verb = dryRun ? "Would resolve" : "Resolved";
|
|
9322
|
+
console.log(`${verb} ${resolved.length} label logo(s); ${none.length} without an image; ${failed.length} failed.`);
|
|
9323
|
+
for (const slug of resolved) {
|
|
9324
|
+
console.log(` ${slug}`);
|
|
9325
|
+
}
|
|
9326
|
+
for (const item of failed) {
|
|
9327
|
+
console.log(` ${item.slug}: ${item.error}`);
|
|
9328
|
+
}
|
|
9329
|
+
if (failed.length > 0) {
|
|
9330
|
+
process.exitCode = 1;
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9012
9333
|
async function runArtistResolveQueue(options, listArtistsCommand2) {
|
|
9013
9334
|
const limit = parseListLimit(options.limit);
|
|
9014
9335
|
const result = await listArtistsCommand2(limit ?? 50);
|
|
@@ -9059,7 +9380,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
|
9059
9380
|
return;
|
|
9060
9381
|
}
|
|
9061
9382
|
const candidate = path2.join(dir, name);
|
|
9062
|
-
return
|
|
9383
|
+
return existsSync7(candidate) ? candidate : undefined;
|
|
9063
9384
|
};
|
|
9064
9385
|
const resolveFile = (explicit, name) => {
|
|
9065
9386
|
if (explicit) {
|
|
@@ -9271,7 +9592,7 @@ async function runTrackUpdate(trackId, options, trackUpdateCommand3) {
|
|
|
9271
9592
|
if (options.analyzedFrom !== undefined && options.analyzedFrom !== "full" && options.analyzedFrom !== "preview") {
|
|
9272
9593
|
throw new Error(`Invalid --analyzed-from: ${options.analyzedFrom} (expected full or preview)`);
|
|
9273
9594
|
}
|
|
9274
|
-
const embeddingRaw = options.embeddingFile ?
|
|
9595
|
+
const embeddingRaw = options.embeddingFile ? readFileSync7(options.embeddingFile, "utf8") : options.embedding;
|
|
9275
9596
|
const embedding = parseEmbeddingArg(embeddingRaw);
|
|
9276
9597
|
const result = await trackUpdateCommand3(trackId, {
|
|
9277
9598
|
analyzedAt: options.analyzedAt,
|
|
@@ -9644,6 +9965,7 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
9644
9965
|
const result = await writeCommand(sector, {
|
|
9645
9966
|
body: options.body,
|
|
9646
9967
|
bodyFile: options.bodyFile,
|
|
9968
|
+
promptVersion: parsePromptVersion(options.promptVersion),
|
|
9647
9969
|
title: options.title
|
|
9648
9970
|
});
|
|
9649
9971
|
if (options.json) {
|
|
@@ -9653,6 +9975,109 @@ async function runLogbookWrite(sector, options, writeCommand) {
|
|
|
9653
9975
|
const skipped = "skipped" in result && result.skipped;
|
|
9654
9976
|
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
9977
|
}
|
|
9978
|
+
function requirePromptSlug(slug) {
|
|
9979
|
+
if (!slug) {
|
|
9980
|
+
throw new Error("Missing prompt slug. `fluncle admin prompts list` names them all.");
|
|
9981
|
+
}
|
|
9982
|
+
return slug;
|
|
9983
|
+
}
|
|
9984
|
+
async function runPromptsList(options, promptsListCommand2) {
|
|
9985
|
+
const prompts = await promptsListCommand2();
|
|
9986
|
+
if (options.json) {
|
|
9987
|
+
printJson({ ok: true, prompts });
|
|
9988
|
+
return;
|
|
9989
|
+
}
|
|
9990
|
+
const { promptRows: promptRows2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
9991
|
+
for (const row of promptRows2(prompts)) {
|
|
9992
|
+
console.log(row);
|
|
9993
|
+
}
|
|
9994
|
+
}
|
|
9995
|
+
async function runPromptGet(slug, options, promptGetCommand2) {
|
|
9996
|
+
const resolved = await promptGetCommand2(requirePromptSlug(slug));
|
|
9997
|
+
if (options.json) {
|
|
9998
|
+
printJson(resolved);
|
|
9999
|
+
return;
|
|
10000
|
+
}
|
|
10001
|
+
const live = resolved.source === "override" ? `v${resolved.version}, an operator edit` : "the repo's baked default (v0)";
|
|
10002
|
+
console.log(`${resolved.slug}: ${live}`);
|
|
10003
|
+
console.log("");
|
|
10004
|
+
console.log(resolved.body);
|
|
10005
|
+
}
|
|
10006
|
+
async function runPromptHistory(slug, options, promptDetailCommand2) {
|
|
10007
|
+
const detail = await promptDetailCommand2(requirePromptSlug(slug));
|
|
10008
|
+
if (options.json) {
|
|
10009
|
+
printJson({
|
|
10010
|
+
activeVersion: detail.activeVersion,
|
|
10011
|
+
ok: true,
|
|
10012
|
+
slug: detail.slug,
|
|
10013
|
+
source: detail.source,
|
|
10014
|
+
versions: detail.versions
|
|
10015
|
+
});
|
|
10016
|
+
return;
|
|
10017
|
+
}
|
|
10018
|
+
if (detail.versions.length === 0) {
|
|
10019
|
+
console.log(`${detail.slug}: never edited. The repo's baked default is what runs.`);
|
|
10020
|
+
return;
|
|
10021
|
+
}
|
|
10022
|
+
const { historyRows: historyRows2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
10023
|
+
for (const row of historyRows2(detail.versions)) {
|
|
10024
|
+
console.log(row);
|
|
10025
|
+
}
|
|
10026
|
+
}
|
|
10027
|
+
async function runPromptDiff(slug, options, commands) {
|
|
10028
|
+
const against = commands.parseAgainst(options.against);
|
|
10029
|
+
const result = await commands.promptDiffCommand(requirePromptSlug(slug), against);
|
|
10030
|
+
if (options.json) {
|
|
10031
|
+
printJson({ ok: true, ...result });
|
|
10032
|
+
return;
|
|
10033
|
+
}
|
|
10034
|
+
const live = result.live.source === "override" ? `v${result.live.version}` : "the repo's baked default";
|
|
10035
|
+
if (result.added === 0 && result.removed === 0) {
|
|
10036
|
+
console.log(`${result.slug}: ${live} and ${result.against.label} are the same body.`);
|
|
10037
|
+
return;
|
|
10038
|
+
}
|
|
10039
|
+
const { renderDiff: renderDiff2 } = await Promise.resolve().then(() => (init_admin_prompts(), exports_admin_prompts));
|
|
10040
|
+
console.log(`${result.slug}: ${result.against.label} (-) against ${live} (+)`);
|
|
10041
|
+
for (const line of renderDiff2(result.lines)) {
|
|
10042
|
+
console.log(line);
|
|
10043
|
+
}
|
|
10044
|
+
console.log(`${result.added} added, ${result.removed} removed.`);
|
|
10045
|
+
}
|
|
10046
|
+
async function runPromptUpdate(slug, options, promptUpdateCommand2) {
|
|
10047
|
+
const result = await promptUpdateCommand2(requirePromptSlug(slug), {
|
|
10048
|
+
bodyFile: options.bodyFile,
|
|
10049
|
+
note: options.note
|
|
10050
|
+
});
|
|
10051
|
+
if (options.json) {
|
|
10052
|
+
printJson({ ok: true, ...result });
|
|
10053
|
+
return;
|
|
10054
|
+
}
|
|
10055
|
+
console.log(`${result.slug}: v${result.version} is live. Nothing to deploy.`);
|
|
10056
|
+
}
|
|
10057
|
+
async function runPromptRollback(slug, version, options, commands) {
|
|
10058
|
+
const promptSlug = requirePromptSlug(slug);
|
|
10059
|
+
if (!version) {
|
|
10060
|
+
throw new Error(`Missing version. \`fluncle admin prompts history ${promptSlug}\` lists what you can go back to.`);
|
|
10061
|
+
}
|
|
10062
|
+
const parsed = commands.parseVersion(version);
|
|
10063
|
+
if (parsed === undefined) {
|
|
10064
|
+
throw new Error(`A version reads as 3 or v3. Got "${version}".`);
|
|
10065
|
+
}
|
|
10066
|
+
const result = await commands.promptRollbackCommand(promptSlug, parsed);
|
|
10067
|
+
if (options.json) {
|
|
10068
|
+
printJson({ ok: true, ...result });
|
|
10069
|
+
return;
|
|
10070
|
+
}
|
|
10071
|
+
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}.`);
|
|
10072
|
+
}
|
|
10073
|
+
async function runPromptReset(slug, options, promptResetCommand2) {
|
|
10074
|
+
const result = await promptResetCommand2(requirePromptSlug(slug));
|
|
10075
|
+
if (options.json) {
|
|
10076
|
+
printJson({ ok: true, ...result });
|
|
10077
|
+
return;
|
|
10078
|
+
}
|
|
10079
|
+
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}.`);
|
|
10080
|
+
}
|
|
9656
10081
|
async function runAdd(spotifyUrl, options, addCommand3) {
|
|
9657
10082
|
if (!spotifyUrl) {
|
|
9658
10083
|
throw new Error("Missing Spotify track URL");
|
|
@@ -9858,7 +10283,7 @@ async function runGalaxyEmbeddings(options, galaxyEmbeddingsCommand2) {
|
|
|
9858
10283
|
console.log(`${result.embeddings.length} embedding(s)${result.nextCursor ? ` \xB7 nextCursor: ${result.nextCursor}` : " \xB7 end of corpus"}`);
|
|
9859
10284
|
}
|
|
9860
10285
|
async function runGalaxyMapWrite(options, galaxyMapWriteCommand2) {
|
|
9861
|
-
const raw = JSON.parse(
|
|
10286
|
+
const raw = JSON.parse(readFileSync7(options.file, "utf8"));
|
|
9862
10287
|
const clusters = Array.isArray(raw) || raw === null ? raw : raw.clusters;
|
|
9863
10288
|
if (!Array.isArray(clusters)) {
|
|
9864
10289
|
throw new Error("Invalid --file: expected { clusters: [...] } or a JSON array of cluster rows");
|
|
@@ -10400,6 +10825,7 @@ function normalizeCommanderError(error) {
|
|
|
10400
10825
|
return new Error(message);
|
|
10401
10826
|
}
|
|
10402
10827
|
var stringOptions = new Set([
|
|
10828
|
+
"--against",
|
|
10403
10829
|
"--analyzed-at",
|
|
10404
10830
|
"--analyzed-from",
|
|
10405
10831
|
"--at",
|
|
@@ -10451,6 +10877,7 @@ var stringOptions = new Set([
|
|
|
10451
10877
|
"--plate-background",
|
|
10452
10878
|
"--platform",
|
|
10453
10879
|
"--poster",
|
|
10880
|
+
"--prompt-version",
|
|
10454
10881
|
"--props",
|
|
10455
10882
|
"--query",
|
|
10456
10883
|
"--reasoning",
|
package/package.json
CHANGED