@proletariat/cli 0.3.26 → 0.3.28
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/dev.js +7 -0
- package/bin/run.js +7 -0
- package/dist/commands/action/show.js +7 -1
- package/dist/commands/agent/shell.js +24 -10
- package/dist/commands/branch/list.js +14 -11
- package/dist/commands/branch/validate.js +10 -1
- package/dist/commands/claude.js +12 -40
- package/dist/commands/docker/clean.js +7 -9
- package/dist/commands/docker/index.js +5 -4
- package/dist/commands/docker/list.d.ts +1 -0
- package/dist/commands/docker/list.js +31 -17
- package/dist/commands/docker/status.d.ts +3 -1
- package/dist/commands/docker/status.js +28 -2
- package/dist/commands/docker/sync.js +7 -6
- package/dist/commands/epic/list.js +17 -2
- package/dist/commands/execution/list.js +25 -17
- package/dist/commands/pmo/init.js +22 -3
- package/dist/commands/repo/list.js +14 -8
- package/dist/commands/repo/view.js +2 -1
- package/dist/commands/roadmap/list.js +16 -1
- package/dist/commands/session/health.js +11 -10
- package/dist/commands/session/list.js +15 -8
- package/dist/commands/staff/list.d.ts +3 -1
- package/dist/commands/staff/list.js +15 -1
- package/dist/commands/theme/list.d.ts +3 -0
- package/dist/commands/theme/list.js +25 -0
- package/dist/commands/ticket/complete.js +4 -1
- package/dist/commands/ticket/create.d.ts +1 -0
- package/dist/commands/ticket/create.js +30 -0
- package/dist/commands/ticket/delete.js +3 -3
- package/dist/commands/ticket/edit.js +2 -2
- package/dist/commands/ticket/list.js +24 -5
- package/dist/commands/ticket/move.js +4 -1
- package/dist/commands/ticket/view.js +4 -2
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +22 -5
- package/dist/commands/work/complete.js +2 -2
- package/dist/commands/work/ready.js +2 -2
- package/dist/commands/work/revise.js +2 -2
- package/dist/commands/work/spawn.js +6 -21
- package/dist/commands/work/start.js +10 -25
- package/dist/commands/work/watch.js +57 -33
- package/dist/commands/workspace/prune.d.ts +3 -2
- package/dist/commands/workspace/prune.js +70 -10
- package/dist/lib/agents/commands.js +4 -0
- package/dist/lib/agents/index.js +12 -0
- package/dist/lib/execution/devcontainer.d.ts +4 -0
- package/dist/lib/execution/devcontainer.js +88 -3
- package/dist/lib/mcp/helpers.d.ts +15 -0
- package/dist/lib/mcp/helpers.js +15 -0
- package/dist/lib/mcp/tools/action.js +5 -5
- package/dist/lib/mcp/tools/board.js +7 -7
- package/dist/lib/mcp/tools/category.js +5 -5
- package/dist/lib/mcp/tools/cli-passthrough.js +30 -30
- package/dist/lib/mcp/tools/epic.js +8 -8
- package/dist/lib/mcp/tools/phase.js +7 -7
- package/dist/lib/mcp/tools/project.js +10 -10
- package/dist/lib/mcp/tools/roadmap.js +7 -7
- package/dist/lib/mcp/tools/spec.js +9 -9
- package/dist/lib/mcp/tools/status.js +6 -6
- package/dist/lib/mcp/tools/template.js +6 -6
- package/dist/lib/mcp/tools/ticket.js +19 -19
- package/dist/lib/mcp/tools/view.js +4 -4
- package/dist/lib/mcp/tools/work.js +6 -6
- package/dist/lib/mcp/tools/workflow.js +5 -5
- package/dist/lib/pmo/index.js +4 -0
- package/dist/lib/pmo/storage/base.js +49 -0
- package/dist/lib/pmo/types.d.ts +1 -1
- package/dist/lib/pmo/types.js +1 -0
- package/dist/lib/pr/index.d.ts +5 -0
- package/dist/lib/pr/index.js +69 -0
- package/dist/lib/repos/index.js +4 -0
- package/dist/lib/string-utils.d.ts +10 -0
- package/dist/lib/string-utils.js +16 -0
- package/oclif.manifest.json +3331 -3253
- package/package.json +3 -2
package/dist/lib/agents/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { isValidAgentName, getSuggestedAgentNames, BUILTIN_THEMES, getThemePersi
|
|
|
7
7
|
import { getWorkspaceRepositories, getActiveTheme } from '../database/index.js';
|
|
8
8
|
import { styles } from '../styles.js';
|
|
9
9
|
import { createDevcontainerConfig } from '../execution/devcontainer.js';
|
|
10
|
+
import { getGitIdentity } from '../pr/index.js';
|
|
10
11
|
/**
|
|
11
12
|
* Detect the current agent name from environment or directory structure.
|
|
12
13
|
* Returns null if not running in an agent context.
|
|
@@ -93,6 +94,11 @@ function getRemoteUrl(repoPath) {
|
|
|
93
94
|
export async function createAgentWorktrees(workspacePath, agents, hqPath, options) {
|
|
94
95
|
const mountMode = options?.mountMode || 'worktree'; // Default to worktree for real-time file sync
|
|
95
96
|
const modeLabel = mountMode === 'worktree' ? 'worktree' : 'clone';
|
|
97
|
+
// Detect git identity once for all agents (TKT-934)
|
|
98
|
+
const gitIdentity = getGitIdentity();
|
|
99
|
+
if (!gitIdentity.name && !gitIdentity.email) {
|
|
100
|
+
console.log(chalk.yellow('Warning: Could not detect git identity for devcontainer. Commits may use default identity.'));
|
|
101
|
+
}
|
|
96
102
|
if (hqPath) {
|
|
97
103
|
// HQ mode - create worktrees/clones for all repos in repos/ directory
|
|
98
104
|
const reposDir = path.join(hqPath, 'repos');
|
|
@@ -227,6 +233,8 @@ export async function createAgentWorktrees(workspacePath, agents, hqPath, option
|
|
|
227
233
|
agentDir,
|
|
228
234
|
repoWorktrees: mountMode === 'worktree' && createdRepos.length > 0 ? createdRepos : undefined,
|
|
229
235
|
mountMode,
|
|
236
|
+
gitUserName: gitIdentity.name || undefined,
|
|
237
|
+
gitUserEmail: gitIdentity.email || undefined,
|
|
230
238
|
});
|
|
231
239
|
}
|
|
232
240
|
console.log(chalk.green(`✅ Agent ${agent} created with ${createdRepos.length} ${modeLabel}(s)`));
|
|
@@ -249,6 +257,8 @@ export async function createAgentWorktrees(workspacePath, agents, hqPath, option
|
|
|
249
257
|
agentName: agent,
|
|
250
258
|
agentDir,
|
|
251
259
|
mountMode: mountMode,
|
|
260
|
+
gitUserName: gitIdentity.name || undefined,
|
|
261
|
+
gitUserEmail: gitIdentity.email || undefined,
|
|
252
262
|
});
|
|
253
263
|
}
|
|
254
264
|
console.log(chalk.green(`✅ Placeholder agent ${agent} created`));
|
|
@@ -367,6 +377,8 @@ export async function createAgentWorktrees(workspacePath, agents, hqPath, option
|
|
|
367
377
|
agentDir,
|
|
368
378
|
repoWorktrees: mountMode === 'worktree' ? [repoName] : undefined, // Only pass repos for worktree mode
|
|
369
379
|
mountMode,
|
|
380
|
+
gitUserName: gitIdentity.name || undefined,
|
|
381
|
+
gitUserEmail: gitIdentity.email || undefined,
|
|
370
382
|
});
|
|
371
383
|
}
|
|
372
384
|
console.log(chalk.green(`✅ Agent ${agent} created with ${modeLabel}`));
|
|
@@ -17,6 +17,10 @@ export interface DevcontainerOptions {
|
|
|
17
17
|
prltChannel?: string;
|
|
18
18
|
/** Mount mode: 'worktree' needs parent repo mounts + git wrapper, 'clone' is self-contained */
|
|
19
19
|
mountMode?: MountMode;
|
|
20
|
+
/** Git user.name for commit attribution (detected from gh/git config on host) */
|
|
21
|
+
gitUserName?: string;
|
|
22
|
+
/** Git user.email for commit attribution (detected from gh/git config on host) */
|
|
23
|
+
gitUserEmail?: string;
|
|
20
24
|
}
|
|
21
25
|
export interface DevcontainerJson {
|
|
22
26
|
name: string;
|
|
@@ -106,6 +106,12 @@ export function generateDevcontainerJson(options, config) {
|
|
|
106
106
|
PRLT_HOST_PATH: options.agentDir,
|
|
107
107
|
// Mount mode - allows scripts to know if git wrapper is needed
|
|
108
108
|
PRLT_MOUNT_MODE: mountMode,
|
|
109
|
+
// Git identity for commit attribution (detected from host's gh/git config)
|
|
110
|
+
...(options.gitUserName ? { PRLT_GIT_USER_NAME: options.gitUserName } : {}),
|
|
111
|
+
...(options.gitUserEmail ? { PRLT_GIT_USER_EMAIL: options.gitUserEmail } : {}),
|
|
112
|
+
// prlt channel info for version updates at container startup (TKT-954)
|
|
113
|
+
PRLT_REGISTRY: channel.registry,
|
|
114
|
+
...(!useMount ? { PRLT_VERSION: channel.version || 'latest' } : {}),
|
|
109
115
|
// /hq/.proletariat/bin contains prlt wrapper with ESM loader for native modules
|
|
110
116
|
PATH: '/hq/.proletariat/bin:/home/node/.npm-global/bin:/usr/local/bin:/usr/bin:/bin',
|
|
111
117
|
},
|
|
@@ -121,7 +127,7 @@ export function generateDevcontainerJson(options, config) {
|
|
|
121
127
|
*/
|
|
122
128
|
export function generateDockerfile(options) {
|
|
123
129
|
const timezone = options.timezone || 'America/Los_Angeles';
|
|
124
|
-
return `FROM node:
|
|
130
|
+
return `FROM node:22
|
|
125
131
|
|
|
126
132
|
# Ensure we run as root for apt-get and system setup
|
|
127
133
|
USER root
|
|
@@ -452,11 +458,90 @@ else
|
|
|
452
458
|
echo "Warning: No GitHub token found, git push will require manual auth"
|
|
453
459
|
fi
|
|
454
460
|
|
|
455
|
-
#
|
|
461
|
+
# Configure git user identity for commit attribution
|
|
462
|
+
# Uses env vars set by host (from gh/git config), with fallback detection
|
|
463
|
+
configure_git_identity() {
|
|
464
|
+
local git_name="\${PRLT_GIT_USER_NAME:-}"
|
|
465
|
+
local git_email="\${PRLT_GIT_USER_EMAIL:-}"
|
|
466
|
+
|
|
467
|
+
# Fallback: try gh api user if env vars are empty and gh is authenticated
|
|
468
|
+
if { [ -z "$git_name" ] || [ -z "$git_email" ]; } && command -v gh &> /dev/null && gh auth status &>/dev/null; then
|
|
469
|
+
if [ -z "$git_name" ]; then
|
|
470
|
+
git_name=$(gh api user -q '.name // .login' 2>/dev/null || true)
|
|
471
|
+
fi
|
|
472
|
+
if [ -z "$git_email" ]; then
|
|
473
|
+
git_email=$(gh api user -q '.email // empty' 2>/dev/null || true)
|
|
474
|
+
# Try emails API if public email is not set
|
|
475
|
+
if [ -z "$git_email" ]; then
|
|
476
|
+
git_email=$(gh api user/emails -q '[.[] | select(.primary)] | .[0].email' 2>/dev/null || true)
|
|
477
|
+
fi
|
|
478
|
+
fi
|
|
479
|
+
fi
|
|
480
|
+
|
|
481
|
+
# Fallback: try git config from mounted repos
|
|
482
|
+
if [ -z "$git_name" ] || [ -z "$git_email" ]; then
|
|
483
|
+
for repo_dir in /workspace/*/; do
|
|
484
|
+
if [ -d "$repo_dir/.git" ] || [ -f "$repo_dir/.git" ]; then
|
|
485
|
+
if [ -z "$git_name" ]; then
|
|
486
|
+
git_name=$(/usr/bin/git -C "$repo_dir" config user.name 2>/dev/null || true)
|
|
487
|
+
fi
|
|
488
|
+
if [ -z "$git_email" ]; then
|
|
489
|
+
git_email=$(/usr/bin/git -C "$repo_dir" config user.email 2>/dev/null || true)
|
|
490
|
+
fi
|
|
491
|
+
if [ -n "$git_name" ] && [ -n "$git_email" ]; then
|
|
492
|
+
break
|
|
493
|
+
fi
|
|
494
|
+
fi
|
|
495
|
+
done
|
|
496
|
+
fi
|
|
497
|
+
|
|
498
|
+
# Apply git config
|
|
499
|
+
if [ -n "$git_name" ]; then
|
|
500
|
+
/usr/bin/git config --global user.name "$git_name"
|
|
501
|
+
echo "Git user.name set to: $git_name"
|
|
502
|
+
fi
|
|
503
|
+
if [ -n "$git_email" ]; then
|
|
504
|
+
/usr/bin/git config --global user.email "$git_email"
|
|
505
|
+
echo "Git user.email set to: $git_email"
|
|
506
|
+
fi
|
|
507
|
+
|
|
508
|
+
# Warning if identity could not be determined
|
|
509
|
+
if [ -z "$git_name" ] && [ -z "$git_email" ]; then
|
|
510
|
+
echo "Warning: Could not determine git identity. Commits may use default identity."
|
|
511
|
+
echo " To fix: run 'gh auth login' or set git config user.name/user.email in your repo"
|
|
512
|
+
elif [ -z "$git_name" ]; then
|
|
513
|
+
echo "Warning: Could not determine git user.name"
|
|
514
|
+
elif [ -z "$git_email" ]; then
|
|
515
|
+
echo "Warning: Could not determine git user.email"
|
|
516
|
+
fi
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
configure_git_identity
|
|
520
|
+
|
|
521
|
+
# Check if prlt is already installed globally (via npm)
|
|
522
|
+
# TKT-954: Also check for updates - Docker layer caching may have installed an older version
|
|
456
523
|
if command -v prlt &> /dev/null; then
|
|
457
524
|
PRLT_PATH=$(which prlt)
|
|
458
525
|
if [[ "$PRLT_PATH" == "/home/node/.npm-global/bin/prlt" ]]; then
|
|
459
|
-
|
|
526
|
+
DESIRED_VERSION="\${PRLT_VERSION:-latest}"
|
|
527
|
+
CURRENT_VERSION=$(prlt --version 2>/dev/null | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+' || echo "unknown")
|
|
528
|
+
|
|
529
|
+
# Determine the target version to compare against
|
|
530
|
+
if [ "$DESIRED_VERSION" = "latest" ] || [ "$DESIRED_VERSION" = "dev" ] || [ "$DESIRED_VERSION" = "next" ]; then
|
|
531
|
+
# For tags, check npm registry for the actual version number
|
|
532
|
+
TARGET_VERSION=$(npm view "@proletariat/cli@\${DESIRED_VERSION}" version 2>/dev/null || echo "unknown")
|
|
533
|
+
else
|
|
534
|
+
# For pinned versions (e.g., "1.2.3"), use directly
|
|
535
|
+
TARGET_VERSION="$DESIRED_VERSION"
|
|
536
|
+
fi
|
|
537
|
+
|
|
538
|
+
if [ "$TARGET_VERSION" != "unknown" ] && [ "$CURRENT_VERSION" != "$TARGET_VERSION" ]; then
|
|
539
|
+
echo "Updating prlt from v\${CURRENT_VERSION} to v\${TARGET_VERSION} (channel: \${DESIRED_VERSION})..."
|
|
540
|
+
npm install -g "@proletariat/cli@\${DESIRED_VERSION}" 2>&1
|
|
541
|
+
echo "prlt updated successfully"
|
|
542
|
+
else
|
|
543
|
+
echo "prlt v\${CURRENT_VERSION} is up to date"
|
|
544
|
+
fi
|
|
460
545
|
exit 0
|
|
461
546
|
fi
|
|
462
547
|
fi
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Helper Functions
|
|
3
3
|
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
8
|
+
import type { ServerRequest, ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
4
9
|
import type { Ticket } from '../pmo/types.js';
|
|
5
10
|
import type { McpToolResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Register an MCP tool with strict parameter validation.
|
|
13
|
+
*
|
|
14
|
+
* Uses z.object().strict() so that unknown/extra parameters are rejected
|
|
15
|
+
* with a clear error instead of being silently stripped.
|
|
16
|
+
* See: https://github.com/anthropics/proletariat/issues/366
|
|
17
|
+
*/
|
|
18
|
+
export declare function strictTool<T extends Record<string, z.ZodType>>(server: McpServer, name: string, description: string, shape: T, handler: (params: {
|
|
19
|
+
[K in keyof T]: z.infer<T[K]>;
|
|
20
|
+
}, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => CallToolResult | Promise<CallToolResult>): void;
|
|
6
21
|
export declare function formatTicket(t: Ticket): {
|
|
7
22
|
id: string;
|
|
8
23
|
title: string;
|
package/dist/lib/mcp/helpers.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Helper Functions
|
|
3
3
|
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* Register an MCP tool with strict parameter validation.
|
|
7
|
+
*
|
|
8
|
+
* Uses z.object().strict() so that unknown/extra parameters are rejected
|
|
9
|
+
* with a clear error instead of being silently stripped.
|
|
10
|
+
* See: https://github.com/anthropics/proletariat/issues/366
|
|
11
|
+
*/
|
|
12
|
+
export function strictTool(server, name, description, shape, handler) {
|
|
13
|
+
const strictSchema = z.object(shape).strict();
|
|
14
|
+
server.registerTool(name, {
|
|
15
|
+
description,
|
|
16
|
+
inputSchema: strictSchema,
|
|
17
|
+
}, handler);
|
|
18
|
+
}
|
|
4
19
|
export function formatTicket(t) {
|
|
5
20
|
return {
|
|
6
21
|
id: t.id,
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* MCP Action Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { errorResponse } from '../helpers.js';
|
|
5
|
+
import { errorResponse, strictTool } from '../helpers.js';
|
|
6
6
|
export function registerActionTools(server, ctx) {
|
|
7
|
-
server
|
|
7
|
+
strictTool(server, 'action_list', 'List work actions', { include_builtin: z.boolean().optional() }, async (params) => {
|
|
8
8
|
try {
|
|
9
9
|
const actions = await ctx.storage.listActions({
|
|
10
10
|
isBuiltin: params.include_builtin ? undefined : false,
|
|
@@ -29,7 +29,7 @@ export function registerActionTools(server, ctx) {
|
|
|
29
29
|
return errorResponse(error);
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
|
-
server
|
|
32
|
+
strictTool(server, 'action_show', 'Get action details', { id: z.string().describe('Action ID') }, async (params) => {
|
|
33
33
|
try {
|
|
34
34
|
const action = await ctx.storage.getAction(params.id);
|
|
35
35
|
if (!action)
|
|
@@ -45,7 +45,7 @@ export function registerActionTools(server, ctx) {
|
|
|
45
45
|
return errorResponse(error);
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
|
-
server
|
|
48
|
+
strictTool(server, 'action_create', 'Create a work action', {
|
|
49
49
|
name: z.string().describe('Action name'),
|
|
50
50
|
prompt: z.string().describe('Start prompt'),
|
|
51
51
|
description: z.string().optional(),
|
|
@@ -71,7 +71,7 @@ export function registerActionTools(server, ctx) {
|
|
|
71
71
|
return errorResponse(error);
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
server
|
|
74
|
+
strictTool(server, 'action_delete', 'Delete an action', { id: z.string().describe('Action ID') }, async (params) => {
|
|
75
75
|
try {
|
|
76
76
|
await ctx.storage.deleteAction(params.id);
|
|
77
77
|
return {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* MCP Board Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { errorResponse } from '../helpers.js';
|
|
5
|
+
import { errorResponse, strictTool } from '../helpers.js';
|
|
6
6
|
export function registerBoardTools(server, ctx) {
|
|
7
|
-
server
|
|
7
|
+
strictTool(server, 'board_show', 'Show the kanban board', { project: z.string().optional().describe('Project ID') }, async (params) => {
|
|
8
8
|
try {
|
|
9
9
|
let projectId = params.project;
|
|
10
10
|
if (!projectId) {
|
|
@@ -43,7 +43,7 @@ export function registerBoardTools(server, ctx) {
|
|
|
43
43
|
return errorResponse(error);
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
|
-
server
|
|
46
|
+
strictTool(server, 'board_columns', 'Get column names for a project', { project: z.string().optional().describe('Project ID') }, async (params) => {
|
|
47
47
|
try {
|
|
48
48
|
let projectId = params.project;
|
|
49
49
|
if (!projectId) {
|
|
@@ -64,7 +64,7 @@ export function registerBoardTools(server, ctx) {
|
|
|
64
64
|
return errorResponse(error);
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
-
server
|
|
67
|
+
strictTool(server, 'board_create_column', 'Add a new column to the board', {
|
|
68
68
|
project: z.string().describe('Project ID'),
|
|
69
69
|
name: z.string().describe('Column name'),
|
|
70
70
|
position: z.number().optional().describe('Position'),
|
|
@@ -82,7 +82,7 @@ export function registerBoardTools(server, ctx) {
|
|
|
82
82
|
return errorResponse(error);
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
|
-
server
|
|
85
|
+
strictTool(server, 'board_rename_column', 'Rename a column', {
|
|
86
86
|
project: z.string().describe('Project ID'),
|
|
87
87
|
column_id: z.string().describe('Column ID'),
|
|
88
88
|
name: z.string().describe('New name'),
|
|
@@ -100,7 +100,7 @@ export function registerBoardTools(server, ctx) {
|
|
|
100
100
|
return errorResponse(error);
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
|
-
server
|
|
103
|
+
strictTool(server, 'board_move_column', 'Reorder a column', {
|
|
104
104
|
project: z.string().describe('Project ID'),
|
|
105
105
|
column_id: z.string().describe('Column ID'),
|
|
106
106
|
position: z.number().describe('New position'),
|
|
@@ -118,7 +118,7 @@ export function registerBoardTools(server, ctx) {
|
|
|
118
118
|
return errorResponse(error);
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
|
-
server
|
|
121
|
+
strictTool(server, 'board_delete_column', 'Delete a column', {
|
|
122
122
|
project: z.string().describe('Project ID'),
|
|
123
123
|
column_id: z.string().describe('Column ID'),
|
|
124
124
|
cascade: z.boolean().optional().describe('Delete tickets in column'),
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* MCP Category Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { errorResponse } from '../helpers.js';
|
|
5
|
+
import { errorResponse, strictTool } from '../helpers.js';
|
|
6
6
|
export function registerCategoryTools(server, ctx) {
|
|
7
|
-
server
|
|
7
|
+
strictTool(server, 'category_list', 'List categories', { type: z.enum(['ticket', 'status']).optional() }, async (params) => {
|
|
8
8
|
try {
|
|
9
9
|
const categories = await ctx.storage.listCategories({ type: params.type });
|
|
10
10
|
return {
|
|
@@ -26,7 +26,7 @@ export function registerCategoryTools(server, ctx) {
|
|
|
26
26
|
return errorResponse(error);
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
server
|
|
29
|
+
strictTool(server, 'category_create', 'Create a category', {
|
|
30
30
|
name: z.string().describe('Category name'),
|
|
31
31
|
type: z.enum(['ticket', 'status']).describe('Category type'),
|
|
32
32
|
description: z.string().optional(),
|
|
@@ -50,7 +50,7 @@ export function registerCategoryTools(server, ctx) {
|
|
|
50
50
|
return errorResponse(error);
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
|
-
server
|
|
53
|
+
strictTool(server, 'category_rename', 'Rename a category', {
|
|
54
54
|
id: z.string().describe('Category ID'),
|
|
55
55
|
name: z.string().describe('New name'),
|
|
56
56
|
}, async (params) => {
|
|
@@ -67,7 +67,7 @@ export function registerCategoryTools(server, ctx) {
|
|
|
67
67
|
return errorResponse(error);
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
|
-
server
|
|
70
|
+
strictTool(server, 'category_delete', 'Delete a category', { id: z.string().describe('Category ID') }, async (params) => {
|
|
71
71
|
try {
|
|
72
72
|
await ctx.storage.deleteCategory(params.id);
|
|
73
73
|
return {
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* They're wrapped for MCP but return formatted text output.
|
|
6
6
|
*/
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import { errorResponse, textResponse } from '../helpers.js';
|
|
8
|
+
import { errorResponse, textResponse, strictTool } from '../helpers.js';
|
|
9
9
|
export function registerAgentTools(server, ctx) {
|
|
10
|
-
server
|
|
10
|
+
strictTool(server, 'agent_list', 'List all agents', { type: z.enum(['staff', 'temp', 'all']).optional() }, async (params) => {
|
|
11
11
|
try {
|
|
12
12
|
const typeFlag = params.type ? `--type ${params.type}` : '';
|
|
13
13
|
const output = ctx.runCommand(`prlt agent list ${typeFlag} --json 2>/dev/null || prlt agent list ${typeFlag}`);
|
|
@@ -17,7 +17,7 @@ export function registerAgentTools(server, ctx) {
|
|
|
17
17
|
return errorResponse(error);
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
|
-
server
|
|
20
|
+
strictTool(server, 'agent_status', 'Check agent status', {}, async () => {
|
|
21
21
|
try {
|
|
22
22
|
const output = ctx.runCommand('prlt agent status --json 2>/dev/null || prlt agent status');
|
|
23
23
|
return textResponse(output);
|
|
@@ -26,7 +26,7 @@ export function registerAgentTools(server, ctx) {
|
|
|
26
26
|
return errorResponse(error);
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
server
|
|
29
|
+
strictTool(server, 'agent_add', 'Add new agents', {
|
|
30
30
|
names: z.array(z.string()).optional().describe('Agent names'),
|
|
31
31
|
theme: z.string().optional().describe('Theme for names'),
|
|
32
32
|
clone: z.boolean().optional().describe('Use git clone instead of worktree'),
|
|
@@ -42,7 +42,7 @@ export function registerAgentTools(server, ctx) {
|
|
|
42
42
|
return errorResponse(error);
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
|
-
server
|
|
45
|
+
strictTool(server, 'agent_remove', 'Remove an agent', { name: z.string().describe('Agent name') }, async (params) => {
|
|
46
46
|
try {
|
|
47
47
|
const output = ctx.runCommand(`prlt agent remove ${params.name} --json`);
|
|
48
48
|
return textResponse(output);
|
|
@@ -53,7 +53,7 @@ export function registerAgentTools(server, ctx) {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
export function registerDockerTools(server, ctx) {
|
|
56
|
-
server
|
|
56
|
+
strictTool(server, 'docker_status', 'Check Docker daemon status', {}, async () => {
|
|
57
57
|
try {
|
|
58
58
|
const output = ctx.runCommand('prlt docker status');
|
|
59
59
|
return textResponse(output);
|
|
@@ -62,7 +62,7 @@ export function registerDockerTools(server, ctx) {
|
|
|
62
62
|
return errorResponse(error);
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
|
-
server
|
|
65
|
+
strictTool(server, 'docker_list', 'List Docker containers', {}, async () => {
|
|
66
66
|
try {
|
|
67
67
|
const output = ctx.runCommand('prlt docker list');
|
|
68
68
|
return textResponse(output);
|
|
@@ -71,7 +71,7 @@ export function registerDockerTools(server, ctx) {
|
|
|
71
71
|
return errorResponse(error);
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
server
|
|
74
|
+
strictTool(server, 'docker_start', 'Start Docker containers', { agent: z.string().optional().describe('Agent name') }, async (params) => {
|
|
75
75
|
try {
|
|
76
76
|
const agentArg = params.agent || '';
|
|
77
77
|
const output = ctx.runCommand(`prlt docker start ${agentArg}`);
|
|
@@ -81,7 +81,7 @@ export function registerDockerTools(server, ctx) {
|
|
|
81
81
|
return errorResponse(error);
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
|
-
server
|
|
84
|
+
strictTool(server, 'docker_stop', 'Stop Docker containers', { agent: z.string().optional().describe('Agent name') }, async (params) => {
|
|
85
85
|
try {
|
|
86
86
|
const agentArg = params.agent || '';
|
|
87
87
|
const output = ctx.runCommand(`prlt docker stop ${agentArg}`);
|
|
@@ -91,7 +91,7 @@ export function registerDockerTools(server, ctx) {
|
|
|
91
91
|
return errorResponse(error);
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
|
-
server
|
|
94
|
+
strictTool(server, 'docker_logs', 'Get container logs', {
|
|
95
95
|
agent: z.string().describe('Agent name'),
|
|
96
96
|
lines: z.number().optional().describe('Number of lines'),
|
|
97
97
|
}, async (params) => {
|
|
@@ -106,7 +106,7 @@ export function registerDockerTools(server, ctx) {
|
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
export function registerRepoTools(server, ctx) {
|
|
109
|
-
server
|
|
109
|
+
strictTool(server, 'repo_list', 'List repositories in workspace', {}, async () => {
|
|
110
110
|
try {
|
|
111
111
|
const output = ctx.runCommand('prlt repo list');
|
|
112
112
|
return textResponse(output);
|
|
@@ -115,7 +115,7 @@ export function registerRepoTools(server, ctx) {
|
|
|
115
115
|
return errorResponse(error);
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
|
-
server
|
|
118
|
+
strictTool(server, 'repo_add', 'Add a repository', {
|
|
119
119
|
path: z.string().describe('Repository path or URL'),
|
|
120
120
|
name: z.string().optional().describe('Name for the repo'),
|
|
121
121
|
}, async (params) => {
|
|
@@ -128,7 +128,7 @@ export function registerRepoTools(server, ctx) {
|
|
|
128
128
|
return errorResponse(error);
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
|
-
server
|
|
131
|
+
strictTool(server, 'repo_remove', 'Remove a repository', { name: z.string().describe('Repository name') }, async (params) => {
|
|
132
132
|
try {
|
|
133
133
|
const output = ctx.runCommand(`prlt repo remove ${params.name}`);
|
|
134
134
|
return textResponse(output);
|
|
@@ -139,7 +139,7 @@ export function registerRepoTools(server, ctx) {
|
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
export function registerBranchTools(server, ctx) {
|
|
142
|
-
server
|
|
142
|
+
strictTool(server, 'branch_list', 'List branches', {}, async () => {
|
|
143
143
|
try {
|
|
144
144
|
const output = ctx.runCommand('prlt branch list');
|
|
145
145
|
return textResponse(output);
|
|
@@ -148,7 +148,7 @@ export function registerBranchTools(server, ctx) {
|
|
|
148
148
|
return errorResponse(error);
|
|
149
149
|
}
|
|
150
150
|
});
|
|
151
|
-
server
|
|
151
|
+
strictTool(server, 'branch_create', 'Create a branch for a ticket', {
|
|
152
152
|
ticket_id: z.string().describe('Ticket ID'),
|
|
153
153
|
name: z.string().optional().describe('Branch name override'),
|
|
154
154
|
}, async (params) => {
|
|
@@ -161,7 +161,7 @@ export function registerBranchTools(server, ctx) {
|
|
|
161
161
|
return errorResponse(error);
|
|
162
162
|
}
|
|
163
163
|
});
|
|
164
|
-
server
|
|
164
|
+
strictTool(server, 'branch_where', 'Show which ticket/branch you are on', {}, async () => {
|
|
165
165
|
try {
|
|
166
166
|
const output = ctx.runCommand('prlt branch where');
|
|
167
167
|
return textResponse(output);
|
|
@@ -172,7 +172,7 @@ export function registerBranchTools(server, ctx) {
|
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
174
|
export function registerGitHubTools(server, ctx) {
|
|
175
|
-
server
|
|
175
|
+
strictTool(server, 'gh_status', 'Check GitHub CLI status', {}, async () => {
|
|
176
176
|
try {
|
|
177
177
|
const output = ctx.runCommand('prlt gh status');
|
|
178
178
|
return textResponse(output);
|
|
@@ -181,7 +181,7 @@ export function registerGitHubTools(server, ctx) {
|
|
|
181
181
|
return errorResponse(error);
|
|
182
182
|
}
|
|
183
183
|
});
|
|
184
|
-
server
|
|
184
|
+
strictTool(server, 'gh_login', 'Login to GitHub', {}, async () => {
|
|
185
185
|
try {
|
|
186
186
|
const output = ctx.runCommand('prlt gh login');
|
|
187
187
|
return textResponse(output);
|
|
@@ -190,7 +190,7 @@ export function registerGitHubTools(server, ctx) {
|
|
|
190
190
|
return errorResponse(error);
|
|
191
191
|
}
|
|
192
192
|
});
|
|
193
|
-
server
|
|
193
|
+
strictTool(server, 'pr_create', 'Create a pull request', {
|
|
194
194
|
ticket_id: z.string().optional().describe('Ticket ID'),
|
|
195
195
|
title: z.string().optional().describe('PR title'),
|
|
196
196
|
body: z.string().optional().describe('PR body'),
|
|
@@ -208,7 +208,7 @@ export function registerGitHubTools(server, ctx) {
|
|
|
208
208
|
return errorResponse(error);
|
|
209
209
|
}
|
|
210
210
|
});
|
|
211
|
-
server
|
|
211
|
+
strictTool(server, 'pr_list', 'List pull requests', {}, async () => {
|
|
212
212
|
try {
|
|
213
213
|
const output = ctx.runCommand('prlt pr list');
|
|
214
214
|
return textResponse(output);
|
|
@@ -217,7 +217,7 @@ export function registerGitHubTools(server, ctx) {
|
|
|
217
217
|
return errorResponse(error);
|
|
218
218
|
}
|
|
219
219
|
});
|
|
220
|
-
server
|
|
220
|
+
strictTool(server, 'pr_status', 'Check PR status', {}, async () => {
|
|
221
221
|
try {
|
|
222
222
|
const output = ctx.runCommand('prlt pr status');
|
|
223
223
|
return textResponse(output);
|
|
@@ -228,7 +228,7 @@ export function registerGitHubTools(server, ctx) {
|
|
|
228
228
|
});
|
|
229
229
|
}
|
|
230
230
|
export function registerInitTools(server, ctx) {
|
|
231
|
-
server
|
|
231
|
+
strictTool(server, 'init', 'Initialize an HQ workspace', {
|
|
232
232
|
name: z.string().describe('HQ name'),
|
|
233
233
|
path: z.string().optional().describe('HQ path'),
|
|
234
234
|
repos: z.array(z.string()).optional().describe('Repository paths'),
|
|
@@ -247,7 +247,7 @@ export function registerInitTools(server, ctx) {
|
|
|
247
247
|
return errorResponse(error);
|
|
248
248
|
}
|
|
249
249
|
});
|
|
250
|
-
server
|
|
250
|
+
strictTool(server, 'pmo_init', 'Initialize PMO in existing workspace', {
|
|
251
251
|
template: z.string().optional().describe('Board template'),
|
|
252
252
|
name: z.string().optional().describe('Board name'),
|
|
253
253
|
}, async (params) => {
|
|
@@ -263,7 +263,7 @@ export function registerInitTools(server, ctx) {
|
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
export function registerUtilityTools(server, ctx) {
|
|
266
|
-
server
|
|
266
|
+
strictTool(server, 'whoami', 'Show current context (agent, workspace)', {}, async () => {
|
|
267
267
|
try {
|
|
268
268
|
const output = ctx.runCommand('prlt whoami');
|
|
269
269
|
return textResponse(output);
|
|
@@ -272,7 +272,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
272
272
|
return errorResponse(error);
|
|
273
273
|
}
|
|
274
274
|
});
|
|
275
|
-
server
|
|
275
|
+
strictTool(server, 'commit', 'Create a commit with ticket reference', {
|
|
276
276
|
message: z.string().describe('Commit message'),
|
|
277
277
|
ticket_id: z.string().optional().describe('Ticket ID'),
|
|
278
278
|
}, async (params) => {
|
|
@@ -285,7 +285,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
285
285
|
return errorResponse(error);
|
|
286
286
|
}
|
|
287
287
|
});
|
|
288
|
-
server
|
|
288
|
+
strictTool(server, 'execution_list', 'List work executions', {}, async () => {
|
|
289
289
|
try {
|
|
290
290
|
const output = ctx.runCommand('prlt execution list');
|
|
291
291
|
return textResponse(output);
|
|
@@ -294,7 +294,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
294
294
|
return errorResponse(error);
|
|
295
295
|
}
|
|
296
296
|
});
|
|
297
|
-
server
|
|
297
|
+
strictTool(server, 'execution_view', 'View execution details', { id: z.string().describe('Execution ID') }, async (params) => {
|
|
298
298
|
try {
|
|
299
299
|
const output = ctx.runCommand(`prlt execution view ${params.id}`);
|
|
300
300
|
return textResponse(output);
|
|
@@ -303,7 +303,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
303
303
|
return errorResponse(error);
|
|
304
304
|
}
|
|
305
305
|
});
|
|
306
|
-
server
|
|
306
|
+
strictTool(server, 'execution_logs', 'Get execution logs', { id: z.string().describe('Execution ID') }, async (params) => {
|
|
307
307
|
try {
|
|
308
308
|
const output = ctx.runCommand(`prlt execution logs ${params.id}`);
|
|
309
309
|
return textResponse(output);
|
|
@@ -312,7 +312,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
312
312
|
return errorResponse(error);
|
|
313
313
|
}
|
|
314
314
|
});
|
|
315
|
-
server
|
|
315
|
+
strictTool(server, 'session_list', 'List tmux sessions', {}, async () => {
|
|
316
316
|
try {
|
|
317
317
|
const output = ctx.runCommand('prlt session list');
|
|
318
318
|
return textResponse(output);
|
|
@@ -321,7 +321,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
321
321
|
return errorResponse(error);
|
|
322
322
|
}
|
|
323
323
|
});
|
|
324
|
-
server
|
|
324
|
+
strictTool(server, 'config_show', 'Show configuration', {}, async () => {
|
|
325
325
|
try {
|
|
326
326
|
const output = ctx.runCommand('prlt config');
|
|
327
327
|
return textResponse(output);
|