orizu 0.5.17 → 0.5.19
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/README.md +15 -0
- package/dist/archive-artifacts-cli.js +1 -3
- package/dist/artifact-pull.js +1 -3
- package/dist/diff-comments-cli.js +120 -32
- package/dist/error-response.js +17 -17
- package/dist/github-setup.js +3 -11
- package/dist/help.js +22 -2
- package/dist/index.js +43 -107
- package/dist/json-response.js +21 -0
- package/dist/markdown-report-input.js +67 -0
- package/dist/optimization-export-cli.js +30 -0
- package/dist/optimizations-list-cli.js +1 -3
- package/dist/prompt-draft-push.js +7 -5
- package/dist/prompt-length-wire.js +30 -0
- package/dist/prompt-report-cli.js +86 -0
- package/dist/prompt-summary-table.js +37 -0
- package/dist/scorer-draft-push.js +1 -22
- package/dist/scores-accept-cli.js +1 -3
- package/dist/zip-draft-push.js +1 -24
- package/package.json +1 -1
- package/src/archive-artifacts-cli.ts +1 -7
- package/src/artifact-pull.ts +1 -4
- package/src/diff-comments-cli.ts +177 -37
- package/src/error-response.ts +23 -21
- package/src/github-setup.ts +3 -12
- package/src/help.ts +22 -2
- package/src/index.ts +54 -132
- package/src/json-response.ts +37 -0
- package/src/markdown-report-input.ts +80 -0
- package/src/optimization-export-cli.ts +72 -0
- package/src/optimizations-list-cli.ts +1 -4
- package/src/prompt-draft-push.ts +8 -6
- package/src/prompt-length-wire.ts +65 -0
- package/src/prompt-report-cli.ts +135 -0
- package/src/prompt-summary-table.ts +57 -0
- package/src/scorer-draft-push.ts +1 -6
- package/src/scores-accept-cli.ts +1 -4
- package/src/zip-draft-push.ts +1 -6
- package/vendor/skills/orizu-cli/SKILL.md +1 -0
- package/vendor/skills/orizu-cli/references/cli-reference.md +15 -1
- package/vendor/skills/orizu-cli/references/prompt-control-plane.md +19 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function sanitizeTerminalText(value) {
|
|
2
|
+
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
3
|
+
}
|
|
4
|
+
export function sanitizeHumanInlineText(sanitizer, value) {
|
|
5
|
+
return sanitizer(value).replaceAll('\r', '').replaceAll('\n', '\\n');
|
|
6
|
+
}
|
|
7
|
+
export async function parseJsonResponse(response, context) {
|
|
8
|
+
const contentType = response.headers.get('content-type') || '';
|
|
9
|
+
const rawBody = await response.text();
|
|
10
|
+
if (!contentType.includes('application/json')) {
|
|
11
|
+
throw new Error(`${context} returned non-JSON response (status ${response.status}). ` +
|
|
12
|
+
`Body preview: ${sanitizeTerminalText(rawBody.slice(0, 180))}`);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(rawBody);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new Error(`${context} returned invalid JSON (status ${response.status}). ` +
|
|
19
|
+
`Body preview: ${sanitizeTerminalText(rawBody.slice(0, 180))}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { basename } from 'path';
|
|
3
|
+
export const MARKDOWN_REPORT_MAX_BYTES = 2 * 1024 * 1024;
|
|
4
|
+
function getArg(args, name) {
|
|
5
|
+
const index = args.indexOf(name);
|
|
6
|
+
if (index === -1 || index + 1 >= args.length)
|
|
7
|
+
return null;
|
|
8
|
+
return args[index + 1];
|
|
9
|
+
}
|
|
10
|
+
function expandHomePath(path) {
|
|
11
|
+
if (!path.startsWith('~/'))
|
|
12
|
+
return path;
|
|
13
|
+
return `${process.env.HOME || ''}/${path.slice(2)}`;
|
|
14
|
+
}
|
|
15
|
+
function rejectDashPrefixedOptionValue(name, value) {
|
|
16
|
+
if (value?.startsWith('-')) {
|
|
17
|
+
throw new Error(`Invalid value for ${name}: option values cannot start with a dash`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function readSourceFile(pathArg) {
|
|
21
|
+
const expandedPath = expandHomePath(pathArg);
|
|
22
|
+
try {
|
|
23
|
+
return readFileSync(expandedPath, 'utf8');
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
27
|
+
throw new Error(`File not found: ${expandedPath}`);
|
|
28
|
+
}
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
throw new Error(`Failed to read file '${expandedPath}': ${message}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function readMarkdownReportInput(args, reportLabel) {
|
|
34
|
+
const report = getArg(args, '--report');
|
|
35
|
+
const reportFile = getArg(args, '--report-file');
|
|
36
|
+
rejectDashPrefixedOptionValue('--report', report);
|
|
37
|
+
rejectDashPrefixedOptionValue('--report-file', reportFile);
|
|
38
|
+
if (report && reportFile) {
|
|
39
|
+
throw new Error('Use either --report or --report-file, not both');
|
|
40
|
+
}
|
|
41
|
+
if (!report && !reportFile)
|
|
42
|
+
return null;
|
|
43
|
+
let markdown;
|
|
44
|
+
let sourceName;
|
|
45
|
+
if (reportFile) {
|
|
46
|
+
const expandedPath = expandHomePath(reportFile);
|
|
47
|
+
markdown = readSourceFile(reportFile);
|
|
48
|
+
sourceName = basename(expandedPath);
|
|
49
|
+
}
|
|
50
|
+
else if (report?.startsWith('@')) {
|
|
51
|
+
const path = report.slice(1);
|
|
52
|
+
const expandedPath = expandHomePath(path);
|
|
53
|
+
markdown = readSourceFile(path);
|
|
54
|
+
sourceName = basename(expandedPath);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
markdown = report || '';
|
|
58
|
+
sourceName = 'inline';
|
|
59
|
+
}
|
|
60
|
+
if (!markdown.trim()) {
|
|
61
|
+
throw new Error(`${reportLabel} report markdown must not be blank`);
|
|
62
|
+
}
|
|
63
|
+
if (Buffer.byteLength(markdown, 'utf8') > MARKDOWN_REPORT_MAX_BYTES) {
|
|
64
|
+
throw new Error(`${reportLabel} report exceeds ${MARKDOWN_REPORT_MAX_BYTES} bytes`);
|
|
65
|
+
}
|
|
66
|
+
return { markdown, sourceName };
|
|
67
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { parseJsonResponse, sanitizeHumanInlineText, } from './json-response.js';
|
|
2
|
+
export function printDiffCommentsSuppressionMarker(ctx, data) {
|
|
3
|
+
const reason = data.diffCommentsSuppressedReason;
|
|
4
|
+
if (typeof reason !== 'string' || reason.length === 0) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
ctx.printLine(`Diff comments suppressed: ${sanitizeHumanInlineText(ctx.sanitizeTerminalText, reason)}`);
|
|
8
|
+
}
|
|
9
|
+
export async function exportOptimizationRunCommand(ctx) {
|
|
10
|
+
const runId = ctx.getPositionalArg(2) || ctx.getArg('--run-id');
|
|
11
|
+
const outPathArg = ctx.getArg('--out');
|
|
12
|
+
if (!runId) {
|
|
13
|
+
throw new Error('Usage: orizu optimizations export <run-id> [--out <path>] [--json]');
|
|
14
|
+
}
|
|
15
|
+
const response = await ctx.authedFetch(`/api/cli/optimization-runs/${encodeURIComponent(runId)}/export`);
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
throw new Error(`Failed to export optimization run: ${await response.text()}`);
|
|
18
|
+
}
|
|
19
|
+
const data = await parseJsonResponse(response, 'Optimization export');
|
|
20
|
+
if (ctx.hasJsonFlag() && !outPathArg) {
|
|
21
|
+
ctx.printJson(data);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const filename = outPathArg
|
|
25
|
+
? ctx.expandHomePath(outPathArg)
|
|
26
|
+
: `${runId}.optimization.json`;
|
|
27
|
+
ctx.writeTextFileEnsuringDir(filename, `${JSON.stringify(data, null, 2)}\n`);
|
|
28
|
+
ctx.printLine(`Saved optimization export to ${ctx.sanitizeTerminalText(filename)}`);
|
|
29
|
+
printDiffCommentsSuppressionMarker(ctx, data);
|
|
30
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { authedFetch } from './http.js';
|
|
14
14
|
import { extractErrorMessage } from './error-response.js';
|
|
15
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
15
16
|
// ALI-1175: best scores here derive from agent-reported score runs — nothing is
|
|
16
17
|
// server-attested yet. Both the table footer AND the --json payload carry this
|
|
17
18
|
// signal so no consumer, human or machine, mistakes the number for attested
|
|
@@ -25,9 +26,6 @@ function argValue(args, flag) {
|
|
|
25
26
|
}
|
|
26
27
|
return args[index + 1];
|
|
27
28
|
}
|
|
28
|
-
function sanitizeTerminalText(value) {
|
|
29
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
30
|
-
}
|
|
31
29
|
// Shared-parser behavior (artifact-pull.ts pattern): a non-JSON or malformed
|
|
32
30
|
// body becomes a bounded, sanitized error — never a raw JSON.parse throw.
|
|
33
31
|
async function parseJsonPayload(response, context) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { authedFetch } from './http.js';
|
|
2
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
2
3
|
import { appendRegistrationTagWarning } from './registration-tag-warning.js';
|
|
3
4
|
/**
|
|
4
5
|
* ADR-007 P4 (ALI-1074): the session-scoped, commit-first prompt push.
|
|
@@ -18,11 +19,6 @@ import { appendRegistrationTagWarning } from './registration-tag-warning.js';
|
|
|
18
19
|
* Lives outside index.ts per the CLI line ratchet (ALI-976).
|
|
19
20
|
*/
|
|
20
21
|
export const PROMPT_PRIMARY_GIT_FILENAME = 'prompt.md';
|
|
21
|
-
// Mirrors index.ts `sanitizeTerminalText` (precedent: artifact-pull.ts keeps
|
|
22
|
-
// its own copy to avoid importing the CLI entrypoint).
|
|
23
|
-
function sanitizeTerminalText(value) {
|
|
24
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
25
|
-
}
|
|
26
22
|
/**
|
|
27
23
|
* Build the git file set for a prompt-version draft: the primary text at the
|
|
28
24
|
* canonical prompt.md plus every sidecar at its own relative path. A sidecar
|
|
@@ -74,6 +70,12 @@ export async function pushPromptDraft(input) {
|
|
|
74
70
|
parentVersionId: input.parentVersionId,
|
|
75
71
|
createdBy: manifest.provenance || { kind: 'human-edit' },
|
|
76
72
|
files,
|
|
73
|
+
...(input.report
|
|
74
|
+
? {
|
|
75
|
+
reportMarkdown: input.report.markdown,
|
|
76
|
+
reportSourceName: input.report.sourceName,
|
|
77
|
+
}
|
|
78
|
+
: {}),
|
|
77
79
|
}),
|
|
78
80
|
});
|
|
79
81
|
if (!response.ok) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const CLI_LENGTH_STATS_FIELDS = [
|
|
2
|
+
'tokens',
|
|
3
|
+
'lines',
|
|
4
|
+
'chars',
|
|
5
|
+
'words',
|
|
6
|
+
];
|
|
7
|
+
export const CLI_LENGTH_DELTA_SPLIT_UNAVAILABLE_REASONS = [
|
|
8
|
+
'diff_degraded_size_limit',
|
|
9
|
+
'diff_degraded_cell_limit',
|
|
10
|
+
];
|
|
11
|
+
export const CLI_LENGTH_MEASUREMENT_UNAVAILABLE_REASONS = [
|
|
12
|
+
'length_measurement_size_limit',
|
|
13
|
+
'length_measurement_failed',
|
|
14
|
+
'body_resolution_failed',
|
|
15
|
+
'measurement_cap_exceeded',
|
|
16
|
+
'enrichment_failed',
|
|
17
|
+
'bodies_unavailable_event_cap',
|
|
18
|
+
];
|
|
19
|
+
export function formatFiniteLengthCount(value, signed = false) {
|
|
20
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
21
|
+
return null;
|
|
22
|
+
const formatted = Math.abs(value).toLocaleString('en-US');
|
|
23
|
+
if (!signed)
|
|
24
|
+
return formatted;
|
|
25
|
+
if (value > 0)
|
|
26
|
+
return `+${formatted}`;
|
|
27
|
+
if (value < 0)
|
|
28
|
+
return `-${formatted}`;
|
|
29
|
+
return formatted;
|
|
30
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { extractErrorMessage } from './error-response.js';
|
|
2
|
+
import { authedFetch } from './http.js';
|
|
3
|
+
import { parseJsonResponse, sanitizeTerminalText } from './json-response.js';
|
|
4
|
+
import { readMarkdownReportInput } from './markdown-report-input.js';
|
|
5
|
+
const IDENTICAL_PROMPT_VERSION_ERROR = 'Prompt version is identical to the current prompt version.';
|
|
6
|
+
function getArg(args, name) {
|
|
7
|
+
const index = args.indexOf(name);
|
|
8
|
+
if (index === -1 || index + 1 >= args.length)
|
|
9
|
+
return null;
|
|
10
|
+
return args[index + 1];
|
|
11
|
+
}
|
|
12
|
+
function rejectDashPrefixedOptionValue(name, value) {
|
|
13
|
+
if (value?.startsWith('-')) {
|
|
14
|
+
throw new Error(`Invalid value for ${name}: option values cannot start with a dash`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function promptReportCommand(args, context) {
|
|
18
|
+
const prompt = getArg(args, '--prompt');
|
|
19
|
+
const projectArg = getArg(args, '--project');
|
|
20
|
+
const version = getArg(args, '--version');
|
|
21
|
+
const versionId = getArg(args, '--version-id');
|
|
22
|
+
for (const [name, value] of [
|
|
23
|
+
['--prompt', prompt],
|
|
24
|
+
['--project', projectArg],
|
|
25
|
+
['--version-id', versionId],
|
|
26
|
+
]) {
|
|
27
|
+
rejectDashPrefixedOptionValue(name, value);
|
|
28
|
+
}
|
|
29
|
+
if (!prompt) {
|
|
30
|
+
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> --project <team/project> ' +
|
|
31
|
+
'(--version <n> | --version-id <id>) ' +
|
|
32
|
+
'(--report <markdown|@file> | --report-file <path>) [--json]');
|
|
33
|
+
}
|
|
34
|
+
if (Boolean(version) === Boolean(versionId)) {
|
|
35
|
+
throw new Error('Exactly one of --version or --version-id is required');
|
|
36
|
+
}
|
|
37
|
+
if (version && (!/^[1-9]\d*$/.test(version) || !Number.isSafeInteger(Number(version)))) {
|
|
38
|
+
throw new Error('--version must be a positive integer');
|
|
39
|
+
}
|
|
40
|
+
const report = readMarkdownReportInput(args, 'Prompt');
|
|
41
|
+
if (!report) {
|
|
42
|
+
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> --project <team/project> ' +
|
|
43
|
+
'(--version <n> | --version-id <id>) ' +
|
|
44
|
+
'(--report <markdown|@file> | --report-file <path>) [--json]');
|
|
45
|
+
}
|
|
46
|
+
const project = projectArg || await context.resolveProjectSlug(null);
|
|
47
|
+
const query = new URLSearchParams({ project });
|
|
48
|
+
if (version)
|
|
49
|
+
query.set('version', version);
|
|
50
|
+
else
|
|
51
|
+
query.set('versionId', versionId);
|
|
52
|
+
const fetcher = context.fetcher ?? authedFetch;
|
|
53
|
+
const response = await fetcher(`/api/cli/prompts/${encodeURIComponent(prompt)}/report?${query.toString()}`, {
|
|
54
|
+
method: 'PATCH',
|
|
55
|
+
headers: { 'Content-Type': 'application/json' },
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
reportMarkdown: report.markdown,
|
|
58
|
+
reportSourceName: report.sourceName,
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`Failed to update prompt report: ${await extractErrorMessage(response)}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await parseJsonResponse(response, 'Prompt report update');
|
|
65
|
+
if (context.json) {
|
|
66
|
+
context.printJson(data);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const versionLabel = data.version
|
|
70
|
+
? data.version.versionNumber === null
|
|
71
|
+
? data.version.id
|
|
72
|
+
: `v${data.version.versionNumber}`
|
|
73
|
+
: data.promptVersionId || versionId || `v${version}`;
|
|
74
|
+
const promptName = data.prompt?.name || prompt;
|
|
75
|
+
const status = data.version?.status || 'updated';
|
|
76
|
+
context.printLine(`Uploaded prompt report for ${sanitizeTerminalText(promptName)} ` +
|
|
77
|
+
`(${sanitizeTerminalText(versionLabel)}) [${sanitizeTerminalText(status)}]`);
|
|
78
|
+
}
|
|
79
|
+
export async function promptPushErrorMessage(response, kind, hasReport) {
|
|
80
|
+
const message = await extractErrorMessage(response);
|
|
81
|
+
if (hasReport && response.status === 409 && message === IDENTICAL_PROMPT_VERSION_ERROR) {
|
|
82
|
+
return (`${IDENTICAL_PROMPT_VERSION_ERROR} ` +
|
|
83
|
+
'Attach the report to the existing version with `orizu prompts report set`.');
|
|
84
|
+
}
|
|
85
|
+
return `Failed to push ${kind}: ${message}`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
2
|
+
import { formatFiniteLengthCount, } from './prompt-length-wire.js';
|
|
3
|
+
export function printPromptSummaryTable(items, emptyMessage, printLine) {
|
|
4
|
+
if (items.length === 0) {
|
|
5
|
+
printLine(emptyMessage);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const rows = items.map(item => ({
|
|
9
|
+
id: sanitizeTerminalText(item.id),
|
|
10
|
+
name: sanitizeTerminalText(item.name),
|
|
11
|
+
role: sanitizeTerminalText(item.role),
|
|
12
|
+
status: sanitizeTerminalText(item.status || 'active'),
|
|
13
|
+
tokens: item.lengthStats == null
|
|
14
|
+
? '—'
|
|
15
|
+
: (() => {
|
|
16
|
+
const count = formatFiniteLengthCount(item.lengthStats.tokens);
|
|
17
|
+
return count === null ? '—' : `~${count}`;
|
|
18
|
+
})(),
|
|
19
|
+
lines: item.lengthStats == null
|
|
20
|
+
? '—'
|
|
21
|
+
: formatFiniteLengthCount(item.lengthStats.lines) ?? '—',
|
|
22
|
+
chars: item.lengthStats == null
|
|
23
|
+
? '—'
|
|
24
|
+
: formatFiniteLengthCount(item.lengthStats.chars) ?? '—',
|
|
25
|
+
words: item.lengthStats == null
|
|
26
|
+
? '—'
|
|
27
|
+
: formatFiniteLengthCount(item.lengthStats.words) ?? '—',
|
|
28
|
+
}));
|
|
29
|
+
const headers = ['ID', 'NAME', 'ROLE', 'STATUS', 'TOKENS', 'LINES', 'CHARS', 'WORDS'];
|
|
30
|
+
const keys = ['id', 'name', 'role', 'status', 'tokens', 'lines', 'chars', 'words'];
|
|
31
|
+
const widths = keys.map((key, index) => Math.max(headers[index].length, ...rows.map(row => row[key].length)));
|
|
32
|
+
printLine(headers.map((header, index) => header.padEnd(widths[index])).join(' '));
|
|
33
|
+
printLine(widths.map(width => '-'.repeat(width)).join(' '));
|
|
34
|
+
rows.forEach(row => {
|
|
35
|
+
printLine(keys.map((key, index) => row[key].padEnd(widths[index])).join(' '));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
import { authedFetch } from './http.js';
|
|
2
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
2
3
|
import { appendRegistrationTagWarning } from './registration-tag-warning.js';
|
|
3
|
-
/**
|
|
4
|
-
* ADR-007 P5 (ALI-1074): the session-scoped, commit-first scorer push.
|
|
5
|
-
*
|
|
6
|
-
* `orizu scorers register --session <id>` creates the version through
|
|
7
|
-
* POST /api/cli/scorers/drafts: the server commits the scorer's canonical
|
|
8
|
-
* `manifest.json` to the session's `orizu/session-*` branch (one Git Data API
|
|
9
|
-
* commit) and then writes a DRAFT row pinning
|
|
10
|
-
* repo_path/content_sha/commit_sha. The draft seals — and gets its version
|
|
11
|
-
* number — when the session branch merges via `orizu session finish` +
|
|
12
|
-
* promotion-manifest apply.
|
|
13
|
-
*
|
|
14
|
-
* The git filename is ALWAYS `manifest.json`: the server read side
|
|
15
|
-
* (lib/artifact-git-read.ts SCORER_MANIFEST_FILENAMES) prefers that name.
|
|
16
|
-
*
|
|
17
|
-
* Lives outside index.ts per the CLI line ratchet (ALI-976); mirrors
|
|
18
|
-
* prompt-draft-push.ts.
|
|
19
|
-
*/
|
|
20
|
-
// Mirrors index.ts `sanitizeTerminalText` (precedent: artifact-pull.ts keeps
|
|
21
|
-
// its own copy to avoid importing the CLI entrypoint).
|
|
22
|
-
function sanitizeTerminalText(value) {
|
|
23
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
24
|
-
}
|
|
25
4
|
/** The full `orizu scorers register` command (moved out of index.ts for the
|
|
26
5
|
* CLI line ratchet): --session takes the ADR-007 P5 commit-first draft path,
|
|
27
6
|
* sessionless stays on the legacy create endpoint. */
|
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
* own argument parsing and printing via injected io.
|
|
12
12
|
*/
|
|
13
13
|
import { authedFetch } from './http.js';
|
|
14
|
-
|
|
15
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
16
|
-
}
|
|
14
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
17
15
|
function argValue(args, flag) {
|
|
18
16
|
const index = args.indexOf(flag);
|
|
19
17
|
if (index === -1 || index + 1 >= args.length || args[index + 1].startsWith('--')) {
|
package/dist/zip-draft-push.js
CHANGED
|
@@ -1,31 +1,8 @@
|
|
|
1
1
|
import { basename } from 'path';
|
|
2
2
|
import { zipDirectoryToBase64 } from './artifact-archive.js';
|
|
3
3
|
import { authedFetch } from './http.js';
|
|
4
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
4
5
|
import { appendRegistrationTagWarning } from './registration-tag-warning.js';
|
|
5
|
-
/**
|
|
6
|
-
* ADR-007 P5 (ALI-1074): the session-scoped, commit-first runner/optimizer
|
|
7
|
-
* push.
|
|
8
|
-
*
|
|
9
|
-
* `orizu runners|optimizers push --session <id>` sends the SAME deterministic
|
|
10
|
-
* zip as the legacy push to POST /api/cli/{runners|optimizers}/drafts: the
|
|
11
|
-
* server unpacks the zip's file set and commits it to the session's
|
|
12
|
-
* `orizu/session-*` branch (one Git Data API commit; binary entries travel
|
|
13
|
-
* base64), keeps uploading the zip to storage (dual-write until ALI-1046),
|
|
14
|
-
* and writes a DRAFT row pinning repo_path/content_sha/commit_sha. The draft
|
|
15
|
-
* seals — and gets its version number — when the session branch merges via
|
|
16
|
-
* `orizu session finish` + promotion-manifest apply.
|
|
17
|
-
*
|
|
18
|
-
* Labels cannot ride a draft push (`--label` with `--session` is an error at
|
|
19
|
-
* the command layer): labels address sealed versions only.
|
|
20
|
-
*
|
|
21
|
-
* Lives outside index.ts per the CLI line ratchet (ALI-976); mirrors
|
|
22
|
-
* prompt-draft-push.ts.
|
|
23
|
-
*/
|
|
24
|
-
// Mirrors index.ts `sanitizeTerminalText` (precedent: artifact-pull.ts keeps
|
|
25
|
-
// its own copy to avoid importing the CLI entrypoint).
|
|
26
|
-
function sanitizeTerminalText(value) {
|
|
27
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '');
|
|
28
|
-
}
|
|
29
6
|
/** The full `orizu runners|optimizers push` command (moved out of index.ts
|
|
30
7
|
* for the CLI line ratchet): --session takes the ADR-007 P5 commit-first
|
|
31
8
|
* draft path, sessionless stays on the legacy zip-only endpoint. */
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { authedFetch } from './http.js'
|
|
10
10
|
import { extractErrorMessage } from './error-response.js'
|
|
11
|
+
import { sanitizeTerminalText } from './json-response.js'
|
|
11
12
|
|
|
12
13
|
type ArchiveStatus = 'active' | 'archived' | 'all'
|
|
13
14
|
type ArchiveAction = 'archive' | 'restore'
|
|
@@ -109,13 +110,6 @@ function argValue(args: readonly string[], flag: string): string | null {
|
|
|
109
110
|
return args[index + 1]
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
function sanitizeTerminalText(value: unknown): string {
|
|
113
|
-
return String(value).replace(
|
|
114
|
-
/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g,
|
|
115
|
-
''
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
113
|
function columnWidths(headers: string[], rows: string[][]): number[] {
|
|
120
114
|
return headers.map((header, index) =>
|
|
121
115
|
Math.max(header.length, ...rows.map(row => row[index]?.length || 0))
|
package/src/artifact-pull.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { tmpdir } from 'os'
|
|
|
18
18
|
import { dirname, join } from 'path'
|
|
19
19
|
|
|
20
20
|
import { authedFetch } from './http.js'
|
|
21
|
+
import { sanitizeTerminalText } from './json-response.js'
|
|
21
22
|
|
|
22
23
|
export type PullableArtifactKind = 'runner' | 'optimizer'
|
|
23
24
|
|
|
@@ -31,10 +32,6 @@ export interface PullArtifactIo {
|
|
|
31
32
|
// Shared with the runners exec download path in index.ts.
|
|
32
33
|
export const ARTIFACT_MAX_BYTES = 25 * 1024 * 1024
|
|
33
34
|
|
|
34
|
-
function sanitizeTerminalText(value: unknown): string {
|
|
35
|
-
return String(value).replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
35
|
function expandHomePath(path: string): string {
|
|
39
36
|
if (path.startsWith('~/')) {
|
|
40
37
|
const home = process.env.HOME || ''
|