@parall/cli 1.31.0 → 1.32.1
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/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +12 -3
- package/dist/commands/approvals.d.ts.map +1 -1
- package/dist/commands/approvals.js +3 -3
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +4 -1
- package/dist/commands/clip.d.ts +3 -0
- package/dist/commands/clip.d.ts.map +1 -0
- package/dist/commands/clip.js +178 -0
- package/dist/commands/comments.d.ts +10 -0
- package/dist/commands/comments.d.ts.map +1 -0
- package/dist/commands/comments.js +115 -0
- package/dist/commands/dm.d.ts.map +1 -1
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +1 -3
- package/dist/commands/machines.d.ts.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +68 -20
- package/dist/commands/messages.d.ts +1 -1
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +11 -2
- package/dist/commands/schedules.d.ts.map +1 -1
- package/dist/commands/schedules.js +20 -4
- package/dist/commands/tasks.d.ts.map +1 -1
- package/dist/commands/tasks.js +11 -3
- package/dist/commands/wiki.d.ts.map +1 -1
- package/dist/commands/wiki.js +14 -11
- package/dist/index.js +4 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +5 -1
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +28 -17
- package/dist/lib/upload.d.ts.map +1 -1
- package/dist/lib/upload.js +24 -8
- package/dist/lib/wiki.d.ts.map +1 -1
- package/dist/lib/wiki.js +76 -51
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,aAAa,EAEb,mBAAmB,EACnB,OAAO,EACP,YAAY,EACb,MAAM,aAAa,CAAC;AAmCrB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,QAqBA;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,QAmBA;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,QAIA;AAuBD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE;;;;;;GASvD;AAMD,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,cAAc,EAAE,KAAK,CAAC,EAAE,MAAM;CAM/E;AAaD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAuB9C;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7C,OAAO,CAAC,aAAa,CAAC,CASxB;AA6CD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,QAiJrD"}
|
package/dist/commands/agents.js
CHANGED
|
@@ -16,7 +16,10 @@ function parseOptionalInt(value, field) {
|
|
|
16
16
|
function parsePermissions(value) {
|
|
17
17
|
if (!value)
|
|
18
18
|
return undefined;
|
|
19
|
-
const permissions = value
|
|
19
|
+
const permissions = value
|
|
20
|
+
.split(',')
|
|
21
|
+
.map((v) => v.trim())
|
|
22
|
+
.filter(Boolean);
|
|
20
23
|
return permissions.length > 0 ? permissions : undefined;
|
|
21
24
|
}
|
|
22
25
|
function parseOptionalSeconds(value, field, fallback) {
|
|
@@ -40,13 +43,19 @@ export function validateMachineOptions(opts) {
|
|
|
40
43
|
throw new Error('cpu-cores/memory-mb/storage-gb require --machine-label custom');
|
|
41
44
|
}
|
|
42
45
|
if (opts.machineType === 'cloud' && opts.machineLabel === 'custom') {
|
|
43
|
-
if (opts.cpuCores === undefined ||
|
|
46
|
+
if (opts.cpuCores === undefined ||
|
|
47
|
+
opts.memoryMB === undefined ||
|
|
48
|
+
opts.storageGB === undefined) {
|
|
44
49
|
throw new Error('custom machine requires --cpu-cores --memory-mb --storage-gb');
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
53
|
export function validateApiKeyOutputOptions(opts) {
|
|
49
|
-
const selected = [
|
|
54
|
+
const selected = [
|
|
55
|
+
opts.apiKeyFile !== undefined,
|
|
56
|
+
opts.showApiKey === true,
|
|
57
|
+
opts.discardApiKey === true,
|
|
58
|
+
].filter(Boolean).length;
|
|
50
59
|
if (selected > 1) {
|
|
51
60
|
throw new Error('--api-key-file, --show-api-key, and --discard-api-key are mutually exclusive');
|
|
52
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../src/commands/approvals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../src/commands/approvals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,QAmIxD"}
|
|
@@ -96,8 +96,8 @@ export function registerApprovalCommands(program) {
|
|
|
96
96
|
const deadline = Date.now() + timeoutMs;
|
|
97
97
|
while (true) {
|
|
98
98
|
const approval = await client.getApproval(id);
|
|
99
|
-
const isTerminal = approval.status !== 'pending'
|
|
100
|
-
|
|
99
|
+
const isTerminal = approval.status !== 'pending' &&
|
|
100
|
+
!(approval.status === 'approved' && !approval.execution_status);
|
|
101
101
|
if (isTerminal) {
|
|
102
102
|
printJson(approval);
|
|
103
103
|
const ok = approval.status === 'approved' && approval.execution_status === 'succeeded';
|
|
@@ -109,7 +109,7 @@ export function registerApprovalCommands(program) {
|
|
|
109
109
|
console.error('Timed out waiting for approval decision');
|
|
110
110
|
process.exit(2);
|
|
111
111
|
}
|
|
112
|
-
await new Promise(r => setTimeout(r, Math.min(pollMs, deadline - now)));
|
|
112
|
+
await new Promise((r) => setTimeout(r, Math.min(pollMs, deadline - now)));
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/commands/chats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/commands/chats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAiJpD"}
|
package/dist/commands/chats.js
CHANGED
|
@@ -82,7 +82,10 @@ export function registerChatCommands(program) {
|
|
|
82
82
|
const { client, orgId } = resolveCredentials();
|
|
83
83
|
const result = await client.createChat(orgId, {
|
|
84
84
|
type: opts.type,
|
|
85
|
-
member_ids: opts.memberIds
|
|
85
|
+
member_ids: opts.memberIds
|
|
86
|
+
.split(',')
|
|
87
|
+
.map((s) => stripPrllScheme(s.trim()))
|
|
88
|
+
.filter(Boolean),
|
|
86
89
|
name: opts.name,
|
|
87
90
|
description: opts.description,
|
|
88
91
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clip.d.ts","sourceRoot":"","sources":["../../src/commands/clip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8BpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAuJpD"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { resolveCredentials } from '../lib/client.js';
|
|
2
|
+
import { printJson, printError } from '../lib/output.js';
|
|
3
|
+
/**
|
|
4
|
+
* Derive a CLI-friendly alias from a registry source string.
|
|
5
|
+
* Handles scoped packages ("@scope/name@1.0.0" → "name") and
|
|
6
|
+
* plain packages ("name@1.0.0" → "name").
|
|
7
|
+
*/
|
|
8
|
+
function deriveAlias(source) {
|
|
9
|
+
let s = source.trim();
|
|
10
|
+
if (s.startsWith('@')) {
|
|
11
|
+
const slashIdx = s.indexOf('/');
|
|
12
|
+
if (slashIdx > 0) {
|
|
13
|
+
const rest = s.slice(slashIdx + 1);
|
|
14
|
+
const atIdx = rest.indexOf('@');
|
|
15
|
+
s = atIdx > 0 ? rest.slice(0, atIdx) : rest;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const atIdx = s.indexOf('@');
|
|
20
|
+
if (atIdx > 0)
|
|
21
|
+
s = s.slice(0, atIdx);
|
|
22
|
+
}
|
|
23
|
+
// Normalize to server's allowed alias charset: ^[a-z0-9][a-z0-9-_]*$
|
|
24
|
+
return s
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^a-z0-9-_]/g, '-')
|
|
27
|
+
.replace(/^[^a-z0-9]+/, '');
|
|
28
|
+
}
|
|
29
|
+
export function registerClipCommands(program) {
|
|
30
|
+
const clip = program.command('clip').description('Manage clips');
|
|
31
|
+
clip
|
|
32
|
+
.command('list')
|
|
33
|
+
.description('List clips in the organization')
|
|
34
|
+
.action(async () => {
|
|
35
|
+
try {
|
|
36
|
+
const { client, orgId } = resolveCredentials();
|
|
37
|
+
const clips = await client.listClips(orgId);
|
|
38
|
+
// Table display: alias, name, version, status, source_type
|
|
39
|
+
if (clips.length === 0) {
|
|
40
|
+
printJson({ data: [], message: 'No clips found' });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const rows = clips.map((c) => ({
|
|
44
|
+
alias: c.alias,
|
|
45
|
+
name: c.name,
|
|
46
|
+
version: c.version ?? '-',
|
|
47
|
+
status: c.status,
|
|
48
|
+
source_type: c.source_type,
|
|
49
|
+
}));
|
|
50
|
+
printJson(rows);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
printError(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
clip
|
|
57
|
+
.command('install')
|
|
58
|
+
.description('Install a clip from a registry source')
|
|
59
|
+
.argument('<source>', 'Registry source identifier (used as name and alias)')
|
|
60
|
+
.option('--alias <alias>', 'Override the alias (default: derived from source)')
|
|
61
|
+
.action(async (source, opts) => {
|
|
62
|
+
try {
|
|
63
|
+
const { client, orgId } = resolveCredentials();
|
|
64
|
+
// Derive alias: take the last segment, replace non-alphanumeric with dash, lowercase.
|
|
65
|
+
const alias = opts.alias ?? deriveAlias(source);
|
|
66
|
+
const req = {
|
|
67
|
+
alias,
|
|
68
|
+
name: source,
|
|
69
|
+
manifest: {},
|
|
70
|
+
source_type: 'registry',
|
|
71
|
+
source_ref: source,
|
|
72
|
+
};
|
|
73
|
+
const clip = await client.createClip(orgId, req);
|
|
74
|
+
printJson(clip);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
printError(err);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
clip
|
|
81
|
+
.command('info')
|
|
82
|
+
.description('Show detailed information about a clip by alias')
|
|
83
|
+
.argument('<alias>', 'Clip alias')
|
|
84
|
+
.action(async (alias) => {
|
|
85
|
+
try {
|
|
86
|
+
const { client, orgId } = resolveCredentials();
|
|
87
|
+
const clips = await client.listClips(orgId);
|
|
88
|
+
const found = clips.find((c) => c.alias === alias);
|
|
89
|
+
if (!found) {
|
|
90
|
+
printError(new Error(`Clip with alias "${alias}" not found`));
|
|
91
|
+
}
|
|
92
|
+
// Display full details including manifest commands
|
|
93
|
+
const info = {
|
|
94
|
+
id: found.id,
|
|
95
|
+
alias: found.alias,
|
|
96
|
+
name: found.name,
|
|
97
|
+
version: found.version,
|
|
98
|
+
description: found.description,
|
|
99
|
+
status: found.status,
|
|
100
|
+
source_type: found.source_type,
|
|
101
|
+
source_ref: found.source_ref,
|
|
102
|
+
manifest: found.manifest,
|
|
103
|
+
created_at: found.created_at,
|
|
104
|
+
updated_at: found.updated_at,
|
|
105
|
+
};
|
|
106
|
+
printJson(info);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
printError(err);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
clip
|
|
113
|
+
.command('invoke')
|
|
114
|
+
.description('Invoke a clip command')
|
|
115
|
+
.argument('<alias>', 'Clip alias')
|
|
116
|
+
.argument('<command>', 'Command name to invoke')
|
|
117
|
+
.argument('[input]', 'Input data (JSON string or plain text)')
|
|
118
|
+
.option('--timeout <ms>', 'Timeout in milliseconds', '30000')
|
|
119
|
+
.action(async (alias, command, input, opts) => {
|
|
120
|
+
try {
|
|
121
|
+
const { client, orgId } = resolveCredentials();
|
|
122
|
+
// Parse input: try JSON first, fall back to plain text wrapping.
|
|
123
|
+
let parsedInput = undefined;
|
|
124
|
+
if (input !== undefined) {
|
|
125
|
+
try {
|
|
126
|
+
parsedInput = JSON.parse(input);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Not valid JSON — send as a plain string.
|
|
130
|
+
parsedInput = input;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
let timeoutMs;
|
|
134
|
+
if (opts?.timeout) {
|
|
135
|
+
timeoutMs = parseInt(opts.timeout, 10);
|
|
136
|
+
if (isNaN(timeoutMs) || timeoutMs <= 0) {
|
|
137
|
+
printError(new Error('--timeout must be a positive integer (milliseconds)'));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const req = {
|
|
141
|
+
alias,
|
|
142
|
+
command,
|
|
143
|
+
input: parsedInput,
|
|
144
|
+
timeout_ms: timeoutMs,
|
|
145
|
+
};
|
|
146
|
+
const result = await client.invokeClip(orgId, req);
|
|
147
|
+
if (result.error) {
|
|
148
|
+
printError(new Error(result.error));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
printJson(result.output);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
printError(err);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
clip
|
|
159
|
+
.command('remove')
|
|
160
|
+
.description('Remove a clip by alias')
|
|
161
|
+
.argument('<alias>', 'Clip alias')
|
|
162
|
+
.action(async (alias) => {
|
|
163
|
+
try {
|
|
164
|
+
const { client, orgId } = resolveCredentials();
|
|
165
|
+
// Resolve alias to clip ID
|
|
166
|
+
const clips = await client.listClips(orgId);
|
|
167
|
+
const found = clips.find((c) => c.alias === alias);
|
|
168
|
+
if (!found) {
|
|
169
|
+
printError(new Error(`Clip with alias "${alias}" not found`));
|
|
170
|
+
}
|
|
171
|
+
await client.deleteClip(orgId, found.id);
|
|
172
|
+
printJson({ ok: true, removed: alias });
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
printError(err);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Generic, target-agnostic comment commands over `POST/GET/PATCH/DELETE
|
|
4
|
+
* /comments`. Unlike `parall tasks comments` (task-only) and `parall wiki
|
|
5
|
+
* comment` (wiki page/changeset, builds the URI for you), this group takes a
|
|
6
|
+
* raw `prll://` target URI, so an agent dispatched on a wiki comment can reply
|
|
7
|
+
* by echoing the exact `target_uri` it received.
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerCommentCommands(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/commands/comments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAoGvD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { resolveCredentials } from '../lib/client.js';
|
|
2
|
+
import { printError, printJson, printRefHint, stripPrllScheme } from '../lib/output.js';
|
|
3
|
+
function stripUndefined(obj) {
|
|
4
|
+
return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
|
|
5
|
+
}
|
|
6
|
+
// The unified comment API addresses targets by full `prll://` URI (task,
|
|
7
|
+
// wiki page, wiki changeset, or wiki inline anchor). Accept the URI with or
|
|
8
|
+
// without the scheme so `--target prll://wik_x/Foo.md` and `--target
|
|
9
|
+
// wik_x/Foo.md` both work.
|
|
10
|
+
function normalizeTarget(target) {
|
|
11
|
+
return target.startsWith('prll://') ? target : `prll://${target}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generic, target-agnostic comment commands over `POST/GET/PATCH/DELETE
|
|
15
|
+
* /comments`. Unlike `parall tasks comments` (task-only) and `parall wiki
|
|
16
|
+
* comment` (wiki page/changeset, builds the URI for you), this group takes a
|
|
17
|
+
* raw `prll://` target URI, so an agent dispatched on a wiki comment can reply
|
|
18
|
+
* by echoing the exact `target_uri` it received.
|
|
19
|
+
*/
|
|
20
|
+
export function registerCommentCommands(program) {
|
|
21
|
+
const comments = program
|
|
22
|
+
.command('comments')
|
|
23
|
+
.description('Manage comments on any prll:// target (task / wiki page / changeset / inline anchor)');
|
|
24
|
+
comments
|
|
25
|
+
.command('add')
|
|
26
|
+
.description('Add a comment to a prll:// target')
|
|
27
|
+
.requiredOption('--target <uri>', 'Target prll:// URI (task / wiki page / changeset / inline anchor)')
|
|
28
|
+
.requiredOption('--body <text>', 'Comment body')
|
|
29
|
+
.option('--parent <id>', 'Parent comment ID (task comments only — threaded reply)')
|
|
30
|
+
.action(async (opts) => {
|
|
31
|
+
try {
|
|
32
|
+
const { client, orgId } = resolveCredentials();
|
|
33
|
+
const result = await client.createComment(orgId, {
|
|
34
|
+
target_uri: normalizeTarget(opts.target),
|
|
35
|
+
body: opts.body,
|
|
36
|
+
parent_id: opts.parent ? stripPrllScheme(opts.parent) : undefined,
|
|
37
|
+
});
|
|
38
|
+
printJson(result);
|
|
39
|
+
printRefHint(result.id);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
printError(err);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
comments
|
|
46
|
+
.command('list')
|
|
47
|
+
.description('List comments on a prll:// target')
|
|
48
|
+
.requiredOption('--target <uri>', 'Target prll:// URI')
|
|
49
|
+
.option('--limit <n>', 'Maximum number of comments to return', '50')
|
|
50
|
+
.option('--cursor <cursor>', 'Pagination cursor')
|
|
51
|
+
.option('--order <order>', 'Sort order (asc or desc)')
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
try {
|
|
54
|
+
const { client, orgId } = resolveCredentials();
|
|
55
|
+
const params = stripUndefined({
|
|
56
|
+
limit: Number(opts.limit),
|
|
57
|
+
cursor: opts.cursor,
|
|
58
|
+
order: opts.order,
|
|
59
|
+
});
|
|
60
|
+
const result = await client.getComments(orgId, {
|
|
61
|
+
target_uri: normalizeTarget(opts.target),
|
|
62
|
+
...params,
|
|
63
|
+
});
|
|
64
|
+
printJson(result);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
printError(err);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
comments
|
|
71
|
+
.command('get')
|
|
72
|
+
.description('Get a single comment by ID')
|
|
73
|
+
.argument('<commentId>', 'Comment ID')
|
|
74
|
+
.action(async (commentId) => {
|
|
75
|
+
try {
|
|
76
|
+
const { client, orgId } = resolveCredentials();
|
|
77
|
+
const result = await client.getComment(orgId, stripPrllScheme(commentId));
|
|
78
|
+
printJson(result);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
printError(err);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
comments
|
|
85
|
+
.command('update')
|
|
86
|
+
.description('Update a comment (author only)')
|
|
87
|
+
.argument('<commentId>', 'Comment ID')
|
|
88
|
+
.requiredOption('--body <text>', 'New comment body')
|
|
89
|
+
.action(async (commentId, opts) => {
|
|
90
|
+
try {
|
|
91
|
+
const { client, orgId } = resolveCredentials();
|
|
92
|
+
const result = await client.updateComment(orgId, stripPrllScheme(commentId), {
|
|
93
|
+
body: opts.body,
|
|
94
|
+
});
|
|
95
|
+
printJson(result);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
printError(err);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
comments
|
|
102
|
+
.command('delete')
|
|
103
|
+
.description('Delete a comment (author only)')
|
|
104
|
+
.argument('<commentId>', 'Comment ID')
|
|
105
|
+
.action(async (commentId) => {
|
|
106
|
+
try {
|
|
107
|
+
const { client, orgId } = resolveCredentials();
|
|
108
|
+
await client.deleteComment(orgId, stripPrllScheme(commentId));
|
|
109
|
+
printJson({ ok: true });
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
printError(err);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/commands/dm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"dm.d.ts","sourceRoot":"","sources":["../../src/commands/dm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,QAwDlD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAkEpD"}
|
package/dist/commands/files.js
CHANGED
|
@@ -43,9 +43,7 @@ export function registerFileCommands(program) {
|
|
|
43
43
|
// Sanitize server-provided filename to prevent path traversal
|
|
44
44
|
const safeName = path.basename(fileInfo.file_name || id);
|
|
45
45
|
// Determine output path
|
|
46
|
-
const outputPath = opts.output
|
|
47
|
-
? path.resolve(opts.output)
|
|
48
|
-
: path.resolve(safeName);
|
|
46
|
+
const outputPath = opts.output ? path.resolve(opts.output) : path.resolve(safeName);
|
|
49
47
|
// If output is a directory, write file inside it
|
|
50
48
|
let finalPath = outputPath;
|
|
51
49
|
if (fs.existsSync(outputPath) && fs.statSync(outputPath).isDirectory()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machines.d.ts","sourceRoot":"","sources":["../../src/commands/machines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"machines.d.ts","sourceRoot":"","sources":["../../src/commands/machines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAwFvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,QAulBnD"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -168,7 +168,9 @@ export function registerMcpCommands(program) {
|
|
|
168
168
|
size: result.size,
|
|
169
169
|
};
|
|
170
170
|
return {
|
|
171
|
-
content: [
|
|
171
|
+
content: [
|
|
172
|
+
{ type: 'text', text: result.content || JSON.stringify(structuredContent, null, 2) },
|
|
173
|
+
],
|
|
172
174
|
structuredContent,
|
|
173
175
|
};
|
|
174
176
|
});
|
|
@@ -182,9 +184,21 @@ export function registerMcpCommands(program) {
|
|
|
182
184
|
wiki: z.string().describe('Wiki slug or ID'),
|
|
183
185
|
query: z.string().describe('Search query'),
|
|
184
186
|
ref: z.string().optional().describe('Optional git ref for API-backed search'),
|
|
185
|
-
path_prefix: z
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
path_prefix: z
|
|
188
|
+
.string()
|
|
189
|
+
.optional()
|
|
190
|
+
.describe('Restrict search to a file or directory path prefix'),
|
|
191
|
+
limit: z
|
|
192
|
+
.number()
|
|
193
|
+
.int()
|
|
194
|
+
.positive()
|
|
195
|
+
.max(20)
|
|
196
|
+
.optional()
|
|
197
|
+
.describe('Maximum number of results; default 5'),
|
|
198
|
+
include_content: z
|
|
199
|
+
.boolean()
|
|
200
|
+
.optional()
|
|
201
|
+
.describe('Include full matched section content in each result'),
|
|
188
202
|
},
|
|
189
203
|
outputSchema: {
|
|
190
204
|
results: z.array(z.object({
|
|
@@ -205,7 +219,7 @@ export function registerMcpCommands(program) {
|
|
|
205
219
|
source: z.enum(['local_mount', 'api']),
|
|
206
220
|
})),
|
|
207
221
|
},
|
|
208
|
-
}, async ({ wiki, query, ref, path_prefix: pathPrefix, limit, include_content: includeContent }) => {
|
|
222
|
+
}, async ({ wiki, query, ref, path_prefix: pathPrefix, limit, include_content: includeContent, }) => {
|
|
209
223
|
const results = await searchWiki(ctx, wiki, query, {
|
|
210
224
|
ref,
|
|
211
225
|
pathPrefix,
|
|
@@ -228,9 +242,21 @@ export function registerMcpCommands(program) {
|
|
|
228
242
|
wiki: z.string().describe('Wiki slug or ID'),
|
|
229
243
|
query: z.string().describe('Natural-language query'),
|
|
230
244
|
ref: z.string().optional().describe('Optional git ref for API-backed queries'),
|
|
231
|
-
path_prefix: z
|
|
232
|
-
|
|
233
|
-
|
|
245
|
+
path_prefix: z
|
|
246
|
+
.string()
|
|
247
|
+
.optional()
|
|
248
|
+
.describe('Restrict the query to a file or directory path prefix'),
|
|
249
|
+
limit: z
|
|
250
|
+
.number()
|
|
251
|
+
.int()
|
|
252
|
+
.positive()
|
|
253
|
+
.max(20)
|
|
254
|
+
.optional()
|
|
255
|
+
.describe('Maximum number of section results; default 5'),
|
|
256
|
+
include_content: z
|
|
257
|
+
.boolean()
|
|
258
|
+
.optional()
|
|
259
|
+
.describe('Include full matched section content in each result'),
|
|
234
260
|
},
|
|
235
261
|
outputSchema: {
|
|
236
262
|
wiki_id: z.string(),
|
|
@@ -269,7 +295,7 @@ export function registerMcpCommands(program) {
|
|
|
269
295
|
reasoning: z.array(z.string()),
|
|
270
296
|
})),
|
|
271
297
|
},
|
|
272
|
-
}, async ({ wiki, query, ref, path_prefix: pathPrefix, limit, include_content: includeContent }) => {
|
|
298
|
+
}, async ({ wiki, query, ref, path_prefix: pathPrefix, limit, include_content: includeContent, }) => {
|
|
273
299
|
const result = await queryWiki(ctx, wiki, query, {
|
|
274
300
|
ref,
|
|
275
301
|
pathPrefix,
|
|
@@ -290,7 +316,10 @@ export function registerMcpCommands(program) {
|
|
|
290
316
|
inputSchema: {
|
|
291
317
|
wiki: z.string().describe('Wiki slug or ID'),
|
|
292
318
|
ref: z.string().optional().describe('Optional git ref for API-backed outline'),
|
|
293
|
-
path_prefix: z
|
|
319
|
+
path_prefix: z
|
|
320
|
+
.string()
|
|
321
|
+
.optional()
|
|
322
|
+
.describe('Restrict outline to a file or directory path prefix'),
|
|
294
323
|
},
|
|
295
324
|
outputSchema: {
|
|
296
325
|
wiki_id: z.string(),
|
|
@@ -331,7 +360,10 @@ export function registerMcpCommands(program) {
|
|
|
331
360
|
inputSchema: {
|
|
332
361
|
wiki: z.string().describe('Wiki slug or ID'),
|
|
333
362
|
node_id: z.string().describe('Section node ID returned by wiki_search'),
|
|
334
|
-
ref: z
|
|
363
|
+
ref: z
|
|
364
|
+
.string()
|
|
365
|
+
.optional()
|
|
366
|
+
.describe('Optional git ref; when set, reads from the Parall API instead of a local mount'),
|
|
335
367
|
},
|
|
336
368
|
outputSchema: {
|
|
337
369
|
wiki_id: z.string(),
|
|
@@ -392,11 +424,23 @@ export function registerMcpCommands(program) {
|
|
|
392
424
|
inputSchema: {
|
|
393
425
|
wiki: z.string().describe('Wiki slug or ID'),
|
|
394
426
|
title: z.string().min(1).describe('Changeset title'),
|
|
395
|
-
message: z
|
|
427
|
+
message: z
|
|
428
|
+
.string()
|
|
429
|
+
.optional()
|
|
430
|
+
.describe('Changeset commit message (supports prll:// refs)'),
|
|
396
431
|
changeset_id: z.string().optional().describe('Existing changeset ID to update'),
|
|
397
|
-
source_chat_id: z
|
|
398
|
-
|
|
399
|
-
|
|
432
|
+
source_chat_id: z
|
|
433
|
+
.string()
|
|
434
|
+
.optional()
|
|
435
|
+
.describe('Optional source chat ID for approval workflow linkage'),
|
|
436
|
+
source_message_id: z
|
|
437
|
+
.string()
|
|
438
|
+
.optional()
|
|
439
|
+
.describe('Optional source message ID for approval workflow linkage'),
|
|
440
|
+
source_run_id: z
|
|
441
|
+
.string()
|
|
442
|
+
.optional()
|
|
443
|
+
.describe('Optional source run ID for approval workflow linkage'),
|
|
400
444
|
},
|
|
401
445
|
outputSchema: {
|
|
402
446
|
wiki_id: z.string(),
|
|
@@ -408,12 +452,14 @@ export function registerMcpCommands(program) {
|
|
|
408
452
|
auto_merged: z.boolean(),
|
|
409
453
|
requires_review: z.boolean(),
|
|
410
454
|
next_action: z.string(),
|
|
411
|
-
post_merge_sync: z
|
|
455
|
+
post_merge_sync: z
|
|
456
|
+
.object({
|
|
412
457
|
applied: z.number(),
|
|
413
458
|
fastForwarded: z.number(),
|
|
414
459
|
conflicts: z.array(z.unknown()),
|
|
415
460
|
failed: z.array(z.unknown()),
|
|
416
|
-
})
|
|
461
|
+
})
|
|
462
|
+
.nullable(),
|
|
417
463
|
post_merge_sync_error: z.string().nullable(),
|
|
418
464
|
diff_files: z.array(z.object({
|
|
419
465
|
path: z.string(),
|
|
@@ -421,15 +467,17 @@ export function registerMcpCommands(program) {
|
|
|
421
467
|
deletions: z.number(),
|
|
422
468
|
})),
|
|
423
469
|
source: z.literal('local_mount'),
|
|
424
|
-
changeset: z
|
|
470
|
+
changeset: z
|
|
471
|
+
.object({
|
|
425
472
|
id: z.string(),
|
|
426
473
|
wiki_id: z.string(),
|
|
427
474
|
title: z.string(),
|
|
428
475
|
status: z.string(),
|
|
429
476
|
changed_paths: z.array(z.string()).optional(),
|
|
430
|
-
})
|
|
477
|
+
})
|
|
478
|
+
.passthrough(),
|
|
431
479
|
},
|
|
432
|
-
}, async ({ wiki, title, message, changeset_id: changesetId, source_chat_id: sourceChatId, source_message_id: sourceMessageId, source_run_id: sourceRunId }) => {
|
|
480
|
+
}, async ({ wiki, title, message, changeset_id: changesetId, source_chat_id: sourceChatId, source_message_id: sourceMessageId, source_run_id: sourceRunId, }) => {
|
|
433
481
|
const runtime = resolveRuntimeContext();
|
|
434
482
|
const result = await proposeWikiChangeset(ctx, wiki, {
|
|
435
483
|
title,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/commands/messages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/commands/messages.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAqJvD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { ApiError } from '@parall/sdk';
|
|
1
2
|
import { resolveCredentials, resolveRuntimeContext } from '../lib/client.js';
|
|
2
|
-
import {
|
|
3
|
+
import { printError, printJson, printRefHint, stripPrllScheme } from '../lib/output.js';
|
|
3
4
|
import { uploadFile } from '../lib/upload.js';
|
|
4
5
|
export function registerMessageCommands(program) {
|
|
5
6
|
const messages = program.command('messages').description('Manage messages');
|
|
@@ -63,6 +64,12 @@ export function registerMessageCommands(program) {
|
|
|
63
64
|
printError(new Error('Chat ID required — provide as argument or set PRLL_CHAT_ID'));
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
67
|
+
// `messages send` targets a chat. A user id here is an addressing
|
|
68
|
+
// mistake — point at `dm` instead of letting the server reject it.
|
|
69
|
+
if (chatId.startsWith('usr_')) {
|
|
70
|
+
printError(new ApiError(400, `prll://${chatId} is a user, not a chat. To message a user use: parall dm prll://${chatId} --text "..."`, 'INVALID_TARGET'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
66
73
|
if (opts.file && opts.attachment) {
|
|
67
74
|
printError(new Error('--file and --attachment are mutually exclusive'));
|
|
68
75
|
return;
|
|
@@ -112,7 +119,9 @@ export function registerMessageCommands(program) {
|
|
|
112
119
|
.action(async (messageId, opts) => {
|
|
113
120
|
try {
|
|
114
121
|
const { client } = resolveCredentials();
|
|
115
|
-
const params = {
|
|
122
|
+
const params = {
|
|
123
|
+
limit: Number(opts.limit),
|
|
124
|
+
};
|
|
116
125
|
if (opts.before !== undefined)
|
|
117
126
|
params.before = stripPrllScheme(opts.before);
|
|
118
127
|
if (opts.after !== undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../src/commands/schedules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../src/commands/schedules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,QAgTxD"}
|