@arbidocs/cli 0.3.33 → 0.3.34
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/CHANGELOG.md +38 -0
- package/dist/index.js +408 -130
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/scripts/bench-upload.mjs +275 -0
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
5
|
+
var fs5 = require('fs');
|
|
6
|
+
var path5 = require('path');
|
|
7
7
|
var os = require('os');
|
|
8
8
|
var chalk2 = require('chalk');
|
|
9
9
|
var sdk = require('@arbidocs/sdk');
|
|
@@ -16,24 +16,24 @@ var module$1 = require('module');
|
|
|
16
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
|
|
19
|
-
var
|
|
20
|
-
var
|
|
19
|
+
var fs5__default = /*#__PURE__*/_interopDefault(fs5);
|
|
20
|
+
var path5__default = /*#__PURE__*/_interopDefault(path5);
|
|
21
21
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
22
22
|
var chalk2__default = /*#__PURE__*/_interopDefault(chalk2);
|
|
23
23
|
|
|
24
24
|
function getCacheFile() {
|
|
25
|
-
const configDir = process.env.ARBI_CONFIG_DIR ??
|
|
26
|
-
return
|
|
25
|
+
const configDir = process.env.ARBI_CONFIG_DIR ?? path5__default.default.join(os__default.default.homedir(), ".arbi");
|
|
26
|
+
return path5__default.default.join(configDir, "completions.json");
|
|
27
27
|
}
|
|
28
28
|
function ensureDir(filePath) {
|
|
29
|
-
const dir =
|
|
30
|
-
if (!
|
|
31
|
-
|
|
29
|
+
const dir = path5__default.default.dirname(filePath);
|
|
30
|
+
if (!fs5__default.default.existsSync(dir)) {
|
|
31
|
+
fs5__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
function getCachedWorkspaceIds() {
|
|
35
35
|
try {
|
|
36
|
-
const content =
|
|
36
|
+
const content = fs5__default.default.readFileSync(getCacheFile(), "utf-8");
|
|
37
37
|
const cache = JSON.parse(content);
|
|
38
38
|
return cache.workspaces.map((w) => w.id);
|
|
39
39
|
} catch {
|
|
@@ -47,7 +47,7 @@ function updateCompletionCache(workspaces3) {
|
|
|
47
47
|
};
|
|
48
48
|
const filePath = getCacheFile();
|
|
49
49
|
ensureDir(filePath);
|
|
50
|
-
|
|
50
|
+
fs5__default.default.writeFileSync(filePath, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// src/completion.ts
|
|
@@ -194,12 +194,12 @@ var ALIAS_LINE = 'alias A="arbi ask"';
|
|
|
194
194
|
var ALIAS_MARKER = "# arbi-cli alias";
|
|
195
195
|
function getShellRcPath() {
|
|
196
196
|
const shell = process.env.SHELL || "";
|
|
197
|
-
if (shell.includes("zsh")) return
|
|
198
|
-
return
|
|
197
|
+
if (shell.includes("zsh")) return path5.join(os.homedir(), ".zshrc");
|
|
198
|
+
return path5.join(os.homedir(), ".bashrc");
|
|
199
199
|
}
|
|
200
200
|
function isAliasInstalled(rcPath) {
|
|
201
|
-
if (!
|
|
202
|
-
const content =
|
|
201
|
+
if (!fs5.existsSync(rcPath)) return false;
|
|
202
|
+
const content = fs5.readFileSync(rcPath, "utf-8");
|
|
203
203
|
return content.includes(ALIAS_LINE) || content.includes(ALIAS_MARKER);
|
|
204
204
|
}
|
|
205
205
|
function registerConfigCommand(program2) {
|
|
@@ -278,7 +278,7 @@ function registerConfigCommand(program2) {
|
|
|
278
278
|
dim("Usage: A what is the meaning of life");
|
|
279
279
|
return;
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
fs5.appendFileSync(rcPath, `
|
|
282
282
|
${ALIAS_MARKER}
|
|
283
283
|
${ALIAS_LINE}
|
|
284
284
|
`);
|
|
@@ -3600,11 +3600,11 @@ async function promptPassword(message) {
|
|
|
3600
3600
|
async function promptConfirm(message, defaultValue = true) {
|
|
3601
3601
|
return prompts.confirm({ message, default: defaultValue });
|
|
3602
3602
|
}
|
|
3603
|
-
var CACHE_FILE =
|
|
3603
|
+
var CACHE_FILE = path5__default.default.join(os__default.default.homedir(), ".arbi", "version-cache.json");
|
|
3604
3604
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3605
3605
|
function readCache() {
|
|
3606
3606
|
try {
|
|
3607
|
-
const data = JSON.parse(
|
|
3607
|
+
const data = JSON.parse(fs5__default.default.readFileSync(CACHE_FILE, "utf8"));
|
|
3608
3608
|
if (data.latest && data.checkedAt && Date.now() - data.checkedAt < CACHE_TTL_MS) {
|
|
3609
3609
|
return data;
|
|
3610
3610
|
}
|
|
@@ -3614,9 +3614,9 @@ function readCache() {
|
|
|
3614
3614
|
}
|
|
3615
3615
|
function writeCache(latest) {
|
|
3616
3616
|
try {
|
|
3617
|
-
const dir =
|
|
3618
|
-
if (!
|
|
3619
|
-
|
|
3617
|
+
const dir = path5__default.default.dirname(CACHE_FILE);
|
|
3618
|
+
if (!fs5__default.default.existsSync(dir)) fs5__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3619
|
+
fs5__default.default.writeFileSync(CACHE_FILE, JSON.stringify({ latest, checkedAt: Date.now() }) + "\n");
|
|
3620
3620
|
} catch {
|
|
3621
3621
|
}
|
|
3622
3622
|
}
|
|
@@ -3637,13 +3637,13 @@ function getLatestVersion(skipCache = false) {
|
|
|
3637
3637
|
}
|
|
3638
3638
|
}
|
|
3639
3639
|
function getCurrentVersion() {
|
|
3640
|
-
return "0.3.
|
|
3640
|
+
return "0.3.34";
|
|
3641
3641
|
}
|
|
3642
3642
|
function readChangelog(fromVersion, toVersion) {
|
|
3643
3643
|
try {
|
|
3644
3644
|
const globalRoot = child_process.execSync("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
3645
|
-
const changelogPath =
|
|
3646
|
-
const text =
|
|
3645
|
+
const changelogPath = path5__default.default.join(globalRoot, "@arbidocs", "cli", "CHANGELOG.md");
|
|
3646
|
+
const text = fs5__default.default.readFileSync(changelogPath, "utf8");
|
|
3647
3647
|
return extractSections(text, fromVersion, toVersion);
|
|
3648
3648
|
} catch {
|
|
3649
3649
|
return null;
|
|
@@ -3690,17 +3690,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3690
3690
|
async function checkForUpdates(autoUpdate) {
|
|
3691
3691
|
try {
|
|
3692
3692
|
const latest = getLatestVersion();
|
|
3693
|
-
if (!latest || latest === "0.3.
|
|
3693
|
+
if (!latest || latest === "0.3.34") return;
|
|
3694
3694
|
if (autoUpdate) {
|
|
3695
3695
|
warn(`
|
|
3696
|
-
Your arbi version is out of date (${"0.3.
|
|
3696
|
+
Your arbi version is out of date (${"0.3.34"} \u2192 ${latest}). Updating...`);
|
|
3697
3697
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3698
|
-
showChangelog("0.3.
|
|
3698
|
+
showChangelog("0.3.34", latest);
|
|
3699
3699
|
console.log(`Updated to ${latest}.`);
|
|
3700
3700
|
} else {
|
|
3701
3701
|
warn(
|
|
3702
3702
|
`
|
|
3703
|
-
Your arbi version is out of date (${"0.3.
|
|
3703
|
+
Your arbi version is out of date (${"0.3.34"} \u2192 ${latest}).
|
|
3704
3704
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3705
3705
|
);
|
|
3706
3706
|
}
|
|
@@ -3710,9 +3710,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
|
3710
3710
|
function hintUpdateOnError() {
|
|
3711
3711
|
try {
|
|
3712
3712
|
const cached = readCache();
|
|
3713
|
-
if (cached && cached.latest !== "0.3.
|
|
3713
|
+
if (cached && cached.latest !== "0.3.34") {
|
|
3714
3714
|
warn(
|
|
3715
|
-
`Your arbi version is out of date (${"0.3.
|
|
3715
|
+
`Your arbi version is out of date (${"0.3.34"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3716
3716
|
);
|
|
3717
3717
|
}
|
|
3718
3718
|
} catch {
|
|
@@ -3721,18 +3721,18 @@ function hintUpdateOnError() {
|
|
|
3721
3721
|
var MAX_TASKS = 50;
|
|
3722
3722
|
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3723
3723
|
function getTasksFile() {
|
|
3724
|
-
const configDir = process.env.ARBI_CONFIG_DIR ??
|
|
3725
|
-
return
|
|
3724
|
+
const configDir = process.env.ARBI_CONFIG_DIR ?? path5__default.default.join(os__default.default.homedir(), ".arbi");
|
|
3725
|
+
return path5__default.default.join(configDir, "tasks.json");
|
|
3726
3726
|
}
|
|
3727
3727
|
function ensureDir2(filePath) {
|
|
3728
|
-
const dir =
|
|
3729
|
-
if (!
|
|
3730
|
-
|
|
3728
|
+
const dir = path5__default.default.dirname(filePath);
|
|
3729
|
+
if (!fs5__default.default.existsSync(dir)) {
|
|
3730
|
+
fs5__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3731
3731
|
}
|
|
3732
3732
|
}
|
|
3733
3733
|
function readTasks() {
|
|
3734
3734
|
try {
|
|
3735
|
-
const content =
|
|
3735
|
+
const content = fs5__default.default.readFileSync(getTasksFile(), "utf-8");
|
|
3736
3736
|
return JSON.parse(content);
|
|
3737
3737
|
} catch {
|
|
3738
3738
|
return [];
|
|
@@ -3741,7 +3741,7 @@ function readTasks() {
|
|
|
3741
3741
|
function writeTasks(tasks) {
|
|
3742
3742
|
const filePath = getTasksFile();
|
|
3743
3743
|
ensureDir2(filePath);
|
|
3744
|
-
|
|
3744
|
+
fs5__default.default.writeFileSync(filePath, JSON.stringify(tasks, null, 2) + "\n", { mode: 384 });
|
|
3745
3745
|
}
|
|
3746
3746
|
function getTasks() {
|
|
3747
3747
|
const now = Date.now();
|
|
@@ -3975,39 +3975,39 @@ function checkAgentDependency(backend) {
|
|
|
3975
3975
|
dim(`${binary} ${match?.[1] ?? version} \u2713`);
|
|
3976
3976
|
}
|
|
3977
3977
|
function loadSkillContent() {
|
|
3978
|
-
const cliRoot =
|
|
3978
|
+
const cliRoot = path5.resolve(path5.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)))), "..");
|
|
3979
3979
|
try {
|
|
3980
|
-
return
|
|
3980
|
+
return fs5.readFileSync(path5.join(cliRoot, "SKILL.md"), "utf-8");
|
|
3981
3981
|
} catch {
|
|
3982
3982
|
return void 0;
|
|
3983
3983
|
}
|
|
3984
3984
|
}
|
|
3985
3985
|
function installSkill(backend) {
|
|
3986
|
-
const cliRoot =
|
|
3986
|
+
const cliRoot = path5.resolve(path5.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)))), "..");
|
|
3987
3987
|
let skillContent;
|
|
3988
3988
|
try {
|
|
3989
|
-
skillContent =
|
|
3989
|
+
skillContent = fs5.readFileSync(path5.join(cliRoot, "SKILL.md"), "utf-8");
|
|
3990
3990
|
} catch {
|
|
3991
3991
|
return;
|
|
3992
3992
|
}
|
|
3993
3993
|
if (backend === "claude") {
|
|
3994
|
-
const dir =
|
|
3995
|
-
const target =
|
|
3994
|
+
const dir = path5.join(os.homedir(), ".claude", "commands", "arbi");
|
|
3995
|
+
const target = path5.join(dir, "SKILL.md");
|
|
3996
3996
|
try {
|
|
3997
|
-
|
|
3998
|
-
if (!
|
|
3999
|
-
|
|
3997
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
3998
|
+
if (!fs5.existsSync(target) || fs5.readFileSync(target, "utf-8") !== skillContent) {
|
|
3999
|
+
fs5.writeFileSync(target, skillContent, "utf-8");
|
|
4000
4000
|
dim(`Installed ARBI skill \u2192 ${target}`);
|
|
4001
4001
|
}
|
|
4002
4002
|
} catch {
|
|
4003
4003
|
}
|
|
4004
4004
|
} else if (backend === "openclaw") {
|
|
4005
|
-
const workspace =
|
|
4006
|
-
const bootstrap =
|
|
4005
|
+
const workspace = path5.join(os.homedir(), ".arbi", "openclaw-workspace");
|
|
4006
|
+
const bootstrap = path5.join(workspace, "BOOTSTRAP.md");
|
|
4007
4007
|
try {
|
|
4008
|
-
|
|
4009
|
-
if (!
|
|
4010
|
-
|
|
4008
|
+
fs5.mkdirSync(workspace, { recursive: true });
|
|
4009
|
+
if (!fs5.existsSync(bootstrap) || fs5.readFileSync(bootstrap, "utf-8") !== skillContent) {
|
|
4010
|
+
fs5.writeFileSync(bootstrap, skillContent, "utf-8");
|
|
4011
4011
|
dim(`Installed ARBI skill \u2192 ${bootstrap}`);
|
|
4012
4012
|
}
|
|
4013
4013
|
} catch {
|
|
@@ -4656,7 +4656,7 @@ function filterDocs(data, opts) {
|
|
|
4656
4656
|
}
|
|
4657
4657
|
return result;
|
|
4658
4658
|
}
|
|
4659
|
-
async function fetchDocChoices(arbi
|
|
4659
|
+
async function fetchDocChoices(arbi) {
|
|
4660
4660
|
const data = await sdk.documents.listDocuments(arbi);
|
|
4661
4661
|
if (data.length === 0) {
|
|
4662
4662
|
console.log("No documents found.");
|
|
@@ -4728,7 +4728,7 @@ function registerDocsCommand(program2) {
|
|
|
4728
4728
|
}
|
|
4729
4729
|
const writeOut = (payload, defaultExt) => {
|
|
4730
4730
|
if (opts.output) {
|
|
4731
|
-
|
|
4731
|
+
fs5.writeFileSync(opts.output, payload.endsWith("\n") ? payload : payload + "\n");
|
|
4732
4732
|
success(`Wrote ${data.length} rows to ${opts.output} (${defaultExt})`);
|
|
4733
4733
|
} else {
|
|
4734
4734
|
console.log(payload.endsWith("\n") ? payload.slice(0, -1) : payload);
|
|
@@ -4818,10 +4818,10 @@ function registerDocsCommand(program2) {
|
|
|
4818
4818
|
const doc = program2.command("doc").description("Document management");
|
|
4819
4819
|
doc.command("get [ids...]").description("Get document details (interactive picker if no IDs given)").action(
|
|
4820
4820
|
(ids) => runAction(async () => {
|
|
4821
|
-
const { arbi
|
|
4821
|
+
const { arbi } = await resolveWorkspace();
|
|
4822
4822
|
let docIds = ids && ids.length > 0 ? ids : void 0;
|
|
4823
4823
|
if (!docIds) {
|
|
4824
|
-
const choices = await fetchDocChoices(arbi
|
|
4824
|
+
const choices = await fetchDocChoices(arbi);
|
|
4825
4825
|
const selected = await promptCheckbox("Select documents", choices);
|
|
4826
4826
|
if (selected.length === 0) return;
|
|
4827
4827
|
docIds = selected;
|
|
@@ -4849,10 +4849,10 @@ function registerDocsCommand(program2) {
|
|
|
4849
4849
|
);
|
|
4850
4850
|
doc.command("delete [ids...]").description("Delete documents (interactive picker if no IDs given)").action(
|
|
4851
4851
|
(ids) => runAction(async () => {
|
|
4852
|
-
const { arbi
|
|
4852
|
+
const { arbi } = await resolveWorkspace();
|
|
4853
4853
|
let docIds = ids && ids.length > 0 ? ids : void 0;
|
|
4854
4854
|
if (!docIds) {
|
|
4855
|
-
const choices = await fetchDocChoices(arbi
|
|
4855
|
+
const choices = await fetchDocChoices(arbi);
|
|
4856
4856
|
const selected = await promptCheckbox("Select documents to delete", choices);
|
|
4857
4857
|
if (selected.length === 0) return;
|
|
4858
4858
|
docIds = selected;
|
|
@@ -4873,8 +4873,8 @@ function registerDocsCommand(program2) {
|
|
|
4873
4873
|
);
|
|
4874
4874
|
success(`Updated ${data.length} document(s).`);
|
|
4875
4875
|
} else {
|
|
4876
|
-
const { arbi
|
|
4877
|
-
const choices = await fetchDocChoices(arbi
|
|
4876
|
+
const { arbi } = await resolveWorkspace();
|
|
4877
|
+
const choices = await fetchDocChoices(arbi);
|
|
4878
4878
|
const docId = await promptSearch("Select document to update", choices);
|
|
4879
4879
|
const field = await promptSelect("Field to update", [
|
|
4880
4880
|
{ name: "Title", value: "title" },
|
|
@@ -5005,12 +5005,16 @@ function registerDocsCommand(program2) {
|
|
|
5005
5005
|
const h = Math.floor(m / 60);
|
|
5006
5006
|
return `${h}h${m % 60}m`;
|
|
5007
5007
|
};
|
|
5008
|
+
const formatClock = (ts) => {
|
|
5009
|
+
const d = new Date(ts);
|
|
5010
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
5011
|
+
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
5012
|
+
};
|
|
5008
5013
|
const printStatus = (prefix = "") => {
|
|
5009
|
-
const
|
|
5014
|
+
const now = Date.now();
|
|
5015
|
+
const elapsed = now - startMs;
|
|
5010
5016
|
const rate = submitted > 0 ? submitted / elapsed * 1e3 : 0;
|
|
5011
|
-
const
|
|
5012
|
-
const etaMs = rate > 0 ? remaining / rate * 1e3 : 0;
|
|
5013
|
-
const bar = `submitted=${submitted}/${total} ok=${succeeded} fail=${failed} rate=${rate.toFixed(1)}/s elapsed=${formatDuration(elapsed)}` + (rate > 0 && remaining > 0 ? ` eta=${formatDuration(etaMs)}` : "");
|
|
5017
|
+
const bar = `[${formatClock(now)}] ${submitted}/${total} patched=${succeeded} failed=${failed} rate=${rate.toFixed(1)}/s elapsed=${formatDuration(elapsed)}`;
|
|
5014
5018
|
console.log(`${prefix}${bar}`);
|
|
5015
5019
|
};
|
|
5016
5020
|
let statusTimer;
|
|
@@ -5098,6 +5102,8 @@ function registerDocsCommand(program2) {
|
|
|
5098
5102
|
})()
|
|
5099
5103
|
);
|
|
5100
5104
|
}
|
|
5105
|
+
|
|
5106
|
+
// src/commands/upload-shared.ts
|
|
5101
5107
|
function printSummary(summary) {
|
|
5102
5108
|
console.log("");
|
|
5103
5109
|
console.log("Upload summary:");
|
|
@@ -5115,24 +5121,296 @@ function printSummary(summary) {
|
|
|
5115
5121
|
}
|
|
5116
5122
|
}
|
|
5117
5123
|
}
|
|
5124
|
+
function countSupportedFiles(dirPath) {
|
|
5125
|
+
let count = 0;
|
|
5126
|
+
for (const entry of fs5__default.default.readdirSync(dirPath, { withFileTypes: true })) {
|
|
5127
|
+
const full = `${dirPath}/${entry.name}`;
|
|
5128
|
+
if (entry.isDirectory()) {
|
|
5129
|
+
count += countSupportedFiles(full);
|
|
5130
|
+
} else if (entry.isFile()) {
|
|
5131
|
+
const ext = path5__default.default.extname(entry.name).toLowerCase();
|
|
5132
|
+
if (sdk.documents.SUPPORTED_EXTENSIONS.has(ext)) count++;
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
return count;
|
|
5136
|
+
}
|
|
5137
|
+
function mergeBatchResult(summary, uploadedDocs, result, sourceLabel, opts) {
|
|
5138
|
+
for (const [folder, info] of result.folders) {
|
|
5139
|
+
summary.folders += 1;
|
|
5140
|
+
summary.totalFiles += info.fileCount;
|
|
5141
|
+
if (!opts.json) {
|
|
5142
|
+
success(
|
|
5143
|
+
` ${folder || "<root>"}: ${info.fileCount} file(s) \u2192 ${info.doc_ext_ids.length} uploaded`
|
|
5144
|
+
);
|
|
5145
|
+
if (info.skipped.length > 0) {
|
|
5146
|
+
warn(` Skipped: ${info.skipped.map((s) => `${s.file_name} (${s.reason})`).join(", ")}`);
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
for (const docId of info.doc_ext_ids) uploadedDocs.set(docId, sourceLabel);
|
|
5150
|
+
}
|
|
5151
|
+
summary.uploaded += result.doc_ext_ids.length;
|
|
5152
|
+
summary.skipped += result.skipped.length;
|
|
5153
|
+
summary.docIds.push(...result.doc_ext_ids);
|
|
5154
|
+
summary.skippedDetails.push(...result.skipped);
|
|
5155
|
+
}
|
|
5156
|
+
function classifyDirectInputs(inputPaths) {
|
|
5157
|
+
const out = [];
|
|
5158
|
+
for (const p of inputPaths) {
|
|
5159
|
+
if (!fs5__default.default.existsSync(p)) {
|
|
5160
|
+
error(`Path not found: ${p}`);
|
|
5161
|
+
process.exit(1);
|
|
5162
|
+
}
|
|
5163
|
+
const resolved = path5__default.default.resolve(p);
|
|
5164
|
+
const stat = fs5__default.default.statSync(resolved);
|
|
5165
|
+
if (stat.isDirectory()) {
|
|
5166
|
+
out.push({ kind: "dir", absolutePath: resolved, originalPath: p });
|
|
5167
|
+
continue;
|
|
5168
|
+
}
|
|
5169
|
+
const ext = path5__default.default.extname(resolved).toLowerCase();
|
|
5170
|
+
if (ext === ".zip") {
|
|
5171
|
+
out.push({ kind: "zip", absolutePath: resolved, originalPath: p });
|
|
5172
|
+
continue;
|
|
5173
|
+
}
|
|
5174
|
+
if (sdk.documentsNode.ARCHIVE_EXTENSIONS.has(ext)) {
|
|
5175
|
+
out.push({ kind: "archive", absolutePath: resolved, originalPath: p });
|
|
5176
|
+
continue;
|
|
5177
|
+
}
|
|
5178
|
+
if (!sdk.documents.SUPPORTED_EXTENSIONS.has(ext)) {
|
|
5179
|
+
warn(`Skipping unsupported file: ${p}`);
|
|
5180
|
+
continue;
|
|
5181
|
+
}
|
|
5182
|
+
out.push({ kind: "file", absolutePath: resolved, originalPath: p });
|
|
5183
|
+
}
|
|
5184
|
+
return out;
|
|
5185
|
+
}
|
|
5186
|
+
async function runDirectUploadMode(inputPaths, opts) {
|
|
5187
|
+
const isInteractive = process.stdout.isTTY === true;
|
|
5188
|
+
const watchPref = getConfig()?.watch !== false;
|
|
5189
|
+
const willWatch = opts.watch === false ? false : opts.watch === true || watchPref && isInteractive;
|
|
5190
|
+
const inputs = classifyDirectInputs(inputPaths);
|
|
5191
|
+
if (inputs.length === 0) {
|
|
5192
|
+
warn("No supported files found to upload.");
|
|
5193
|
+
return;
|
|
5194
|
+
}
|
|
5195
|
+
if (opts.dryRun) {
|
|
5196
|
+
for (const inp of inputs) {
|
|
5197
|
+
if (inp.kind === "file") {
|
|
5198
|
+
const folder = opts.folder ?? "<workspace root>";
|
|
5199
|
+
console.log(` ${inp.originalPath} \u2192 ${folder}`);
|
|
5200
|
+
} else if (inp.kind === "dir") {
|
|
5201
|
+
const count = countSupportedFiles(inp.absolutePath);
|
|
5202
|
+
console.log(` ${inp.originalPath}: directory (${count} supported file(s))`);
|
|
5203
|
+
} else if (inp.kind === "zip") {
|
|
5204
|
+
console.log(` ${inp.originalPath}: zip archive (contents would be extracted + uploaded)`);
|
|
5205
|
+
} else {
|
|
5206
|
+
console.log(
|
|
5207
|
+
` ${inp.originalPath}: ${path5__default.default.extname(inp.absolutePath).slice(1)} archive (contents would be extracted + uploaded)`
|
|
5208
|
+
);
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
console.log(`Would upload ${inputs.length} input(s) via --s3.`);
|
|
5212
|
+
return;
|
|
5213
|
+
}
|
|
5214
|
+
const { arbi, config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace, {
|
|
5215
|
+
skipNotifications: willWatch
|
|
5216
|
+
});
|
|
5217
|
+
const creds = store.requireCredentials();
|
|
5218
|
+
const workspaceKey = await sdk.getRawWorkspaceKey(arbi, workspaceId, creds.signingPrivateKeyBase64);
|
|
5219
|
+
const summary = {
|
|
5220
|
+
totalFiles: 0,
|
|
5221
|
+
uploaded: 0,
|
|
5222
|
+
skipped: 0,
|
|
5223
|
+
duplicates: 0,
|
|
5224
|
+
folders: 0,
|
|
5225
|
+
docIds: [],
|
|
5226
|
+
skippedDetails: []
|
|
5227
|
+
};
|
|
5228
|
+
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
5229
|
+
const directoryOpts = {
|
|
5230
|
+
configExtId: opts.config,
|
|
5231
|
+
onBatchStart: (progress) => {
|
|
5232
|
+
if (!opts.json) {
|
|
5233
|
+
dim(
|
|
5234
|
+
` [${progress.batch}/${progress.totalBatches}] Uploading ${progress.filesInBatch} file(s) from ${progress.folder} via direct-to-MinIO...`
|
|
5235
|
+
);
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
};
|
|
5239
|
+
const plainFiles = [];
|
|
5240
|
+
for (const inp of inputs) {
|
|
5241
|
+
if (inp.kind === "file") {
|
|
5242
|
+
plainFiles.push(inp.absolutePath);
|
|
5243
|
+
continue;
|
|
5244
|
+
}
|
|
5245
|
+
if (inp.kind === "dir") {
|
|
5246
|
+
const result2 = await sdk.documentsNode.uploadLocalDirectoryDirect(
|
|
5247
|
+
arbi,
|
|
5248
|
+
workspaceKey,
|
|
5249
|
+
inp.absolutePath,
|
|
5250
|
+
directoryOpts
|
|
5251
|
+
);
|
|
5252
|
+
if (result2.doc_ext_ids.length === 0 && result2.skipped.length === 0) {
|
|
5253
|
+
warn(`No supported files found in directory: ${inp.originalPath}`);
|
|
5254
|
+
continue;
|
|
5255
|
+
}
|
|
5256
|
+
mergeBatchResult(summary, uploadedDocs, result2, inp.originalPath, opts);
|
|
5257
|
+
if (!opts.json) {
|
|
5258
|
+
success(
|
|
5259
|
+
`Uploaded directory: ${inp.originalPath} (${result2.doc_ext_ids.length} document(s) total)`
|
|
5260
|
+
);
|
|
5261
|
+
}
|
|
5262
|
+
continue;
|
|
5263
|
+
}
|
|
5264
|
+
if (inp.kind === "zip") {
|
|
5265
|
+
const result2 = await sdk.documentsNode.uploadLocalZipDirect(
|
|
5266
|
+
arbi,
|
|
5267
|
+
workspaceKey,
|
|
5268
|
+
inp.absolutePath,
|
|
5269
|
+
directoryOpts
|
|
5270
|
+
);
|
|
5271
|
+
if (result2.doc_ext_ids.length === 0 && result2.skipped.length === 0) {
|
|
5272
|
+
warn(`No supported files found in zip: ${inp.originalPath}`);
|
|
5273
|
+
continue;
|
|
5274
|
+
}
|
|
5275
|
+
mergeBatchResult(summary, uploadedDocs, result2, inp.originalPath, opts);
|
|
5276
|
+
if (!opts.json) {
|
|
5277
|
+
success(
|
|
5278
|
+
`Uploaded zip: ${inp.originalPath} (${result2.doc_ext_ids.length} document(s) total)`
|
|
5279
|
+
);
|
|
5280
|
+
}
|
|
5281
|
+
continue;
|
|
5282
|
+
}
|
|
5283
|
+
const result = await sdk.documentsNode.uploadLocalArchiveDirect(
|
|
5284
|
+
arbi,
|
|
5285
|
+
workspaceKey,
|
|
5286
|
+
inp.absolutePath,
|
|
5287
|
+
directoryOpts
|
|
5288
|
+
);
|
|
5289
|
+
if (result.doc_ext_ids.length === 0 && result.skipped.length === 0) {
|
|
5290
|
+
warn(`No supported files found in archive: ${inp.originalPath}`);
|
|
5291
|
+
continue;
|
|
5292
|
+
}
|
|
5293
|
+
mergeBatchResult(summary, uploadedDocs, result, inp.originalPath, opts);
|
|
5294
|
+
if (!opts.json) {
|
|
5295
|
+
success(
|
|
5296
|
+
`Uploaded archive: ${inp.originalPath} (${result.doc_ext_ids.length} document(s) total)`
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5299
|
+
}
|
|
5300
|
+
if (plainFiles.length > 0) {
|
|
5301
|
+
if (!opts.json) {
|
|
5302
|
+
dim(
|
|
5303
|
+
` Uploading ${plainFiles.length} file(s)${opts.folder ? ` \u2192 ${opts.folder}` : ""} via direct-to-MinIO...`
|
|
5304
|
+
);
|
|
5305
|
+
}
|
|
5306
|
+
const result = await sdk.documentsNode.uploadLocalFilesDirect(arbi, workspaceKey, plainFiles, {
|
|
5307
|
+
folder: opts.folder,
|
|
5308
|
+
configExtId: opts.config
|
|
5309
|
+
});
|
|
5310
|
+
summary.totalFiles += plainFiles.length;
|
|
5311
|
+
summary.uploaded += result.doc_ext_ids.length;
|
|
5312
|
+
summary.skipped += result.skipped.length;
|
|
5313
|
+
summary.docIds.push(...result.doc_ext_ids);
|
|
5314
|
+
summary.skippedDetails.push(...result.skipped);
|
|
5315
|
+
for (let i = 0; i < result.doc_ext_ids.length && i < plainFiles.length; i++) {
|
|
5316
|
+
uploadedDocs.set(result.doc_ext_ids[i], path5__default.default.basename(plainFiles[i]));
|
|
5317
|
+
}
|
|
5318
|
+
if (!opts.json) {
|
|
5319
|
+
success(
|
|
5320
|
+
` ${opts.folder || "<root>"}: ${result.doc_ext_ids.length} uploaded, ${result.skipped.length} skipped`
|
|
5321
|
+
);
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
if (opts.json) {
|
|
5325
|
+
console.log(JSON.stringify(summary));
|
|
5326
|
+
} else {
|
|
5327
|
+
printSummary(summary);
|
|
5328
|
+
}
|
|
5329
|
+
if (willWatch && uploadedDocs.size > 0) {
|
|
5330
|
+
const pending = new Set(uploadedDocs.keys());
|
|
5331
|
+
const failed = /* @__PURE__ */ new Map();
|
|
5332
|
+
console.log(`
|
|
5333
|
+
Watching ${pending.size} document(s)...`);
|
|
5334
|
+
let onDone;
|
|
5335
|
+
const done = new Promise((r) => {
|
|
5336
|
+
onDone = r;
|
|
5337
|
+
});
|
|
5338
|
+
const conn = await sdk.connectWebSocket({
|
|
5339
|
+
baseUrl: config.baseUrl,
|
|
5340
|
+
accessToken,
|
|
5341
|
+
onMessage: (msg) => {
|
|
5342
|
+
if (client.isMessageType(msg, "task_update")) {
|
|
5343
|
+
if (!pending.has(msg.doc_ext_id)) return;
|
|
5344
|
+
const docName = uploadedDocs.get(msg.doc_ext_id) || msg.file_name;
|
|
5345
|
+
const extra = msg;
|
|
5346
|
+
if (msg.status === "failed") {
|
|
5347
|
+
const reason = extra.error_reason || extra.status_details || extra.detail || "Unknown error";
|
|
5348
|
+
failed.set(msg.doc_ext_id, reason);
|
|
5349
|
+
console.log(` ${docName}: ${status(msg.status)} \u2014 ${reason}`);
|
|
5350
|
+
pending.delete(msg.doc_ext_id);
|
|
5351
|
+
} else {
|
|
5352
|
+
console.log(` ${docName}: ${status(msg.status)} (${msg.progress}%)`);
|
|
5353
|
+
if (sdk.DOC_TERMINAL_STATUSES.has(msg.status)) pending.delete(msg.doc_ext_id);
|
|
5354
|
+
}
|
|
5355
|
+
if (pending.size === 0) conn.close();
|
|
5356
|
+
}
|
|
5357
|
+
},
|
|
5358
|
+
onClose: () => {
|
|
5359
|
+
if (failed.size > 0) {
|
|
5360
|
+
error(`
|
|
5361
|
+
${failed.size} document(s) failed to process:`);
|
|
5362
|
+
for (const [docId, reason] of failed) {
|
|
5363
|
+
error(` ${uploadedDocs.get(docId) || docId}: ${reason}`);
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
if (pending.size > 0) {
|
|
5367
|
+
warn(`
|
|
5368
|
+
Connection closed. ${pending.size} document(s) still processing.`);
|
|
5369
|
+
dim('Run "arbi watch" to continue monitoring, or "arbi docs" to check status.');
|
|
5370
|
+
} else if (failed.size === 0 && uploadedDocs.size > 0) {
|
|
5371
|
+
success("\nAll documents processed successfully.");
|
|
5372
|
+
}
|
|
5373
|
+
onDone();
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
5376
|
+
await done;
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
|
|
5380
|
+
// src/commands/upload.ts
|
|
5118
5381
|
function registerUploadCommand(program2) {
|
|
5119
5382
|
program2.command("add [paths...]").alias("upload").description("Add files, directories, or zip archives to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-W, --watch", "Watch document processing progress after upload").option("--no-watch", "Skip watching document processing").option("--dry-run", "Show what would be uploaded without uploading").option("--json", "Output results as JSON").option("--config <id>", "Config ext_id to use (e.g. cfg-xxx for SKIP_DUPLICATES)").option("--manifest <file>", "Read newline-delimited paths from file (eDiscovery mode)").option("--log <file>", "Append per-file JSONL audit log (eDiscovery mode)").option("--resume", "Skip paths already completed in --log (requires --log)").option("--fail-fast", "Abort on first upload error").option("--root <dir>", "Root directory for backend folder paths (defaults to common parent)").option(
|
|
5120
5383
|
"--limit <n>",
|
|
5121
5384
|
"Max files to upload this run (applied after --resume filter, manifest mode only)"
|
|
5122
|
-
).
|
|
5385
|
+
).option(
|
|
5386
|
+
"-s, --s3",
|
|
5387
|
+
"Upload via the direct-to-MinIO flow (SecretBox on the client, presigned PUT)"
|
|
5388
|
+
).option("--folder <name>", "Backend folder for plain-file uploads (direct upload only)").action(
|
|
5123
5389
|
(paths, opts) => runAction(async () => {
|
|
5124
5390
|
const isManifestMode = Boolean(opts.manifest || opts.log || opts.resume);
|
|
5125
5391
|
const inputPaths = paths ?? [];
|
|
5126
5392
|
if (isManifestMode) {
|
|
5393
|
+
if (opts.s3) {
|
|
5394
|
+
error("--s3 is not supported with manifest mode yet.");
|
|
5395
|
+
process.exit(1);
|
|
5396
|
+
}
|
|
5127
5397
|
await runManifestMode(inputPaths, opts);
|
|
5128
5398
|
return;
|
|
5129
5399
|
}
|
|
5400
|
+
if (opts.s3) {
|
|
5401
|
+
if (inputPaths.length === 0) {
|
|
5402
|
+
error("No paths provided.");
|
|
5403
|
+
process.exit(1);
|
|
5404
|
+
}
|
|
5405
|
+
await runDirectUploadMode(inputPaths, opts);
|
|
5406
|
+
return;
|
|
5407
|
+
}
|
|
5130
5408
|
if (inputPaths.length === 0) {
|
|
5131
5409
|
error("No paths provided. Pass file/dir args or use --manifest <file>.");
|
|
5132
5410
|
process.exit(1);
|
|
5133
5411
|
}
|
|
5134
5412
|
for (const p of inputPaths) {
|
|
5135
|
-
if (!
|
|
5413
|
+
if (!fs5__default.default.existsSync(p)) {
|
|
5136
5414
|
error(`Path not found: ${p}`);
|
|
5137
5415
|
process.exit(1);
|
|
5138
5416
|
}
|
|
@@ -5174,10 +5452,10 @@ function registerUploadCommand(program2) {
|
|
|
5174
5452
|
}
|
|
5175
5453
|
};
|
|
5176
5454
|
for (const filePath of inputPaths) {
|
|
5177
|
-
const stat =
|
|
5455
|
+
const stat = fs5__default.default.statSync(filePath);
|
|
5178
5456
|
if (stat.isDirectory()) {
|
|
5179
5457
|
if (opts.dryRun) {
|
|
5180
|
-
const count =
|
|
5458
|
+
const count = countSupportedFiles2(filePath);
|
|
5181
5459
|
console.log(`${filePath}: ${count} supported file(s) would be uploaded`);
|
|
5182
5460
|
summary.totalFiles += count;
|
|
5183
5461
|
continue;
|
|
@@ -5378,12 +5656,12 @@ function updateSummary(summary, result) {
|
|
|
5378
5656
|
summary.docIds.push(...result.doc_ext_ids);
|
|
5379
5657
|
summary.skippedDetails.push(...result.skipped);
|
|
5380
5658
|
}
|
|
5381
|
-
function
|
|
5659
|
+
function countSupportedFiles2(dirPath) {
|
|
5382
5660
|
let count = 0;
|
|
5383
|
-
for (const entry of
|
|
5661
|
+
for (const entry of fs5__default.default.readdirSync(dirPath, { withFileTypes: true })) {
|
|
5384
5662
|
const fullPath = `${dirPath}/${entry.name}`;
|
|
5385
5663
|
if (entry.isDirectory()) {
|
|
5386
|
-
count +=
|
|
5664
|
+
count += countSupportedFiles2(fullPath);
|
|
5387
5665
|
} else if (entry.isFile()) {
|
|
5388
5666
|
const ext = entry.name.toLowerCase().lastIndexOf(".");
|
|
5389
5667
|
if (ext >= 0) {
|
|
@@ -5398,8 +5676,8 @@ function countSupportedFiles(dirPath) {
|
|
|
5398
5676
|
}
|
|
5399
5677
|
function readLogState(logPath) {
|
|
5400
5678
|
const state = /* @__PURE__ */ new Map();
|
|
5401
|
-
if (!
|
|
5402
|
-
const text =
|
|
5679
|
+
if (!fs5__default.default.existsSync(logPath)) return state;
|
|
5680
|
+
const text = fs5__default.default.readFileSync(logPath, "utf8");
|
|
5403
5681
|
for (const line of text.split("\n")) {
|
|
5404
5682
|
const trimmed = line.trim();
|
|
5405
5683
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -5415,7 +5693,7 @@ function readLogState(logPath) {
|
|
|
5415
5693
|
return state;
|
|
5416
5694
|
}
|
|
5417
5695
|
function readTextManifest(manifestPath) {
|
|
5418
|
-
const text =
|
|
5696
|
+
const text = fs5__default.default.readFileSync(manifestPath, "utf8");
|
|
5419
5697
|
const out = [];
|
|
5420
5698
|
for (const raw of text.split("\n")) {
|
|
5421
5699
|
const line = raw.replace(/\r$/, "").trim();
|
|
@@ -5487,8 +5765,8 @@ function writeCsvAtomic(filePath, header, rows) {
|
|
|
5487
5765
|
lines.push(padded.map(csvField).join(","));
|
|
5488
5766
|
}
|
|
5489
5767
|
const tmp = filePath + ".tmp";
|
|
5490
|
-
|
|
5491
|
-
|
|
5768
|
+
fs5__default.default.writeFileSync(tmp, lines.join("\n") + "\n");
|
|
5769
|
+
fs5__default.default.renameSync(tmp, filePath);
|
|
5492
5770
|
}
|
|
5493
5771
|
function findColumn(header, candidates) {
|
|
5494
5772
|
const normalized = header.map((h) => h.trim().toLowerCase());
|
|
@@ -5499,7 +5777,7 @@ function findColumn(header, candidates) {
|
|
|
5499
5777
|
return -1;
|
|
5500
5778
|
}
|
|
5501
5779
|
function loadCsvManifest(csvPath, rootDir) {
|
|
5502
|
-
const text =
|
|
5780
|
+
const text = fs5__default.default.readFileSync(csvPath, "utf8");
|
|
5503
5781
|
const all = parseCsv(text);
|
|
5504
5782
|
if (all.length === 0) {
|
|
5505
5783
|
error(`Empty CSV: ${csvPath}`);
|
|
@@ -5530,7 +5808,7 @@ function loadCsvManifest(csvPath, rootDir) {
|
|
|
5530
5808
|
for (const row of rows) {
|
|
5531
5809
|
while (row.length < header.length) row.push("");
|
|
5532
5810
|
}
|
|
5533
|
-
const root = rootDir ?
|
|
5811
|
+
const root = rootDir ? path5__default.default.resolve(rootDir) : process.cwd();
|
|
5534
5812
|
const paths = [];
|
|
5535
5813
|
const pathToRow = /* @__PURE__ */ new Map();
|
|
5536
5814
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -5538,8 +5816,8 @@ function loadCsvManifest(csvPath, rootDir) {
|
|
|
5538
5816
|
const name = (row[nameCol] ?? "").trim();
|
|
5539
5817
|
if (!name) continue;
|
|
5540
5818
|
const folder = (row[folderCol] ?? "").trim();
|
|
5541
|
-
const rel = folder ?
|
|
5542
|
-
const abs =
|
|
5819
|
+
const rel = folder ? path5__default.default.join(folder, name) : name;
|
|
5820
|
+
const abs = path5__default.default.resolve(root, rel);
|
|
5543
5821
|
paths.push(abs);
|
|
5544
5822
|
pathToRow.set(abs, i);
|
|
5545
5823
|
}
|
|
@@ -5563,11 +5841,11 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5563
5841
|
const rawPaths = [];
|
|
5564
5842
|
let csv = null;
|
|
5565
5843
|
if (opts.manifest) {
|
|
5566
|
-
if (!
|
|
5844
|
+
if (!fs5__default.default.existsSync(opts.manifest)) {
|
|
5567
5845
|
error(`Manifest not found: ${opts.manifest}`);
|
|
5568
5846
|
process.exit(1);
|
|
5569
5847
|
}
|
|
5570
|
-
const ext =
|
|
5848
|
+
const ext = path5__default.default.extname(opts.manifest).toLowerCase();
|
|
5571
5849
|
if (ext === ".csv" || ext === ".tsv") {
|
|
5572
5850
|
csv = loadCsvManifest(opts.manifest, opts.root);
|
|
5573
5851
|
rawPaths.push(...csv.paths);
|
|
@@ -5576,15 +5854,15 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5576
5854
|
}
|
|
5577
5855
|
}
|
|
5578
5856
|
for (const p of inputPaths) {
|
|
5579
|
-
if (!
|
|
5857
|
+
if (!fs5__default.default.existsSync(p)) {
|
|
5580
5858
|
error(`Path not found: ${p}`);
|
|
5581
5859
|
process.exit(1);
|
|
5582
5860
|
}
|
|
5583
|
-
const stat =
|
|
5861
|
+
const stat = fs5__default.default.statSync(p);
|
|
5584
5862
|
if (stat.isDirectory()) {
|
|
5585
5863
|
rawPaths.push(...sdk.documentsNode.walkSupportedFiles(p));
|
|
5586
5864
|
} else {
|
|
5587
|
-
rawPaths.push(
|
|
5865
|
+
rawPaths.push(path5__default.default.resolve(p));
|
|
5588
5866
|
}
|
|
5589
5867
|
}
|
|
5590
5868
|
if (rawPaths.length === 0) {
|
|
@@ -5622,7 +5900,7 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5622
5900
|
const humanOutput = !opts.json;
|
|
5623
5901
|
if (humanOutput) {
|
|
5624
5902
|
console.log(
|
|
5625
|
-
`Manifest: ${rawPaths.length} file(s)` + (csv ? ` from ${
|
|
5903
|
+
`Manifest: ${rawPaths.length} file(s)` + (csv ? ` from ${path5__default.default.basename(csv.filePath)}` : "") + (resumedCount ? ` (${resumedCount} already done, skipping)` : "") + (limit !== null && limitedOut > 0 ? ` (limit=${limit}, ${limitedOut} deferred to next run)` : "")
|
|
5626
5904
|
);
|
|
5627
5905
|
}
|
|
5628
5906
|
if (opts.dryRun) {
|
|
@@ -5651,9 +5929,9 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5651
5929
|
const auth = { baseUrl: config.baseUrl, accessToken };
|
|
5652
5930
|
let logFd = null;
|
|
5653
5931
|
if (opts.log) {
|
|
5654
|
-
const dir =
|
|
5655
|
-
|
|
5656
|
-
logFd =
|
|
5932
|
+
const dir = path5__default.default.dirname(path5__default.default.resolve(opts.log));
|
|
5933
|
+
fs5__default.default.mkdirSync(dir, { recursive: true });
|
|
5934
|
+
logFd = fs5__default.default.openSync(opts.log, "a");
|
|
5657
5935
|
const header = JSON.stringify({
|
|
5658
5936
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5659
5937
|
event: "run_start",
|
|
@@ -5663,8 +5941,8 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5663
5941
|
toUpload: pathsToUpload.length,
|
|
5664
5942
|
resumed: resumedCount
|
|
5665
5943
|
});
|
|
5666
|
-
|
|
5667
|
-
|
|
5944
|
+
fs5__default.default.writeSync(logFd, header + "\n");
|
|
5945
|
+
fs5__default.default.fsyncSync(logFd);
|
|
5668
5946
|
}
|
|
5669
5947
|
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
5670
5948
|
const runStart = Date.now();
|
|
@@ -5681,8 +5959,8 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5681
5959
|
attempt: o.attempt,
|
|
5682
5960
|
...o.batchId ? { batchId: o.batchId } : {}
|
|
5683
5961
|
};
|
|
5684
|
-
|
|
5685
|
-
|
|
5962
|
+
fs5__default.default.writeSync(logFd, JSON.stringify(rec) + "\n");
|
|
5963
|
+
fs5__default.default.fsyncSync(logFd);
|
|
5686
5964
|
};
|
|
5687
5965
|
const total = pathsToUpload.length;
|
|
5688
5966
|
let done = 0;
|
|
@@ -5702,7 +5980,7 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5702
5980
|
};
|
|
5703
5981
|
const printInlineOutcome = (o) => {
|
|
5704
5982
|
if (!humanOutput) return;
|
|
5705
|
-
const name =
|
|
5983
|
+
const name = path5__default.default.basename(o.path);
|
|
5706
5984
|
if (o.status === "rejected") {
|
|
5707
5985
|
clearProgress();
|
|
5708
5986
|
warn(` \u2717 ${name}: ${o.reason}`);
|
|
@@ -5734,7 +6012,7 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5734
6012
|
switch (outcome.status) {
|
|
5735
6013
|
case "uploaded":
|
|
5736
6014
|
uploadedCount++;
|
|
5737
|
-
if (outcome.docId) uploadedDocs.set(outcome.docId,
|
|
6015
|
+
if (outcome.docId) uploadedDocs.set(outcome.docId, path5__default.default.basename(outcome.path));
|
|
5738
6016
|
break;
|
|
5739
6017
|
case "duplicate":
|
|
5740
6018
|
duplicateCount++;
|
|
@@ -5773,9 +6051,9 @@ async function runManifestMode(inputPaths, opts) {
|
|
|
5773
6051
|
...result.summary,
|
|
5774
6052
|
elapsedMs: Date.now() - runStart
|
|
5775
6053
|
});
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
6054
|
+
fs5__default.default.writeSync(logFd, footer + "\n");
|
|
6055
|
+
fs5__default.default.fsyncSync(logFd);
|
|
6056
|
+
fs5__default.default.closeSync(logFd);
|
|
5779
6057
|
}
|
|
5780
6058
|
clearProgress();
|
|
5781
6059
|
if (opts.json) {
|
|
@@ -5864,7 +6142,7 @@ Connection closed. ${pending.size} document(s) still processing.`);
|
|
|
5864
6142
|
function registerDownloadCommand(program2) {
|
|
5865
6143
|
program2.command("download [doc-id]").description("Download a document (interactive picker if no ID given)").option("-o, --output <path>", "Output file path").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
5866
6144
|
(docId, opts) => runAction(async () => {
|
|
5867
|
-
const { arbi, config, accessToken
|
|
6145
|
+
const { arbi, config, accessToken } = await resolveWorkspace(opts.workspace);
|
|
5868
6146
|
if (!docId) {
|
|
5869
6147
|
const data = await sdk.documents.listDocuments(arbi);
|
|
5870
6148
|
if (data.length === 0) {
|
|
@@ -5888,11 +6166,11 @@ function registerDownloadCommand(program2) {
|
|
|
5888
6166
|
const match = disposition.match(/filename[*]?=(?:UTF-8''|"?)([^";]+)/i);
|
|
5889
6167
|
if (match) filename = decodeURIComponent(match[1].replace(/"/g, ""));
|
|
5890
6168
|
}
|
|
5891
|
-
const outputPath = opts.output ||
|
|
6169
|
+
const outputPath = opts.output || path5__default.default.join(process.cwd(), filename);
|
|
5892
6170
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
5893
|
-
|
|
6171
|
+
fs5__default.default.writeFileSync(outputPath, buffer);
|
|
5894
6172
|
success(
|
|
5895
|
-
`Downloaded: ${
|
|
6173
|
+
`Downloaded: ${path5__default.default.basename(outputPath)} (${(buffer.length / (1024 * 1024)).toFixed(1)} MB)`
|
|
5896
6174
|
);
|
|
5897
6175
|
})()
|
|
5898
6176
|
);
|
|
@@ -6557,7 +6835,7 @@ function registerDmCommand(program2) {
|
|
|
6557
6835
|
await dm.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
6558
6836
|
});
|
|
6559
6837
|
}
|
|
6560
|
-
async function fetchTagChoices(arbi
|
|
6838
|
+
async function fetchTagChoices(arbi) {
|
|
6561
6839
|
const data = await sdk.tags.listTags(arbi);
|
|
6562
6840
|
if (data.length === 0) {
|
|
6563
6841
|
console.log("No tags found.");
|
|
@@ -6576,7 +6854,7 @@ function registerTagsCommand(program2) {
|
|
|
6576
6854
|
const tags = program2.command("tags").description("Manage tags");
|
|
6577
6855
|
tags.command("list").description("List tags in the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
6578
6856
|
(opts) => runAction(async () => {
|
|
6579
|
-
const { arbi
|
|
6857
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
6580
6858
|
const data = await sdk.tags.listTags(arbi);
|
|
6581
6859
|
if (data.length === 0) {
|
|
6582
6860
|
console.log("No tags found.");
|
|
@@ -6604,7 +6882,7 @@ function registerTagsCommand(program2) {
|
|
|
6604
6882
|
"checkbox"
|
|
6605
6883
|
).option("-i, --instruction <text>", "Tag instruction").option("--shared", "Make tag shared", false).action(
|
|
6606
6884
|
(name, opts) => runAction(async () => {
|
|
6607
|
-
const { arbi
|
|
6885
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
6608
6886
|
const interactive = !name;
|
|
6609
6887
|
if (!name) {
|
|
6610
6888
|
name = await promptInput("Tag name");
|
|
@@ -6635,9 +6913,9 @@ function registerTagsCommand(program2) {
|
|
|
6635
6913
|
);
|
|
6636
6914
|
tags.command("delete [id]").description("Delete a tag (interactive picker if no ID given)").action(
|
|
6637
6915
|
(id) => runAction(async () => {
|
|
6638
|
-
const { arbi
|
|
6916
|
+
const { arbi } = await resolveWorkspace();
|
|
6639
6917
|
if (!id) {
|
|
6640
|
-
const { choices } = await fetchTagChoices(arbi
|
|
6918
|
+
const { choices } = await fetchTagChoices(arbi);
|
|
6641
6919
|
id = await promptSelect("Select tag to delete", choices);
|
|
6642
6920
|
}
|
|
6643
6921
|
const data = await sdk.tags.deleteTag(arbi, id);
|
|
@@ -6646,9 +6924,9 @@ function registerTagsCommand(program2) {
|
|
|
6646
6924
|
);
|
|
6647
6925
|
tags.command("update [id] [json]").description("Update a tag (interactive picker + form if no args)").action(
|
|
6648
6926
|
(id, json) => runAction(async () => {
|
|
6649
|
-
const { arbi
|
|
6927
|
+
const { arbi } = await resolveWorkspace();
|
|
6650
6928
|
if (!id) {
|
|
6651
|
-
const { choices } = await fetchTagChoices(arbi
|
|
6929
|
+
const { choices } = await fetchTagChoices(arbi);
|
|
6652
6930
|
id = await promptSelect("Select tag to update", choices);
|
|
6653
6931
|
}
|
|
6654
6932
|
let body;
|
|
@@ -6781,7 +7059,7 @@ function registerConversationsCommand(program2) {
|
|
|
6781
7059
|
const conv = program2.command("conversations").description("Manage conversations");
|
|
6782
7060
|
conv.command("list").description("List conversations in the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
6783
7061
|
(opts) => runAction(async () => {
|
|
6784
|
-
const { arbi
|
|
7062
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
6785
7063
|
const data = await sdk.conversations.listConversations(arbi);
|
|
6786
7064
|
if (data.length === 0) {
|
|
6787
7065
|
console.log("No conversations found.");
|
|
@@ -7683,15 +7961,15 @@ compdef _arbi_completions arbi
|
|
|
7683
7961
|
${MARKER_END}`;
|
|
7684
7962
|
function getShellRcPath2() {
|
|
7685
7963
|
const shell = process.env.SHELL || "";
|
|
7686
|
-
if (shell.includes("zsh")) return
|
|
7687
|
-
return
|
|
7964
|
+
if (shell.includes("zsh")) return path5.join(os.homedir(), ".zshrc");
|
|
7965
|
+
return path5.join(os.homedir(), ".bashrc");
|
|
7688
7966
|
}
|
|
7689
7967
|
function isZsh() {
|
|
7690
7968
|
return (process.env.SHELL || "").includes("zsh");
|
|
7691
7969
|
}
|
|
7692
7970
|
function isCompletionInstalled(rcPath) {
|
|
7693
|
-
if (!
|
|
7694
|
-
const content =
|
|
7971
|
+
if (!fs5.existsSync(rcPath)) return false;
|
|
7972
|
+
const content = fs5.readFileSync(rcPath, "utf-8");
|
|
7695
7973
|
return content.includes(MARKER_START);
|
|
7696
7974
|
}
|
|
7697
7975
|
function removeCompletionBlock(content) {
|
|
@@ -7712,7 +7990,7 @@ function registerCompletionCommand(program2) {
|
|
|
7712
7990
|
return;
|
|
7713
7991
|
}
|
|
7714
7992
|
const snippet = isZsh() ? ZSH_COMPLETION : BASH_COMPLETION;
|
|
7715
|
-
|
|
7993
|
+
fs5.appendFileSync(rcPath, snippet + "\n");
|
|
7716
7994
|
success(`Installed tab completion in ${rcPath}`);
|
|
7717
7995
|
dim("");
|
|
7718
7996
|
dim(`Run: source ${rcPath}`);
|
|
@@ -7724,9 +8002,9 @@ function registerCompletionCommand(program2) {
|
|
|
7724
8002
|
dim("Completion is not installed.");
|
|
7725
8003
|
return;
|
|
7726
8004
|
}
|
|
7727
|
-
const content =
|
|
8005
|
+
const content = fs5.readFileSync(rcPath, "utf-8");
|
|
7728
8006
|
const cleaned = removeCompletionBlock(content);
|
|
7729
|
-
|
|
8007
|
+
fs5.writeFileSync(rcPath, cleaned);
|
|
7730
8008
|
success(`Removed tab completion from ${rcPath}`);
|
|
7731
8009
|
dim(`Run: source ${rcPath}`);
|
|
7732
8010
|
});
|
|
@@ -7742,7 +8020,7 @@ function registerCompletionCommand(program2) {
|
|
|
7742
8020
|
function resolvePath(p) {
|
|
7743
8021
|
const raw = p ?? ".";
|
|
7744
8022
|
const expanded = raw.startsWith("~") ? raw.replace("~", os.homedir()) : raw;
|
|
7745
|
-
return
|
|
8023
|
+
return path5.resolve(expanded);
|
|
7746
8024
|
}
|
|
7747
8025
|
function formatSize2(bytes) {
|
|
7748
8026
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -7752,11 +8030,11 @@ function formatSize2(bytes) {
|
|
|
7752
8030
|
}
|
|
7753
8031
|
function registerLocalCommand(program2) {
|
|
7754
8032
|
const local = program2.command("local").description("Local filesystem operations");
|
|
7755
|
-
local.command("ls [path]").description("List files in a directory").option("-l, --long", "Show file sizes and types").action((
|
|
7756
|
-
const dir = resolvePath(
|
|
8033
|
+
local.command("ls [path]").description("List files in a directory").option("-l, --long", "Show file sizes and types").action((path7, opts) => {
|
|
8034
|
+
const dir = resolvePath(path7);
|
|
7757
8035
|
let entries;
|
|
7758
8036
|
try {
|
|
7759
|
-
entries =
|
|
8037
|
+
entries = fs5.readdirSync(dir);
|
|
7760
8038
|
} catch {
|
|
7761
8039
|
console.error(`Cannot read directory: ${dir}`);
|
|
7762
8040
|
process.exit(1);
|
|
@@ -7764,7 +8042,7 @@ function registerLocalCommand(program2) {
|
|
|
7764
8042
|
for (const entry of entries.filter((e) => !e.startsWith(".")).sort()) {
|
|
7765
8043
|
if (opts?.long) {
|
|
7766
8044
|
try {
|
|
7767
|
-
const stat =
|
|
8045
|
+
const stat = fs5.statSync(path5.join(dir, entry));
|
|
7768
8046
|
const type = stat.isDirectory() ? "dir" : "file";
|
|
7769
8047
|
const size = stat.isFile() ? formatSize2(stat.size) : "-";
|
|
7770
8048
|
console.log(`${type.padEnd(5)} ${size.padStart(10)} ${entry}`);
|
|
@@ -7778,7 +8056,7 @@ function registerLocalCommand(program2) {
|
|
|
7778
8056
|
});
|
|
7779
8057
|
local.command("find <pattern>").description('Find files matching a glob (e.g. "**/*.pdf")').option("-d, --dir <path>", "Directory to search in", ".").action((pattern, opts) => {
|
|
7780
8058
|
const dir = resolvePath(opts.dir);
|
|
7781
|
-
const results =
|
|
8059
|
+
const results = fs5.globSync(pattern, { cwd: dir });
|
|
7782
8060
|
if (results.length === 0) {
|
|
7783
8061
|
console.log(`No files matching "${pattern}" in ${dir}`);
|
|
7784
8062
|
return;
|
|
@@ -7791,7 +8069,7 @@ function registerLocalCommand(program2) {
|
|
|
7791
8069
|
const filePath = resolvePath(file);
|
|
7792
8070
|
let content;
|
|
7793
8071
|
try {
|
|
7794
|
-
content =
|
|
8072
|
+
content = fs5.readFileSync(filePath, "utf-8");
|
|
7795
8073
|
} catch {
|
|
7796
8074
|
console.error(`Cannot read file: ${filePath}`);
|
|
7797
8075
|
process.exit(1);
|
|
@@ -7803,10 +8081,10 @@ function registerLocalCommand(program2) {
|
|
|
7803
8081
|
console.log(content);
|
|
7804
8082
|
}
|
|
7805
8083
|
});
|
|
7806
|
-
local.command("tree [path]").description("Show directory tree").option("-d, --depth <n>", "Maximum depth", "3").action((
|
|
7807
|
-
const dir = resolvePath(
|
|
8084
|
+
local.command("tree [path]").description("Show directory tree").option("-d, --depth <n>", "Maximum depth", "3").action((path7, opts) => {
|
|
8085
|
+
const dir = resolvePath(path7);
|
|
7808
8086
|
const maxDepth = parseInt(opts?.depth ?? "3", 10);
|
|
7809
|
-
console.log(
|
|
8087
|
+
console.log(path5.basename(dir) + "/");
|
|
7810
8088
|
printTree(dir, "", maxDepth, 0);
|
|
7811
8089
|
});
|
|
7812
8090
|
}
|
|
@@ -7814,7 +8092,7 @@ function printTree(dir, prefix, maxDepth, depth) {
|
|
|
7814
8092
|
if (depth >= maxDepth) return;
|
|
7815
8093
|
let entries;
|
|
7816
8094
|
try {
|
|
7817
|
-
entries =
|
|
8095
|
+
entries = fs5.readdirSync(dir).filter((e) => !e.startsWith(".")).sort();
|
|
7818
8096
|
} catch {
|
|
7819
8097
|
return;
|
|
7820
8098
|
}
|
|
@@ -7822,10 +8100,10 @@ function printTree(dir, prefix, maxDepth, depth) {
|
|
|
7822
8100
|
const entry = entries[i];
|
|
7823
8101
|
const isLast = i === entries.length - 1;
|
|
7824
8102
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
7825
|
-
const full =
|
|
8103
|
+
const full = path5.join(dir, entry);
|
|
7826
8104
|
let isDir = false;
|
|
7827
8105
|
try {
|
|
7828
|
-
isDir =
|
|
8106
|
+
isDir = fs5.statSync(full).isDirectory();
|
|
7829
8107
|
} catch {
|
|
7830
8108
|
continue;
|
|
7831
8109
|
}
|
|
@@ -7880,7 +8158,7 @@ console.info = (...args) => {
|
|
|
7880
8158
|
_origInfo(...args);
|
|
7881
8159
|
};
|
|
7882
8160
|
var program = new commander.Command();
|
|
7883
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
8161
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.34");
|
|
7884
8162
|
registerConfigCommand(program);
|
|
7885
8163
|
registerLoginCommand(program);
|
|
7886
8164
|
registerRegisterCommand(program);
|