@fairmint/captable-ai 0.1.35 → 0.1.36
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/index.js +223 -81
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18569,8 +18569,8 @@ var COMMAND_REGISTRY = [
|
|
|
18569
18569
|
{
|
|
18570
18570
|
name: "objects revert",
|
|
18571
18571
|
group: "captable",
|
|
18572
|
-
description: "Preview or revert draft objects using backend dependency closure. Execution requires explicit final IDs (<object-id
|
|
18573
|
-
usage: "captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --all] [--json]\ncaptable-ai objects revert (<object-id> | --objects id1,id2,... | --all) [--yes] [--json]",
|
|
18572
|
+
description: "Preview or revert draft objects using backend dependency closure. Execution requires explicit final IDs (<object-id>, --objects or --objects-file) or --all.",
|
|
18573
|
+
usage: "captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --objects-file <path|-> | --all] [--json]\ncaptable-ai objects revert (<object-id> | --objects id1,id2,... | --objects-file <path|-> | --all) [--yes] [--json]",
|
|
18574
18574
|
requiresAuth: true,
|
|
18575
18575
|
requiresPortal: true,
|
|
18576
18576
|
flags: [
|
|
@@ -18584,6 +18584,11 @@ var COMMAND_REGISTRY = [
|
|
|
18584
18584
|
description: "Comma-separated final object IDs to revert selectively.",
|
|
18585
18585
|
type: "string"
|
|
18586
18586
|
},
|
|
18587
|
+
{
|
|
18588
|
+
name: "objects-file",
|
|
18589
|
+
description: "File of final object IDs to revert, one per line (- for stdin).",
|
|
18590
|
+
type: "string"
|
|
18591
|
+
},
|
|
18587
18592
|
{
|
|
18588
18593
|
name: "all",
|
|
18589
18594
|
description: "Revert all pending drafts for the active company.",
|
|
@@ -18693,8 +18698,8 @@ var COMMAND_REGISTRY = [
|
|
|
18693
18698
|
{
|
|
18694
18699
|
name: "commit",
|
|
18695
18700
|
group: "captable",
|
|
18696
|
-
description: "Commit pending draft objects to the cap table. Use --dry-run to preview selected/final IDs without writing. Execution requires --objects with final IDs from preview, or --all. Exits with NOTHING_TO_COMMIT if no drafts exist.",
|
|
18697
|
-
usage: "captable-ai commit --dry-run [--objects id1,id2,...] [--json]\ncaptable-ai commit (--objects id1,id2,... | --all) [--json]",
|
|
18701
|
+
description: "Commit pending draft objects to the cap table. Use --dry-run to preview selected/final IDs without writing. Execution requires --objects or --objects-file with final IDs from preview, or --all. Exits with NOTHING_TO_COMMIT if no drafts exist.",
|
|
18702
|
+
usage: "captable-ai commit --dry-run [--objects id1,id2,... | --objects-file <path|->] [--json]\ncaptable-ai commit (--objects id1,id2,... | --objects-file <path|-> | --all) [--json]",
|
|
18698
18703
|
requiresAuth: true,
|
|
18699
18704
|
requiresPortal: true,
|
|
18700
18705
|
flags: [
|
|
@@ -18712,6 +18717,11 @@ var COMMAND_REGISTRY = [
|
|
|
18712
18717
|
name: "objects",
|
|
18713
18718
|
description: "Comma-separated final object IDs to commit selectively. Use preview.applyObjectIds.",
|
|
18714
18719
|
type: "string"
|
|
18720
|
+
},
|
|
18721
|
+
{
|
|
18722
|
+
name: "objects-file",
|
|
18723
|
+
description: "File of final object IDs to commit, one per line (- for stdin).",
|
|
18724
|
+
type: "string"
|
|
18715
18725
|
}
|
|
18716
18726
|
]
|
|
18717
18727
|
},
|
|
@@ -19291,22 +19301,24 @@ Examples:
|
|
|
19291
19301
|
var HELP_OBJECTS_REVERT = `objects revert \u2014 Preview or revert draft objects
|
|
19292
19302
|
|
|
19293
19303
|
Usage:
|
|
19294
|
-
captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --all] [--json]
|
|
19304
|
+
captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --objects-file <path|-> | --all] [--json]
|
|
19295
19305
|
captable-ai objects revert <object-id> [--yes] [--json]
|
|
19296
19306
|
captable-ai objects revert --objects id1,id2,... [--yes] [--json]
|
|
19307
|
+
captable-ai objects revert --objects-file <path|-> [--yes] [--json]
|
|
19297
19308
|
captable-ai objects revert --all [--yes] [--json]
|
|
19298
19309
|
|
|
19299
19310
|
Previews or reverts draft objects using the backend dependency closure. Preview
|
|
19300
19311
|
returns selected IDs, final IDs, auto-included IDs, invalid IDs, dependency
|
|
19301
19312
|
reasons, blockers, and the applyObjectIds value to use for execution.
|
|
19302
19313
|
|
|
19303
|
-
Execution requires explicit final IDs (<object-id
|
|
19314
|
+
Execution requires explicit final IDs (<object-id>, --objects or --objects-file) or --all.
|
|
19304
19315
|
Use IDs from preview.applyObjectIds when applyObjectIds is not null. Revert-all
|
|
19305
19316
|
prompts for confirmation unless --yes or --json is set.
|
|
19306
19317
|
|
|
19307
19318
|
Options:
|
|
19308
19319
|
--dry-run Preview mode \u2014 no write
|
|
19309
19320
|
--objects IDS Revert specific final object IDs (comma-separated)
|
|
19321
|
+
--objects-file F Read the IDs from a file, one per line (- for stdin); for long lists
|
|
19310
19322
|
--all Revert all pending drafts for the active company
|
|
19311
19323
|
--yes Skip the confirmation prompt (for scripts)
|
|
19312
19324
|
|
|
@@ -19368,14 +19380,14 @@ ${HELP_SCHEMAS_GET}`;
|
|
|
19368
19380
|
var HELP_COMMIT = `commit \u2014 Commit pending drafts to the cap table
|
|
19369
19381
|
|
|
19370
19382
|
Usage:
|
|
19371
|
-
captable-ai commit --dry-run [--objects id1,id2,...] [--json]
|
|
19372
|
-
captable-ai commit (--objects id1,id2,... | --all) [--json]
|
|
19383
|
+
captable-ai commit --dry-run [--objects id1,id2,... | --objects-file <path|->] [--json]
|
|
19384
|
+
captable-ai commit (--objects id1,id2,... | --objects-file <path|-> | --all) [--json]
|
|
19373
19385
|
|
|
19374
19386
|
Previews or commits pending draft objects using the backend dependency closure.
|
|
19375
19387
|
Preview returns selected IDs, final IDs, auto-included IDs, invalid IDs,
|
|
19376
19388
|
dependency reasons, blockers, and the applyObjectIds value to use for execution.
|
|
19377
19389
|
|
|
19378
|
-
Execution requires explicit final IDs (--objects) or --all. Use IDs from
|
|
19390
|
+
Execution requires explicit final IDs (--objects or --objects-file) or --all. Use IDs from
|
|
19379
19391
|
preview.applyObjectIds when applyObjectIds is not null. Exits with
|
|
19380
19392
|
NOTHING_TO_COMMIT if no drafts exist.
|
|
19381
19393
|
|
|
@@ -19385,6 +19397,8 @@ Options:
|
|
|
19385
19397
|
--objects id1,id2,... Commit only specific object IDs (comma-separated). The server
|
|
19386
19398
|
validates that all transitive dependencies are satisfied.
|
|
19387
19399
|
Note: IDs containing commas are not supported.
|
|
19400
|
+
--objects-file F Read the IDs from a file, one per line (- for stdin), for lists too
|
|
19401
|
+
long for one command line. The dry run writes one when it must.
|
|
19388
19402
|
|
|
19389
19403
|
Global:
|
|
19390
19404
|
--json Machine-readable JSON output
|
|
@@ -19609,6 +19623,89 @@ Environment:
|
|
|
19609
19623
|
Global:
|
|
19610
19624
|
--json Machine-readable JSON output`;
|
|
19611
19625
|
|
|
19626
|
+
// src/selection-input.ts
|
|
19627
|
+
import { createHash, randomBytes } from "crypto";
|
|
19628
|
+
import { chmod, mkdir as mkdir2, readFile as readFile2, rename, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
19629
|
+
import { homedir as homedir2 } from "os";
|
|
19630
|
+
import { join as join2 } from "path";
|
|
19631
|
+
var CLI_SELECTION_MAX_BYTES = 1e5;
|
|
19632
|
+
function isPlainId(id) {
|
|
19633
|
+
return id.length > 0 && id === id.trim();
|
|
19634
|
+
}
|
|
19635
|
+
function canSelectInline(objectIds) {
|
|
19636
|
+
if (!objectIds.every((id) => isPlainId(id) && !id.includes(","))) return false;
|
|
19637
|
+
const joined = objectIds.join(",");
|
|
19638
|
+
const quotes = joined.split("'").length - 1;
|
|
19639
|
+
return Buffer.byteLength(`--objects=${joined}`, "utf8") + 2 + quotes * 3 <= CLI_SELECTION_MAX_BYTES;
|
|
19640
|
+
}
|
|
19641
|
+
function canSelectFromFile(objectIds) {
|
|
19642
|
+
return objectIds.every((id) => isPlainId(id) && !/[\r\n]/.test(id));
|
|
19643
|
+
}
|
|
19644
|
+
function parseObjectIdLines(text) {
|
|
19645
|
+
return text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
19646
|
+
}
|
|
19647
|
+
var processSelectionReader = {
|
|
19648
|
+
readFile: (path) => readFile2(path, "utf8"),
|
|
19649
|
+
stdinIsTerminal: () => process.stdin.isTTY === true,
|
|
19650
|
+
// Reads to end of input, like any `-` filter: a pipe that never closes waits, as `cat -` does.
|
|
19651
|
+
readStdin: async () => {
|
|
19652
|
+
const chunks = [];
|
|
19653
|
+
for await (const chunk of process.stdin) {
|
|
19654
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
19655
|
+
}
|
|
19656
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
19657
|
+
}
|
|
19658
|
+
};
|
|
19659
|
+
async function readSelectionIds(source, reader = processSelectionReader) {
|
|
19660
|
+
let text;
|
|
19661
|
+
try {
|
|
19662
|
+
if (source === "-") {
|
|
19663
|
+
if (reader.stdinIsTerminal()) {
|
|
19664
|
+
return {
|
|
19665
|
+
ok: false,
|
|
19666
|
+
message: "--objects-file - reads ids from stdin, but nothing is piped in."
|
|
19667
|
+
};
|
|
19668
|
+
}
|
|
19669
|
+
text = await reader.readStdin();
|
|
19670
|
+
} else {
|
|
19671
|
+
text = await reader.readFile(source);
|
|
19672
|
+
}
|
|
19673
|
+
} catch (error51) {
|
|
19674
|
+
const reason = error51 instanceof Error ? error51.message : String(error51);
|
|
19675
|
+
return { ok: false, message: `Could not read --objects-file ${source}: ${reason}` };
|
|
19676
|
+
}
|
|
19677
|
+
const objectIds = parseObjectIdLines(text);
|
|
19678
|
+
if (objectIds.length === 0) {
|
|
19679
|
+
return {
|
|
19680
|
+
ok: false,
|
|
19681
|
+
message: `The --objects-file ${source === "-" ? "input" : source} must include at least one object ID.`
|
|
19682
|
+
};
|
|
19683
|
+
}
|
|
19684
|
+
return { ok: true, objectIds };
|
|
19685
|
+
}
|
|
19686
|
+
function selectionsDir() {
|
|
19687
|
+
return join2(homedir2(), ".captable-ai", "selections");
|
|
19688
|
+
}
|
|
19689
|
+
async function writeSelectionFile(name, objectIds) {
|
|
19690
|
+
if (!canSelectFromFile(objectIds)) return null;
|
|
19691
|
+
const dir = selectionsDir();
|
|
19692
|
+
const digest = createHash("sha256").update(JSON.stringify(objectIds)).digest("hex").slice(0, 32);
|
|
19693
|
+
const path = join2(dir, `${name.replace(/[^A-Za-z0-9._-]/g, "_")}-${digest}.txt`);
|
|
19694
|
+
const temp = `${path}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
19695
|
+
try {
|
|
19696
|
+
await mkdir2(dir, { recursive: true, mode: 448 });
|
|
19697
|
+
await chmod(dir, 448);
|
|
19698
|
+
await writeFile2(temp, `${objectIds.join("\n")}
|
|
19699
|
+
`, { mode: 384, flag: "wx" });
|
|
19700
|
+
await chmod(temp, 384);
|
|
19701
|
+
await rename(temp, path);
|
|
19702
|
+
return path;
|
|
19703
|
+
} catch {
|
|
19704
|
+
await rm2(temp, { force: true }).catch(() => void 0);
|
|
19705
|
+
return null;
|
|
19706
|
+
}
|
|
19707
|
+
}
|
|
19708
|
+
|
|
19612
19709
|
// src/commands/draft-operations.ts
|
|
19613
19710
|
function parseObjectIdsList(raw) {
|
|
19614
19711
|
if (raw === void 0) return void 0;
|
|
@@ -19617,6 +19714,23 @@ function parseObjectIdsList(raw) {
|
|
|
19617
19714
|
function hasObjectIds(raw, objectIds) {
|
|
19618
19715
|
return raw !== void 0 && (objectIds?.length ?? 0) > 0;
|
|
19619
19716
|
}
|
|
19717
|
+
async function resolveObjectsInput(args, otherSelectorMessage = null, reader = processSelectionReader) {
|
|
19718
|
+
const objectsRaw = getFlagValue(args, "objects");
|
|
19719
|
+
const fileSource = getFlagValue(args, "objects-file");
|
|
19720
|
+
if (objectsRaw !== void 0 && fileSource !== void 0) {
|
|
19721
|
+
return { kind: "invalid", message: "Specify either --objects or --objects-file, not both." };
|
|
19722
|
+
}
|
|
19723
|
+
if (fileSource !== void 0) {
|
|
19724
|
+
if (otherSelectorMessage !== null) return { kind: "invalid", message: otherSelectorMessage };
|
|
19725
|
+
const read = await readSelectionIds(fileSource, reader);
|
|
19726
|
+
return read.ok ? { kind: "ids", objectIds: read.objectIds } : { kind: "invalid", message: read.message };
|
|
19727
|
+
}
|
|
19728
|
+
const objectIds = parseObjectIdsList(objectsRaw);
|
|
19729
|
+
if (objectsRaw !== void 0 && !hasObjectIds(objectsRaw, objectIds)) {
|
|
19730
|
+
return { kind: "invalid", message: "The --objects flag must include at least one object ID." };
|
|
19731
|
+
}
|
|
19732
|
+
return objectIds === void 0 ? { kind: "none" } : { kind: "ids", objectIds };
|
|
19733
|
+
}
|
|
19620
19734
|
function operationPastTense(operation) {
|
|
19621
19735
|
return operation === "commit" ? "committed" : "reverted";
|
|
19622
19736
|
}
|
|
@@ -19667,7 +19781,7 @@ function canApplyRevertAllFallback(data, operation) {
|
|
|
19667
19781
|
function shellQuote(value) {
|
|
19668
19782
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
19669
19783
|
}
|
|
19670
|
-
function printDraftOperationPreview(data, options) {
|
|
19784
|
+
async function printDraftOperationPreview(data, options) {
|
|
19671
19785
|
const applied = operationPastTense(options.operation);
|
|
19672
19786
|
const objectCount = data.finalIds.length;
|
|
19673
19787
|
if (objectCount === 0) {
|
|
@@ -19702,10 +19816,29 @@ Run \`${options.command} --all\` to revert all pending drafts.
|
|
|
19702
19816
|
printLine("\nResolve the reported issues before applying this preview.\n");
|
|
19703
19817
|
return;
|
|
19704
19818
|
}
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
Run \`${
|
|
19819
|
+
if (data.applyObjectIds === null) {
|
|
19820
|
+
printLine(`
|
|
19821
|
+
Run \`${options.command} --all\` to apply this preview.
|
|
19708
19822
|
`);
|
|
19823
|
+
return;
|
|
19824
|
+
}
|
|
19825
|
+
if (canSelectInline(data.applyObjectIds)) {
|
|
19826
|
+
printLine(
|
|
19827
|
+
`
|
|
19828
|
+
Run \`${options.command} --objects=${shellQuote(data.applyObjectIds.join(","))}\` to apply this preview.
|
|
19829
|
+
`
|
|
19830
|
+
);
|
|
19831
|
+
return;
|
|
19832
|
+
}
|
|
19833
|
+
const file2 = await writeSelectionFile(`${options.operation}-apply`, data.applyObjectIds);
|
|
19834
|
+
printLine(
|
|
19835
|
+
file2 ? `
|
|
19836
|
+
These ${data.applyObjectIds.length} IDs cannot be given inline (too many for one command line, or an ID with a comma). They are in ${file2}.
|
|
19837
|
+
Run \`${options.command} --objects-file ${shellQuote(file2)}\` to apply this preview.
|
|
19838
|
+
` : `
|
|
19839
|
+
These ${data.applyObjectIds.length} IDs cannot be put on one command line or in a file as they are (too many, or an ID with surrounding spaces or a line break). Apply this preview from the Studio timeline or the MCP.
|
|
19840
|
+
`
|
|
19841
|
+
);
|
|
19709
19842
|
}
|
|
19710
19843
|
|
|
19711
19844
|
// src/commands/commit.ts
|
|
@@ -19715,8 +19848,8 @@ async function runCommit(args, rawArgv) {
|
|
|
19715
19848
|
`);
|
|
19716
19849
|
process.exit(0);
|
|
19717
19850
|
}
|
|
19718
|
-
validateFlags(args, { flags: ["objects"], booleans: ["all", "dry-run"] });
|
|
19719
|
-
const USAGE2 = "captable-ai commit --dry-run [--objects id1,id2,...] [--json]\ncaptable-ai commit (--objects id1,id2,... | --all) [--json]";
|
|
19851
|
+
validateFlags(args, { flags: ["objects", "objects-file"], booleans: ["all", "dry-run"] });
|
|
19852
|
+
const USAGE2 = "captable-ai commit --dry-run [--objects id1,id2,... | --objects-file <path|->] [--json]\ncaptable-ai commit (--objects id1,id2,... | --objects-file <path|-> | --all) [--json]";
|
|
19720
19853
|
if (args.positional.length > 0) {
|
|
19721
19854
|
exitWithUsage(
|
|
19722
19855
|
`Unexpected argument: ${args.positional[0]}. This command takes no positional arguments.`,
|
|
@@ -19725,14 +19858,14 @@ async function runCommit(args, rawArgv) {
|
|
|
19725
19858
|
}
|
|
19726
19859
|
const dryRun = hasFlag(args, "dry-run");
|
|
19727
19860
|
const all = hasFlag(args, "all");
|
|
19728
|
-
const
|
|
19729
|
-
|
|
19730
|
-
|
|
19731
|
-
|
|
19732
|
-
|
|
19733
|
-
|
|
19861
|
+
const objectsInput = await resolveObjectsInput(
|
|
19862
|
+
args,
|
|
19863
|
+
all ? "Specify either --objects (or --objects-file) or --all, not both." : null
|
|
19864
|
+
);
|
|
19865
|
+
if (objectsInput.kind === "invalid") exitWithUsage(objectsInput.message, USAGE2);
|
|
19866
|
+
const objectIds = objectsInput.kind === "ids" ? objectsInput.objectIds : void 0;
|
|
19734
19867
|
if (all && objectIds) {
|
|
19735
|
-
exitWithUsage("Specify either --objects or --all, not both.", USAGE2);
|
|
19868
|
+
exitWithUsage("Specify either --objects (or --objects-file) or --all, not both.", USAGE2);
|
|
19736
19869
|
}
|
|
19737
19870
|
if (dryRun) {
|
|
19738
19871
|
const portalId2 = await getActivePortalId();
|
|
@@ -19751,7 +19884,7 @@ async function runCommit(args, rawArgv) {
|
|
|
19751
19884
|
printJson({ data: data2 });
|
|
19752
19885
|
return;
|
|
19753
19886
|
}
|
|
19754
|
-
printDraftOperationPreview(data2, { command: "captable-ai commit", operation: "commit" });
|
|
19887
|
+
await printDraftOperationPreview(data2, { command: "captable-ai commit", operation: "commit" });
|
|
19755
19888
|
return;
|
|
19756
19889
|
}
|
|
19757
19890
|
const selection = resolveDraftOperationSelection(
|
|
@@ -20476,12 +20609,12 @@ async function runDocumentsRestartExtraction(args, rawArgv) {
|
|
|
20476
20609
|
|
|
20477
20610
|
// src/jobs/tracker.ts
|
|
20478
20611
|
import { randomUUID } from "crypto";
|
|
20479
|
-
import { appendFile, mkdir as
|
|
20480
|
-
import { homedir as
|
|
20481
|
-
import { join as
|
|
20482
|
-
var CONFIG_DIR2 =
|
|
20483
|
-
var JOBS_FILE =
|
|
20484
|
-
var LOCK_DIR =
|
|
20612
|
+
import { appendFile, mkdir as mkdir3, readFile as readFile3, rename as rename2, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
20613
|
+
import { homedir as homedir3 } from "os";
|
|
20614
|
+
import { join as join3 } from "path";
|
|
20615
|
+
var CONFIG_DIR2 = join3(homedir3(), ".captable-ai");
|
|
20616
|
+
var JOBS_FILE = join3(CONFIG_DIR2, "jobs.jsonl");
|
|
20617
|
+
var LOCK_DIR = join3(CONFIG_DIR2, "jobs.lock");
|
|
20485
20618
|
var VALID_JOB_STATUSES = /* @__PURE__ */ new Set(["submitted", "running", "complete", "failed"]);
|
|
20486
20619
|
var VALID_JOB_KINDS = /* @__PURE__ */ new Set(["extraction"]);
|
|
20487
20620
|
function isRecord3(v) {
|
|
@@ -20492,7 +20625,7 @@ function isJobEntry(value) {
|
|
|
20492
20625
|
return typeof value.id === "string" && typeof value.kind === "string" && VALID_JOB_KINDS.has(value.kind) && typeof value.portalId === "string" && typeof value.submittedAt === "string" && typeof value.status === "string" && VALID_JOB_STATUSES.has(value.status);
|
|
20493
20626
|
}
|
|
20494
20627
|
async function ensureDir() {
|
|
20495
|
-
await
|
|
20628
|
+
await mkdir3(CONFIG_DIR2, { recursive: true, mode: 448 });
|
|
20496
20629
|
}
|
|
20497
20630
|
function sleep(ms) {
|
|
20498
20631
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -20509,7 +20642,7 @@ async function withJobsLock(fn) {
|
|
|
20509
20642
|
const startedAt = Date.now();
|
|
20510
20643
|
for (; ; ) {
|
|
20511
20644
|
try {
|
|
20512
|
-
await
|
|
20645
|
+
await mkdir3(LOCK_DIR, { mode: 448 });
|
|
20513
20646
|
break;
|
|
20514
20647
|
} catch (err) {
|
|
20515
20648
|
if (!isErrno(err, "EEXIST")) throw err;
|
|
@@ -20522,7 +20655,7 @@ async function withJobsLock(fn) {
|
|
|
20522
20655
|
try {
|
|
20523
20656
|
return await fn();
|
|
20524
20657
|
} finally {
|
|
20525
|
-
await
|
|
20658
|
+
await rm3(LOCK_DIR, { recursive: true, force: true });
|
|
20526
20659
|
}
|
|
20527
20660
|
}
|
|
20528
20661
|
function generateJobId() {
|
|
@@ -20537,7 +20670,7 @@ async function appendJob(entry) {
|
|
|
20537
20670
|
async function listJobs(filter) {
|
|
20538
20671
|
let raw;
|
|
20539
20672
|
try {
|
|
20540
|
-
raw = await
|
|
20673
|
+
raw = await readFile3(JOBS_FILE, "utf8");
|
|
20541
20674
|
} catch (err) {
|
|
20542
20675
|
if (!isErrno(err, "ENOENT")) throw err;
|
|
20543
20676
|
return [];
|
|
@@ -20598,10 +20731,10 @@ async function pruneJobs(before) {
|
|
|
20598
20731
|
async function atomicWriteJobs(content) {
|
|
20599
20732
|
const tmp = `${JOBS_FILE}.${process.pid}.${Date.now()}.tmp`;
|
|
20600
20733
|
try {
|
|
20601
|
-
await
|
|
20602
|
-
await
|
|
20734
|
+
await writeFile3(tmp, content, { mode: 384 });
|
|
20735
|
+
await rename2(tmp, JOBS_FILE);
|
|
20603
20736
|
} catch (err) {
|
|
20604
|
-
await
|
|
20737
|
+
await rm3(tmp, { force: true });
|
|
20605
20738
|
throw err;
|
|
20606
20739
|
}
|
|
20607
20740
|
}
|
|
@@ -20778,12 +20911,12 @@ function flagMissingIds(missingIds) {
|
|
|
20778
20911
|
}
|
|
20779
20912
|
|
|
20780
20913
|
// src/commands/documents-upload.ts
|
|
20781
|
-
import { createHash } from "crypto";
|
|
20782
|
-
import { readFile as
|
|
20914
|
+
import { createHash as createHash2 } from "crypto";
|
|
20915
|
+
import { readFile as readFile4, stat } from "fs/promises";
|
|
20783
20916
|
import { basename } from "path";
|
|
20784
20917
|
async function hashFile(path) {
|
|
20785
|
-
const data = await
|
|
20786
|
-
return
|
|
20918
|
+
const data = await readFile4(path);
|
|
20919
|
+
return createHash2("sha256").update(data).digest("hex");
|
|
20787
20920
|
}
|
|
20788
20921
|
async function runDocumentsUpload(args, rawArgv) {
|
|
20789
20922
|
if (rawArgv.includes("--help") || rawArgv.includes("-h")) {
|
|
@@ -20839,7 +20972,7 @@ async function runDocumentsUpload(args, rawArgv) {
|
|
|
20839
20972
|
}
|
|
20840
20973
|
for (const { doc, filePath } of toUpload) {
|
|
20841
20974
|
if (!isJsonMode()) printLine(` \u2191 Uploading ${doc.name}...`);
|
|
20842
|
-
const fileData = await
|
|
20975
|
+
const fileData = await readFile4(filePath);
|
|
20843
20976
|
const putRes = await fetch(doc.presignedUrl, {
|
|
20844
20977
|
method: "PUT",
|
|
20845
20978
|
headers: { "Content-Type": doc.contentType },
|
|
@@ -20890,11 +21023,11 @@ ${successCount}/${results.length} document(s) confirmed.`);
|
|
|
20890
21023
|
}
|
|
20891
21024
|
|
|
20892
21025
|
// src/commands/feedback.ts
|
|
20893
|
-
import { appendFile as appendFile2, mkdir as
|
|
20894
|
-
import { homedir as
|
|
20895
|
-
import { join as
|
|
20896
|
-
var CONFIG_DIR3 =
|
|
20897
|
-
var FEEDBACK_FILE =
|
|
21026
|
+
import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile5, rename as rename3, rm as rm4, writeFile as writeFile4 } from "fs/promises";
|
|
21027
|
+
import { homedir as homedir4 } from "os";
|
|
21028
|
+
import { join as join4 } from "path";
|
|
21029
|
+
var CONFIG_DIR3 = join4(homedir4(), ".captable-ai");
|
|
21030
|
+
var FEEDBACK_FILE = join4(CONFIG_DIR3, "feedback.jsonl");
|
|
20898
21031
|
function isErrno2(err, code) {
|
|
20899
21032
|
return typeof err === "object" && err !== null && "code" in err && err.code === code;
|
|
20900
21033
|
}
|
|
@@ -20963,7 +21096,7 @@ async function runFeedback(args, rawArgv) {
|
|
|
20963
21096
|
if (!text.trim()) {
|
|
20964
21097
|
exitWithUsage("Feedback text cannot be empty.", 'Usage: captable-ai feedback "<message>"');
|
|
20965
21098
|
}
|
|
20966
|
-
await
|
|
21099
|
+
await mkdir4(CONFIG_DIR3, { recursive: true, mode: 448 });
|
|
20967
21100
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), text: text.trim(), sent: false };
|
|
20968
21101
|
await appendFile2(FEEDBACK_FILE, `${JSON.stringify(entry)}
|
|
20969
21102
|
`, { mode: 384 });
|
|
@@ -21046,14 +21179,14 @@ async function runFeedbackSend() {
|
|
|
21046
21179
|
);
|
|
21047
21180
|
}
|
|
21048
21181
|
const updated = entries.map((e) => e.sent ? e : { ...e, sent: true });
|
|
21049
|
-
await
|
|
21182
|
+
await mkdir4(CONFIG_DIR3, { recursive: true, mode: 448 });
|
|
21050
21183
|
const tmp = `${FEEDBACK_FILE}.${process.pid}.${Date.now()}.tmp`;
|
|
21051
21184
|
try {
|
|
21052
|
-
await
|
|
21185
|
+
await writeFile4(tmp, updated.map((e) => `${JSON.stringify(e)}
|
|
21053
21186
|
`).join(""), { mode: 384 });
|
|
21054
|
-
await
|
|
21187
|
+
await rename3(tmp, FEEDBACK_FILE);
|
|
21055
21188
|
} catch (err) {
|
|
21056
|
-
await
|
|
21189
|
+
await rm4(tmp, { force: true });
|
|
21057
21190
|
throw err;
|
|
21058
21191
|
}
|
|
21059
21192
|
if (isJsonMode()) {
|
|
@@ -21065,7 +21198,7 @@ async function runFeedbackSend() {
|
|
|
21065
21198
|
async function readEntries() {
|
|
21066
21199
|
let raw;
|
|
21067
21200
|
try {
|
|
21068
|
-
raw = await
|
|
21201
|
+
raw = await readFile5(FEEDBACK_FILE, "utf8");
|
|
21069
21202
|
} catch (err) {
|
|
21070
21203
|
if (!isErrno2(err, "ENOENT")) {
|
|
21071
21204
|
exitWithError(
|
|
@@ -21283,7 +21416,7 @@ async function fetchTrackedDocuments(portalId, assetIds) {
|
|
|
21283
21416
|
|
|
21284
21417
|
// src/commands/login.ts
|
|
21285
21418
|
import { execFile } from "child_process";
|
|
21286
|
-
import { randomBytes, timingSafeEqual } from "crypto";
|
|
21419
|
+
import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
|
|
21287
21420
|
import { createServer } from "http";
|
|
21288
21421
|
import { platform } from "os";
|
|
21289
21422
|
import { createInterface } from "readline";
|
|
@@ -21396,7 +21529,7 @@ function tryParseLoginPaste(line, expectedState) {
|
|
|
21396
21529
|
async function runLogin(args) {
|
|
21397
21530
|
validateFlags(args, { flags: [], booleans: [] });
|
|
21398
21531
|
const jsonMode2 = isJsonMode();
|
|
21399
|
-
const state =
|
|
21532
|
+
const state = randomBytes2(16).toString("hex");
|
|
21400
21533
|
let settled = false;
|
|
21401
21534
|
let timeoutId;
|
|
21402
21535
|
let rl;
|
|
@@ -22407,16 +22540,19 @@ async function runObjectsRevert(args, rawArgv) {
|
|
|
22407
22540
|
`);
|
|
22408
22541
|
process.exit(0);
|
|
22409
22542
|
}
|
|
22410
|
-
validateFlags(args, { flags: ["objects"], booleans: ["all", "dry-run", "yes"] });
|
|
22543
|
+
validateFlags(args, { flags: ["objects", "objects-file"], booleans: ["all", "dry-run", "yes"] });
|
|
22411
22544
|
const objectIdRaw = args.positional[0];
|
|
22412
22545
|
const objectId = objectIdRaw?.trim();
|
|
22413
22546
|
const all = hasFlag(args, "all");
|
|
22414
22547
|
const dryRun = hasFlag(args, "dry-run");
|
|
22415
22548
|
const yes = hasFlag(args, "yes");
|
|
22416
|
-
const
|
|
22417
|
-
const
|
|
22418
|
-
|
|
22419
|
-
|
|
22549
|
+
const USAGE2 = "captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --objects-file <path|-> | --all] [--json]\ncaptable-ai objects revert (<object-id> | --objects id1,id2,... | --objects-file <path|-> | --all) [--yes] [--json]";
|
|
22550
|
+
const objectsInput = await resolveObjectsInput(
|
|
22551
|
+
args,
|
|
22552
|
+
objectIdRaw !== void 0 || all ? "Specify only one of an object ID, --objects (or --objects-file), or --all." : null
|
|
22553
|
+
);
|
|
22554
|
+
if (objectsInput.kind === "invalid") exitWithUsage(objectsInput.message, USAGE2);
|
|
22555
|
+
const objectIdsFromFlag = objectsInput.kind === "ids" ? objectsInput.objectIds : void 0;
|
|
22420
22556
|
if (args.positional.length > 1) {
|
|
22421
22557
|
exitWithUsage(
|
|
22422
22558
|
`Too many arguments: expected one object ID, got ${args.positional.length}.`,
|
|
@@ -22426,12 +22562,12 @@ async function runObjectsRevert(args, rawArgv) {
|
|
|
22426
22562
|
if (objectIdRaw !== void 0 && !objectId) {
|
|
22427
22563
|
exitWithUsage("Object ID must be a non-empty string.", USAGE2);
|
|
22428
22564
|
}
|
|
22429
|
-
if (objectIdsRaw !== void 0 && !hasExplicitObjectIds) {
|
|
22430
|
-
exitWithUsage("The --objects flag must include at least one object ID.", USAGE2);
|
|
22431
|
-
}
|
|
22432
22565
|
const selectionSources = [Boolean(objectId), Boolean(objectIdsFromFlag), all].filter(Boolean);
|
|
22433
22566
|
if (selectionSources.length > 1) {
|
|
22434
|
-
exitWithUsage(
|
|
22567
|
+
exitWithUsage(
|
|
22568
|
+
"Specify only one of an object ID, --objects (or --objects-file), or --all.",
|
|
22569
|
+
USAGE2
|
|
22570
|
+
);
|
|
22435
22571
|
}
|
|
22436
22572
|
const objectIds = objectId ? [objectId] : objectIdsFromFlag;
|
|
22437
22573
|
if (dryRun) {
|
|
@@ -22450,7 +22586,7 @@ async function runObjectsRevert(args, rawArgv) {
|
|
|
22450
22586
|
printJson({ data: res2.data });
|
|
22451
22587
|
return;
|
|
22452
22588
|
}
|
|
22453
|
-
printDraftOperationPreview(res2.data, {
|
|
22589
|
+
await printDraftOperationPreview(res2.data, {
|
|
22454
22590
|
command: "captable-ai objects revert",
|
|
22455
22591
|
operation: "revert"
|
|
22456
22592
|
});
|
|
@@ -23103,13 +23239,14 @@ async function runImportStart(args) {
|
|
|
23103
23239
|
function scopeFlag(ids) {
|
|
23104
23240
|
return ids && ids.length > 0 ? ` --s3-asset-ids ${ids.join(",")}` : "";
|
|
23105
23241
|
}
|
|
23106
|
-
|
|
23107
|
-
|
|
23108
|
-
|
|
23109
|
-
|
|
23242
|
+
function selectionTooLong(action) {
|
|
23243
|
+
return (action.id === "preview_commit" || action.id === "confirm_commit") && action.objectIds !== void 0 && !canSelectInline(action.objectIds);
|
|
23244
|
+
}
|
|
23245
|
+
function importStatusCommand(action, sessionId, selectionFile) {
|
|
23246
|
+
if (selectionTooLong(action) && selectionFile === null) {
|
|
23110
23247
|
return {
|
|
23111
23248
|
id: action.id,
|
|
23112
|
-
label: `This import has ${action.objectIds?.length ?? 0} drafts, too many to select on one command line. Commit them from the Studio timeline, or with the MCP. Not --all: the portal also has pending drafts from other sources.`,
|
|
23249
|
+
label: `This import has ${action.objectIds?.length ?? 0} drafts, too many to select on one command line, and they could not be written to a file. Commit them from the Studio timeline, or with the MCP. Not --all: the portal also has pending drafts from other sources.`,
|
|
23113
23250
|
required: action.required
|
|
23114
23251
|
};
|
|
23115
23252
|
}
|
|
@@ -23139,7 +23276,8 @@ function importStatusCommand(action, sessionId) {
|
|
|
23139
23276
|
return `captable-ai objects list --status draft --ids=${shellQuote(reviewable.join(","))}`;
|
|
23140
23277
|
}
|
|
23141
23278
|
case "preview_commit":
|
|
23142
|
-
|
|
23279
|
+
if (!action.objectIds) return "captable-ai commit --dry-run";
|
|
23280
|
+
return selectionTooLong(action) && selectionFile !== null ? `captable-ai commit --dry-run --objects-file ${shellQuote(selectionFile)}` : `captable-ai commit --dry-run --objects=${shellQuote(action.objectIds.join(","))}`;
|
|
23143
23281
|
case "confirm_commit":
|
|
23144
23282
|
return action.objectIds ? "captable-ai commit --objects <final IDs from the dry run>" : "captable-ai commit --all";
|
|
23145
23283
|
default: {
|
|
@@ -23233,7 +23371,11 @@ async function runImportStatus(args) {
|
|
|
23233
23371
|
response.data.session = { ...response.data.session, ...completed.data.session };
|
|
23234
23372
|
}
|
|
23235
23373
|
}
|
|
23236
|
-
const
|
|
23374
|
+
const longSelection = plan.actions.find(selectionTooLong)?.objectIds;
|
|
23375
|
+
const selectionFile = longSelection ? await writeSelectionFile(`import-${sessionId}`, longSelection) : null;
|
|
23376
|
+
const nextActions = plan.actions.map(
|
|
23377
|
+
(action) => importStatusCommand(action, sessionId, selectionFile)
|
|
23378
|
+
);
|
|
23237
23379
|
const suggestMonitoring = shouldSuggestBackgroundMonitoring(plan.phase);
|
|
23238
23380
|
const data = {
|
|
23239
23381
|
...response.data,
|
|
@@ -23457,11 +23599,11 @@ function formatNumber(n) {
|
|
|
23457
23599
|
}
|
|
23458
23600
|
|
|
23459
23601
|
// src/profiles.ts
|
|
23460
|
-
import { mkdir as
|
|
23461
|
-
import { homedir as
|
|
23462
|
-
import { join as
|
|
23463
|
-
var CONFIG_DIR4 =
|
|
23464
|
-
var PROFILES_FILE =
|
|
23602
|
+
import { mkdir as mkdir5, readFile as readFile6, rename as rename4, rm as rm5, writeFile as writeFile5 } from "fs/promises";
|
|
23603
|
+
import { homedir as homedir5 } from "os";
|
|
23604
|
+
import { join as join5 } from "path";
|
|
23605
|
+
var CONFIG_DIR4 = join5(homedir5(), ".captable-ai");
|
|
23606
|
+
var PROFILES_FILE = join5(CONFIG_DIR4, "profiles.json");
|
|
23465
23607
|
function isRecord9(value) {
|
|
23466
23608
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23467
23609
|
}
|
|
@@ -23489,7 +23631,7 @@ function parseProfiles(raw) {
|
|
|
23489
23631
|
}
|
|
23490
23632
|
async function readProfiles() {
|
|
23491
23633
|
try {
|
|
23492
|
-
const raw = await
|
|
23634
|
+
const raw = await readFile6(PROFILES_FILE, "utf8");
|
|
23493
23635
|
return parseProfiles(raw);
|
|
23494
23636
|
} catch (err) {
|
|
23495
23637
|
if (isErrno3(err, "ENOENT")) return { profiles: {}, default: null };
|
|
@@ -23503,13 +23645,13 @@ async function readProfiles() {
|
|
|
23503
23645
|
}
|
|
23504
23646
|
async function writeProfiles(data) {
|
|
23505
23647
|
try {
|
|
23506
|
-
await
|
|
23648
|
+
await mkdir5(CONFIG_DIR4, { recursive: true, mode: 448 });
|
|
23507
23649
|
const tmp = `${PROFILES_FILE}.${process.pid}.${Date.now()}.tmp`;
|
|
23508
23650
|
try {
|
|
23509
|
-
await
|
|
23510
|
-
await
|
|
23651
|
+
await writeFile5(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
23652
|
+
await rename4(tmp, PROFILES_FILE);
|
|
23511
23653
|
} catch (err) {
|
|
23512
|
-
await
|
|
23654
|
+
await rm5(tmp, { force: true });
|
|
23513
23655
|
throw err;
|
|
23514
23656
|
}
|
|
23515
23657
|
} catch (err) {
|
package/package.json
CHANGED