@proletariat/cli 0.3.35 → 0.3.36
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/dist/commands/agent/auth.d.ts +12 -2
- package/dist/commands/agent/auth.js +128 -4
- package/dist/commands/agent/list.js +16 -7
- package/dist/commands/agent/status.js +32 -4
- package/dist/commands/board/watch.js +6 -0
- package/dist/commands/branch/list.d.ts +1 -0
- package/dist/commands/branch/list.js +43 -12
- package/dist/commands/branch/where.js +3 -2
- package/dist/commands/category/list.d.ts +2 -1
- package/dist/commands/category/list.js +38 -13
- package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
- package/dist/commands/{claude.js → claude/index.js} +12 -12
- package/dist/commands/claude/open.d.ts +13 -0
- package/dist/commands/claude/open.js +175 -0
- package/dist/commands/diet.js +18 -2
- package/dist/commands/docker/logs.js +7 -3
- package/dist/commands/docker/shell.js +6 -0
- package/dist/commands/docker/start.js +20 -4
- package/dist/commands/docker/sync.d.ts +4 -0
- package/dist/commands/docker/sync.js +30 -2
- package/dist/commands/epic/show.d.ts +13 -0
- package/dist/commands/epic/show.js +16 -0
- package/dist/commands/epic/view.js +27 -0
- package/dist/commands/execution/config.d.ts +0 -4
- package/dist/commands/execution/config.js +10 -32
- package/dist/commands/execution/index.js +2 -1
- package/dist/commands/execution/logs.js +1 -1
- package/dist/commands/execution/stop.js +2 -1
- package/dist/commands/execution/view.js +22 -26
- package/dist/commands/init.js +2 -19
- package/dist/commands/label/create.js +2 -1
- package/dist/commands/label/delete.js +2 -1
- package/dist/commands/label/group/create.js +2 -1
- package/dist/commands/label/group/list.js +2 -1
- package/dist/commands/label/list.js +2 -1
- package/dist/commands/mcp-server.js +25 -0
- package/dist/commands/phase/template/list.js +2 -1
- package/dist/commands/project/create.js +3 -4
- package/dist/commands/project/update.js +5 -6
- package/dist/commands/pull.js +24 -0
- package/dist/commands/session/create.d.ts +19 -0
- package/dist/commands/session/create.js +102 -0
- package/dist/commands/session/health.js +1 -20
- package/dist/commands/session/index.js +14 -1
- package/dist/commands/session/list.js +26 -7
- package/dist/commands/session/peek.d.ts +38 -0
- package/dist/commands/session/peek.js +316 -0
- package/dist/commands/session/poke.d.ts +27 -0
- package/dist/commands/session/poke.js +219 -0
- package/dist/commands/spec/view.js +29 -0
- package/dist/commands/template/list.js +2 -1
- package/dist/commands/theme/add-names.d.ts +4 -0
- package/dist/commands/theme/add-names.js +11 -1
- package/dist/commands/theme/create.d.ts +2 -0
- package/dist/commands/theme/create.js +8 -0
- package/dist/commands/ticket/bulk.js +2 -2
- package/dist/commands/ticket/complete.js +2 -2
- package/dist/commands/ticket/create.js +21 -0
- package/dist/commands/ticket/delete.js +8 -0
- package/dist/commands/ticket/edit.js +25 -0
- package/dist/commands/ticket/index.js +2 -2
- package/dist/commands/ticket/move.js +25 -2
- package/dist/commands/ticket/resolve.js +3 -4
- package/dist/commands/ticket/show.d.ts +13 -0
- package/dist/commands/ticket/show.js +16 -0
- package/dist/commands/ticket/template/list.js +2 -1
- package/dist/commands/ticket/view.d.ts +0 -1
- package/dist/commands/ticket/view.js +30 -1
- package/dist/commands/work/index.js +4 -0
- package/dist/commands/work/start.js +169 -94
- package/dist/commands/work/status.d.ts +14 -0
- package/dist/commands/work/status.js +60 -0
- package/dist/commands/workflow/index.js +2 -1
- package/dist/commands/workflow/show.d.ts +13 -0
- package/dist/commands/workflow/show.js +16 -0
- package/dist/commands/workspace/add.js +15 -0
- package/dist/commands/workspace/list.js +2 -1
- package/dist/commands/workspace/prune.js +5 -5
- package/dist/lib/branch/index.d.ts +1 -0
- package/dist/lib/execution/config.d.ts +15 -1
- package/dist/lib/execution/config.js +28 -0
- package/dist/lib/execution/runners.d.ts +11 -0
- package/dist/lib/execution/runners.js +53 -19
- package/dist/lib/execution/session-utils.d.ts +11 -1
- package/dist/lib/execution/session-utils.js +26 -1
- package/dist/lib/execution/storage.d.ts +5 -0
- package/dist/lib/execution/storage.js +18 -3
- package/dist/lib/execution/types.d.ts +2 -0
- package/dist/lib/mcp/tools/board.js +4 -6
- package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
- package/dist/lib/mcp/tools/epic.js +8 -3
- package/dist/lib/mcp/tools/spec.js +1 -1
- package/dist/lib/mcp/tools/ticket.js +11 -9
- package/dist/lib/mcp/tools/work.js +96 -6
- package/dist/lib/mcp/types.d.ts +10 -0
- package/dist/lib/multiline-input.js +2 -1
- package/dist/lib/pmo/base-command.js +4 -4
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/base.js +195 -50
- package/dist/lib/pmo/storage/types.d.ts +1 -0
- package/dist/lib/prompt-command.d.ts +20 -0
- package/dist/lib/prompt-command.js +38 -2
- package/dist/lib/prompt-json.d.ts +36 -4
- package/dist/lib/prompt-json.js +129 -7
- package/dist/lib/styles.d.ts +37 -0
- package/dist/lib/styles.js +73 -0
- package/oclif.manifest.json +3259 -2701
- package/package.json +1 -1
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { formatTicket, errorResponse, strictTool } from '../helpers.js';
|
|
6
|
+
import { spawnAgentForTicket } from '../../execution/spawner.js';
|
|
7
|
+
import { createEphemeralAgent } from '../../agents/commands.js';
|
|
6
8
|
export function registerWorkTools(server, ctx) {
|
|
7
9
|
strictTool(server, 'work_status', 'Get current work status (in-progress tickets)', {}, async () => {
|
|
8
10
|
try {
|
|
@@ -31,7 +33,7 @@ export function registerWorkTools(server, ctx) {
|
|
|
31
33
|
return errorResponse(error);
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
|
-
strictTool(server, '
|
|
36
|
+
strictTool(server, 'work_assign', 'Assign a ticket to someone for work preparation (does NOT move to In Progress — use the CLI "work start" command to actually start work with an agent/session)', {
|
|
35
37
|
ticket_id: z.string().describe('Ticket ID'),
|
|
36
38
|
assignee: z.string().optional().describe('Who is working'),
|
|
37
39
|
}, async (params) => {
|
|
@@ -42,16 +44,14 @@ export function registerWorkTools(server, ctx) {
|
|
|
42
44
|
if (params.assignee) {
|
|
43
45
|
await ctx.storage.updateTicket(params.ticket_id, { assignee: params.assignee });
|
|
44
46
|
}
|
|
45
|
-
const
|
|
46
|
-
const progressCol = columns.find((c) => c.toLowerCase().includes('progress') || c.toLowerCase().includes('doing')) || columns[Math.min(1, columns.length - 1)];
|
|
47
|
-
const moved = await ctx.storage.moveTicket(ticket.projectId, params.ticket_id, progressCol);
|
|
47
|
+
const updated = await ctx.storage.getTicket(params.ticket_id);
|
|
48
48
|
return {
|
|
49
49
|
content: [{
|
|
50
50
|
type: 'text',
|
|
51
51
|
text: JSON.stringify({
|
|
52
52
|
success: true,
|
|
53
|
-
ticket: formatTicket(
|
|
54
|
-
message: `
|
|
53
|
+
ticket: formatTicket(updated),
|
|
54
|
+
message: `Assigned ${updated.id}: ${updated.title}${params.assignee ? ` to ${params.assignee}` : ''}`,
|
|
55
55
|
}, null, 2),
|
|
56
56
|
}],
|
|
57
57
|
};
|
|
@@ -129,4 +129,94 @@ export function registerWorkTools(server, ctx) {
|
|
|
129
129
|
return errorResponse(error);
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
+
strictTool(server, 'work_start', 'Start work on a ticket — spawns an agent with a running container/session, creates a git branch, and moves ticket to In Progress only after successful spawn', {
|
|
133
|
+
ticket_id: z.string().describe('Ticket ID to start work on'),
|
|
134
|
+
agent: z.string().optional().describe('Agent name to assign (defaults to creating an ephemeral agent)'),
|
|
135
|
+
environment: z.enum(['devcontainer', 'host']).optional().describe('Execution environment (default: devcontainer if available)'),
|
|
136
|
+
display_mode: z.enum(['background', 'terminal']).optional().describe('Display mode (default: background — MCP runs headless)'),
|
|
137
|
+
skip_permissions: z.boolean().optional().describe('Skip permission prompts (danger mode, default: false)'),
|
|
138
|
+
create_pr: z.boolean().optional().describe('Create PR when work is ready (default: false)'),
|
|
139
|
+
}, async (params) => {
|
|
140
|
+
try {
|
|
141
|
+
// Require workspace context for spawn operations
|
|
142
|
+
if (!ctx.getWorkspaceContext) {
|
|
143
|
+
throw new Error('Workspace not initialized. work_start requires a workspace with agents. Run "prlt init" first.');
|
|
144
|
+
}
|
|
145
|
+
const { workspaceInfo, executionStorage, db, pmoPath } = ctx.getWorkspaceContext();
|
|
146
|
+
// Validate ticket exists
|
|
147
|
+
const ticket = await ctx.storage.getTicket(params.ticket_id);
|
|
148
|
+
if (!ticket)
|
|
149
|
+
throw new Error(`Ticket not found: ${params.ticket_id}`);
|
|
150
|
+
// Check ticket is not blocked
|
|
151
|
+
if (ticket.blockedBy && ticket.blockedBy.length > 0) {
|
|
152
|
+
throw new Error(`Ticket ${ticket.id} is blocked by: ${ticket.blockedBy.join(', ')}. Resolve blockers first.`);
|
|
153
|
+
}
|
|
154
|
+
// Check for existing running execution
|
|
155
|
+
const runningExec = executionStorage.getRunningExecution(ticket.id);
|
|
156
|
+
if (runningExec) {
|
|
157
|
+
throw new Error(`Ticket ${ticket.id} already has a running execution: ${runningExec.id} (agent: ${runningExec.agentName})`);
|
|
158
|
+
}
|
|
159
|
+
// Select or create agent
|
|
160
|
+
let agentName;
|
|
161
|
+
if (params.agent) {
|
|
162
|
+
// Use specified agent — verify it exists
|
|
163
|
+
const agentExists = workspaceInfo.agents.some(a => a.name === params.agent);
|
|
164
|
+
if (!agentExists) {
|
|
165
|
+
throw new Error(`Agent "${params.agent}" not found. Available agents: ${workspaceInfo.agents.map(a => a.name).join(', ') || 'none'}`);
|
|
166
|
+
}
|
|
167
|
+
agentName = params.agent;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Create an ephemeral agent (default for MCP)
|
|
171
|
+
const ephemeralResult = await createEphemeralAgent(workspaceInfo);
|
|
172
|
+
agentName = ephemeralResult.name;
|
|
173
|
+
}
|
|
174
|
+
// Spawn the agent with background mode (MCP is headless)
|
|
175
|
+
const displayMode = params.display_mode || 'background';
|
|
176
|
+
const environment = params.environment;
|
|
177
|
+
const result = await spawnAgentForTicket(ticket, agentName, ctx.storage, executionStorage, workspaceInfo, db, pmoPath, {
|
|
178
|
+
environment,
|
|
179
|
+
displayMode,
|
|
180
|
+
skipPermissions: params.skip_permissions ?? false,
|
|
181
|
+
createPR: params.create_pr ?? false,
|
|
182
|
+
skipRemoteCheck: false,
|
|
183
|
+
});
|
|
184
|
+
if (result.success) {
|
|
185
|
+
// Fetch updated ticket to return current state
|
|
186
|
+
const updatedTicket = await ctx.storage.getTicket(params.ticket_id);
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: JSON.stringify({
|
|
191
|
+
success: true,
|
|
192
|
+
executionId: result.executionId,
|
|
193
|
+
ticketId: result.ticketId,
|
|
194
|
+
agent: result.agentName,
|
|
195
|
+
status: 'running',
|
|
196
|
+
ticket: updatedTicket ? formatTicket(updatedTicket) : undefined,
|
|
197
|
+
message: `Started work on ${ticket.id}: ${ticket.title} (agent: ${agentName})`,
|
|
198
|
+
}, null, 2),
|
|
199
|
+
}],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
return {
|
|
204
|
+
content: [{
|
|
205
|
+
type: 'text',
|
|
206
|
+
text: JSON.stringify({
|
|
207
|
+
success: false,
|
|
208
|
+
ticketId: result.ticketId,
|
|
209
|
+
agent: result.agentName,
|
|
210
|
+
error: result.error || 'Spawn failed',
|
|
211
|
+
message: `Failed to start work on ${ticket.id}: ${result.error}`,
|
|
212
|
+
}, null, 2),
|
|
213
|
+
}],
|
|
214
|
+
isError: true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
return errorResponse(error);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
132
222
|
}
|
package/dist/lib/mcp/types.d.ts
CHANGED
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
5
|
import type { SQLiteStorage } from '../pmo/storage/index.js';
|
|
6
|
+
import type Database from 'better-sqlite3';
|
|
7
|
+
import type { WorkspaceInfo } from '../agents/commands.js';
|
|
8
|
+
import type { ExecutionStorage } from '../execution/storage.js';
|
|
6
9
|
export interface McpToolContext {
|
|
7
10
|
storage: SQLiteStorage;
|
|
8
11
|
runCommand: (cmd: string) => string;
|
|
12
|
+
/** Workspace info — available when running in a workspace with agents */
|
|
13
|
+
getWorkspaceContext?: () => {
|
|
14
|
+
workspaceInfo: WorkspaceInfo;
|
|
15
|
+
executionStorage: ExecutionStorage;
|
|
16
|
+
db: Database.Database;
|
|
17
|
+
pmoPath: string;
|
|
18
|
+
};
|
|
9
19
|
}
|
|
10
20
|
export type McpToolResult = {
|
|
11
21
|
content: Array<{
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import * as readline from 'node:readline';
|
|
17
17
|
import chalk from 'chalk';
|
|
18
|
+
import { isNonTTY } from './prompt-json.js';
|
|
18
19
|
// ANSI escape codes for terminal control
|
|
19
20
|
const ESC = '\u001B';
|
|
20
21
|
const CSI = `${ESC}[`;
|
|
@@ -83,7 +84,7 @@ function showCursor() {
|
|
|
83
84
|
export async function multiLineInput(options) {
|
|
84
85
|
const { message, default: defaultValue = '', hint = 'Ctrl+D to finish, Ctrl+C to cancel', required = false, validate, } = options;
|
|
85
86
|
// If not a TTY, return the default value
|
|
86
|
-
if (
|
|
87
|
+
if (isNonTTY()) {
|
|
87
88
|
return { value: defaultValue, cancelled: false };
|
|
88
89
|
}
|
|
89
90
|
return new Promise((resolve) => {
|
|
@@ -3,7 +3,7 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import { getPMOContext } from './pmo-context.js';
|
|
4
4
|
import { styles } from '../styles.js';
|
|
5
5
|
import { PromptCommand } from '../prompt-command.js';
|
|
6
|
-
import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, } from '../prompt-json.js';
|
|
6
|
+
import { shouldOutputJson, isNonTTY, outputPromptAsJson, outputErrorAsJson, createMetadata, } from '../prompt-json.js';
|
|
7
7
|
/**
|
|
8
8
|
* Base flags for JSON/agent mode support
|
|
9
9
|
* Include these in your command's flags by spreading: ...jsonModeFlags
|
|
@@ -168,7 +168,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
168
168
|
return numA - numB;
|
|
169
169
|
});
|
|
170
170
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
171
|
-
const effectiveJsonMode = options?.jsonMode ?? (
|
|
171
|
+
const effectiveJsonMode = options?.jsonMode ?? (isNonTTY()
|
|
172
172
|
? {
|
|
173
173
|
flags: { json: true },
|
|
174
174
|
commandName: this.id ?? 'unknown',
|
|
@@ -234,7 +234,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
234
234
|
async selectFromList(options) {
|
|
235
235
|
const { message, items, getName, getValue, getCommand, jsonMode, allowCancel = false, cancelValue, } = options;
|
|
236
236
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
237
|
-
const effectiveJsonMode = jsonMode ?? (
|
|
237
|
+
const effectiveJsonMode = jsonMode ?? (isNonTTY()
|
|
238
238
|
? { flags: { json: true }, commandName: this.id ?? 'unknown' }
|
|
239
239
|
: null);
|
|
240
240
|
// Build choices with command field
|
|
@@ -285,7 +285,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
285
285
|
async promptForInput(options) {
|
|
286
286
|
const { message, fieldName, defaultValue, validate, jsonMode } = options;
|
|
287
287
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
288
|
-
const effectiveJsonMode = jsonMode ?? (
|
|
288
|
+
const effectiveJsonMode = jsonMode ?? (isNonTTY()
|
|
289
289
|
? { flags: { json: true }, commandName: this.id ?? 'unknown', commandHint: '', example: undefined }
|
|
290
290
|
: null);
|
|
291
291
|
// Check for JSON mode
|
|
@@ -169,7 +169,7 @@ export class ActionStorage {
|
|
|
169
169
|
? JSON.parse(row.default_category)
|
|
170
170
|
: undefined,
|
|
171
171
|
defaultMoveToCategory: row.default_category,
|
|
172
|
-
modifiesCode: row.
|
|
172
|
+
modifiesCode: row.modifies_code === 1,
|
|
173
173
|
isBuiltin: row.is_builtin === 1,
|
|
174
174
|
createdAt: new Date(row.created_at),
|
|
175
175
|
};
|
|
@@ -693,6 +693,200 @@ git add -A && prlt commit "your change" && git push
|
|
|
693
693
|
modifiesCode: true,
|
|
694
694
|
position: 3,
|
|
695
695
|
},
|
|
696
|
+
{
|
|
697
|
+
id: 'review',
|
|
698
|
+
name: 'Code Review',
|
|
699
|
+
description: 'Review the implementation and post feedback on the PR',
|
|
700
|
+
prompt: `${PRLT_USAGE_RULE}
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
# Action: Code Review
|
|
705
|
+
|
|
706
|
+
Review this ticket's implementation thoroughly:
|
|
707
|
+
- Check for bugs, edge cases, and potential issues
|
|
708
|
+
- Look for security vulnerabilities
|
|
709
|
+
- Verify it meets all acceptance criteria
|
|
710
|
+
- Check code quality and maintainability
|
|
711
|
+
- Suggest improvements if appropriate
|
|
712
|
+
|
|
713
|
+
After reviewing, determine your verdict:
|
|
714
|
+
- **APPROVE**: Code is ready to merge, no significant issues
|
|
715
|
+
- **REQUEST_CHANGES**: There are issues that must be fixed before merging
|
|
716
|
+
- **COMMENT**: General feedback, no blocking issues but some suggestions
|
|
717
|
+
|
|
718
|
+
Do NOT modify any code. This is a read-only review.`,
|
|
719
|
+
endPrompt: `When you have finished reviewing, post your review on the PR using \`gh pr review\`.
|
|
720
|
+
|
|
721
|
+
Choose the appropriate command based on your verdict:
|
|
722
|
+
|
|
723
|
+
**If approving:**
|
|
724
|
+
\`\`\`bash
|
|
725
|
+
gh pr review --approve --body "## Code Review
|
|
726
|
+
|
|
727
|
+
### What looks good
|
|
728
|
+
- ...
|
|
729
|
+
|
|
730
|
+
### Verdict
|
|
731
|
+
APPROVED - Code is ready to merge."
|
|
732
|
+
\`\`\`
|
|
733
|
+
|
|
734
|
+
**If requesting changes:**
|
|
735
|
+
\`\`\`bash
|
|
736
|
+
gh pr review --request-changes --body "## Code Review
|
|
737
|
+
|
|
738
|
+
### What looks good
|
|
739
|
+
- ...
|
|
740
|
+
|
|
741
|
+
### Concerns
|
|
742
|
+
- ...
|
|
743
|
+
|
|
744
|
+
### Suggested improvements
|
|
745
|
+
- ...
|
|
746
|
+
|
|
747
|
+
### Verdict
|
|
748
|
+
REQUEST CHANGES - Issues must be addressed before merging."
|
|
749
|
+
\`\`\`
|
|
750
|
+
|
|
751
|
+
**If commenting:**
|
|
752
|
+
\`\`\`bash
|
|
753
|
+
gh pr review --comment --body "## Code Review
|
|
754
|
+
|
|
755
|
+
### What looks good
|
|
756
|
+
- ...
|
|
757
|
+
|
|
758
|
+
### Suggestions
|
|
759
|
+
- ...
|
|
760
|
+
|
|
761
|
+
### Verdict
|
|
762
|
+
COMMENT - Some suggestions but no blocking issues."
|
|
763
|
+
\`\`\`
|
|
764
|
+
|
|
765
|
+
Format the body with: what looks good, concerns (if any), suggested improvements (if any), and your verdict.
|
|
766
|
+
|
|
767
|
+
No commits are needed for code review.`,
|
|
768
|
+
suggestedForCategories: ['started', 'completed'],
|
|
769
|
+
modifiesCode: false,
|
|
770
|
+
position: 4,
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
id: 'review-fix',
|
|
774
|
+
name: 'Review & Fix',
|
|
775
|
+
description: 'Review the implementation, fix issues, and post feedback on the PR',
|
|
776
|
+
prompt: `${PRLT_USAGE_RULE}
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
# Action: Review & Fix
|
|
781
|
+
|
|
782
|
+
Review this ticket's implementation thoroughly and fix any issues found:
|
|
783
|
+
- Check for bugs, edge cases, and potential issues
|
|
784
|
+
- Look for security vulnerabilities
|
|
785
|
+
- Verify it meets all acceptance criteria
|
|
786
|
+
- Check code quality and maintainability
|
|
787
|
+
- Fix any issues you find directly in the code
|
|
788
|
+
|
|
789
|
+
**IMPORTANT: Commit and push frequently!**
|
|
790
|
+
- Commit after each fix or logical group of changes
|
|
791
|
+
- Push after every 1-2 commits to save your work
|
|
792
|
+
|
|
793
|
+
\`\`\`bash
|
|
794
|
+
git add -A && prlt commit "fix: address code review findings" && git push
|
|
795
|
+
\`\`\``,
|
|
796
|
+
endPrompt: `When you have finished reviewing and fixing:
|
|
797
|
+
|
|
798
|
+
1. **If issues were found and fixed**, post a review summary and push your fixes:
|
|
799
|
+
\`\`\`bash
|
|
800
|
+
gh pr review --comment --body "## Code Review & Fix Summary
|
|
801
|
+
|
|
802
|
+
### Issues found and fixed
|
|
803
|
+
- ...
|
|
804
|
+
|
|
805
|
+
### What looks good
|
|
806
|
+
- ...
|
|
807
|
+
|
|
808
|
+
### Changes made
|
|
809
|
+
- ...
|
|
810
|
+
"
|
|
811
|
+
prlt commit "fix: address code review findings"
|
|
812
|
+
git push
|
|
813
|
+
\`\`\`
|
|
814
|
+
|
|
815
|
+
2. **If no issues were found**, approve the PR:
|
|
816
|
+
\`\`\`bash
|
|
817
|
+
gh pr review --approve --body "## Code Review
|
|
818
|
+
|
|
819
|
+
### What looks good
|
|
820
|
+
- ...
|
|
821
|
+
|
|
822
|
+
### Verdict
|
|
823
|
+
APPROVED - Code looks great, no issues found."
|
|
824
|
+
\`\`\``,
|
|
825
|
+
suggestedForCategories: ['started', 'completed'],
|
|
826
|
+
modifiesCode: true,
|
|
827
|
+
position: 5,
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
id: 'revise',
|
|
831
|
+
name: 'Revise',
|
|
832
|
+
description: 'Pull the branch, read PR review feedback, implement fixes, and push',
|
|
833
|
+
prompt: `${PRLT_USAGE_RULE}
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
# Action: Revise
|
|
838
|
+
|
|
839
|
+
Address the feedback on this ticket's pull request:
|
|
840
|
+
|
|
841
|
+
1. **Pull the latest branch** to ensure you have the most recent code:
|
|
842
|
+
\`\`\`bash
|
|
843
|
+
git pull
|
|
844
|
+
\`\`\`
|
|
845
|
+
|
|
846
|
+
2. **Read all review comments and requested changes** from the PR:
|
|
847
|
+
\`\`\`bash
|
|
848
|
+
gh pr view
|
|
849
|
+
gh api repos/{owner}/{repo}/pulls/{number}/comments
|
|
850
|
+
\`\`\`
|
|
851
|
+
|
|
852
|
+
3. **Understand each piece of feedback** before making changes — read carefully and understand the reviewer's intent
|
|
853
|
+
|
|
854
|
+
4. **Implement the requested fixes** and address each review comment:
|
|
855
|
+
- Make the necessary code changes to address each point
|
|
856
|
+
- Respond to questions with explanations
|
|
857
|
+
- Ensure all requested changes are addressed
|
|
858
|
+
|
|
859
|
+
**IMPORTANT: Commit and push frequently!**
|
|
860
|
+
- Commit after each fix or logical group of changes
|
|
861
|
+
- Push after every 1-2 commits to save your work
|
|
862
|
+
|
|
863
|
+
\`\`\`bash
|
|
864
|
+
git add -A && prlt commit "fix: address PR review feedback" && git push
|
|
865
|
+
\`\`\``,
|
|
866
|
+
endPrompt: `After addressing all feedback:
|
|
867
|
+
|
|
868
|
+
1. **Commit your changes**:
|
|
869
|
+
\`\`\`bash
|
|
870
|
+
git add -A
|
|
871
|
+
prlt commit "fix: address PR review feedback"
|
|
872
|
+
\`\`\`
|
|
873
|
+
|
|
874
|
+
2. **Push your changes**:
|
|
875
|
+
\`\`\`bash
|
|
876
|
+
git push
|
|
877
|
+
\`\`\`
|
|
878
|
+
|
|
879
|
+
3. **Optionally reply to resolved review threads** using the GitHub API:
|
|
880
|
+
\`\`\`bash
|
|
881
|
+
gh api repos/{owner}/{repo}/pulls/{number}/comments
|
|
882
|
+
\`\`\`
|
|
883
|
+
|
|
884
|
+
The PR will be updated automatically with your pushed changes.`,
|
|
885
|
+
suggestedForCategories: ['completed'],
|
|
886
|
+
defaultMoveToCategory: 'started',
|
|
887
|
+
modifiesCode: true,
|
|
888
|
+
position: 6,
|
|
889
|
+
},
|
|
696
890
|
{
|
|
697
891
|
id: 'test',
|
|
698
892
|
name: 'Write Tests',
|
|
@@ -733,56 +927,7 @@ git add -A && prlt commit "add tests for X" && git push
|
|
|
733
927
|
**IMPORTANT:** Use the global \`prlt\` command.`,
|
|
734
928
|
suggestedForCategories: ['started', 'completed'],
|
|
735
929
|
modifiesCode: true,
|
|
736
|
-
position:
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
id: 'review',
|
|
740
|
-
name: 'Code Review',
|
|
741
|
-
description: 'Review the implementation for issues',
|
|
742
|
-
prompt: `Review this ticket's implementation thoroughly:
|
|
743
|
-
- Check for bugs, edge cases, and potential issues
|
|
744
|
-
- Look for security vulnerabilities
|
|
745
|
-
- Verify it meets all acceptance criteria
|
|
746
|
-
- Check code quality and maintainability
|
|
747
|
-
- Suggest improvements if appropriate
|
|
748
|
-
|
|
749
|
-
Output a review summary with your findings and any concerns.`,
|
|
750
|
-
endPrompt: `When you have finished reviewing, output a detailed review summary with:
|
|
751
|
-
- ✅ What looks good
|
|
752
|
-
- ⚠️ Concerns or potential issues
|
|
753
|
-
- 🔧 Suggested improvements
|
|
754
|
-
- 📋 Verdict: Approve, Request Changes, or Needs Discussion
|
|
755
|
-
|
|
756
|
-
No commits are needed for code review.`,
|
|
757
|
-
suggestedForCategories: ['started', 'completed'],
|
|
758
|
-
modifiesCode: false,
|
|
759
|
-
position: 5,
|
|
760
|
-
},
|
|
761
|
-
{
|
|
762
|
-
id: 'revise',
|
|
763
|
-
name: 'Revise',
|
|
764
|
-
description: 'Address PR feedback and review comments',
|
|
765
|
-
prompt: `${PRLT_USAGE_RULE}
|
|
766
|
-
|
|
767
|
-
---
|
|
768
|
-
|
|
769
|
-
# Action: Revise
|
|
770
|
-
|
|
771
|
-
Address the feedback on this ticket's pull request:
|
|
772
|
-
- Review all comments and requested changes carefully
|
|
773
|
-
- Make the necessary code changes to address each point
|
|
774
|
-
- Respond to questions with explanations
|
|
775
|
-
- Push updates to the PR branch
|
|
776
|
-
- Mark resolved conversations as resolved`,
|
|
777
|
-
endPrompt: `After addressing the feedback:
|
|
778
|
-
1. Commit your changes using \`prlt commit "your message"\`
|
|
779
|
-
2. Push your changes: \`git push\`
|
|
780
|
-
|
|
781
|
-
The PR will be updated automatically.`,
|
|
782
|
-
suggestedForCategories: ['completed'],
|
|
783
|
-
defaultMoveToCategory: 'started',
|
|
784
|
-
modifiesCode: true,
|
|
785
|
-
position: 6,
|
|
930
|
+
position: 7,
|
|
786
931
|
},
|
|
787
932
|
];
|
|
788
933
|
// Use INSERT OR REPLACE to always update builtin actions with latest prompts
|
|
@@ -30,6 +30,26 @@ import { type JsonFlags } from './prompt-json.js';
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
export declare abstract class PromptCommand extends Command {
|
|
33
|
+
/**
|
|
34
|
+
* TTY-aware log method - strips ANSI codes and emoji in non-TTY mode.
|
|
35
|
+
*
|
|
36
|
+
* Use this instead of this.log() when outputting styled text (chalk colors, emoji prefixes).
|
|
37
|
+
* In TTY mode, outputs styled text as-is. In non-TTY mode, strips ANSI and emoji.
|
|
38
|
+
*
|
|
39
|
+
* @param message - The styled message (may contain ANSI codes and emoji)
|
|
40
|
+
* @param args - Additional arguments passed to this.log()
|
|
41
|
+
*/
|
|
42
|
+
protected logPlain(message?: string, ...args: string[]): void;
|
|
43
|
+
/**
|
|
44
|
+
* Check if plain output mode is active (non-TTY, PRLT_PLAIN, NO_COLOR).
|
|
45
|
+
* Convenience wrapper for use in commands.
|
|
46
|
+
*/
|
|
47
|
+
protected get isPlain(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Check if running in non-TTY environment.
|
|
50
|
+
* Convenience wrapper for use in commands.
|
|
51
|
+
*/
|
|
52
|
+
protected get isNonTTY(): boolean;
|
|
33
53
|
/**
|
|
34
54
|
* Prompt wrapper - drop-in replacement for inquirer.prompt
|
|
35
55
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import { isAgentMode, outputPromptAsJson, createMetadata, normalizeChoices, } from './prompt-json.js';
|
|
3
|
+
import { isAgentMode, isNonTTY, outputPromptAsJson, createMetadata, normalizeChoices, } from './prompt-json.js';
|
|
4
|
+
import { isPlainOutput, plainText } from './styles.js';
|
|
4
5
|
/**
|
|
5
6
|
* Lightweight base command with prompt() method for JSON mode support.
|
|
6
7
|
*
|
|
@@ -31,6 +32,41 @@ import { isAgentMode, outputPromptAsJson, createMetadata, normalizeChoices, } fr
|
|
|
31
32
|
* ```
|
|
32
33
|
*/
|
|
33
34
|
export class PromptCommand extends Command {
|
|
35
|
+
/**
|
|
36
|
+
* TTY-aware log method - strips ANSI codes and emoji in non-TTY mode.
|
|
37
|
+
*
|
|
38
|
+
* Use this instead of this.log() when outputting styled text (chalk colors, emoji prefixes).
|
|
39
|
+
* In TTY mode, outputs styled text as-is. In non-TTY mode, strips ANSI and emoji.
|
|
40
|
+
*
|
|
41
|
+
* @param message - The styled message (may contain ANSI codes and emoji)
|
|
42
|
+
* @param args - Additional arguments passed to this.log()
|
|
43
|
+
*/
|
|
44
|
+
logPlain(message, ...args) {
|
|
45
|
+
if (message === undefined) {
|
|
46
|
+
this.log();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (isPlainOutput()) {
|
|
50
|
+
this.log(plainText(message), ...args);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.log(message, ...args);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if plain output mode is active (non-TTY, PRLT_PLAIN, NO_COLOR).
|
|
58
|
+
* Convenience wrapper for use in commands.
|
|
59
|
+
*/
|
|
60
|
+
get isPlain() {
|
|
61
|
+
return isPlainOutput();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if running in non-TTY environment.
|
|
65
|
+
* Convenience wrapper for use in commands.
|
|
66
|
+
*/
|
|
67
|
+
get isNonTTY() {
|
|
68
|
+
return isNonTTY();
|
|
69
|
+
}
|
|
34
70
|
/**
|
|
35
71
|
* Prompt wrapper - drop-in replacement for inquirer.prompt
|
|
36
72
|
*
|
|
@@ -73,7 +109,7 @@ export class PromptCommand extends Command {
|
|
|
73
109
|
*/
|
|
74
110
|
async prompt(questions, jsonModeConfig) {
|
|
75
111
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
76
|
-
if (!jsonModeConfig &&
|
|
112
|
+
if (!jsonModeConfig && isNonTTY()) {
|
|
77
113
|
jsonModeConfig = { flags: { json: true }, commandName: this.id ?? 'unknown' };
|
|
78
114
|
}
|
|
79
115
|
// Check for JSON/agent mode
|
|
@@ -193,6 +193,27 @@ export interface ExecutionResultJsonOutput {
|
|
|
193
193
|
* Union type for all JSON output types
|
|
194
194
|
*/
|
|
195
195
|
export type JsonOutput = PromptJsonOutput | SuccessJsonOutput | ErrorJsonOutput | DryRunJsonOutput | ConfirmationNeededJsonOutput | ExecutionResultJsonOutput;
|
|
196
|
+
/**
|
|
197
|
+
* All valid JSON envelope type discriminators.
|
|
198
|
+
* Used for contract tests and schema validation.
|
|
199
|
+
*/
|
|
200
|
+
export declare const JSON_ENVELOPE_TYPES: readonly ["prompt", "success", "error", "dry-run", "confirmation_needed", "execution_result"];
|
|
201
|
+
export type JsonEnvelopeType = typeof JSON_ENVELOPE_TYPES[number];
|
|
202
|
+
/**
|
|
203
|
+
* Required fields per envelope type for contract validation.
|
|
204
|
+
* Tests use this to verify no fields are accidentally removed.
|
|
205
|
+
*/
|
|
206
|
+
export declare const JSON_ENVELOPE_REQUIRED_FIELDS: Record<JsonEnvelopeType, string[]>;
|
|
207
|
+
/**
|
|
208
|
+
* Validate that a parsed JSON object conforms to the machine-mode envelope schema.
|
|
209
|
+
*
|
|
210
|
+
* Returns an array of validation errors (empty = valid).
|
|
211
|
+
* Useful for contract tests and runtime validation of JSON output.
|
|
212
|
+
*
|
|
213
|
+
* @param obj - Parsed JSON object to validate
|
|
214
|
+
* @returns Array of validation error strings (empty if valid)
|
|
215
|
+
*/
|
|
216
|
+
export declare function validateJsonEnvelope(obj: unknown): string[];
|
|
196
217
|
/**
|
|
197
218
|
* Flags interface for JSON mode detection
|
|
198
219
|
*/
|
|
@@ -211,9 +232,18 @@ export interface MachineOutputFlags {
|
|
|
211
232
|
machine?: boolean;
|
|
212
233
|
}
|
|
213
234
|
/**
|
|
214
|
-
* Check if the current environment is non-TTY (piped output)
|
|
235
|
+
* Check if the current environment is non-TTY (piped input or output)
|
|
236
|
+
*
|
|
237
|
+
* Uses the "either" strategy: returns true if EITHER stdin OR stdout is non-TTY.
|
|
238
|
+
* This covers the primary use case of scripts/agents calling prlt as a subprocess,
|
|
239
|
+
* where both stdin and stdout are typically non-TTY.
|
|
240
|
+
*
|
|
241
|
+
* Returns true if:
|
|
242
|
+
* - stdin is not a TTY (e.g., piped input)
|
|
243
|
+
* - stdout is not a TTY (e.g., piped output)
|
|
244
|
+
* - PRLT_JSON=1 environment variable is set (overrides TTY detection)
|
|
215
245
|
*
|
|
216
|
-
* @returns true if stdout is not a TTY
|
|
246
|
+
* @returns true if either stdin or stdout is not a TTY, or PRLT_JSON=1 is set
|
|
217
247
|
*/
|
|
218
248
|
export declare function isNonTTY(): boolean;
|
|
219
249
|
/**
|
|
@@ -221,7 +251,8 @@ export declare function isNonTTY(): boolean;
|
|
|
221
251
|
*
|
|
222
252
|
* Returns true if:
|
|
223
253
|
* - The --json flag is set (or -m/--machine aliases)
|
|
224
|
-
* - The environment is
|
|
254
|
+
* - The PRLT_JSON=1 environment variable is set
|
|
255
|
+
* - Either stdin or stdout is non-TTY (piped input/output)
|
|
225
256
|
*
|
|
226
257
|
* @param flags - Command flags object
|
|
227
258
|
* @returns true if JSON mode should be used
|
|
@@ -236,7 +267,8 @@ export declare const isAgentMode: typeof shouldOutputJson;
|
|
|
236
267
|
*
|
|
237
268
|
* Returns true if:
|
|
238
269
|
* - The --json flag is set (or -m/--machine aliases)
|
|
239
|
-
* - The environment is
|
|
270
|
+
* - The PRLT_JSON=1 environment variable is set
|
|
271
|
+
* - Either stdin or stdout is non-TTY (piped input/output)
|
|
240
272
|
*
|
|
241
273
|
* @param flags - Command flags object
|
|
242
274
|
* @returns true if machine-readable output mode should be used
|