@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
package/dist/lib/wiki.js
CHANGED
|
@@ -377,9 +377,9 @@ export async function proposeWikiChangeset(ctx, wikiRef, options) {
|
|
|
377
377
|
};
|
|
378
378
|
}
|
|
379
379
|
function changesetRequiresReview(changeset) {
|
|
380
|
-
return changeset.status === 'proposed'
|
|
381
|
-
|
|
382
|
-
|
|
380
|
+
return (changeset.status === 'proposed' ||
|
|
381
|
+
changeset.status === 'approval_pending' ||
|
|
382
|
+
changeset.status === 'approved');
|
|
383
383
|
}
|
|
384
384
|
function describeProposeNextAction(changeset, postMergeSync, postMergeSyncError) {
|
|
385
385
|
if (changeset.status === 'merged') {
|
|
@@ -479,8 +479,8 @@ export async function requestWikiAccess(ctx, wikiRef, targetPath, reason) {
|
|
|
479
479
|
path: normalizedPath,
|
|
480
480
|
reason: reason?.trim() || undefined,
|
|
481
481
|
status: 'submitted',
|
|
482
|
-
message: 'Access request noted. The server access-request endpoint is not yet implemented. '
|
|
483
|
-
|
|
482
|
+
message: 'Access request noted. The server access-request endpoint is not yet implemented. ' +
|
|
483
|
+
'Ask a wiki admin to grant access manually.',
|
|
484
484
|
};
|
|
485
485
|
}
|
|
486
486
|
throw error;
|
|
@@ -606,7 +606,14 @@ export function planSyncActions(input) {
|
|
|
606
606
|
actions.push({ kind: 'conflict-delete', path: p, baseSha: baseSha });
|
|
607
607
|
}
|
|
608
608
|
else {
|
|
609
|
-
actions.push({
|
|
609
|
+
actions.push({
|
|
610
|
+
kind: 'conflict-write',
|
|
611
|
+
path: p,
|
|
612
|
+
remoteSha,
|
|
613
|
+
remoteSize: remote.size,
|
|
614
|
+
baseSha,
|
|
615
|
+
localSha,
|
|
616
|
+
});
|
|
610
617
|
}
|
|
611
618
|
}
|
|
612
619
|
return actions;
|
|
@@ -616,11 +623,14 @@ export async function syncSingleWiki(ctx, wiki, mountPath) {
|
|
|
616
623
|
const metaDir = path.join(mountPath, PRLL_WIKI_DIR);
|
|
617
624
|
await fs.mkdir(metaDir, { recursive: true });
|
|
618
625
|
const token = resolveApiToken(ctx);
|
|
619
|
-
const baseUrl = (ctx.baseUrl ??
|
|
626
|
+
const baseUrl = (ctx.baseUrl ??
|
|
627
|
+
process.env.PRLL_WIKI_URL ??
|
|
628
|
+
process.env.PRLL_API_URL ??
|
|
629
|
+
'').replace(/\/+$/, '');
|
|
620
630
|
const manifestUrl = `${baseUrl}/wiki/v1/orgs/${ctx.orgId}/wikis/${wiki.id}/manifest`;
|
|
621
631
|
const bulkDownloadUrl = `${baseUrl}/wiki/v1/orgs/${ctx.orgId}/wikis/${wiki.id}/files/bulk-download`;
|
|
622
632
|
// 1. Fetch server manifest + read local manifest.
|
|
623
|
-
const manifestResp = await wikiServiceFetch(manifestUrl, token);
|
|
633
|
+
const manifestResp = (await wikiServiceFetch(manifestUrl, token));
|
|
624
634
|
const serverEntries = manifestResp.data;
|
|
625
635
|
const serverByPath = new Map(serverEntries.map((e) => [e.path, e]));
|
|
626
636
|
const localManifest = await readLocalManifest(mountPath);
|
|
@@ -960,7 +970,7 @@ function requireMountToken(mount) {
|
|
|
960
970
|
async function wikiServiceFetch(url, token, options = {}) {
|
|
961
971
|
const method = options.method ?? 'GET';
|
|
962
972
|
const headers = {
|
|
963
|
-
|
|
973
|
+
Authorization: `Bearer ${token}`,
|
|
964
974
|
'Content-Type': 'application/json',
|
|
965
975
|
};
|
|
966
976
|
if (process.env.PRLL_SWIMLANE_NAME) {
|
|
@@ -983,10 +993,10 @@ async function bulkDownloadFiles(bulkDownloadUrl, token, paths) {
|
|
|
983
993
|
const results = [];
|
|
984
994
|
for (let i = 0; i < paths.length; i += BATCH_SIZE) {
|
|
985
995
|
const batch = paths.slice(i, i + BATCH_SIZE);
|
|
986
|
-
const raw = await wikiServiceFetch(bulkDownloadUrl, token, {
|
|
996
|
+
const raw = (await wikiServiceFetch(bulkDownloadUrl, token, {
|
|
987
997
|
method: 'POST',
|
|
988
998
|
body: JSON.stringify({ paths: batch }),
|
|
989
|
-
});
|
|
999
|
+
}));
|
|
990
1000
|
results.push(...raw.data);
|
|
991
1001
|
}
|
|
992
1002
|
return results;
|
|
@@ -1112,9 +1122,7 @@ function buildUnifiedDiff(filePath, oldText, newText) {
|
|
|
1112
1122
|
const newLines = newText ? newText.split('\n') : [];
|
|
1113
1123
|
const aPath = oldText ? `a/${filePath}` : '/dev/null';
|
|
1114
1124
|
const bPath = newText ? `b/${filePath}` : '/dev/null';
|
|
1115
|
-
const parts = [
|
|
1116
|
-
`diff --git a/${filePath} b/${filePath}\n`,
|
|
1117
|
-
];
|
|
1125
|
+
const parts = [`diff --git a/${filePath} b/${filePath}\n`];
|
|
1118
1126
|
if (!oldText) {
|
|
1119
1127
|
parts.push('new file mode 100644\n');
|
|
1120
1128
|
}
|
|
@@ -1221,7 +1229,10 @@ async function resolveLocalWikiMount(ctx, wiki) {
|
|
|
1221
1229
|
if (!(await pathExists(root))) {
|
|
1222
1230
|
return null;
|
|
1223
1231
|
}
|
|
1224
|
-
const baseUrl = (ctx.baseUrl ??
|
|
1232
|
+
const baseUrl = (ctx.baseUrl ??
|
|
1233
|
+
process.env.PRLL_WIKI_URL ??
|
|
1234
|
+
process.env.PRLL_API_URL ??
|
|
1235
|
+
'').replace(/\/+$/, '');
|
|
1225
1236
|
const wikiBase = `${baseUrl}/wiki/v1/orgs/${ctx.orgId}/wikis/${wiki.id}`;
|
|
1226
1237
|
return {
|
|
1227
1238
|
root,
|
|
@@ -1379,11 +1390,11 @@ async function collectLocalMarkdownDescriptors(root, allowedPrefixes) {
|
|
|
1379
1390
|
}
|
|
1380
1391
|
async function buildLocalNodeSectionFiles(wiki, root, descriptors, cached) {
|
|
1381
1392
|
const cachedByPath = new Map();
|
|
1382
|
-
if (cached
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1393
|
+
if (cached &&
|
|
1394
|
+
cached.version === LOCAL_NODE_SECTION_ARTIFACT_VERSION &&
|
|
1395
|
+
cached.wiki_id === wiki.id &&
|
|
1396
|
+
cached.wiki_slug === wiki.slug &&
|
|
1397
|
+
cached.wiki_name === wiki.name) {
|
|
1387
1398
|
for (const file of cached.files) {
|
|
1388
1399
|
cachedByPath.set(file.path, file);
|
|
1389
1400
|
}
|
|
@@ -1391,9 +1402,9 @@ async function buildLocalNodeSectionFiles(wiki, root, descriptors, cached) {
|
|
|
1391
1402
|
const files = [];
|
|
1392
1403
|
for (const descriptor of descriptors) {
|
|
1393
1404
|
const existing = cachedByPath.get(descriptor.path);
|
|
1394
|
-
if (existing
|
|
1395
|
-
|
|
1396
|
-
|
|
1405
|
+
if (existing &&
|
|
1406
|
+
existing.size === descriptor.size &&
|
|
1407
|
+
existing.mtime_ms === descriptor.mtime_ms) {
|
|
1397
1408
|
files.push(existing);
|
|
1398
1409
|
continue;
|
|
1399
1410
|
}
|
|
@@ -1434,13 +1445,14 @@ function filterNodeSectionsByPathPrefix(sections, pathPrefix) {
|
|
|
1434
1445
|
if (!pathPrefix) {
|
|
1435
1446
|
return sections;
|
|
1436
1447
|
}
|
|
1437
|
-
return sections.filter((section) =>
|
|
1448
|
+
return sections.filter((section) => section.path === pathPrefix || section.path.startsWith(`${pathPrefix}/`));
|
|
1438
1449
|
}
|
|
1439
1450
|
function countMatchingMarkdownFiles(files, pathPrefix) {
|
|
1440
1451
|
if (!pathPrefix) {
|
|
1441
1452
|
return files.length;
|
|
1442
1453
|
}
|
|
1443
|
-
return files.filter((file) =>
|
|
1454
|
+
return files.filter((file) => file.path === pathPrefix || file.path.startsWith(`${pathPrefix}/`))
|
|
1455
|
+
.length;
|
|
1444
1456
|
}
|
|
1445
1457
|
function countMatchingSectionFiles(sections, pathPrefix) {
|
|
1446
1458
|
const paths = new Set();
|
|
@@ -1552,7 +1564,10 @@ function parseMarkdownFile(wiki, file) {
|
|
|
1552
1564
|
}
|
|
1553
1565
|
const nodes = [];
|
|
1554
1566
|
const firstHeadingLine = headings[0].line;
|
|
1555
|
-
const preface = lines
|
|
1567
|
+
const preface = lines
|
|
1568
|
+
.slice(frontMatterEnd, firstHeadingLine - 1)
|
|
1569
|
+
.join('\n')
|
|
1570
|
+
.trim();
|
|
1556
1571
|
if (preface) {
|
|
1557
1572
|
nodes.push(buildNodeSection(wiki, {
|
|
1558
1573
|
nodeId: `${file.path}:preface`,
|
|
@@ -1576,16 +1591,17 @@ function parseMarkdownFile(wiki, file) {
|
|
|
1576
1591
|
level: current.level,
|
|
1577
1592
|
startLine: current.line,
|
|
1578
1593
|
endLine: nextLine - 1,
|
|
1579
|
-
content: lines
|
|
1594
|
+
content: lines
|
|
1595
|
+
.slice(current.line, nextLine - 1)
|
|
1596
|
+
.join('\n')
|
|
1597
|
+
.trim(),
|
|
1580
1598
|
}));
|
|
1581
1599
|
}
|
|
1582
1600
|
return nodes;
|
|
1583
1601
|
}
|
|
1584
1602
|
function buildNodeSection(wiki, input) {
|
|
1585
1603
|
const content = input.content.trim();
|
|
1586
|
-
const sectionPath = input.headingPath.length > 0
|
|
1587
|
-
? `${input.path} > ${input.headingPath.join(' > ')}`
|
|
1588
|
-
: input.path;
|
|
1604
|
+
const sectionPath = input.headingPath.length > 0 ? `${input.path} > ${input.headingPath.join(' > ')}` : input.path;
|
|
1589
1605
|
return {
|
|
1590
1606
|
wiki_id: wiki.id,
|
|
1591
1607
|
wiki_slug: wiki.slug,
|
|
@@ -1607,7 +1623,9 @@ function buildIndexedNode(section) {
|
|
|
1607
1623
|
section.title,
|
|
1608
1624
|
section.heading_path?.join(' ') ?? '',
|
|
1609
1625
|
section.content,
|
|
1610
|
-
]
|
|
1626
|
+
]
|
|
1627
|
+
.join('\n')
|
|
1628
|
+
.trim();
|
|
1611
1629
|
const termFreq = new Map();
|
|
1612
1630
|
const tokens = tokenize(searchText);
|
|
1613
1631
|
for (const token of tokens) {
|
|
@@ -1735,15 +1753,9 @@ function buildIndexedDocuments(sections) {
|
|
|
1735
1753
|
const documents = [];
|
|
1736
1754
|
for (const [filePath, fileSections] of byPath.entries()) {
|
|
1737
1755
|
fileSections.sort((a, b) => a.start_line - b.start_line);
|
|
1738
|
-
const headings = Array.from(new Set(fileSections
|
|
1739
|
-
.flatMap((section) => section.heading_path ?? [])
|
|
1740
|
-
.filter(Boolean)));
|
|
1756
|
+
const headings = Array.from(new Set(fileSections.flatMap((section) => section.heading_path ?? []).filter(Boolean)));
|
|
1741
1757
|
const title = fileSections.find((section) => section.level === 0)?.title ?? defaultFileTitle(filePath);
|
|
1742
|
-
const searchText = [
|
|
1743
|
-
filePath,
|
|
1744
|
-
title,
|
|
1745
|
-
headings.join(' '),
|
|
1746
|
-
].join('\n').trim();
|
|
1758
|
+
const searchText = [filePath, title, headings.join(' ')].join('\n').trim();
|
|
1747
1759
|
const tokens = tokenize(searchText);
|
|
1748
1760
|
const termFreq = new Map();
|
|
1749
1761
|
for (const token of tokens) {
|
|
@@ -1826,13 +1838,13 @@ function scoreTreeAwareNode(node, queryTokens, lowerQuery, documentScore, scope)
|
|
|
1826
1838
|
}
|
|
1827
1839
|
const matchedAncestors = (node.section.heading_path ?? [])
|
|
1828
1840
|
.slice(0, -1)
|
|
1829
|
-
.filter((heading) => heading.toLowerCase().includes(lowerQuery)
|
|
1830
|
-
|
|
1841
|
+
.filter((heading) => heading.toLowerCase().includes(lowerQuery) ||
|
|
1842
|
+
queryTokens.some((token) => heading.toLowerCase().includes(token)));
|
|
1831
1843
|
if (matchedAncestors.length > 0) {
|
|
1832
1844
|
score += matchedAncestors.length * 1.25;
|
|
1833
1845
|
reasoning.push('ancestor headings match the query context');
|
|
1834
1846
|
}
|
|
1835
|
-
const headingTokenHits = queryTokens.filter((token) => (
|
|
1847
|
+
const headingTokenHits = queryTokens.filter((token) => (node.section.heading_path ?? []).some((heading) => heading.toLowerCase().includes(token))).length;
|
|
1836
1848
|
if (headingTokenHits > 0) {
|
|
1837
1849
|
score += headingTokenHits * 0.6;
|
|
1838
1850
|
reasoning.push('heading path overlaps with query terms');
|
|
@@ -1843,11 +1855,13 @@ function scoreTreeAwareNode(node, queryTokens, lowerQuery, documentScore, scope)
|
|
|
1843
1855
|
return { score, reasoning };
|
|
1844
1856
|
}
|
|
1845
1857
|
function findMatchedHeadings(document, lowerQuery, queryTokens) {
|
|
1846
|
-
return document.headings
|
|
1858
|
+
return document.headings
|
|
1859
|
+
.filter((heading) => {
|
|
1847
1860
|
const lower = heading.toLowerCase();
|
|
1848
|
-
return (lowerQuery && lower.includes(lowerQuery))
|
|
1849
|
-
|
|
1850
|
-
})
|
|
1861
|
+
return ((lowerQuery && lower.includes(lowerQuery)) ||
|
|
1862
|
+
queryTokens.some((token) => lower.includes(token)));
|
|
1863
|
+
})
|
|
1864
|
+
.slice(0, 5);
|
|
1851
1865
|
}
|
|
1852
1866
|
function scoreNode(node, queryTokens, lowerQuery, docFreq, totalDocs, avgDocLen) {
|
|
1853
1867
|
const k1 = 1.5;
|
|
@@ -1863,7 +1877,7 @@ function scoreNode(node, queryTokens, lowerQuery, docFreq, totalDocs, avgDocLen)
|
|
|
1863
1877
|
if (df === 0) {
|
|
1864
1878
|
continue;
|
|
1865
1879
|
}
|
|
1866
|
-
const idf = Math.log(1 + (
|
|
1880
|
+
const idf = Math.log(1 + (totalDocs - df + 0.5) / (df + 0.5));
|
|
1867
1881
|
score += idf * ((tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (docLen / avgDocLen))));
|
|
1868
1882
|
}
|
|
1869
1883
|
if (lowerQuery) {
|
|
@@ -1967,7 +1981,10 @@ function detectFrontMatterEnd(lines) {
|
|
|
1967
1981
|
return 0;
|
|
1968
1982
|
}
|
|
1969
1983
|
function normalizeHeadingTitle(raw) {
|
|
1970
|
-
return raw
|
|
1984
|
+
return raw
|
|
1985
|
+
.replace(TRAILING_FENCE_RE, '')
|
|
1986
|
+
.trim()
|
|
1987
|
+
.replace(/^`+|`+$/g, '');
|
|
1971
1988
|
}
|
|
1972
1989
|
function parseNodeId(nodeId) {
|
|
1973
1990
|
const match = nodeId.match(/^(.*):(doc|preface|L(\d+))$/);
|
|
@@ -2021,7 +2038,9 @@ function normalizeWikiPath(value) {
|
|
|
2021
2038
|
if (!value) {
|
|
2022
2039
|
return '';
|
|
2023
2040
|
}
|
|
2024
|
-
const normalized = toPosix(value.trim())
|
|
2041
|
+
const normalized = toPosix(value.trim())
|
|
2042
|
+
.replace(/^\.?\//, '')
|
|
2043
|
+
.replace(/^\/+/, '');
|
|
2025
2044
|
return normalized === '.' ? '' : normalized.replace(/\/+$/, '');
|
|
2026
2045
|
}
|
|
2027
2046
|
function normalizeRequiredWikiPath(value) {
|
|
@@ -2046,7 +2065,10 @@ function resolveMountPath(mountPath, mountRoot) {
|
|
|
2046
2065
|
? path.resolve(trimmedMountPath)
|
|
2047
2066
|
: path.resolve(absoluteRoot, trimmedMountPath);
|
|
2048
2067
|
const relative = path.relative(absoluteRoot, candidate);
|
|
2049
|
-
if (!relative ||
|
|
2068
|
+
if (!relative ||
|
|
2069
|
+
relative === '.' ||
|
|
2070
|
+
relative === '..' ||
|
|
2071
|
+
relative.startsWith(`..${path.sep}`)) {
|
|
2050
2072
|
throw new Error(`mount path "${mountPath}" escapes PRLL_WIKI_MOUNT_ROOT`);
|
|
2051
2073
|
}
|
|
2052
2074
|
return candidate;
|
|
@@ -2060,7 +2082,10 @@ function resolvePathInsideRoot(root, relativePath) {
|
|
|
2060
2082
|
const normalized = normalizeWikiPath(relativePath);
|
|
2061
2083
|
const candidate = path.resolve(root, normalized);
|
|
2062
2084
|
const relative = path.relative(root, candidate);
|
|
2063
|
-
if (relative === '' ||
|
|
2085
|
+
if (relative === '' ||
|
|
2086
|
+
relative === '.' ||
|
|
2087
|
+
relative === '..' ||
|
|
2088
|
+
relative.startsWith(`..${path.sep}`)) {
|
|
2064
2089
|
throw new Error(`path "${relativePath}" escapes wiki root`);
|
|
2065
2090
|
}
|
|
2066
2091
|
return candidate;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.1",
|
|
4
4
|
"description": "CLI client for Parall — universal agent & human access to Parall API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@modelcontextprotocol/sdk": "1.27.1",
|
|
31
31
|
"commander": "^13.0.0",
|
|
32
32
|
"zod": "^4.3.6",
|
|
33
|
-
"@parall/sdk": "1.
|
|
33
|
+
"@parall/sdk": "1.32.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.0.0",
|