orizu 0.5.6 → 0.5.8
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 +13 -2
- package/dist/credentials.js +44 -0
- package/dist/help.js +77 -7
- package/dist/hosted-bootstrap.js +39 -0
- package/dist/hosted-harness-opencode.js +21 -1
- package/dist/hosted-harness.js +9 -0
- package/dist/hosted-harvest.js +116 -0
- package/dist/hosted-headless.js +163 -0
- package/dist/hosted-loop.js +119 -5
- package/dist/hosted-run-event-sink.js +21 -0
- package/dist/hosted-runtime-assets.js +27 -0
- package/dist/hosted-session-cli.js +51 -9
- package/dist/http.js +16 -1
- package/dist/index.js +54 -86
- package/dist/manifests-cli.js +103 -5
- package/dist/report-comments-cli.js +325 -0
- package/dist/skill-installer.js +16 -1
- package/package.json +1 -1
- package/src/credentials.ts +46 -0
- package/src/help.ts +77 -7
- package/src/hosted-bootstrap.ts +46 -0
- package/src/hosted-harness-opencode.ts +24 -2
- package/src/hosted-harness.ts +9 -0
- package/src/hosted-harvest.ts +159 -0
- package/src/hosted-headless.ts +178 -0
- package/src/hosted-loop.ts +133 -4
- package/src/hosted-run-event-sink.ts +28 -0
- package/src/hosted-runtime-assets.ts +31 -0
- package/src/hosted-session-cli.ts +50 -9
- package/src/http.ts +23 -1
- package/src/index.ts +74 -156
- package/src/manifests-cli.ts +110 -5
- package/src/report-comments-cli.ts +524 -0
- package/src/skill-installer.ts +18 -1
- package/vendor/skills/orizu-cli/SKILL.md +9 -2
- package/vendor/skills/orizu-cli/references/prompt-control-plane.md +1 -1
package/src/index.ts
CHANGED
|
@@ -68,6 +68,11 @@ import { hostedCommand } from './hosted-session-cli.js'
|
|
|
68
68
|
import { workspaceSyncCommand } from './workspace-sync.js'
|
|
69
69
|
import { runGitCredential } from './git-credential.js'
|
|
70
70
|
import { type GithubLinkResult, runGithubLink, runInteractiveHostedSetup } from './github-setup.js'
|
|
71
|
+
import {
|
|
72
|
+
reportCommentsCommand,
|
|
73
|
+
throwDeprecatedPromptCommentsCommand,
|
|
74
|
+
type ReportCommentsCliContext,
|
|
75
|
+
} from './report-comments-cli.js'
|
|
71
76
|
|
|
72
77
|
function getErrorMessage(error: unknown): string {
|
|
73
78
|
return error instanceof Error ? error.message : String(error)
|
|
@@ -144,60 +149,18 @@ interface PromptSummary {
|
|
|
144
149
|
description?: string | null
|
|
145
150
|
}
|
|
146
151
|
|
|
147
|
-
interface
|
|
148
|
-
|
|
149
|
-
initials?: string
|
|
150
|
-
color?: string
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
interface PromptCommentAnchor {
|
|
154
|
-
text: string | null
|
|
155
|
-
startLine: number | null
|
|
156
|
-
endLine: number | null
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
interface PromptCommentReply {
|
|
160
|
-
id: string
|
|
161
|
-
body: string
|
|
162
|
-
author: PromptCommentAuthor
|
|
163
|
-
createdAt: string
|
|
164
|
-
updatedAt: string
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
interface PromptCommentThread {
|
|
168
|
-
id: string
|
|
169
|
-
status: 'open' | 'resolved'
|
|
170
|
-
body: string
|
|
171
|
-
anchor: PromptCommentAnchor | null
|
|
172
|
-
author: PromptCommentAuthor
|
|
173
|
-
createdAt: string
|
|
174
|
-
updatedAt: string
|
|
175
|
-
resolvedAt: string | null
|
|
176
|
-
resolvedByUserId: string | null
|
|
177
|
-
replyCount: number
|
|
178
|
-
replies: PromptCommentReply[]
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
interface PromptCommentsPayload {
|
|
182
|
-
prompt: {
|
|
183
|
-
id: string
|
|
184
|
-
name: string
|
|
185
|
-
role: string
|
|
186
|
-
description?: string | null
|
|
187
|
-
}
|
|
188
|
-
version: {
|
|
152
|
+
interface TaskReportPayload {
|
|
153
|
+
task: {
|
|
189
154
|
id: string
|
|
190
|
-
|
|
191
|
-
versionLabel?: string | null
|
|
155
|
+
title?: string | null
|
|
192
156
|
status?: string | null
|
|
157
|
+
report: {
|
|
158
|
+
markdown: string
|
|
159
|
+
sourceName: string | null
|
|
160
|
+
createdAt: string | null
|
|
161
|
+
updatedAt?: string | null
|
|
162
|
+
}
|
|
193
163
|
}
|
|
194
|
-
summary: {
|
|
195
|
-
threadCount: number
|
|
196
|
-
openThreadCount: number
|
|
197
|
-
resolvedThreadCount: number
|
|
198
|
-
replyCount: number
|
|
199
|
-
}
|
|
200
|
-
comments: PromptCommentThread[]
|
|
201
164
|
}
|
|
202
165
|
|
|
203
166
|
interface ScorerSummary {
|
|
@@ -1083,78 +1046,6 @@ function printTaskStatusSummary(data: TaskStatusPayload) {
|
|
|
1083
1046
|
}
|
|
1084
1047
|
}
|
|
1085
1048
|
|
|
1086
|
-
function compactTerminalText(value: string, maxLength = 160): string {
|
|
1087
|
-
const compact = sanitizeTerminalText(value).replace(/\s+/g, ' ').trim()
|
|
1088
|
-
if (compact.length <= maxLength) {
|
|
1089
|
-
return compact
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
return `${compact.slice(0, Math.max(0, maxLength - 1)).trim()}…`
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
function printIndentedBody(value: string, indent: string) {
|
|
1096
|
-
const lines = sanitizeTerminalText(value || '').split(/\r?\n/)
|
|
1097
|
-
for (const line of lines) {
|
|
1098
|
-
printLine(`${indent}${line}`)
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
function formatPromptCommentAnchor(anchor: PromptCommentAnchor | null): string | null {
|
|
1103
|
-
if (!anchor) {
|
|
1104
|
-
return null
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
const lineLabel = anchor.startLine && anchor.endLine
|
|
1108
|
-
? anchor.startLine === anchor.endLine
|
|
1109
|
-
? `line ${anchor.startLine}`
|
|
1110
|
-
: `lines ${anchor.startLine}-${anchor.endLine}`
|
|
1111
|
-
: null
|
|
1112
|
-
const selectedText = anchor.text ? `"${compactTerminalText(anchor.text, 180)}"` : null
|
|
1113
|
-
|
|
1114
|
-
if (lineLabel && selectedText) {
|
|
1115
|
-
return `${lineLabel}: ${selectedText}`
|
|
1116
|
-
}
|
|
1117
|
-
return lineLabel || selectedText
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
function printPromptComments(data: PromptCommentsPayload) {
|
|
1121
|
-
const versionLabel = data.version.versionLabel || (
|
|
1122
|
-
data.version.versionNumber ? `v${data.version.versionNumber}` : data.version.id
|
|
1123
|
-
)
|
|
1124
|
-
|
|
1125
|
-
printLine(`Prompt: ${sanitizeTerminalText(data.prompt.name)} (${sanitizeTerminalText(data.prompt.id)})`)
|
|
1126
|
-
printLine(`Version: ${sanitizeTerminalText(String(versionLabel))} (${sanitizeTerminalText(data.version.id)})`)
|
|
1127
|
-
printLine(
|
|
1128
|
-
`Comments: ${data.summary.threadCount} thread${data.summary.threadCount === 1 ? '' : 's'} ` +
|
|
1129
|
-
`(${data.summary.openThreadCount} open, ${data.summary.resolvedThreadCount} resolved, ${data.summary.replyCount} replies)`
|
|
1130
|
-
)
|
|
1131
|
-
|
|
1132
|
-
if (data.comments.length === 0) {
|
|
1133
|
-
printLine('\nNo comments found for this prompt version.')
|
|
1134
|
-
return
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
for (const [index, thread] of data.comments.entries()) {
|
|
1138
|
-
const authorName = thread.author?.name || 'Unknown'
|
|
1139
|
-
const anchor = formatPromptCommentAnchor(thread.anchor)
|
|
1140
|
-
printLine('')
|
|
1141
|
-
printLine(`${index + 1}. [${thread.status}] ${sanitizeTerminalText(authorName)} · ${sanitizeTerminalText(thread.createdAt)}`)
|
|
1142
|
-
if (anchor) {
|
|
1143
|
-
printLine(` Selection: ${anchor}`)
|
|
1144
|
-
}
|
|
1145
|
-
printIndentedBody(thread.body, ' ')
|
|
1146
|
-
|
|
1147
|
-
if (thread.replies.length > 0) {
|
|
1148
|
-
printLine(` Replies (${thread.replies.length})`)
|
|
1149
|
-
for (const reply of thread.replies) {
|
|
1150
|
-
const replyAuthor = reply.author?.name || 'Unknown'
|
|
1151
|
-
printLine(` - ${sanitizeTerminalText(replyAuthor)} · ${sanitizeTerminalText(reply.createdAt)}`)
|
|
1152
|
-
printIndentedBody(reply.body, ' ')
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
1049
|
const DEFAULT_AUTH_CALLBACK_PORT = 43123
|
|
1159
1050
|
|
|
1160
1051
|
function resolveAuthCallbackPort(): number {
|
|
@@ -1562,37 +1453,6 @@ async function listJudges() {
|
|
|
1562
1453
|
printPromptSummaries(data.judges, 'No judges found.')
|
|
1563
1454
|
}
|
|
1564
1455
|
|
|
1565
|
-
async function listPromptComments() {
|
|
1566
|
-
const promptRef = getPositionalArg(2)
|
|
1567
|
-
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
1568
|
-
const label = getArg('--label')
|
|
1569
|
-
const version = getArg('--version')
|
|
1570
|
-
|
|
1571
|
-
if (!promptRef) {
|
|
1572
|
-
throw new Error('Usage: orizu prompts comments <prompt-id-or-name> --project <team/project> [--label <label> | --version <version-id>] [--json]')
|
|
1573
|
-
}
|
|
1574
|
-
if (label && version) {
|
|
1575
|
-
throw new Error('Use either --label or --version, not both')
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
const params = new URLSearchParams({ project })
|
|
1579
|
-
if (label) params.set('label', label)
|
|
1580
|
-
if (version) params.set('version', version)
|
|
1581
|
-
|
|
1582
|
-
const response = await authedFetch(`/api/cli/prompts/${encodeURIComponent(promptRef)}/comments?${params.toString()}`)
|
|
1583
|
-
if (!response.ok) {
|
|
1584
|
-
throw new Error(`Failed to fetch prompt comments: ${await response.text()}`)
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
const data = await parseJsonResponse<PromptCommentsPayload>(response, 'Prompt comments')
|
|
1588
|
-
if (hasJsonFlag()) {
|
|
1589
|
-
printJson(data as unknown as Record<string, unknown>)
|
|
1590
|
-
return
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
printPromptComments(data)
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
1456
|
async function listScorers() {
|
|
1597
1457
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
1598
1458
|
const response = await authedFetch(`/api/cli/scorers?project=${encodeURIComponent(project)}`)
|
|
@@ -2957,6 +2817,22 @@ function printJson(value: Record<string, unknown>) {
|
|
|
2957
2817
|
printLine(JSON.stringify(value))
|
|
2958
2818
|
}
|
|
2959
2819
|
|
|
2820
|
+
function createReportCommentsCliContext(): ReportCommentsCliContext {
|
|
2821
|
+
return {
|
|
2822
|
+
getArg,
|
|
2823
|
+
getPositionalArg,
|
|
2824
|
+
rejectDashPrefixedOptionValue,
|
|
2825
|
+
resolveProjectSlug,
|
|
2826
|
+
readSourceFile,
|
|
2827
|
+
authedFetch,
|
|
2828
|
+
parseJsonResponse,
|
|
2829
|
+
hasJsonFlag,
|
|
2830
|
+
printJson,
|
|
2831
|
+
printLine,
|
|
2832
|
+
sanitizeTerminalText,
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2960
2836
|
function printCapabilities() {
|
|
2961
2837
|
const capabilities = getCapabilities(getCliVersion())
|
|
2962
2838
|
if (hasJsonFlag()) {
|
|
@@ -4994,6 +4870,39 @@ async function setTaskReport() {
|
|
|
4994
4870
|
)
|
|
4995
4871
|
}
|
|
4996
4872
|
|
|
4873
|
+
async function getTaskReport() {
|
|
4874
|
+
const taskId = getArg('--task')
|
|
4875
|
+
rejectDashPrefixedOptionValue('--task', taskId)
|
|
4876
|
+
if (!taskId) {
|
|
4877
|
+
throw new Error('Usage: orizu tasks report get --task <taskId> [--json]')
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
const response = await authedFetch(`/api/cli/tasks/${encodeURIComponent(taskId)}/report`)
|
|
4881
|
+
if (!response.ok) {
|
|
4882
|
+
throw new Error(`Failed to read task report: ${await response.text()}`)
|
|
4883
|
+
}
|
|
4884
|
+
|
|
4885
|
+
const data = await parseJsonResponse<TaskReportPayload>(response, 'Task report get')
|
|
4886
|
+
if (hasJsonFlag()) {
|
|
4887
|
+
printJson(data as unknown as Record<string, unknown>)
|
|
4888
|
+
return
|
|
4889
|
+
}
|
|
4890
|
+
|
|
4891
|
+
const title = data.task.title ? `${data.task.title} ` : ''
|
|
4892
|
+
printLine(`Task report: ${sanitizeTerminalText(title)}(${sanitizeTerminalText(data.task.id)})`)
|
|
4893
|
+
if (data.task.status) {
|
|
4894
|
+
printLine(`Status: ${sanitizeTerminalText(data.task.status)}`)
|
|
4895
|
+
}
|
|
4896
|
+
if (data.task.report.sourceName) {
|
|
4897
|
+
printLine(`Source: ${sanitizeTerminalText(data.task.report.sourceName)}`)
|
|
4898
|
+
}
|
|
4899
|
+
if (data.task.report.createdAt) {
|
|
4900
|
+
printLine(`Created: ${sanitizeTerminalText(data.task.report.createdAt)}`)
|
|
4901
|
+
}
|
|
4902
|
+
printLine('')
|
|
4903
|
+
printLine(sanitizeTerminalText(data.task.report.markdown))
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4997
4906
|
interface AppDetailPayload {
|
|
4998
4907
|
id: string
|
|
4999
4908
|
name: string
|
|
@@ -6339,6 +6248,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
6339
6248
|
return
|
|
6340
6249
|
}
|
|
6341
6250
|
|
|
6251
|
+
if (command === 'comments') {
|
|
6252
|
+
await reportCommentsCommand(subcommand, createReportCommentsCliContext())
|
|
6253
|
+
return
|
|
6254
|
+
}
|
|
6255
|
+
|
|
6342
6256
|
if (command === 'teams' && subcommand === 'list') {
|
|
6343
6257
|
await listTeams()
|
|
6344
6258
|
return
|
|
@@ -6383,8 +6297,7 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
6383
6297
|
}
|
|
6384
6298
|
|
|
6385
6299
|
if (command === 'prompts' && subcommand === 'comments') {
|
|
6386
|
-
|
|
6387
|
-
return
|
|
6300
|
+
throwDeprecatedPromptCommentsCommand()
|
|
6388
6301
|
}
|
|
6389
6302
|
|
|
6390
6303
|
if (command === 'prompts' && subcommand === 'pull') {
|
|
@@ -6594,6 +6507,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
6594
6507
|
return
|
|
6595
6508
|
}
|
|
6596
6509
|
|
|
6510
|
+
if (command === 'tasks' && subcommand === 'report' && cliArgs[2] === 'get') {
|
|
6511
|
+
await getTaskReport()
|
|
6512
|
+
return
|
|
6513
|
+
}
|
|
6514
|
+
|
|
6597
6515
|
if (command === 'tasks' && subcommand === 'pause') { await updateTaskStatus('paused'); return }
|
|
6598
6516
|
if (command === 'tasks' && subcommand === 'unpause') { await updateTaskStatus('active'); return }
|
|
6599
6517
|
if (command === 'tasks' && subcommand === 'complete') { await updateTaskStatus('completed'); return }
|
package/src/manifests-cli.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface ManifestsCommandIo {
|
|
|
16
16
|
resolveProjectSlug?: (arg: string | null) => Promise<string>
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const MANIFEST_ACTIONS = new Set(['approve', 'reject', 'apply'])
|
|
19
|
+
const MANIFEST_ACTIONS = new Set(['approve', 'reject', 'apply', 'revert'])
|
|
20
20
|
|
|
21
21
|
async function responseMessage(response: Response): Promise<string> {
|
|
22
22
|
try {
|
|
@@ -93,6 +93,93 @@ function num(value: unknown): number {
|
|
|
93
93
|
return typeof value === 'number' ? value : 0
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
// Auto-applied manifests (ALI-1040) landed by SERVER POLICY, not a human approver
|
|
97
|
+
// (approved_by is NULL). Mark them so a reviewer can tell policy applies from
|
|
98
|
+
// human applies at a glance; the reason lives in the outcome for `show`.
|
|
99
|
+
function wasAutoApplied(manifest: Record<string, unknown>): boolean {
|
|
100
|
+
return asRecord(manifest.outcome).autoApplied === true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** STATUS cell: `applied*` when the server auto-applied it, else the raw status. */
|
|
104
|
+
function statusDisplay(manifest: Record<string, unknown>): string {
|
|
105
|
+
const status = typeof manifest.status === 'string' ? manifest.status : '(unknown)'
|
|
106
|
+
return wasAutoApplied(manifest) ? `${status}*` : status
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** One-line auto-apply audit note for `show`, or null when not auto-applied. */
|
|
110
|
+
function autoApplyNote(manifest: Record<string, unknown>): string | null {
|
|
111
|
+
if (!wasAutoApplied(manifest)) return null
|
|
112
|
+
const reason = asRecord(manifest.outcome).autoApplyReason
|
|
113
|
+
return typeof reason === 'string' && reason.length > 0
|
|
114
|
+
? `auto-applied by policy: ${reason}`
|
|
115
|
+
: 'auto-applied by policy'
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// -- list table (ALI-1038) ----------------------------------------------------
|
|
119
|
+
|
|
120
|
+
/** "3m" / "4h" / "2d" — enough resolution to pick a manifest out of a list. */
|
|
121
|
+
function relativeAge(iso: unknown, now: number): string {
|
|
122
|
+
if (typeof iso !== 'string') return '-'
|
|
123
|
+
const then = Date.parse(iso)
|
|
124
|
+
if (Number.isNaN(then)) return '-'
|
|
125
|
+
const mins = Math.max(0, Math.floor((now - then) / 60_000))
|
|
126
|
+
if (mins < 60) return `${mins}m`
|
|
127
|
+
const hours = Math.floor(mins / 60)
|
|
128
|
+
if (hours < 48) return `${hours}h`
|
|
129
|
+
return `${Math.floor(hours / 24)}d`
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** One-glance change summary from the stored proposedState — no live API call. */
|
|
133
|
+
function changesSummary(manifest: Record<string, unknown>): string {
|
|
134
|
+
if (manifest.actionType !== 'repo_merge') return '-'
|
|
135
|
+
const proposed = asRecord(manifest.proposedState)
|
|
136
|
+
const files = num(proposed.filesChanged)
|
|
137
|
+
const parts = `${files} file${files === 1 ? '' : 's'} +${num(proposed.additions)}/-${num(proposed.deletions)}`
|
|
138
|
+
// Instruction files steer agent behavior — reviewers should see the flag in the list.
|
|
139
|
+
return proposed.touches_instruction_files === true ? `${parts} !instr` : parts
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Reviewable-first (pending_approval, then draft), newest first within a group. */
|
|
143
|
+
function listOrder(a: Record<string, unknown>, b: Record<string, unknown>): number {
|
|
144
|
+
const rank = (m: Record<string, unknown>): number =>
|
|
145
|
+
m.status === 'pending_approval' ? 0 : m.status === 'draft' ? 1 : 2
|
|
146
|
+
const byRank = rank(a) - rank(b)
|
|
147
|
+
if (byRank !== 0) return byRank
|
|
148
|
+
const created = (m: Record<string, unknown>): number =>
|
|
149
|
+
typeof m.createdAt === 'string' ? Date.parse(m.createdAt) || 0 : 0
|
|
150
|
+
return created(b) - created(a)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Render manifests as the standard padEnd table (matches teams/projects list). */
|
|
154
|
+
function manifestsTable(manifests: Record<string, unknown>[], now: number): string {
|
|
155
|
+
if (manifests.length === 0) return 'promotion manifests\n(none)'
|
|
156
|
+
const rows = [...manifests].sort(listOrder).map(manifest => ({
|
|
157
|
+
id: typeof manifest.id === 'string' ? manifest.id : '(unknown)',
|
|
158
|
+
status: statusDisplay(manifest),
|
|
159
|
+
type: typeof manifest.actionType === 'string' ? manifest.actionType : '(unknown)',
|
|
160
|
+
changes: changesSummary(manifest),
|
|
161
|
+
author: typeof manifest.authorActorType === 'string' ? manifest.authorActorType : '-',
|
|
162
|
+
age: relativeAge(manifest.createdAt, now),
|
|
163
|
+
}))
|
|
164
|
+
const idWidth = Math.max('ID'.length, ...rows.map(row => row.id.length))
|
|
165
|
+
const statusWidth = Math.max('STATUS'.length, ...rows.map(row => row.status.length))
|
|
166
|
+
const typeWidth = Math.max('TYPE'.length, ...rows.map(row => row.type.length))
|
|
167
|
+
const changesWidth = Math.max('CHANGES'.length, ...rows.map(row => row.changes.length))
|
|
168
|
+
const authorWidth = Math.max('AUTHOR'.length, ...rows.map(row => row.author.length))
|
|
169
|
+
const header =
|
|
170
|
+
`${'ID'.padEnd(idWidth)} ${'STATUS'.padEnd(statusWidth)} ${'TYPE'.padEnd(typeWidth)} ` +
|
|
171
|
+
`${'CHANGES'.padEnd(changesWidth)} ${'AUTHOR'.padEnd(authorWidth)} AGE`
|
|
172
|
+
const divider =
|
|
173
|
+
`${'-'.repeat(idWidth)} ${'-'.repeat(statusWidth)} ${'-'.repeat(typeWidth)} ` +
|
|
174
|
+
`${'-'.repeat(changesWidth)} ${'-'.repeat(authorWidth)} ---`
|
|
175
|
+
const body = rows.map(
|
|
176
|
+
row =>
|
|
177
|
+
`${row.id.padEnd(idWidth)} ${row.status.padEnd(statusWidth)} ${row.type.padEnd(typeWidth)} ` +
|
|
178
|
+
`${row.changes.padEnd(changesWidth)} ${row.author.padEnd(authorWidth)} ${row.age}`
|
|
179
|
+
)
|
|
180
|
+
return [header, divider, ...body].join('\n')
|
|
181
|
+
}
|
|
182
|
+
|
|
96
183
|
// repo_merge manifests (ALI-972) render the compare summary from stored evidence
|
|
97
184
|
// — no live GitHub call — so a reviewer can approve informed without a PR.
|
|
98
185
|
function repoMergeShow(manifest: Record<string, unknown>): string {
|
|
@@ -130,7 +217,7 @@ export async function manifestsCommand(args: string[], io: ManifestsCommandIo):
|
|
|
130
217
|
const response = await fetcherFrom(io)(`/api/cli/promotion-manifests${query}`)
|
|
131
218
|
const data = await requireOk(response, 'Manifest list')
|
|
132
219
|
const manifests = Array.isArray(data.manifests) ? (data.manifests as Record<string, unknown>[]) : []
|
|
133
|
-
emit(io, { manifests },
|
|
220
|
+
emit(io, { manifests }, manifestsTable(manifests, Date.now()))
|
|
134
221
|
return 0
|
|
135
222
|
}
|
|
136
223
|
|
|
@@ -142,7 +229,9 @@ export async function manifestsCommand(args: string[], io: ManifestsCommandIo):
|
|
|
142
229
|
const response = await fetcherFrom(io)(`/api/cli/promotion-manifests/${encodeURIComponent(id)}`)
|
|
143
230
|
const data = await requireOk(response, 'Manifest show')
|
|
144
231
|
const manifest = (data.manifest ?? {}) as Record<string, unknown>
|
|
145
|
-
const
|
|
232
|
+
const base = manifest.actionType === 'repo_merge' ? repoMergeShow(manifest) : manifestLine(manifest)
|
|
233
|
+
const note = autoApplyNote(manifest)
|
|
234
|
+
const human = note ? `${base}\n ${note}` : base
|
|
146
235
|
emit(io, { manifest }, human)
|
|
147
236
|
return 0
|
|
148
237
|
}
|
|
@@ -159,10 +248,26 @@ export async function manifestsCommand(args: string[], io: ManifestsCommandIo):
|
|
|
159
248
|
})
|
|
160
249
|
const data = await requireOk(response, `Manifest ${subcommand}`)
|
|
161
250
|
const manifest = (data.manifest ?? {}) as Record<string, unknown>
|
|
162
|
-
|
|
251
|
+
const lines = [manifestLine(manifest)]
|
|
252
|
+
// Reject reaps the session branch best-effort; a failed reap must never be
|
|
253
|
+
// silent (ALI-1043) — surface it with the exact cleanup command.
|
|
254
|
+
if (subcommand === 'reject' && manifest.actionType === 'repo_merge') {
|
|
255
|
+
const outcome = asRecord(manifest.outcome)
|
|
256
|
+
const branch = asRecord(manifest.proposedState).branch
|
|
257
|
+
if (outcome.branchDeleted === true) {
|
|
258
|
+
lines.push('session branch deleted')
|
|
259
|
+
} else if (typeof branch === 'string' && branch.length > 0) {
|
|
260
|
+
lines.push(
|
|
261
|
+
`warning: the session branch could not be deleted — remove it with: git push origin --delete ${branch}`
|
|
262
|
+
)
|
|
263
|
+
} else {
|
|
264
|
+
lines.push('warning: the session branch could not be deleted (branch name unavailable)')
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
emit(io, { manifest }, lines.join('\n'))
|
|
163
268
|
return 0
|
|
164
269
|
}
|
|
165
270
|
|
|
166
|
-
io.print('Usage: orizu manifests <list|show|approve|reject|apply> ... [--json]')
|
|
271
|
+
io.print('Usage: orizu manifests <list|show|approve|reject|apply|revert> ... [--json]')
|
|
167
272
|
return 1
|
|
168
273
|
}
|