@parall/cli 1.33.0 → 1.35.0
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/mcp.d.ts +5 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +31 -482
- package/dist/commands/wiki.d.ts.map +1 -1
- package/dist/commands/wiki.js +38 -22
- package/dist/lib/wiki-frontmatter.d.ts +9 -0
- package/dist/lib/wiki-frontmatter.d.ts.map +1 -0
- package/dist/lib/wiki-frontmatter.js +64 -0
- package/dist/lib/wiki-tools.d.ts +33 -0
- package/dist/lib/wiki-tools.d.ts.map +1 -0
- package/dist/lib/wiki-tools.js +540 -0
- package/dist/lib/wiki.d.ts +33 -15
- package/dist/lib/wiki.d.ts.map +1 -1
- package/dist/lib/wiki.js +436 -147
- package/package.json +11 -3
package/dist/commands/wiki.js
CHANGED
|
@@ -33,10 +33,10 @@ export function registerWikiCommands(program) {
|
|
|
33
33
|
.command('sync')
|
|
34
34
|
.description('Sync wiki files to local workspace. First run downloads all files; subsequent runs pull updates.')
|
|
35
35
|
.argument('[wiki]', 'Wiki ID or slug (omit to sync all wikis)')
|
|
36
|
-
.action(async (
|
|
36
|
+
.action(async (wikiRef) => {
|
|
37
37
|
try {
|
|
38
38
|
const ctx = resolveCredentials();
|
|
39
|
-
const result = await syncAllMounts(ctx);
|
|
39
|
+
const result = await syncAllMounts(ctx, wikiRef);
|
|
40
40
|
for (const entry of result.synced) {
|
|
41
41
|
process.stderr.write(`wiki ${entry.slug} synced → ${entry.path}\n`);
|
|
42
42
|
}
|
|
@@ -55,22 +55,21 @@ export function registerWikiCommands(program) {
|
|
|
55
55
|
});
|
|
56
56
|
wiki
|
|
57
57
|
.command('status')
|
|
58
|
-
.description('Show local changes
|
|
58
|
+
.description('Show local changes and pending changesets.')
|
|
59
59
|
.argument('[wiki]', 'Wiki ID or slug (auto-resolves if org has one wiki)')
|
|
60
60
|
.action(async (wikiRef) => {
|
|
61
61
|
try {
|
|
62
62
|
const ctx = resolveCredentials();
|
|
63
63
|
const result = await getAfcsStatus(ctx, wikiRef);
|
|
64
64
|
process.stderr.write(`Wiki: ${result.wiki_name} (${result.wiki_slug})\n`);
|
|
65
|
-
process.stderr.write(`Mount: ${result.mount_path}\n`);
|
|
66
|
-
process.stderr.write(`Mode: ${result.mode}\n\n`);
|
|
65
|
+
process.stderr.write(`Mount: ${result.mount_path}\n\n`);
|
|
67
66
|
if (result.local_changes.length === 0) {
|
|
68
67
|
process.stderr.write('Local changes: none\n');
|
|
69
68
|
}
|
|
70
69
|
else {
|
|
71
70
|
process.stderr.write('Local changes:\n');
|
|
72
71
|
for (const file of result.local_changes) {
|
|
73
|
-
const s = file.
|
|
72
|
+
const s = file.action === 'create' ? 'A' : file.action === 'delete' ? 'D' : 'M';
|
|
74
73
|
process.stderr.write(` ${s} ${file.path} (+${file.additions} -${file.deletions})\n`);
|
|
75
74
|
}
|
|
76
75
|
}
|
|
@@ -87,11 +86,6 @@ export function registerWikiCommands(program) {
|
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
|
-
if (result.permissions) {
|
|
91
|
-
process.stderr.write('\nPermissions:\n');
|
|
92
|
-
process.stderr.write(` Read: ${result.permissions.readable_prefixes.join(', ')}\n`);
|
|
93
|
-
process.stderr.write(` Write: ${result.permissions.writable_prefixes.join(', ') || 'none'}\n`);
|
|
94
|
-
}
|
|
95
89
|
printJson(result);
|
|
96
90
|
}
|
|
97
91
|
catch (error) {
|
|
@@ -121,7 +115,7 @@ export function registerWikiCommands(program) {
|
|
|
121
115
|
});
|
|
122
116
|
wiki
|
|
123
117
|
.command('reset')
|
|
124
|
-
.description('Discard all local changes and restore files to the last synced state
|
|
118
|
+
.description('Discard all local changes and restore files to the last synced state.')
|
|
125
119
|
.argument('[wiki]', 'Wiki ID or slug (auto-resolves if org has one wiki)')
|
|
126
120
|
.action(async (wikiRef) => {
|
|
127
121
|
try {
|
|
@@ -134,6 +128,23 @@ export function registerWikiCommands(program) {
|
|
|
134
128
|
printError(error);
|
|
135
129
|
}
|
|
136
130
|
});
|
|
131
|
+
wiki
|
|
132
|
+
.command('access')
|
|
133
|
+
.description('Show your access level (read / maintain / admin) for a wiki path')
|
|
134
|
+
.argument('<path>', 'Path to check (e.g. docs/ops/)')
|
|
135
|
+
.argument('[wiki]', 'Wiki ID or slug (auto-resolves if org has one wiki)')
|
|
136
|
+
.action(async (targetPath, wikiRef) => {
|
|
137
|
+
try {
|
|
138
|
+
const ctx = resolveCredentials();
|
|
139
|
+
const { resolveWikiRefOrDefault } = await import('../lib/wiki.js');
|
|
140
|
+
const wiki = await resolveWikiRefOrDefault(ctx, wikiRef);
|
|
141
|
+
const result = await ctx.client.getWikiAccessStatus(ctx.orgId, wiki.id, targetPath);
|
|
142
|
+
printJson(result);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
printError(error);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
137
148
|
wiki
|
|
138
149
|
.command('request-access')
|
|
139
150
|
.description('Request read/write access to a locked wiki path. Creates an approval card for a maintainer.')
|
|
@@ -153,9 +164,9 @@ export function registerWikiCommands(program) {
|
|
|
153
164
|
});
|
|
154
165
|
wiki
|
|
155
166
|
.command('log')
|
|
156
|
-
.description(
|
|
167
|
+
.description("Show history. With a path: that file's commit history. Without: recent wiki operations.")
|
|
157
168
|
.argument('[wiki]', 'Wiki ID or slug (auto-resolves if org has one wiki)')
|
|
158
|
-
.argument('[path]', 'File path for per-file history')
|
|
169
|
+
.argument('[path]', 'File path for per-file commit history')
|
|
159
170
|
.action(async (wikiRef, filePath) => {
|
|
160
171
|
try {
|
|
161
172
|
const ctx = resolveCredentials();
|
|
@@ -166,7 +177,8 @@ export function registerWikiCommands(program) {
|
|
|
166
177
|
else {
|
|
167
178
|
for (const entry of result.entries) {
|
|
168
179
|
const pathSuffix = entry.path ? ` ${entry.path}` : '';
|
|
169
|
-
|
|
180
|
+
const who = entry.author_name ?? entry.actor_id ?? '';
|
|
181
|
+
process.stderr.write(`${entry.id.slice(0, 8)} ${entry.created_at} ${entry.action}${who ? ` (${who})` : ''}${pathSuffix}\n`);
|
|
170
182
|
}
|
|
171
183
|
}
|
|
172
184
|
printJson(result);
|
|
@@ -345,7 +357,7 @@ export function registerWikiCommands(program) {
|
|
|
345
357
|
// ---- Content browsing (search, query, outline, section) ----
|
|
346
358
|
wiki
|
|
347
359
|
.command('search')
|
|
348
|
-
.description('
|
|
360
|
+
.description('Keyword search over wiki sections. Searches your local workspace copy when synced; otherwise fetches from the server.')
|
|
349
361
|
.argument('<query>', 'Search query')
|
|
350
362
|
.argument('[wiki]', 'Wiki ID or slug')
|
|
351
363
|
.option('--path <path>', 'Restrict to a path prefix')
|
|
@@ -377,8 +389,8 @@ export function registerWikiCommands(program) {
|
|
|
377
389
|
});
|
|
378
390
|
wiki
|
|
379
391
|
.command('query')
|
|
380
|
-
.description('
|
|
381
|
-
.argument('<query>', '
|
|
392
|
+
.description('Heading-aware keyword search that also ranks whole documents. Same lexical scoring as `search` (not semantic), better for multi-word questions.')
|
|
393
|
+
.argument('<query>', 'Query keywords (multi-word supported)')
|
|
382
394
|
.argument('[wiki]', 'Wiki ID or slug')
|
|
383
395
|
.option('--path <path>', 'Restrict to a path prefix')
|
|
384
396
|
.option('--limit <n>', 'Max results (default 5)')
|
|
@@ -453,14 +465,18 @@ export function registerWikiCommands(program) {
|
|
|
453
465
|
});
|
|
454
466
|
wiki
|
|
455
467
|
.command('cat')
|
|
456
|
-
.description('
|
|
468
|
+
.description('Print a wiki file. Reads your local workspace copy when synced (includes your unproposed edits); falls back to the server.')
|
|
457
469
|
.argument('<path>', 'File path (e.g. docs/auth.md)')
|
|
458
470
|
.argument('[wiki]', 'Wiki ID or slug')
|
|
459
|
-
.
|
|
471
|
+
.option('--remote', 'Read the server version even when a local workspace copy exists')
|
|
472
|
+
.action(async (filePath, wikiRef, options) => {
|
|
460
473
|
try {
|
|
461
474
|
const ctx = resolveCredentials();
|
|
462
|
-
const result = await getWikiBlob(ctx, wikiRef, {
|
|
463
|
-
|
|
475
|
+
const result = await getWikiBlob(ctx, wikiRef, {
|
|
476
|
+
path: filePath,
|
|
477
|
+
remote: options.remote,
|
|
478
|
+
});
|
|
479
|
+
process.stderr.write(`${filePath} (${result.size} bytes, source: ${result.source})\n\n`);
|
|
464
480
|
process.stdout.write(result.content);
|
|
465
481
|
if (result.content && !result.content.endsWith('\n'))
|
|
466
482
|
process.stdout.write('\n');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ParsedFrontMatter {
|
|
2
|
+
type?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
tags?: string[];
|
|
5
|
+
}
|
|
6
|
+
/** True when any OKF field was extracted. */
|
|
7
|
+
export declare function hasFrontMatter(fm: ParsedFrontMatter): boolean;
|
|
8
|
+
export declare function parseFrontMatter(lines: string[], frontMatterEnd: number): ParsedFrontMatter;
|
|
9
|
+
//# sourceMappingURL=wiki-frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-frontmatter.d.ts","sourceRoot":"","sources":["../../src/lib/wiki-frontmatter.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAE7D;AAQD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,GAAG,iBAAiB,CAyB3F"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Frontmatter (OKF-inspired) parsing for wiki markdown files.
|
|
2
|
+
//
|
|
3
|
+
// This mirrors the Go implementation in server/pkg/markdown/section.go — keep
|
|
4
|
+
// the two behaviorally consistent. It lives in its own module (rather than
|
|
5
|
+
// growing the already-oversized wiki.ts) per the repo's file-size discipline.
|
|
6
|
+
import { load as loadYaml } from 'js-yaml';
|
|
7
|
+
/** True when any OKF field was extracted. */
|
|
8
|
+
export function hasFrontMatter(fm) {
|
|
9
|
+
return fm.type !== undefined || fm.description !== undefined || fm.tags !== undefined;
|
|
10
|
+
}
|
|
11
|
+
// parseFrontMatter extracts the optional OKF fields (type, description, tags)
|
|
12
|
+
// from the leading YAML frontmatter block. Permissive by design: only
|
|
13
|
+
// `---`-delimited YAML is parsed (a `+++` TOML block is detected for section
|
|
14
|
+
// boundaries by detectFrontMatterEnd but its fields are not extracted); any
|
|
15
|
+
// parse error / missing field / wrong-typed value degrades to undefined so a
|
|
16
|
+
// malformed field never discards a valid one.
|
|
17
|
+
export function parseFrontMatter(lines, frontMatterEnd) {
|
|
18
|
+
// frontMatterEnd is one past the closing fence; opening fence is line 0 and
|
|
19
|
+
// the closing fence is line frontMatterEnd-1, so a block needs >= 2 lines.
|
|
20
|
+
if (frontMatterEnd < 2 || lines.length === 0) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
if (lines[0].trim() !== '---') {
|
|
24
|
+
return {}; // only YAML frontmatter carries OKF fields
|
|
25
|
+
}
|
|
26
|
+
const body = lines.slice(1, frontMatterEnd - 1).join('\n');
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = loadYaml(body);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
const obj = raw;
|
|
38
|
+
return {
|
|
39
|
+
type: frontMatterString(obj.type),
|
|
40
|
+
description: frontMatterString(obj.description),
|
|
41
|
+
tags: frontMatterTags(obj.tags),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function frontMatterString(v) {
|
|
45
|
+
if (typeof v !== 'string') {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const s = v.trim();
|
|
49
|
+
return s === '' ? undefined : s;
|
|
50
|
+
}
|
|
51
|
+
function frontMatterTags(v) {
|
|
52
|
+
if (typeof v === 'string') {
|
|
53
|
+
const s = v.trim();
|
|
54
|
+
return s === '' ? undefined : [s];
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(v)) {
|
|
57
|
+
const out = v
|
|
58
|
+
.filter((e) => typeof e === 'string')
|
|
59
|
+
.map((e) => e.trim())
|
|
60
|
+
.filter((e) => e !== '');
|
|
61
|
+
return out.length > 0 ? out : undefined;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { type ParallContext } from './wiki.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared Parall wiki native tool registry.
|
|
5
|
+
*
|
|
6
|
+
* Single source of truth for the wiki tool surface consumed by:
|
|
7
|
+
* - the MCP server (`commands/mcp.ts`), which registers each definition
|
|
8
|
+
* - the eval harness (`@parall/eval`), which benchmarks the real tools
|
|
9
|
+
*
|
|
10
|
+
* Keep the schemas and handlers here behavior-identical to what the MCP
|
|
11
|
+
* server used to define inline. Do not fork an eval-only clone.
|
|
12
|
+
*/
|
|
13
|
+
export type WikiToolExecutionResult = {
|
|
14
|
+
structuredContent: Record<string, unknown>;
|
|
15
|
+
text: string;
|
|
16
|
+
};
|
|
17
|
+
export type WikiToolDefinition = {
|
|
18
|
+
name: string;
|
|
19
|
+
title: string;
|
|
20
|
+
description: string;
|
|
21
|
+
readOnly: boolean;
|
|
22
|
+
inputSchema: z.ZodRawShape;
|
|
23
|
+
outputSchema: z.ZodRawShape;
|
|
24
|
+
handler: (args: Record<string, unknown>) => Promise<WikiToolExecutionResult>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Build the full wiki native tool registry bound to a Parall context (credentials,
|
|
28
|
+
* agent env, local mount). Returns one definition per wiki capability (list, tree,
|
|
29
|
+
* status, diff, blob, search, query, outline, section, changeset diff, propose),
|
|
30
|
+
* each finalized with input validation. Shared by the MCP server and the eval harness.
|
|
31
|
+
*/
|
|
32
|
+
export declare function buildWikiTools(ctx: ParallContext): WikiToolDefinition[];
|
|
33
|
+
//# sourceMappingURL=wiki-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-tools.d.ts","sourceRoot":"","sources":["../../src/lib/wiki-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAE5B,OAAO,EASL,KAAK,aAAa,EAInB,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;GASG;AAEH,MAAM,MAAM,uBAAuB,GAAG;IACpC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;IAC3B,YAAY,EAAE,CAAC,CAAC,WAAW,CAAC;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC9E,CAAC;AAoBF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,kBAAkB,EAAE,CAiiBvE"}
|