@cerefox/memory 1.0.6 → 1.1.0-beta.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/AGENT_QUICK_REFERENCE.md +11 -2
- package/dist/bin/cerefox.js +808 -184
- package/dist/frontend/assets/index-BMFGsK0D.js +121 -0
- package/dist/frontend/assets/index-BMFGsK0D.js.map +1 -0
- package/dist/frontend/assets/index-C1JXZA9m.css +1 -0
- package/dist/frontend/index.html +2 -2
- package/dist/server-assets/_shared/ef-meta/index.ts +2 -2
- package/dist/server-assets/_shared/mcp-tools/_utils.ts +26 -0
- package/dist/server-assets/_shared/mcp-tools/get-help-content.ts +4 -4
- package/dist/server-assets/_shared/mcp-tools/index.ts +11 -0
- package/dist/server-assets/_shared/mcp-tools/relations.ts +284 -0
- package/dist/server-assets/_shared/mcp-tools/search.ts +14 -8
- package/dist/server-assets/db/migrations/0014_document_relations.sql +59 -0
- package/dist/server-assets/db/rpcs.sql +292 -14
- package/dist/server-assets/db/schema.sql +35 -2
- package/docs/guides/configuration.md +15 -0
- package/docs/guides/setup-local.md +3 -1
- package/docs/guides/upgrading.md +1 -1
- package/package.json +3 -3
- package/dist/frontend/assets/index-Asx5wD7g.css +0 -1
- package/dist/frontend/assets/index-VeqA60-v.js +0 -125
- package/dist/frontend/assets/index-VeqA60-v.js.map +0 -1
package/dist/bin/cerefox.js
CHANGED
|
@@ -5340,7 +5340,7 @@ var init_cli_core = __esm(() => {
|
|
|
5340
5340
|
init_prompts();
|
|
5341
5341
|
});
|
|
5342
5342
|
|
|
5343
|
-
// ../../node_modules/.bun/commander@
|
|
5343
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/error.js
|
|
5344
5344
|
var require_error = __commonJS((exports) => {
|
|
5345
5345
|
class CommanderError extends Error {
|
|
5346
5346
|
constructor(exitCode, code, message) {
|
|
@@ -5364,7 +5364,7 @@ var require_error = __commonJS((exports) => {
|
|
|
5364
5364
|
exports.InvalidArgumentError = InvalidArgumentError;
|
|
5365
5365
|
});
|
|
5366
5366
|
|
|
5367
|
-
// ../../node_modules/.bun/commander@
|
|
5367
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/argument.js
|
|
5368
5368
|
var require_argument = __commonJS((exports) => {
|
|
5369
5369
|
var { InvalidArgumentError } = require_error();
|
|
5370
5370
|
|
|
@@ -5390,7 +5390,7 @@ var require_argument = __commonJS((exports) => {
|
|
|
5390
5390
|
this._name = name;
|
|
5391
5391
|
break;
|
|
5392
5392
|
}
|
|
5393
|
-
if (this._name.
|
|
5393
|
+
if (this._name.endsWith("...")) {
|
|
5394
5394
|
this.variadic = true;
|
|
5395
5395
|
this._name = this._name.slice(0, -3);
|
|
5396
5396
|
}
|
|
@@ -5398,11 +5398,12 @@ var require_argument = __commonJS((exports) => {
|
|
|
5398
5398
|
name() {
|
|
5399
5399
|
return this._name;
|
|
5400
5400
|
}
|
|
5401
|
-
|
|
5401
|
+
_collectValue(value, previous) {
|
|
5402
5402
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
5403
5403
|
return [value];
|
|
5404
5404
|
}
|
|
5405
|
-
|
|
5405
|
+
previous.push(value);
|
|
5406
|
+
return previous;
|
|
5406
5407
|
}
|
|
5407
5408
|
default(value, description) {
|
|
5408
5409
|
this.defaultValue = value;
|
|
@@ -5420,7 +5421,7 @@ var require_argument = __commonJS((exports) => {
|
|
|
5420
5421
|
throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
|
|
5421
5422
|
}
|
|
5422
5423
|
if (this.variadic) {
|
|
5423
|
-
return this.
|
|
5424
|
+
return this._collectValue(arg, previous);
|
|
5424
5425
|
}
|
|
5425
5426
|
return arg;
|
|
5426
5427
|
};
|
|
@@ -5443,17 +5444,21 @@ var require_argument = __commonJS((exports) => {
|
|
|
5443
5444
|
exports.humanReadableArgName = humanReadableArgName;
|
|
5444
5445
|
});
|
|
5445
5446
|
|
|
5446
|
-
// ../../node_modules/.bun/commander@
|
|
5447
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/help.js
|
|
5447
5448
|
var require_help = __commonJS((exports) => {
|
|
5448
5449
|
var { humanReadableArgName } = require_argument();
|
|
5449
5450
|
|
|
5450
5451
|
class Help {
|
|
5451
5452
|
constructor() {
|
|
5452
5453
|
this.helpWidth = undefined;
|
|
5454
|
+
this.minWidthToWrap = 40;
|
|
5453
5455
|
this.sortSubcommands = false;
|
|
5454
5456
|
this.sortOptions = false;
|
|
5455
5457
|
this.showGlobalOptions = false;
|
|
5456
5458
|
}
|
|
5459
|
+
prepareContext(contextOptions) {
|
|
5460
|
+
this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
|
|
5461
|
+
}
|
|
5457
5462
|
visibleCommands(cmd) {
|
|
5458
5463
|
const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
|
|
5459
5464
|
const helpCommand = cmd._getHelpCommand();
|
|
@@ -5528,22 +5533,22 @@ var require_help = __commonJS((exports) => {
|
|
|
5528
5533
|
}
|
|
5529
5534
|
longestSubcommandTermLength(cmd, helper) {
|
|
5530
5535
|
return helper.visibleCommands(cmd).reduce((max, command) => {
|
|
5531
|
-
return Math.max(max, helper.subcommandTerm(command)
|
|
5536
|
+
return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
|
|
5532
5537
|
}, 0);
|
|
5533
5538
|
}
|
|
5534
5539
|
longestOptionTermLength(cmd, helper) {
|
|
5535
5540
|
return helper.visibleOptions(cmd).reduce((max, option) => {
|
|
5536
|
-
return Math.max(max, helper.optionTerm(option)
|
|
5541
|
+
return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
|
|
5537
5542
|
}, 0);
|
|
5538
5543
|
}
|
|
5539
5544
|
longestGlobalOptionTermLength(cmd, helper) {
|
|
5540
5545
|
return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
|
|
5541
|
-
return Math.max(max, helper.optionTerm(option)
|
|
5546
|
+
return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
|
|
5542
5547
|
}, 0);
|
|
5543
5548
|
}
|
|
5544
5549
|
longestArgumentTermLength(cmd, helper) {
|
|
5545
5550
|
return helper.visibleArguments(cmd).reduce((max, argument) => {
|
|
5546
|
-
return Math.max(max, helper.argumentTerm(argument)
|
|
5551
|
+
return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
|
|
5547
5552
|
}, 0);
|
|
5548
5553
|
}
|
|
5549
5554
|
commandUsage(cmd) {
|
|
@@ -5581,7 +5586,11 @@ var require_help = __commonJS((exports) => {
|
|
|
5581
5586
|
extraInfo.push(`env: ${option.envVar}`);
|
|
5582
5587
|
}
|
|
5583
5588
|
if (extraInfo.length > 0) {
|
|
5584
|
-
|
|
5589
|
+
const extraDescription = `(${extraInfo.join(", ")})`;
|
|
5590
|
+
if (option.description) {
|
|
5591
|
+
return `${option.description} ${extraDescription}`;
|
|
5592
|
+
}
|
|
5593
|
+
return extraDescription;
|
|
5585
5594
|
}
|
|
5586
5595
|
return option.description;
|
|
5587
5596
|
}
|
|
@@ -5594,105 +5603,205 @@ var require_help = __commonJS((exports) => {
|
|
|
5594
5603
|
extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
|
|
5595
5604
|
}
|
|
5596
5605
|
if (extraInfo.length > 0) {
|
|
5597
|
-
const
|
|
5606
|
+
const extraDescription = `(${extraInfo.join(", ")})`;
|
|
5598
5607
|
if (argument.description) {
|
|
5599
|
-
return `${argument.description} ${
|
|
5608
|
+
return `${argument.description} ${extraDescription}`;
|
|
5600
5609
|
}
|
|
5601
|
-
return
|
|
5610
|
+
return extraDescription;
|
|
5602
5611
|
}
|
|
5603
5612
|
return argument.description;
|
|
5604
5613
|
}
|
|
5614
|
+
formatItemList(heading, items, helper) {
|
|
5615
|
+
if (items.length === 0)
|
|
5616
|
+
return [];
|
|
5617
|
+
return [helper.styleTitle(heading), ...items, ""];
|
|
5618
|
+
}
|
|
5619
|
+
groupItems(unsortedItems, visibleItems, getGroup) {
|
|
5620
|
+
const result = new Map;
|
|
5621
|
+
unsortedItems.forEach((item) => {
|
|
5622
|
+
const group = getGroup(item);
|
|
5623
|
+
if (!result.has(group))
|
|
5624
|
+
result.set(group, []);
|
|
5625
|
+
});
|
|
5626
|
+
visibleItems.forEach((item) => {
|
|
5627
|
+
const group = getGroup(item);
|
|
5628
|
+
if (!result.has(group)) {
|
|
5629
|
+
result.set(group, []);
|
|
5630
|
+
}
|
|
5631
|
+
result.get(group).push(item);
|
|
5632
|
+
});
|
|
5633
|
+
return result;
|
|
5634
|
+
}
|
|
5605
5635
|
formatHelp(cmd, helper) {
|
|
5606
5636
|
const termWidth = helper.padWidth(cmd, helper);
|
|
5607
|
-
const helpWidth = helper.helpWidth
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
function formatItem(term, description) {
|
|
5611
|
-
if (description) {
|
|
5612
|
-
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
5613
|
-
return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
|
|
5614
|
-
}
|
|
5615
|
-
return term;
|
|
5616
|
-
}
|
|
5617
|
-
function formatList(textArray) {
|
|
5618
|
-
return textArray.join(`
|
|
5619
|
-
`).replace(/^/gm, " ".repeat(itemIndentWidth));
|
|
5637
|
+
const helpWidth = helper.helpWidth ?? 80;
|
|
5638
|
+
function callFormatItem(term, description) {
|
|
5639
|
+
return helper.formatItem(term, termWidth, description, helper);
|
|
5620
5640
|
}
|
|
5621
|
-
let output = [
|
|
5641
|
+
let output = [
|
|
5642
|
+
`${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
|
|
5643
|
+
""
|
|
5644
|
+
];
|
|
5622
5645
|
const commandDescription = helper.commandDescription(cmd);
|
|
5623
5646
|
if (commandDescription.length > 0) {
|
|
5624
5647
|
output = output.concat([
|
|
5625
|
-
helper.
|
|
5648
|
+
helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth),
|
|
5626
5649
|
""
|
|
5627
5650
|
]);
|
|
5628
5651
|
}
|
|
5629
5652
|
const argumentList = helper.visibleArguments(cmd).map((argument) => {
|
|
5630
|
-
return
|
|
5653
|
+
return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument)));
|
|
5631
5654
|
});
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5655
|
+
output = output.concat(this.formatItemList("Arguments:", argumentList, helper));
|
|
5656
|
+
const optionGroups = this.groupItems(cmd.options, helper.visibleOptions(cmd), (option) => option.helpGroupHeading ?? "Options:");
|
|
5657
|
+
optionGroups.forEach((options, group) => {
|
|
5658
|
+
const optionList = options.map((option) => {
|
|
5659
|
+
return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
|
|
5660
|
+
});
|
|
5661
|
+
output = output.concat(this.formatItemList(group, optionList, helper));
|
|
5637
5662
|
});
|
|
5638
|
-
if (
|
|
5639
|
-
output = output.concat(["Options:", formatList(optionList), ""]);
|
|
5640
|
-
}
|
|
5641
|
-
if (this.showGlobalOptions) {
|
|
5663
|
+
if (helper.showGlobalOptions) {
|
|
5642
5664
|
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
|
|
5643
|
-
return
|
|
5665
|
+
return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
|
|
5644
5666
|
});
|
|
5645
|
-
|
|
5646
|
-
output = output.concat([
|
|
5647
|
-
"Global Options:",
|
|
5648
|
-
formatList(globalOptionList),
|
|
5649
|
-
""
|
|
5650
|
-
]);
|
|
5651
|
-
}
|
|
5667
|
+
output = output.concat(this.formatItemList("Global Options:", globalOptionList, helper));
|
|
5652
5668
|
}
|
|
5653
|
-
const
|
|
5654
|
-
|
|
5669
|
+
const commandGroups = this.groupItems(cmd.commands, helper.visibleCommands(cmd), (sub) => sub.helpGroup() || "Commands:");
|
|
5670
|
+
commandGroups.forEach((commands, group) => {
|
|
5671
|
+
const commandList = commands.map((sub) => {
|
|
5672
|
+
return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)), helper.styleSubcommandDescription(helper.subcommandDescription(sub)));
|
|
5673
|
+
});
|
|
5674
|
+
output = output.concat(this.formatItemList(group, commandList, helper));
|
|
5655
5675
|
});
|
|
5656
|
-
if (commandList.length > 0) {
|
|
5657
|
-
output = output.concat(["Commands:", formatList(commandList), ""]);
|
|
5658
|
-
}
|
|
5659
5676
|
return output.join(`
|
|
5660
5677
|
`);
|
|
5661
5678
|
}
|
|
5679
|
+
displayWidth(str) {
|
|
5680
|
+
return stripColor(str).length;
|
|
5681
|
+
}
|
|
5682
|
+
styleTitle(str) {
|
|
5683
|
+
return str;
|
|
5684
|
+
}
|
|
5685
|
+
styleUsage(str) {
|
|
5686
|
+
return str.split(" ").map((word) => {
|
|
5687
|
+
if (word === "[options]")
|
|
5688
|
+
return this.styleOptionText(word);
|
|
5689
|
+
if (word === "[command]")
|
|
5690
|
+
return this.styleSubcommandText(word);
|
|
5691
|
+
if (word[0] === "[" || word[0] === "<")
|
|
5692
|
+
return this.styleArgumentText(word);
|
|
5693
|
+
return this.styleCommandText(word);
|
|
5694
|
+
}).join(" ");
|
|
5695
|
+
}
|
|
5696
|
+
styleCommandDescription(str) {
|
|
5697
|
+
return this.styleDescriptionText(str);
|
|
5698
|
+
}
|
|
5699
|
+
styleOptionDescription(str) {
|
|
5700
|
+
return this.styleDescriptionText(str);
|
|
5701
|
+
}
|
|
5702
|
+
styleSubcommandDescription(str) {
|
|
5703
|
+
return this.styleDescriptionText(str);
|
|
5704
|
+
}
|
|
5705
|
+
styleArgumentDescription(str) {
|
|
5706
|
+
return this.styleDescriptionText(str);
|
|
5707
|
+
}
|
|
5708
|
+
styleDescriptionText(str) {
|
|
5709
|
+
return str;
|
|
5710
|
+
}
|
|
5711
|
+
styleOptionTerm(str) {
|
|
5712
|
+
return this.styleOptionText(str);
|
|
5713
|
+
}
|
|
5714
|
+
styleSubcommandTerm(str) {
|
|
5715
|
+
return str.split(" ").map((word) => {
|
|
5716
|
+
if (word === "[options]")
|
|
5717
|
+
return this.styleOptionText(word);
|
|
5718
|
+
if (word[0] === "[" || word[0] === "<")
|
|
5719
|
+
return this.styleArgumentText(word);
|
|
5720
|
+
return this.styleSubcommandText(word);
|
|
5721
|
+
}).join(" ");
|
|
5722
|
+
}
|
|
5723
|
+
styleArgumentTerm(str) {
|
|
5724
|
+
return this.styleArgumentText(str);
|
|
5725
|
+
}
|
|
5726
|
+
styleOptionText(str) {
|
|
5727
|
+
return str;
|
|
5728
|
+
}
|
|
5729
|
+
styleArgumentText(str) {
|
|
5730
|
+
return str;
|
|
5731
|
+
}
|
|
5732
|
+
styleSubcommandText(str) {
|
|
5733
|
+
return str;
|
|
5734
|
+
}
|
|
5735
|
+
styleCommandText(str) {
|
|
5736
|
+
return str;
|
|
5737
|
+
}
|
|
5662
5738
|
padWidth(cmd, helper) {
|
|
5663
5739
|
return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
|
|
5664
5740
|
}
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
const
|
|
5671
|
-
if (
|
|
5741
|
+
preformatted(str) {
|
|
5742
|
+
return /\n[^\S\r\n]/.test(str);
|
|
5743
|
+
}
|
|
5744
|
+
formatItem(term, termWidth, description, helper) {
|
|
5745
|
+
const itemIndent = 2;
|
|
5746
|
+
const itemIndentStr = " ".repeat(itemIndent);
|
|
5747
|
+
if (!description)
|
|
5748
|
+
return itemIndentStr + term;
|
|
5749
|
+
const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term));
|
|
5750
|
+
const spacerWidth = 2;
|
|
5751
|
+
const helpWidth = this.helpWidth ?? 80;
|
|
5752
|
+
const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
|
|
5753
|
+
let formattedDescription;
|
|
5754
|
+
if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
|
|
5755
|
+
formattedDescription = description;
|
|
5756
|
+
} else {
|
|
5757
|
+
const wrappedDescription = helper.boxWrap(description, remainingWidth);
|
|
5758
|
+
formattedDescription = wrappedDescription.replace(/\n/g, `
|
|
5759
|
+
` + " ".repeat(termWidth + spacerWidth));
|
|
5760
|
+
}
|
|
5761
|
+
return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
|
|
5762
|
+
${itemIndentStr}`);
|
|
5763
|
+
}
|
|
5764
|
+
boxWrap(str, width) {
|
|
5765
|
+
if (width < this.minWidthToWrap)
|
|
5672
5766
|
return str;
|
|
5673
|
-
const
|
|
5674
|
-
const
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5767
|
+
const rawLines = str.split(/\r\n|\n/);
|
|
5768
|
+
const chunkPattern = /[\s]*[^\s]+/g;
|
|
5769
|
+
const wrappedLines = [];
|
|
5770
|
+
rawLines.forEach((line) => {
|
|
5771
|
+
const chunks = line.match(chunkPattern);
|
|
5772
|
+
if (chunks === null) {
|
|
5773
|
+
wrappedLines.push("");
|
|
5774
|
+
return;
|
|
5775
|
+
}
|
|
5776
|
+
let sumChunks = [chunks.shift()];
|
|
5777
|
+
let sumWidth = this.displayWidth(sumChunks[0]);
|
|
5778
|
+
chunks.forEach((chunk) => {
|
|
5779
|
+
const visibleWidth = this.displayWidth(chunk);
|
|
5780
|
+
if (sumWidth + visibleWidth <= width) {
|
|
5781
|
+
sumChunks.push(chunk);
|
|
5782
|
+
sumWidth += visibleWidth;
|
|
5783
|
+
return;
|
|
5784
|
+
}
|
|
5785
|
+
wrappedLines.push(sumChunks.join(""));
|
|
5786
|
+
const nextChunk = chunk.trimStart();
|
|
5787
|
+
sumChunks = [nextChunk];
|
|
5788
|
+
sumWidth = this.displayWidth(nextChunk);
|
|
5789
|
+
});
|
|
5790
|
+
wrappedLines.push(sumChunks.join(""));
|
|
5791
|
+
});
|
|
5792
|
+
return wrappedLines.join(`
|
|
5689
5793
|
`);
|
|
5690
5794
|
}
|
|
5691
5795
|
}
|
|
5796
|
+
function stripColor(str) {
|
|
5797
|
+
const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
|
|
5798
|
+
return str.replace(sgrPattern, "");
|
|
5799
|
+
}
|
|
5692
5800
|
exports.Help = Help;
|
|
5801
|
+
exports.stripColor = stripColor;
|
|
5693
5802
|
});
|
|
5694
5803
|
|
|
5695
|
-
// ../../node_modules/.bun/commander@
|
|
5804
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/option.js
|
|
5696
5805
|
var require_option = __commonJS((exports) => {
|
|
5697
5806
|
var { InvalidArgumentError } = require_error();
|
|
5698
5807
|
|
|
@@ -5720,6 +5829,7 @@ var require_option = __commonJS((exports) => {
|
|
|
5720
5829
|
this.argChoices = undefined;
|
|
5721
5830
|
this.conflictsWith = [];
|
|
5722
5831
|
this.implied = undefined;
|
|
5832
|
+
this.helpGroupHeading = undefined;
|
|
5723
5833
|
}
|
|
5724
5834
|
default(value, description) {
|
|
5725
5835
|
this.defaultValue = value;
|
|
@@ -5758,11 +5868,12 @@ var require_option = __commonJS((exports) => {
|
|
|
5758
5868
|
this.hidden = !!hide;
|
|
5759
5869
|
return this;
|
|
5760
5870
|
}
|
|
5761
|
-
|
|
5871
|
+
_collectValue(value, previous) {
|
|
5762
5872
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
5763
5873
|
return [value];
|
|
5764
5874
|
}
|
|
5765
|
-
|
|
5875
|
+
previous.push(value);
|
|
5876
|
+
return previous;
|
|
5766
5877
|
}
|
|
5767
5878
|
choices(values) {
|
|
5768
5879
|
this.argChoices = values.slice();
|
|
@@ -5771,7 +5882,7 @@ var require_option = __commonJS((exports) => {
|
|
|
5771
5882
|
throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
|
|
5772
5883
|
}
|
|
5773
5884
|
if (this.variadic) {
|
|
5774
|
-
return this.
|
|
5885
|
+
return this._collectValue(arg, previous);
|
|
5775
5886
|
}
|
|
5776
5887
|
return arg;
|
|
5777
5888
|
};
|
|
@@ -5784,7 +5895,14 @@ var require_option = __commonJS((exports) => {
|
|
|
5784
5895
|
return this.short.replace(/^-/, "");
|
|
5785
5896
|
}
|
|
5786
5897
|
attributeName() {
|
|
5787
|
-
|
|
5898
|
+
if (this.negate) {
|
|
5899
|
+
return camelcase(this.name().replace(/^no-/, ""));
|
|
5900
|
+
}
|
|
5901
|
+
return camelcase(this.name());
|
|
5902
|
+
}
|
|
5903
|
+
helpGroup(heading) {
|
|
5904
|
+
this.helpGroupHeading = heading;
|
|
5905
|
+
return this;
|
|
5788
5906
|
}
|
|
5789
5907
|
is(arg) {
|
|
5790
5908
|
return this.short === arg || this.long === arg;
|
|
@@ -5829,21 +5947,45 @@ var require_option = __commonJS((exports) => {
|
|
|
5829
5947
|
function splitOptionFlags(flags) {
|
|
5830
5948
|
let shortFlag;
|
|
5831
5949
|
let longFlag;
|
|
5832
|
-
const
|
|
5833
|
-
|
|
5950
|
+
const shortFlagExp = /^-[^-]$/;
|
|
5951
|
+
const longFlagExp = /^--[^-]/;
|
|
5952
|
+
const flagParts = flags.split(/[ |,]+/).concat("guard");
|
|
5953
|
+
if (shortFlagExp.test(flagParts[0]))
|
|
5834
5954
|
shortFlag = flagParts.shift();
|
|
5835
|
-
|
|
5836
|
-
|
|
5955
|
+
if (longFlagExp.test(flagParts[0]))
|
|
5956
|
+
longFlag = flagParts.shift();
|
|
5957
|
+
if (!shortFlag && shortFlagExp.test(flagParts[0]))
|
|
5958
|
+
shortFlag = flagParts.shift();
|
|
5959
|
+
if (!shortFlag && longFlagExp.test(flagParts[0])) {
|
|
5837
5960
|
shortFlag = longFlag;
|
|
5838
|
-
longFlag =
|
|
5839
|
-
}
|
|
5961
|
+
longFlag = flagParts.shift();
|
|
5962
|
+
}
|
|
5963
|
+
if (flagParts[0].startsWith("-")) {
|
|
5964
|
+
const unsupportedFlag = flagParts[0];
|
|
5965
|
+
const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
|
|
5966
|
+
if (/^-[^-][^-]/.test(unsupportedFlag))
|
|
5967
|
+
throw new Error(`${baseError}
|
|
5968
|
+
- a short flag is a single dash and a single character
|
|
5969
|
+
- either use a single dash and a single character (for a short flag)
|
|
5970
|
+
- or use a double dash for a long option (and can have two, like '--ws, --workspace')`);
|
|
5971
|
+
if (shortFlagExp.test(unsupportedFlag))
|
|
5972
|
+
throw new Error(`${baseError}
|
|
5973
|
+
- too many short flags`);
|
|
5974
|
+
if (longFlagExp.test(unsupportedFlag))
|
|
5975
|
+
throw new Error(`${baseError}
|
|
5976
|
+
- too many long flags`);
|
|
5977
|
+
throw new Error(`${baseError}
|
|
5978
|
+
- unrecognised flag format`);
|
|
5979
|
+
}
|
|
5980
|
+
if (shortFlag === undefined && longFlag === undefined)
|
|
5981
|
+
throw new Error(`option creation failed due to no flags found in '${flags}'.`);
|
|
5840
5982
|
return { shortFlag, longFlag };
|
|
5841
5983
|
}
|
|
5842
5984
|
exports.Option = Option;
|
|
5843
5985
|
exports.DualOptions = DualOptions;
|
|
5844
5986
|
});
|
|
5845
5987
|
|
|
5846
|
-
// ../../node_modules/.bun/commander@
|
|
5988
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/suggestSimilar.js
|
|
5847
5989
|
var require_suggestSimilar = __commonJS((exports) => {
|
|
5848
5990
|
var maxDistance = 3;
|
|
5849
5991
|
function editDistance(a, b) {
|
|
@@ -5916,7 +6058,7 @@ var require_suggestSimilar = __commonJS((exports) => {
|
|
|
5916
6058
|
exports.suggestSimilar = suggestSimilar;
|
|
5917
6059
|
});
|
|
5918
6060
|
|
|
5919
|
-
// ../../node_modules/.bun/commander@
|
|
6061
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/command.js
|
|
5920
6062
|
var require_command = __commonJS((exports) => {
|
|
5921
6063
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
5922
6064
|
var childProcess = __require("node:child_process");
|
|
@@ -5925,7 +6067,7 @@ var require_command = __commonJS((exports) => {
|
|
|
5925
6067
|
var process2 = __require("node:process");
|
|
5926
6068
|
var { Argument, humanReadableArgName } = require_argument();
|
|
5927
6069
|
var { CommanderError } = require_error();
|
|
5928
|
-
var { Help } = require_help();
|
|
6070
|
+
var { Help, stripColor } = require_help();
|
|
5929
6071
|
var { Option, DualOptions } = require_option();
|
|
5930
6072
|
var { suggestSimilar } = require_suggestSimilar();
|
|
5931
6073
|
|
|
@@ -5936,7 +6078,7 @@ var require_command = __commonJS((exports) => {
|
|
|
5936
6078
|
this.options = [];
|
|
5937
6079
|
this.parent = null;
|
|
5938
6080
|
this._allowUnknownOption = false;
|
|
5939
|
-
this._allowExcessArguments =
|
|
6081
|
+
this._allowExcessArguments = false;
|
|
5940
6082
|
this.registeredArguments = [];
|
|
5941
6083
|
this._args = this.registeredArguments;
|
|
5942
6084
|
this.args = [];
|
|
@@ -5963,18 +6105,25 @@ var require_command = __commonJS((exports) => {
|
|
|
5963
6105
|
this._lifeCycleHooks = {};
|
|
5964
6106
|
this._showHelpAfterError = false;
|
|
5965
6107
|
this._showSuggestionAfterError = true;
|
|
6108
|
+
this._savedState = null;
|
|
5966
6109
|
this._outputConfiguration = {
|
|
5967
6110
|
writeOut: (str) => process2.stdout.write(str),
|
|
5968
6111
|
writeErr: (str) => process2.stderr.write(str),
|
|
6112
|
+
outputError: (str, write) => write(str),
|
|
5969
6113
|
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
|
|
5970
6114
|
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
|
|
5971
|
-
|
|
6115
|
+
getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
|
|
6116
|
+
getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
|
|
6117
|
+
stripColor: (str) => stripColor(str)
|
|
5972
6118
|
};
|
|
5973
6119
|
this._hidden = false;
|
|
5974
6120
|
this._helpOption = undefined;
|
|
5975
6121
|
this._addImplicitHelpCommand = undefined;
|
|
5976
6122
|
this._helpCommand = undefined;
|
|
5977
6123
|
this._helpConfiguration = {};
|
|
6124
|
+
this._helpGroupHeading = undefined;
|
|
6125
|
+
this._defaultCommandGroup = undefined;
|
|
6126
|
+
this._defaultOptionGroup = undefined;
|
|
5978
6127
|
}
|
|
5979
6128
|
copyInheritedSettings(sourceCommand) {
|
|
5980
6129
|
this._outputConfiguration = sourceCommand._outputConfiguration;
|
|
@@ -6039,7 +6188,10 @@ var require_command = __commonJS((exports) => {
|
|
|
6039
6188
|
configureOutput(configuration) {
|
|
6040
6189
|
if (configuration === undefined)
|
|
6041
6190
|
return this._outputConfiguration;
|
|
6042
|
-
|
|
6191
|
+
this._outputConfiguration = {
|
|
6192
|
+
...this._outputConfiguration,
|
|
6193
|
+
...configuration
|
|
6194
|
+
};
|
|
6043
6195
|
return this;
|
|
6044
6196
|
}
|
|
6045
6197
|
showHelpAfterError(displayHelp = true) {
|
|
@@ -6070,12 +6222,12 @@ var require_command = __commonJS((exports) => {
|
|
|
6070
6222
|
createArgument(name, description) {
|
|
6071
6223
|
return new Argument(name, description);
|
|
6072
6224
|
}
|
|
6073
|
-
argument(name, description,
|
|
6225
|
+
argument(name, description, parseArg, defaultValue) {
|
|
6074
6226
|
const argument = this.createArgument(name, description);
|
|
6075
|
-
if (typeof
|
|
6076
|
-
argument.default(defaultValue).argParser(
|
|
6227
|
+
if (typeof parseArg === "function") {
|
|
6228
|
+
argument.default(defaultValue).argParser(parseArg);
|
|
6077
6229
|
} else {
|
|
6078
|
-
argument.default(
|
|
6230
|
+
argument.default(parseArg);
|
|
6079
6231
|
}
|
|
6080
6232
|
this.addArgument(argument);
|
|
6081
6233
|
return this;
|
|
@@ -6088,7 +6240,7 @@ var require_command = __commonJS((exports) => {
|
|
|
6088
6240
|
}
|
|
6089
6241
|
addArgument(argument) {
|
|
6090
6242
|
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
6091
|
-
if (previousArgument
|
|
6243
|
+
if (previousArgument?.variadic) {
|
|
6092
6244
|
throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
|
|
6093
6245
|
}
|
|
6094
6246
|
if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
|
|
@@ -6100,10 +6252,13 @@ var require_command = __commonJS((exports) => {
|
|
|
6100
6252
|
helpCommand(enableOrNameAndArgs, description) {
|
|
6101
6253
|
if (typeof enableOrNameAndArgs === "boolean") {
|
|
6102
6254
|
this._addImplicitHelpCommand = enableOrNameAndArgs;
|
|
6255
|
+
if (enableOrNameAndArgs && this._defaultCommandGroup) {
|
|
6256
|
+
this._initCommandGroup(this._getHelpCommand());
|
|
6257
|
+
}
|
|
6103
6258
|
return this;
|
|
6104
6259
|
}
|
|
6105
|
-
|
|
6106
|
-
const [, helpName, helpArgs] =
|
|
6260
|
+
const nameAndArgs = enableOrNameAndArgs ?? "help [command]";
|
|
6261
|
+
const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/);
|
|
6107
6262
|
const helpDescription = description ?? "display help for command";
|
|
6108
6263
|
const helpCommand = this.createCommand(helpName);
|
|
6109
6264
|
helpCommand.helpOption(false);
|
|
@@ -6113,6 +6268,8 @@ var require_command = __commonJS((exports) => {
|
|
|
6113
6268
|
helpCommand.description(helpDescription);
|
|
6114
6269
|
this._addImplicitHelpCommand = true;
|
|
6115
6270
|
this._helpCommand = helpCommand;
|
|
6271
|
+
if (enableOrNameAndArgs || description)
|
|
6272
|
+
this._initCommandGroup(helpCommand);
|
|
6116
6273
|
return this;
|
|
6117
6274
|
}
|
|
6118
6275
|
addHelpCommand(helpCommand, deprecatedDescription) {
|
|
@@ -6122,6 +6279,7 @@ var require_command = __commonJS((exports) => {
|
|
|
6122
6279
|
}
|
|
6123
6280
|
this._addImplicitHelpCommand = true;
|
|
6124
6281
|
this._helpCommand = helpCommand;
|
|
6282
|
+
this._initCommandGroup(helpCommand);
|
|
6125
6283
|
return this;
|
|
6126
6284
|
}
|
|
6127
6285
|
_getHelpCommand() {
|
|
@@ -6201,6 +6359,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6201
6359
|
throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
|
|
6202
6360
|
- already used by option '${matchingOption.flags}'`);
|
|
6203
6361
|
}
|
|
6362
|
+
this._initOptionGroup(option);
|
|
6204
6363
|
this.options.push(option);
|
|
6205
6364
|
}
|
|
6206
6365
|
_registerCommand(command) {
|
|
@@ -6213,6 +6372,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6213
6372
|
const newCmd = knownBy(command).join("|");
|
|
6214
6373
|
throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
|
|
6215
6374
|
}
|
|
6375
|
+
this._initCommandGroup(command);
|
|
6216
6376
|
this.commands.push(command);
|
|
6217
6377
|
}
|
|
6218
6378
|
addOption(option) {
|
|
@@ -6235,7 +6395,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6235
6395
|
if (val !== null && option.parseArg) {
|
|
6236
6396
|
val = this._callParseArg(option, val, oldValue, invalidValueMessage);
|
|
6237
6397
|
} else if (val !== null && option.variadic) {
|
|
6238
|
-
val = option.
|
|
6398
|
+
val = option._collectValue(val, oldValue);
|
|
6239
6399
|
}
|
|
6240
6400
|
if (val == null) {
|
|
6241
6401
|
if (option.negate) {
|
|
@@ -6400,15 +6560,53 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6400
6560
|
return userArgs;
|
|
6401
6561
|
}
|
|
6402
6562
|
parse(argv, parseOptions) {
|
|
6563
|
+
this._prepareForParse();
|
|
6403
6564
|
const userArgs = this._prepareUserArgs(argv, parseOptions);
|
|
6404
6565
|
this._parseCommand([], userArgs);
|
|
6405
6566
|
return this;
|
|
6406
6567
|
}
|
|
6407
6568
|
async parseAsync(argv, parseOptions) {
|
|
6569
|
+
this._prepareForParse();
|
|
6408
6570
|
const userArgs = this._prepareUserArgs(argv, parseOptions);
|
|
6409
6571
|
await this._parseCommand([], userArgs);
|
|
6410
6572
|
return this;
|
|
6411
6573
|
}
|
|
6574
|
+
_prepareForParse() {
|
|
6575
|
+
if (this._savedState === null) {
|
|
6576
|
+
this.saveStateBeforeParse();
|
|
6577
|
+
} else {
|
|
6578
|
+
this.restoreStateBeforeParse();
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
saveStateBeforeParse() {
|
|
6582
|
+
this._savedState = {
|
|
6583
|
+
_name: this._name,
|
|
6584
|
+
_optionValues: { ...this._optionValues },
|
|
6585
|
+
_optionValueSources: { ...this._optionValueSources }
|
|
6586
|
+
};
|
|
6587
|
+
}
|
|
6588
|
+
restoreStateBeforeParse() {
|
|
6589
|
+
if (this._storeOptionsAsProperties)
|
|
6590
|
+
throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
|
|
6591
|
+
- either make a new Command for each call to parse, or stop storing options as properties`);
|
|
6592
|
+
this._name = this._savedState._name;
|
|
6593
|
+
this._scriptPath = null;
|
|
6594
|
+
this.rawArgs = [];
|
|
6595
|
+
this._optionValues = { ...this._savedState._optionValues };
|
|
6596
|
+
this._optionValueSources = { ...this._savedState._optionValueSources };
|
|
6597
|
+
this.args = [];
|
|
6598
|
+
this.processedArgs = [];
|
|
6599
|
+
}
|
|
6600
|
+
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
6601
|
+
if (fs.existsSync(executableFile))
|
|
6602
|
+
return;
|
|
6603
|
+
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
6604
|
+
const executableMissing = `'${executableFile}' does not exist
|
|
6605
|
+
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
6606
|
+
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
6607
|
+
- ${executableDirMessage}`;
|
|
6608
|
+
throw new Error(executableMissing);
|
|
6609
|
+
}
|
|
6412
6610
|
_executeSubCommand(subcommand, args) {
|
|
6413
6611
|
args = args.slice();
|
|
6414
6612
|
let launchWithNode = false;
|
|
@@ -6432,7 +6630,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6432
6630
|
let resolvedScriptPath;
|
|
6433
6631
|
try {
|
|
6434
6632
|
resolvedScriptPath = fs.realpathSync(this._scriptPath);
|
|
6435
|
-
} catch
|
|
6633
|
+
} catch {
|
|
6436
6634
|
resolvedScriptPath = this._scriptPath;
|
|
6437
6635
|
}
|
|
6438
6636
|
executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
|
|
@@ -6458,6 +6656,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6458
6656
|
proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
|
|
6459
6657
|
}
|
|
6460
6658
|
} else {
|
|
6659
|
+
this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
|
|
6461
6660
|
args.unshift(executableFile);
|
|
6462
6661
|
args = incrementNodeInspectorPort(process2.execArgv).concat(args);
|
|
6463
6662
|
proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
|
|
@@ -6483,12 +6682,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6483
6682
|
});
|
|
6484
6683
|
proc.on("error", (err) => {
|
|
6485
6684
|
if (err.code === "ENOENT") {
|
|
6486
|
-
|
|
6487
|
-
const executableMissing = `'${executableFile}' does not exist
|
|
6488
|
-
- if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
6489
|
-
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
6490
|
-
- ${executableDirMessage}`;
|
|
6491
|
-
throw new Error(executableMissing);
|
|
6685
|
+
this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
|
|
6492
6686
|
} else if (err.code === "EACCES") {
|
|
6493
6687
|
throw new Error(`'${executableFile}' not executable`);
|
|
6494
6688
|
}
|
|
@@ -6506,6 +6700,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6506
6700
|
const subCommand = this._findCommand(commandName);
|
|
6507
6701
|
if (!subCommand)
|
|
6508
6702
|
this.help({ error: true });
|
|
6703
|
+
subCommand._prepareForParse();
|
|
6509
6704
|
let promiseChain;
|
|
6510
6705
|
promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, "preSubcommand");
|
|
6511
6706
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
@@ -6575,7 +6770,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6575
6770
|
this.processedArgs = processedArgs;
|
|
6576
6771
|
}
|
|
6577
6772
|
_chainOrCall(promise, fn) {
|
|
6578
|
-
if (promise
|
|
6773
|
+
if (promise?.then && typeof promise.then === "function") {
|
|
6579
6774
|
return promise.then(() => fn());
|
|
6580
6775
|
}
|
|
6581
6776
|
return fn();
|
|
@@ -6652,7 +6847,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6652
6847
|
promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
|
|
6653
6848
|
return promiseChain;
|
|
6654
6849
|
}
|
|
6655
|
-
if (this.parent
|
|
6850
|
+
if (this.parent?.listenerCount(commandEvent)) {
|
|
6656
6851
|
checkForUnknownOptions();
|
|
6657
6852
|
this._processArguments();
|
|
6658
6853
|
this.parent.emit(commandEvent, operands, unknown);
|
|
@@ -6714,24 +6909,31 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6714
6909
|
cmd._checkForConflictingLocalOptions();
|
|
6715
6910
|
});
|
|
6716
6911
|
}
|
|
6717
|
-
parseOptions(
|
|
6912
|
+
parseOptions(args) {
|
|
6718
6913
|
const operands = [];
|
|
6719
6914
|
const unknown = [];
|
|
6720
6915
|
let dest = operands;
|
|
6721
|
-
const args = argv.slice();
|
|
6722
6916
|
function maybeOption(arg) {
|
|
6723
6917
|
return arg.length > 1 && arg[0] === "-";
|
|
6724
6918
|
}
|
|
6919
|
+
const negativeNumberArg = (arg) => {
|
|
6920
|
+
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
|
|
6921
|
+
return false;
|
|
6922
|
+
return !this._getCommandAndAncestors().some((cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short)));
|
|
6923
|
+
};
|
|
6725
6924
|
let activeVariadicOption = null;
|
|
6726
|
-
|
|
6727
|
-
|
|
6925
|
+
let activeGroup = null;
|
|
6926
|
+
let i = 0;
|
|
6927
|
+
while (i < args.length || activeGroup) {
|
|
6928
|
+
const arg = activeGroup ?? args[i++];
|
|
6929
|
+
activeGroup = null;
|
|
6728
6930
|
if (arg === "--") {
|
|
6729
6931
|
if (dest === unknown)
|
|
6730
6932
|
dest.push(arg);
|
|
6731
|
-
dest.push(...args);
|
|
6933
|
+
dest.push(...args.slice(i));
|
|
6732
6934
|
break;
|
|
6733
6935
|
}
|
|
6734
|
-
if (activeVariadicOption && !maybeOption(arg)) {
|
|
6936
|
+
if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
|
|
6735
6937
|
this.emit(`option:${activeVariadicOption.name()}`, arg);
|
|
6736
6938
|
continue;
|
|
6737
6939
|
}
|
|
@@ -6740,14 +6942,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6740
6942
|
const option = this._findOption(arg);
|
|
6741
6943
|
if (option) {
|
|
6742
6944
|
if (option.required) {
|
|
6743
|
-
const value = args
|
|
6945
|
+
const value = args[i++];
|
|
6744
6946
|
if (value === undefined)
|
|
6745
6947
|
this.optionMissingArgument(option);
|
|
6746
6948
|
this.emit(`option:${option.name()}`, value);
|
|
6747
6949
|
} else if (option.optional) {
|
|
6748
6950
|
let value = null;
|
|
6749
|
-
if (args.length
|
|
6750
|
-
value = args
|
|
6951
|
+
if (i < args.length && (!maybeOption(args[i]) || negativeNumberArg(args[i]))) {
|
|
6952
|
+
value = args[i++];
|
|
6751
6953
|
}
|
|
6752
6954
|
this.emit(`option:${option.name()}`, value);
|
|
6753
6955
|
} else {
|
|
@@ -6764,7 +6966,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6764
6966
|
this.emit(`option:${option.name()}`, arg.slice(2));
|
|
6765
6967
|
} else {
|
|
6766
6968
|
this.emit(`option:${option.name()}`);
|
|
6767
|
-
|
|
6969
|
+
activeGroup = `-${arg.slice(2)}`;
|
|
6768
6970
|
}
|
|
6769
6971
|
continue;
|
|
6770
6972
|
}
|
|
@@ -6777,31 +6979,24 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6777
6979
|
continue;
|
|
6778
6980
|
}
|
|
6779
6981
|
}
|
|
6780
|
-
if (maybeOption(arg)) {
|
|
6982
|
+
if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
|
|
6781
6983
|
dest = unknown;
|
|
6782
6984
|
}
|
|
6783
6985
|
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
|
|
6784
6986
|
if (this._findCommand(arg)) {
|
|
6785
6987
|
operands.push(arg);
|
|
6786
|
-
|
|
6787
|
-
unknown.push(...args);
|
|
6988
|
+
unknown.push(...args.slice(i));
|
|
6788
6989
|
break;
|
|
6789
6990
|
} else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
|
|
6790
|
-
operands.push(arg);
|
|
6791
|
-
if (args.length > 0)
|
|
6792
|
-
operands.push(...args);
|
|
6991
|
+
operands.push(arg, ...args.slice(i));
|
|
6793
6992
|
break;
|
|
6794
6993
|
} else if (this._defaultCommandName) {
|
|
6795
|
-
unknown.push(arg);
|
|
6796
|
-
if (args.length > 0)
|
|
6797
|
-
unknown.push(...args);
|
|
6994
|
+
unknown.push(arg, ...args.slice(i));
|
|
6798
6995
|
break;
|
|
6799
6996
|
}
|
|
6800
6997
|
}
|
|
6801
6998
|
if (this._passThroughOptions) {
|
|
6802
|
-
dest.push(arg);
|
|
6803
|
-
if (args.length > 0)
|
|
6804
|
-
dest.push(...args);
|
|
6999
|
+
dest.push(arg, ...args.slice(i));
|
|
6805
7000
|
break;
|
|
6806
7001
|
}
|
|
6807
7002
|
dest.push(arg);
|
|
@@ -7012,6 +7207,32 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7012
7207
|
this._name = str;
|
|
7013
7208
|
return this;
|
|
7014
7209
|
}
|
|
7210
|
+
helpGroup(heading) {
|
|
7211
|
+
if (heading === undefined)
|
|
7212
|
+
return this._helpGroupHeading ?? "";
|
|
7213
|
+
this._helpGroupHeading = heading;
|
|
7214
|
+
return this;
|
|
7215
|
+
}
|
|
7216
|
+
commandsGroup(heading) {
|
|
7217
|
+
if (heading === undefined)
|
|
7218
|
+
return this._defaultCommandGroup ?? "";
|
|
7219
|
+
this._defaultCommandGroup = heading;
|
|
7220
|
+
return this;
|
|
7221
|
+
}
|
|
7222
|
+
optionsGroup(heading) {
|
|
7223
|
+
if (heading === undefined)
|
|
7224
|
+
return this._defaultOptionGroup ?? "";
|
|
7225
|
+
this._defaultOptionGroup = heading;
|
|
7226
|
+
return this;
|
|
7227
|
+
}
|
|
7228
|
+
_initOptionGroup(option) {
|
|
7229
|
+
if (this._defaultOptionGroup && !option.helpGroupHeading)
|
|
7230
|
+
option.helpGroup(this._defaultOptionGroup);
|
|
7231
|
+
}
|
|
7232
|
+
_initCommandGroup(cmd) {
|
|
7233
|
+
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
7234
|
+
cmd.helpGroup(this._defaultCommandGroup);
|
|
7235
|
+
}
|
|
7015
7236
|
nameFromFilename(filename) {
|
|
7016
7237
|
this._name = path.basename(filename, path.extname(filename));
|
|
7017
7238
|
return this;
|
|
@@ -7024,23 +7245,38 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7024
7245
|
}
|
|
7025
7246
|
helpInformation(contextOptions) {
|
|
7026
7247
|
const helper = this.createHelp();
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7248
|
+
const context = this._getOutputContext(contextOptions);
|
|
7249
|
+
helper.prepareContext({
|
|
7250
|
+
error: context.error,
|
|
7251
|
+
helpWidth: context.helpWidth,
|
|
7252
|
+
outputHasColors: context.hasColors
|
|
7253
|
+
});
|
|
7254
|
+
const text = helper.formatHelp(this, helper);
|
|
7255
|
+
if (context.hasColors)
|
|
7256
|
+
return text;
|
|
7257
|
+
return this._outputConfiguration.stripColor(text);
|
|
7031
7258
|
}
|
|
7032
|
-
|
|
7259
|
+
_getOutputContext(contextOptions) {
|
|
7033
7260
|
contextOptions = contextOptions || {};
|
|
7034
|
-
const
|
|
7035
|
-
let
|
|
7036
|
-
|
|
7037
|
-
|
|
7261
|
+
const error = !!contextOptions.error;
|
|
7262
|
+
let baseWrite;
|
|
7263
|
+
let hasColors;
|
|
7264
|
+
let helpWidth;
|
|
7265
|
+
if (error) {
|
|
7266
|
+
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
7267
|
+
hasColors = this._outputConfiguration.getErrHasColors();
|
|
7268
|
+
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
7038
7269
|
} else {
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7270
|
+
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
7271
|
+
hasColors = this._outputConfiguration.getOutHasColors();
|
|
7272
|
+
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
7273
|
+
}
|
|
7274
|
+
const write = (str) => {
|
|
7275
|
+
if (!hasColors)
|
|
7276
|
+
str = this._outputConfiguration.stripColor(str);
|
|
7277
|
+
return baseWrite(str);
|
|
7278
|
+
};
|
|
7279
|
+
return { error, write, hasColors, helpWidth };
|
|
7044
7280
|
}
|
|
7045
7281
|
outputHelp(contextOptions) {
|
|
7046
7282
|
let deprecatedCallback;
|
|
@@ -7048,35 +7284,44 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7048
7284
|
deprecatedCallback = contextOptions;
|
|
7049
7285
|
contextOptions = undefined;
|
|
7050
7286
|
}
|
|
7051
|
-
const
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7287
|
+
const outputContext = this._getOutputContext(contextOptions);
|
|
7288
|
+
const eventContext = {
|
|
7289
|
+
error: outputContext.error,
|
|
7290
|
+
write: outputContext.write,
|
|
7291
|
+
command: this
|
|
7292
|
+
};
|
|
7293
|
+
this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
|
|
7294
|
+
this.emit("beforeHelp", eventContext);
|
|
7295
|
+
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
7055
7296
|
if (deprecatedCallback) {
|
|
7056
7297
|
helpInformation = deprecatedCallback(helpInformation);
|
|
7057
7298
|
if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
|
|
7058
7299
|
throw new Error("outputHelp callback must return a string or a Buffer");
|
|
7059
7300
|
}
|
|
7060
7301
|
}
|
|
7061
|
-
|
|
7302
|
+
outputContext.write(helpInformation);
|
|
7062
7303
|
if (this._getHelpOption()?.long) {
|
|
7063
7304
|
this.emit(this._getHelpOption().long);
|
|
7064
7305
|
}
|
|
7065
|
-
this.emit("afterHelp",
|
|
7066
|
-
this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp",
|
|
7306
|
+
this.emit("afterHelp", eventContext);
|
|
7307
|
+
this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", eventContext));
|
|
7067
7308
|
}
|
|
7068
7309
|
helpOption(flags, description) {
|
|
7069
7310
|
if (typeof flags === "boolean") {
|
|
7070
7311
|
if (flags) {
|
|
7071
|
-
|
|
7312
|
+
if (this._helpOption === null)
|
|
7313
|
+
this._helpOption = undefined;
|
|
7314
|
+
if (this._defaultOptionGroup) {
|
|
7315
|
+
this._initOptionGroup(this._getHelpOption());
|
|
7316
|
+
}
|
|
7072
7317
|
} else {
|
|
7073
7318
|
this._helpOption = null;
|
|
7074
7319
|
}
|
|
7075
7320
|
return this;
|
|
7076
7321
|
}
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7322
|
+
this._helpOption = this.createOption(flags ?? "-h, --help", description ?? "display help for command");
|
|
7323
|
+
if (flags || description)
|
|
7324
|
+
this._initOptionGroup(this._helpOption);
|
|
7080
7325
|
return this;
|
|
7081
7326
|
}
|
|
7082
7327
|
_getHelpOption() {
|
|
@@ -7087,11 +7332,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7087
7332
|
}
|
|
7088
7333
|
addHelpOption(option) {
|
|
7089
7334
|
this._helpOption = option;
|
|
7335
|
+
this._initOptionGroup(option);
|
|
7090
7336
|
return this;
|
|
7091
7337
|
}
|
|
7092
7338
|
help(contextOptions) {
|
|
7093
7339
|
this.outputHelp(contextOptions);
|
|
7094
|
-
let exitCode = process2.exitCode
|
|
7340
|
+
let exitCode = Number(process2.exitCode ?? 0);
|
|
7095
7341
|
if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
|
|
7096
7342
|
exitCode = 1;
|
|
7097
7343
|
}
|
|
@@ -7156,10 +7402,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7156
7402
|
return arg;
|
|
7157
7403
|
});
|
|
7158
7404
|
}
|
|
7405
|
+
function useColor() {
|
|
7406
|
+
if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
|
|
7407
|
+
return false;
|
|
7408
|
+
if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== undefined)
|
|
7409
|
+
return true;
|
|
7410
|
+
return;
|
|
7411
|
+
}
|
|
7159
7412
|
exports.Command = Command;
|
|
7413
|
+
exports.useColor = useColor;
|
|
7160
7414
|
});
|
|
7161
7415
|
|
|
7162
|
-
// ../../node_modules/.bun/commander@
|
|
7416
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/index.js
|
|
7163
7417
|
var require_commander = __commonJS((exports) => {
|
|
7164
7418
|
var { Argument } = require_argument();
|
|
7165
7419
|
var { Command } = require_command();
|
|
@@ -7184,7 +7438,7 @@ var exports_meta = {};
|
|
|
7184
7438
|
__export(exports_meta, {
|
|
7185
7439
|
PKG_VERSION: () => PKG_VERSION
|
|
7186
7440
|
});
|
|
7187
|
-
var PKG_VERSION = "1.0.
|
|
7441
|
+
var PKG_VERSION = "1.1.0-beta.1";
|
|
7188
7442
|
var init_meta = () => {};
|
|
7189
7443
|
|
|
7190
7444
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
@@ -25239,6 +25493,17 @@ function readUnitInterval(name) {
|
|
|
25239
25493
|
function getSearchAlpha() {
|
|
25240
25494
|
return readUnitInterval("CEREFOX_SEARCH_ALPHA") ?? DEFAULT_SEARCH_ALPHA;
|
|
25241
25495
|
}
|
|
25496
|
+
function getConfiguredMinSearchScore() {
|
|
25497
|
+
const explicit = readUnitInterval("CEREFOX_MIN_SEARCH_SCORE");
|
|
25498
|
+
if (explicit !== undefined)
|
|
25499
|
+
return explicit;
|
|
25500
|
+
if (readEnv("CEREFOX_EMBEDDER") === "local")
|
|
25501
|
+
return DEFAULT_MIN_SEARCH_SCORE_LOCAL;
|
|
25502
|
+
return;
|
|
25503
|
+
}
|
|
25504
|
+
function getConfiguredSearchAlpha() {
|
|
25505
|
+
return readUnitInterval("CEREFOX_SEARCH_ALPHA");
|
|
25506
|
+
}
|
|
25242
25507
|
function getMinSearchScore() {
|
|
25243
25508
|
const fallback = readEnv("CEREFOX_EMBEDDER") === "local" ? DEFAULT_MIN_SEARCH_SCORE_LOCAL : DEFAULT_MIN_SEARCH_SCORE;
|
|
25244
25509
|
return readUnitInterval("CEREFOX_MIN_SEARCH_SCORE") ?? fallback;
|
|
@@ -54932,6 +55197,204 @@ var init_types3 = __esm(() => {
|
|
|
54932
55197
|
};
|
|
54933
55198
|
});
|
|
54934
55199
|
|
|
55200
|
+
// ../../_shared/mcp-tools/relations.ts
|
|
55201
|
+
function requireUuid2(value, field) {
|
|
55202
|
+
const s = typeof value === "string" ? value.trim() : "";
|
|
55203
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s)) {
|
|
55204
|
+
throw new McpInvalidParams(`${field} must be a document UUID (got: ${String(value)})`);
|
|
55205
|
+
}
|
|
55206
|
+
return s;
|
|
55207
|
+
}
|
|
55208
|
+
async function setHandler(supabase, args, ctx) {
|
|
55209
|
+
const source = requireUuid2(args.source_id, "source_id");
|
|
55210
|
+
const target = requireUuid2(args.target_id, "target_id");
|
|
55211
|
+
const relType = typeof args.rel_type === "string" ? args.rel_type.trim() : "";
|
|
55212
|
+
if (!relType)
|
|
55213
|
+
throw new McpInvalidParams("rel_type is required");
|
|
55214
|
+
const { data, error: error2 } = await supabase.rpc("cerefox_set_relation", {
|
|
55215
|
+
p_source_id: source,
|
|
55216
|
+
p_target_id: target,
|
|
55217
|
+
p_rel_type: relType,
|
|
55218
|
+
p_author: args.author ?? "mcp-agent",
|
|
55219
|
+
p_author_type: "agent",
|
|
55220
|
+
p_metadata: args.metadata ?? {}
|
|
55221
|
+
});
|
|
55222
|
+
if (error2)
|
|
55223
|
+
throw new Error(`RPC error: ${error2.message}`);
|
|
55224
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
55225
|
+
logUsage(supabase, {
|
|
55226
|
+
operation: "set_relation",
|
|
55227
|
+
accessPath: ctx.accessPath,
|
|
55228
|
+
requestor: args.requestor,
|
|
55229
|
+
document_id: source
|
|
55230
|
+
});
|
|
55231
|
+
const both = row?.is_symmetric ? " (symmetric — the reverse edge was written too)" : "";
|
|
55232
|
+
const effect = relType === "supersedes" ? `
|
|
55233
|
+
Target marked superseded.` : relType === "contradicts" ? `
|
|
55234
|
+
Both documents marked stale.` : "";
|
|
55235
|
+
return `Relation set: ${source} --${relType}--> ${target}${both}.${effect}`;
|
|
55236
|
+
}
|
|
55237
|
+
async function deleteHandler(supabase, args, ctx) {
|
|
55238
|
+
const source = requireUuid2(args.source_id, "source_id");
|
|
55239
|
+
const target = requireUuid2(args.target_id, "target_id");
|
|
55240
|
+
const relType = typeof args.rel_type === "string" ? args.rel_type.trim() : "";
|
|
55241
|
+
if (!relType)
|
|
55242
|
+
throw new McpInvalidParams("rel_type is required");
|
|
55243
|
+
const { data, error: error2 } = await supabase.rpc("cerefox_delete_relation", {
|
|
55244
|
+
p_source_id: source,
|
|
55245
|
+
p_target_id: target,
|
|
55246
|
+
p_rel_type: relType,
|
|
55247
|
+
p_author: args.author ?? "mcp-agent",
|
|
55248
|
+
p_author_type: "agent"
|
|
55249
|
+
});
|
|
55250
|
+
if (error2)
|
|
55251
|
+
throw new Error(`RPC error: ${error2.message}`);
|
|
55252
|
+
const removed = typeof data === "number" ? data : 0;
|
|
55253
|
+
logUsage(supabase, {
|
|
55254
|
+
operation: "delete_relation",
|
|
55255
|
+
accessPath: ctx.accessPath,
|
|
55256
|
+
requestor: args.requestor,
|
|
55257
|
+
document_id: source
|
|
55258
|
+
});
|
|
55259
|
+
if (removed === 0)
|
|
55260
|
+
return "No such relation — nothing removed.";
|
|
55261
|
+
return `Removed ${removed} relation row(s): ${source} --${relType}--> ${target}. ` + "Lifecycle status is left as-is (a document may be superseded by something else too).";
|
|
55262
|
+
}
|
|
55263
|
+
async function getRelationsHandler(supabase, args, ctx) {
|
|
55264
|
+
const docId = requireUuid2(args.document_id, "document_id");
|
|
55265
|
+
const { data, error: error2 } = await supabase.rpc("cerefox_get_relations", {
|
|
55266
|
+
p_document_id: docId
|
|
55267
|
+
});
|
|
55268
|
+
if (error2)
|
|
55269
|
+
throw new Error(`RPC error: ${error2.message}`);
|
|
55270
|
+
const rows = data ?? [];
|
|
55271
|
+
logUsage(supabase, {
|
|
55272
|
+
operation: "get_relations",
|
|
55273
|
+
accessPath: ctx.accessPath,
|
|
55274
|
+
requestor: args.requestor,
|
|
55275
|
+
document_id: docId,
|
|
55276
|
+
result_count: rows.length
|
|
55277
|
+
});
|
|
55278
|
+
if (rows.length === 0)
|
|
55279
|
+
return "No relations for this document.";
|
|
55280
|
+
const lines = rows.map((r) => {
|
|
55281
|
+
const arrow = r.direction === "outbound" ? "→" : "←";
|
|
55282
|
+
const life = r.other_lifecycle && r.other_lifecycle !== "active" ? ` [${r.other_lifecycle}]` : "";
|
|
55283
|
+
return `- ${arrow} ${r.rel_type}: ${r.other_title}${life} [id: ${r.other_id}]`;
|
|
55284
|
+
});
|
|
55285
|
+
return `${rows.length} relation(s):
|
|
55286
|
+
${lines.join(`
|
|
55287
|
+
`)}`;
|
|
55288
|
+
}
|
|
55289
|
+
async function getNeighborsHandler(supabase, args, ctx) {
|
|
55290
|
+
const docId = requireUuid2(args.document_id, "document_id");
|
|
55291
|
+
const relType = typeof args.rel_type === "string" ? args.rel_type.trim() : "";
|
|
55292
|
+
if (!relType)
|
|
55293
|
+
throw new McpInvalidParams("rel_type is required — pick one type to traverse");
|
|
55294
|
+
const depth = Math.max(1, Math.min(args.depth ?? 1, 5));
|
|
55295
|
+
const { data, error: error2 } = await supabase.rpc("cerefox_get_neighbors", {
|
|
55296
|
+
p_document_id: docId,
|
|
55297
|
+
p_rel_type: relType,
|
|
55298
|
+
p_depth: depth,
|
|
55299
|
+
p_from_time: args.from_time ?? null,
|
|
55300
|
+
p_to_time: args.to_time ?? null,
|
|
55301
|
+
p_limit: Math.max(1, Math.min(args.limit ?? 50, 200))
|
|
55302
|
+
});
|
|
55303
|
+
if (error2)
|
|
55304
|
+
throw new Error(`RPC error: ${error2.message}`);
|
|
55305
|
+
const rows = data ?? [];
|
|
55306
|
+
logUsage(supabase, {
|
|
55307
|
+
operation: "get_neighbors",
|
|
55308
|
+
accessPath: ctx.accessPath,
|
|
55309
|
+
requestor: args.requestor,
|
|
55310
|
+
document_id: docId,
|
|
55311
|
+
result_count: rows.length
|
|
55312
|
+
});
|
|
55313
|
+
if (rows.length === 0)
|
|
55314
|
+
return `No documents reachable via "${relType}".`;
|
|
55315
|
+
const lines = rows.map((r) => {
|
|
55316
|
+
const life = r.lifecycle_status && r.lifecycle_status !== "active" ? ` [${r.lifecycle_status}]` : "";
|
|
55317
|
+
return `- depth ${r.depth} (${r.direction}): ${r.title}${life} [id: ${r.document_id}]`;
|
|
55318
|
+
});
|
|
55319
|
+
return `${rows.length} document(s) via "${relType}":
|
|
55320
|
+
${lines.join(`
|
|
55321
|
+
`)}`;
|
|
55322
|
+
}
|
|
55323
|
+
var KNOWN_TYPES = "related_to, references, supersedes, contradicts, duplicates, part_of, follows, reply_to", setRelationTool, deleteRelationTool, getRelationsTool, getNeighborsTool;
|
|
55324
|
+
var init_relations = __esm(() => {
|
|
55325
|
+
init_types3();
|
|
55326
|
+
setRelationTool = {
|
|
55327
|
+
name: "cerefox_set_relation",
|
|
55328
|
+
description: "Link two documents with a typed, directed relation (source → target). " + `Known types with behaviour: ${KNOWN_TYPES}. Symmetric types (related_to, ` + "contradicts, duplicates) write both directions. `supersedes` marks the target " + "superseded; `contradicts` marks both stale. Any other type string is accepted " + "and stored, just without special behaviour. Re-setting the same edge updates it.",
|
|
55329
|
+
inputSchema: {
|
|
55330
|
+
type: "object",
|
|
55331
|
+
required: ["source_id", "target_id", "rel_type"],
|
|
55332
|
+
properties: {
|
|
55333
|
+
source_id: { type: "string", description: "UUID of the source document" },
|
|
55334
|
+
target_id: { type: "string", description: "UUID of the target document" },
|
|
55335
|
+
rel_type: {
|
|
55336
|
+
type: "string",
|
|
55337
|
+
description: `Relation type, e.g. one of: ${KNOWN_TYPES}. Free text is allowed.`
|
|
55338
|
+
},
|
|
55339
|
+
metadata: {
|
|
55340
|
+
type: "object",
|
|
55341
|
+
description: "Optional JSON context for the edge (note, confidence, …)"
|
|
55342
|
+
},
|
|
55343
|
+
author: { type: "string", description: "Who is creating this relation" },
|
|
55344
|
+
requestor: { type: "string", description: "Name of the agent making this request" }
|
|
55345
|
+
}
|
|
55346
|
+
},
|
|
55347
|
+
handler: setHandler
|
|
55348
|
+
};
|
|
55349
|
+
deleteRelationTool = {
|
|
55350
|
+
name: "cerefox_delete_relation",
|
|
55351
|
+
description: "Remove a typed relation between two documents. Symmetric types remove both " + "directions. Lifecycle status set by an earlier relation is NOT reverted.",
|
|
55352
|
+
inputSchema: {
|
|
55353
|
+
type: "object",
|
|
55354
|
+
required: ["source_id", "target_id", "rel_type"],
|
|
55355
|
+
properties: {
|
|
55356
|
+
source_id: { type: "string", description: "UUID of the source document" },
|
|
55357
|
+
target_id: { type: "string", description: "UUID of the target document" },
|
|
55358
|
+
rel_type: { type: "string", description: "Relation type to remove" },
|
|
55359
|
+
author: { type: "string", description: "Who is removing this relation" },
|
|
55360
|
+
requestor: { type: "string", description: "Name of the agent making this request" }
|
|
55361
|
+
}
|
|
55362
|
+
},
|
|
55363
|
+
handler: deleteHandler
|
|
55364
|
+
};
|
|
55365
|
+
getRelationsTool = {
|
|
55366
|
+
name: "cerefox_get_relations",
|
|
55367
|
+
description: "List every relation touching a document, in both directions (→ outbound, " + "← inbound). Shows each neighbour's title and lifecycle status, so an agent " + "can tell whether retrieved knowledge has been superseded or contradicted.",
|
|
55368
|
+
inputSchema: {
|
|
55369
|
+
type: "object",
|
|
55370
|
+
required: ["document_id"],
|
|
55371
|
+
properties: {
|
|
55372
|
+
document_id: { type: "string", description: "UUID of the document" },
|
|
55373
|
+
requestor: { type: "string", description: "Name of the agent making this request" }
|
|
55374
|
+
}
|
|
55375
|
+
},
|
|
55376
|
+
handler: getRelationsHandler
|
|
55377
|
+
};
|
|
55378
|
+
getNeighborsTool = {
|
|
55379
|
+
name: "cerefox_get_neighbors",
|
|
55380
|
+
description: "Walk the relation graph outward from a document along ONE relation type. " + "Use after cerefox_get_relations shows which types exist. depth > 1 follows " + "chains (useful for follows / reply_to); cycles terminate safely. Optional " + "from_time / to_time filter neighbours by their creation time.",
|
|
55381
|
+
inputSchema: {
|
|
55382
|
+
type: "object",
|
|
55383
|
+
required: ["document_id", "rel_type"],
|
|
55384
|
+
properties: {
|
|
55385
|
+
document_id: { type: "string", description: "UUID of the starting document" },
|
|
55386
|
+
rel_type: { type: "string", description: "The single relation type to traverse" },
|
|
55387
|
+
depth: { type: "integer", description: "How many hops to follow (1–5, default 1)" },
|
|
55388
|
+
from_time: { type: "string", description: "ISO-8601: only neighbours created on/after" },
|
|
55389
|
+
to_time: { type: "string", description: "ISO-8601: only neighbours created on/before" },
|
|
55390
|
+
limit: { type: "integer", description: "Max documents to return (default 50, max 200)" },
|
|
55391
|
+
requestor: { type: "string", description: "Name of the agent making this request" }
|
|
55392
|
+
}
|
|
55393
|
+
},
|
|
55394
|
+
handler: getNeighborsHandler
|
|
55395
|
+
};
|
|
55396
|
+
});
|
|
55397
|
+
|
|
54935
55398
|
// ../../_shared/mcp-tools/get-document.ts
|
|
54936
55399
|
async function handler2(supabase, args, ctx) {
|
|
54937
55400
|
const document_id = args.document_id;
|
|
@@ -54987,11 +55450,11 @@ var init_get_document = __esm(() => {
|
|
|
54987
55450
|
});
|
|
54988
55451
|
|
|
54989
55452
|
// ../../_shared/mcp-tools/get-help-content.ts
|
|
54990
|
-
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 9), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project\'s docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you read (shown by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`) when updating a document. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n10. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n11. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title="Same Title", content="...", document_id="abc123",\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
|
|
55453
|
+
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **14 MCP tools** (13 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 9), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_set_relation` | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` | Remove a relation | `source_id`, `target_id`, `rel_type` |\n| `cerefox_get_relations` | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project\'s docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you read (shown by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`) when updating a document. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n10. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n11. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behaviour. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n12. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title="Same Title", content="...", document_id="abc123",\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_set_relation` | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` | Remove a relation | `source_id`, `target_id`, `rel_type` |\n| `cerefox_get_relations` | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
|
|
54991
55454
|
var init_get_help_content = __esm(() => {
|
|
54992
55455
|
HELP_SECTIONS = {
|
|
54993
|
-
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 9), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |",
|
|
54994
|
-
"Essential Rules": '## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you read (shown by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`) when updating a document. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n10. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n11. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.',
|
|
55456
|
+
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 9), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_set_relation` | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` | Remove a relation | `source_id`, `target_id`, `rel_type` |\n| `cerefox_get_relations` | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |",
|
|
55457
|
+
"Essential Rules": '## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.\n8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don\'t write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don\'t construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.\n9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you read (shown by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`) when updating a document. If it\'s stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer\'s work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.\n10. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates\' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.\n11. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behaviour. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.\n12. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc\'s full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.',
|
|
54995
55458
|
"Update Workflow (ID-based -- preferred)": `## Update Workflow (ID-based -- preferred)
|
|
54996
55459
|
|
|
54997
55460
|
\`\`\`
|
|
@@ -55003,7 +55466,7 @@ ingest(title="Same Title", content="...", document_id="abc123",
|
|
|
55003
55466
|
On a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.`,
|
|
55004
55467
|
"Update Workflow (title-based -- fallback)": '## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```',
|
|
55005
55468
|
"Catch-Up Workflow": '## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```',
|
|
55006
|
-
"CLI fallback (when MCP is unavailable)": '## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.'
|
|
55469
|
+
"CLI fallback (when MCP is unavailable)": '## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …).\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_set_relation` | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |\n| `cerefox_delete_relation` | Remove a relation | `source_id`, `target_id`, `rel_type` |\n| `cerefox_get_relations` | All relations touching a document, both directions | `document_id` |\n| `cerefox_get_neighbors` | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.'
|
|
55007
55470
|
};
|
|
55008
55471
|
HELP_SECTION_HEADINGS = ["Tools", "Essential Rules", "Update Workflow (ID-based -- preferred)", "Update Workflow (title-based -- fallback)", "Catch-Up Workflow", "CLI fallback (when MCP is unavailable)"];
|
|
55009
55472
|
});
|
|
@@ -55591,10 +56054,12 @@ async function handler9(supabase, args, ctx) {
|
|
|
55591
56054
|
const project_name = args.project_name;
|
|
55592
56055
|
const match_count = args.match_count ?? 5;
|
|
55593
56056
|
const mode = args.mode ?? "docs";
|
|
55594
|
-
const alpha = args.alpha ??
|
|
55595
|
-
const min_score = args.min_score ??
|
|
56057
|
+
const alpha = args.alpha ?? getConfiguredSearchAlpha();
|
|
56058
|
+
const min_score = args.min_score ?? getConfiguredMinSearchScore();
|
|
55596
56059
|
const min_term_coverage = args.min_term_coverage ?? getMinTermCoverage();
|
|
55597
56060
|
const coverageParam = min_term_coverage !== undefined ? { p_min_term_coverage: min_term_coverage } : {};
|
|
56061
|
+
const scoreParam = min_score !== undefined ? { p_min_score: min_score } : {};
|
|
56062
|
+
const alphaParam = alpha !== undefined ? { p_alpha: alpha } : {};
|
|
55598
56063
|
const metadata_filter = args.metadata_filter ?? null;
|
|
55599
56064
|
const requested_max_bytes = args.max_bytes;
|
|
55600
56065
|
const ceiling = getMaxResponseBytes();
|
|
@@ -55635,10 +56100,10 @@ async function handler9(supabase, args, ctx) {
|
|
|
55635
56100
|
p_query_text: query,
|
|
55636
56101
|
p_query_embedding: embedding,
|
|
55637
56102
|
p_match_count: match_count,
|
|
55638
|
-
p_alpha: alpha,
|
|
55639
56103
|
p_use_upgrade: false,
|
|
55640
56104
|
p_project_id: projectId,
|
|
55641
|
-
|
|
56105
|
+
...alphaParam,
|
|
56106
|
+
...scoreParam,
|
|
55642
56107
|
...metaFilterParam,
|
|
55643
56108
|
...coverageParam
|
|
55644
56109
|
};
|
|
@@ -55648,9 +56113,9 @@ async function handler9(supabase, args, ctx) {
|
|
|
55648
56113
|
p_query_text: query,
|
|
55649
56114
|
p_query_embedding: embedding,
|
|
55650
56115
|
p_match_count: match_count,
|
|
55651
|
-
p_alpha: alpha,
|
|
55652
56116
|
p_project_id: projectId,
|
|
55653
|
-
|
|
56117
|
+
...alphaParam,
|
|
56118
|
+
...scoreParam,
|
|
55654
56119
|
...metaFilterParam,
|
|
55655
56120
|
...coverageParam
|
|
55656
56121
|
};
|
|
@@ -55819,6 +56284,7 @@ var init_set_document_projects = __esm(() => {
|
|
|
55819
56284
|
var ALL_TOOLS, TOOLS_BY_NAME;
|
|
55820
56285
|
var init_mcp_tools = __esm(() => {
|
|
55821
56286
|
init_audit_log();
|
|
56287
|
+
init_relations();
|
|
55822
56288
|
init_get_document();
|
|
55823
56289
|
init_get_help();
|
|
55824
56290
|
init_ingest();
|
|
@@ -55839,6 +56305,10 @@ var init_mcp_tools = __esm(() => {
|
|
|
55839
56305
|
listProjectsTool,
|
|
55840
56306
|
setDocumentProjectsTool,
|
|
55841
56307
|
auditLogTool,
|
|
56308
|
+
setRelationTool,
|
|
56309
|
+
deleteRelationTool,
|
|
56310
|
+
getRelationsTool,
|
|
56311
|
+
getNeighborsTool,
|
|
55842
56312
|
getHelpTool
|
|
55843
56313
|
];
|
|
55844
56314
|
TOOLS_BY_NAME = Object.fromEntries(ALL_TOOLS.map((t) => [t.name, t]));
|
|
@@ -69053,7 +69523,7 @@ var init_server3 = __esm(() => {
|
|
|
69053
69523
|
// src/bin/cerefox.ts
|
|
69054
69524
|
init_cli_core();
|
|
69055
69525
|
|
|
69056
|
-
// ../../node_modules/.bun/commander@
|
|
69526
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
|
|
69057
69527
|
var import__ = __toESM(require_commander(), 1);
|
|
69058
69528
|
var {
|
|
69059
69529
|
program,
|
|
@@ -69478,6 +69948,18 @@ var CONFIG_KEYS = [
|
|
|
69478
69948
|
{
|
|
69479
69949
|
key: "requestor_identity_format",
|
|
69480
69950
|
description: "Regex the requestor/author must match (only enforced when the above is on)."
|
|
69951
|
+
},
|
|
69952
|
+
{
|
|
69953
|
+
key: "min_search_score",
|
|
69954
|
+
description: "0–1 — minimum cosine similarity for vector-side results. Default 0.5 (use 0.6 with the local embedder)."
|
|
69955
|
+
},
|
|
69956
|
+
{
|
|
69957
|
+
key: "min_term_coverage",
|
|
69958
|
+
description: "0–1 — fraction of a query's meaningful terms a keyword OR-fallback match must cover to count as confident. Default 0.5."
|
|
69959
|
+
},
|
|
69960
|
+
{
|
|
69961
|
+
key: "search_alpha",
|
|
69962
|
+
description: "0–1 — hybrid fusion weight: 1 = pure semantic, 0 = pure keyword. Default 0.7."
|
|
69481
69963
|
}
|
|
69482
69964
|
];
|
|
69483
69965
|
function action4(options) {
|
|
@@ -75020,8 +75502,8 @@ import { homedir as homedir6 } from "node:os";
|
|
|
75020
75502
|
import { join as join9 } from "node:path";
|
|
75021
75503
|
|
|
75022
75504
|
// ../../_shared/ef-meta/index.ts
|
|
75023
|
-
var EF_VERSION = "1.0.
|
|
75024
|
-
var EF_LAST_CHANGED = "1.0.
|
|
75505
|
+
var EF_VERSION = "1.1.0-beta.1";
|
|
75506
|
+
var EF_LAST_CHANGED = "1.1.0-beta.1";
|
|
75025
75507
|
|
|
75026
75508
|
// src/cli/util/checks.ts
|
|
75027
75509
|
init_config();
|
|
@@ -75668,11 +76150,17 @@ async function action15(options) {
|
|
|
75668
76150
|
process.exit(1);
|
|
75669
76151
|
}
|
|
75670
76152
|
if (!options.json) {
|
|
75671
|
-
|
|
76153
|
+
if (warnCount > 0) {
|
|
76154
|
+
println(cErr.yellow("⚠ ") + `${warnCount} warning${warnCount === 1 ? "" : "s"} — see above.`);
|
|
76155
|
+
} else {
|
|
76156
|
+
println(cErr.green("✓") + " All checks passed.");
|
|
76157
|
+
}
|
|
75672
76158
|
}
|
|
76159
|
+
if (options.strict && warnCount > 0)
|
|
76160
|
+
process.exit(1);
|
|
75673
76161
|
}
|
|
75674
76162
|
function registerDoctor(program2) {
|
|
75675
|
-
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").action(action15);
|
|
76163
|
+
program2.command("doctor").description("Run diagnostic checks against the installed Cerefox.").option("--json", "Emit machine-readable JSON (no colours, structured output).").option("--strict", "Exit non-zero when any check warns (default: only errors fail).").action(action15);
|
|
75676
76164
|
}
|
|
75677
76165
|
|
|
75678
76166
|
// src/cli/commands/get-audit-log.ts
|
|
@@ -75719,6 +76207,134 @@ function registerGetAuditLog(program2) {
|
|
|
75719
76207
|
program2.command("get-audit-log").description("Query the audit log with optional filters.").option("-d, --document-id <uuid>", "Filter by document.").option("-a, --author <name>", "Filter by author.").option("-o, --operation <type>", "Filter by operation: create, update-content, update-metadata, delete, restore.").option("--since <iso>", "Lower-bound ISO timestamp.").option("--until <iso>", "Upper-bound ISO timestamp.").option("-l, --limit <n>", "Maximum entries (max 200).", "50").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action16);
|
|
75720
76208
|
}
|
|
75721
76209
|
|
|
76210
|
+
// src/cli/commands/relation.ts
|
|
76211
|
+
init_cli_core();
|
|
76212
|
+
init_client();
|
|
76213
|
+
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
76214
|
+
function requireUuid(value, field) {
|
|
76215
|
+
const v = value.trim();
|
|
76216
|
+
if (!UUID_RE3.test(v)) {
|
|
76217
|
+
throw userError(`${field} must be a document UUID (got: ${value}).`, "Search for the document first — results show `[id: <uuid>]`.");
|
|
76218
|
+
}
|
|
76219
|
+
return v;
|
|
76220
|
+
}
|
|
76221
|
+
function registerRelationSet(program2) {
|
|
76222
|
+
program2.command("set <source-id> <rel-type> <target-id>").description("Link two documents: <source> --<rel-type>--> <target>.").option("--meta <json>", "JSON metadata for the edge (note, confidence, …).").option("--author <name>", "Who is creating this relation.").option("--json", "Emit machine-readable JSON.").action(async (sourceId, relType, targetId, options) => {
|
|
76223
|
+
const source = requireUuid(sourceId, "source-id");
|
|
76224
|
+
const target = requireUuid(targetId, "target-id");
|
|
76225
|
+
if (!relType.trim())
|
|
76226
|
+
throw userError("rel-type is required.");
|
|
76227
|
+
let metadata = {};
|
|
76228
|
+
if (options.meta) {
|
|
76229
|
+
try {
|
|
76230
|
+
metadata = JSON.parse(options.meta);
|
|
76231
|
+
} catch {
|
|
76232
|
+
throw userError(`--meta must be valid JSON (got: ${options.meta})`);
|
|
76233
|
+
}
|
|
76234
|
+
}
|
|
76235
|
+
const author = resolveAuthor(options.author);
|
|
76236
|
+
const authorType = resolveAuthorType(undefined);
|
|
76237
|
+
if (author === "unknown") {
|
|
76238
|
+
warn("No --author / CEREFOX_AUTHOR_NAME set — audit log will record this write as 'unknown'.");
|
|
76239
|
+
}
|
|
76240
|
+
const client = getClient();
|
|
76241
|
+
const data = await client.rpc("cerefox_set_relation", {
|
|
76242
|
+
p_source_id: source,
|
|
76243
|
+
p_target_id: target,
|
|
76244
|
+
p_rel_type: relType.trim(),
|
|
76245
|
+
p_author: author,
|
|
76246
|
+
p_author_type: authorType,
|
|
76247
|
+
p_metadata: metadata
|
|
76248
|
+
});
|
|
76249
|
+
const symmetric = Boolean(data?.[0]?.is_symmetric);
|
|
76250
|
+
if (options.json) {
|
|
76251
|
+
printJson({ source, target, rel_type: relType.trim(), symmetric });
|
|
76252
|
+
return;
|
|
76253
|
+
}
|
|
76254
|
+
println(c.green("✓ ") + `${source} --${relType.trim()}--> ${target}` + (symmetric ? c.dim(" (symmetric — reverse edge written too)") : ""));
|
|
76255
|
+
if (relType.trim() === "supersedes")
|
|
76256
|
+
println(c.dim(" Target marked superseded."));
|
|
76257
|
+
if (relType.trim() === "contradicts")
|
|
76258
|
+
println(c.dim(" Both documents marked stale."));
|
|
76259
|
+
});
|
|
76260
|
+
}
|
|
76261
|
+
function registerRelationDelete(program2) {
|
|
76262
|
+
program2.command("delete <source-id> <rel-type> <target-id>").description("Remove a relation (symmetric types remove both directions).").option("--author <name>", "Who is removing this relation.").action(async (sourceId, relType, targetId, options) => {
|
|
76263
|
+
const source = requireUuid(sourceId, "source-id");
|
|
76264
|
+
const target = requireUuid(targetId, "target-id");
|
|
76265
|
+
const author = resolveAuthor(options.author);
|
|
76266
|
+
const authorType = resolveAuthorType(undefined);
|
|
76267
|
+
if (author === "unknown") {
|
|
76268
|
+
warn("No --author / CEREFOX_AUTHOR_NAME set — audit log will record this write as 'unknown'.");
|
|
76269
|
+
}
|
|
76270
|
+
const client = getClient();
|
|
76271
|
+
const removed = await client.rpc("cerefox_delete_relation", {
|
|
76272
|
+
p_source_id: source,
|
|
76273
|
+
p_target_id: target,
|
|
76274
|
+
p_rel_type: relType.trim(),
|
|
76275
|
+
p_author: author,
|
|
76276
|
+
p_author_type: authorType
|
|
76277
|
+
});
|
|
76278
|
+
if (!removed) {
|
|
76279
|
+
println(c.dim("(no such relation — nothing removed)"));
|
|
76280
|
+
return;
|
|
76281
|
+
}
|
|
76282
|
+
println(c.green("✓ ") + `Removed ${removed} relation row(s).`);
|
|
76283
|
+
println(c.dim(" Lifecycle status left as-is — a document may be superseded by something else."));
|
|
76284
|
+
});
|
|
76285
|
+
}
|
|
76286
|
+
function registerRelationList(program2) {
|
|
76287
|
+
program2.command("list <document-id>").description("Show every relation touching a document (both directions).").option("--json", "Emit machine-readable JSON.").action(async (documentId, options) => {
|
|
76288
|
+
const id = requireUuid(documentId, "document-id");
|
|
76289
|
+
const client = getClient();
|
|
76290
|
+
const rows = await client.rpc("cerefox_get_relations", {
|
|
76291
|
+
p_document_id: id
|
|
76292
|
+
}) ?? [];
|
|
76293
|
+
if (options.json) {
|
|
76294
|
+
printJson(rows);
|
|
76295
|
+
return;
|
|
76296
|
+
}
|
|
76297
|
+
if (rows.length === 0) {
|
|
76298
|
+
println(c.dim("(no relations)"));
|
|
76299
|
+
return;
|
|
76300
|
+
}
|
|
76301
|
+
for (const r of rows) {
|
|
76302
|
+
const arrow = r.direction === "outbound" ? "→" : "←";
|
|
76303
|
+
const life = r.other_lifecycle && r.other_lifecycle !== "active" ? c.yellow(` [${r.other_lifecycle}]`) : "";
|
|
76304
|
+
println(` ${arrow} ${c.bold(r.rel_type)} ${r.other_title}${life} ${c.dim(`[id: ${r.other_id}]`)}`);
|
|
76305
|
+
}
|
|
76306
|
+
});
|
|
76307
|
+
}
|
|
76308
|
+
function registerRelationNeighbors(program2) {
|
|
76309
|
+
program2.command("neighbors <document-id> <rel-type>").description("Walk the graph from a document along one relation type.").option("-d, --depth <n>", "Hops to follow (1–5).", "1").option("-l, --limit <n>", "Max documents to return.", "50").option("--json", "Emit machine-readable JSON.").action(async (documentId, relType, options) => {
|
|
76310
|
+
const id = requireUuid(documentId, "document-id");
|
|
76311
|
+
const depth = Number.parseInt(options.depth ?? "1", 10);
|
|
76312
|
+
const limit = Number.parseInt(options.limit ?? "50", 10);
|
|
76313
|
+
if (Number.isNaN(depth) || depth < 1 || depth > 5) {
|
|
76314
|
+
throw userError("--depth must be between 1 and 5.");
|
|
76315
|
+
}
|
|
76316
|
+
const client = getClient();
|
|
76317
|
+
const rows = await client.rpc("cerefox_get_neighbors", {
|
|
76318
|
+
p_document_id: id,
|
|
76319
|
+
p_rel_type: relType.trim(),
|
|
76320
|
+
p_depth: depth,
|
|
76321
|
+
p_limit: Number.isNaN(limit) ? 50 : limit
|
|
76322
|
+
}) ?? [];
|
|
76323
|
+
if (options.json) {
|
|
76324
|
+
printJson(rows);
|
|
76325
|
+
return;
|
|
76326
|
+
}
|
|
76327
|
+
if (rows.length === 0) {
|
|
76328
|
+
println(c.dim(`(nothing reachable via "${relType.trim()}")`));
|
|
76329
|
+
return;
|
|
76330
|
+
}
|
|
76331
|
+
for (const r of rows) {
|
|
76332
|
+
const life = r.lifecycle_status && r.lifecycle_status !== "active" ? c.yellow(` [${r.lifecycle_status}]`) : "";
|
|
76333
|
+
println(` ${c.dim(`depth ${r.depth}`)} ${r.direction === "outbound" ? "→" : "←"} ` + `${r.title}${life} ${c.dim(`[id: ${r.document_id}]`)}`);
|
|
76334
|
+
}
|
|
76335
|
+
});
|
|
76336
|
+
}
|
|
76337
|
+
|
|
75722
76338
|
// src/cli/commands/get-doc.ts
|
|
75723
76339
|
init_cli_core();
|
|
75724
76340
|
init_cli_core();
|
|
@@ -77494,8 +78110,10 @@ async function action29(query, options) {
|
|
|
77494
78110
|
throw userError("Empty query.");
|
|
77495
78111
|
}
|
|
77496
78112
|
const matchCount = parsePositiveInt(options.matchCount, "--match-count", 5);
|
|
77497
|
-
const
|
|
77498
|
-
const
|
|
78113
|
+
const envAlpha = getConfiguredSearchAlpha();
|
|
78114
|
+
const alphaParam = options.alpha !== undefined ? { p_alpha: parseFloat01(options.alpha, "--alpha", envAlpha ?? 0.7) } : envAlpha !== undefined ? { p_alpha: envAlpha } : {};
|
|
78115
|
+
const envScore = getConfiguredMinSearchScore();
|
|
78116
|
+
const scoreParam = options.minScore !== undefined ? { p_min_score: parseFloat01(options.minScore, "--min-score", envScore ?? 0.5) } : envScore !== undefined ? { p_min_score: envScore } : {};
|
|
77499
78117
|
const envCoverage = getMinTermCoverage();
|
|
77500
78118
|
const coverageParam = options.minTermCoverage !== undefined ? { p_min_term_coverage: parseFloat01(options.minTermCoverage, "--min-term-coverage", envCoverage ?? 0.5) } : envCoverage !== undefined ? { p_min_term_coverage: envCoverage } : {};
|
|
77501
78119
|
const maxBytes = parseNonNegativeInt(options.maxBytes, "--max-bytes", getMaxResponseBytes());
|
|
@@ -77537,10 +78155,10 @@ async function action29(query, options) {
|
|
|
77537
78155
|
p_query_text: query,
|
|
77538
78156
|
p_query_embedding: embedding,
|
|
77539
78157
|
p_match_count: matchCount,
|
|
77540
|
-
p_alpha: alpha,
|
|
77541
78158
|
p_use_upgrade: false,
|
|
77542
78159
|
p_project_id: projectId,
|
|
77543
|
-
|
|
78160
|
+
...alphaParam,
|
|
78161
|
+
...scoreParam,
|
|
77544
78162
|
...metaFilterParam,
|
|
77545
78163
|
...coverageParam
|
|
77546
78164
|
};
|
|
@@ -77550,9 +78168,9 @@ async function action29(query, options) {
|
|
|
77550
78168
|
p_query_text: query,
|
|
77551
78169
|
p_query_embedding: embedding,
|
|
77552
78170
|
p_match_count: matchCount,
|
|
77553
|
-
p_alpha: alpha,
|
|
77554
78171
|
p_project_id: projectId,
|
|
77555
|
-
|
|
78172
|
+
...alphaParam,
|
|
78173
|
+
...scoreParam,
|
|
77556
78174
|
...metaFilterParam,
|
|
77557
78175
|
...coverageParam
|
|
77558
78176
|
};
|
|
@@ -77736,7 +78354,8 @@ async function action30(options) {
|
|
|
77736
78354
|
stdio: "inherit"
|
|
77737
78355
|
});
|
|
77738
78356
|
if (result.status !== 0) {
|
|
77739
|
-
|
|
78357
|
+
const notFound2 = result.error?.code === "ENOENT";
|
|
78358
|
+
throw systemError(notFound2 ? `${runtime.description} was not found on PATH (tried \`${runtime.command}\`).` : `${runtime.description} install failed (exit ${result.status}).`, notFound2 ? `Install ${runtime.description}, or upgrade manually: \`${runtime.command} ${runtime.args(target).join(" ")}\`` : `Try the manual command: \`${runtime.command} ${runtime.args(target).join(" ")}\``);
|
|
77740
78359
|
}
|
|
77741
78360
|
println("");
|
|
77742
78361
|
println(c.green(`✓ Upgraded to ${target}.`));
|
|
@@ -81454,7 +82073,7 @@ function logWebUsage(ctx, params) {
|
|
|
81454
82073
|
}
|
|
81455
82074
|
|
|
81456
82075
|
// src/web/routes/discovery.ts
|
|
81457
|
-
var
|
|
82076
|
+
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
81458
82077
|
var DOC_COLS = "id, title, source, source_path, content_hash, metadata, chunk_count, total_chars, review_status, created_at, updated_at, deleted_at";
|
|
81459
82078
|
function jsonByteLength(value) {
|
|
81460
82079
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -81926,7 +82545,7 @@ function registerDiscoveryRoutes(app, ctx) {
|
|
|
81926
82545
|
if (!path) {
|
|
81927
82546
|
return c2.json({ tried_path: "", anchor, matches: [] });
|
|
81928
82547
|
}
|
|
81929
|
-
if (
|
|
82548
|
+
if (UUID_RE4.test(path)) {
|
|
81930
82549
|
if (path === fromDocId) {
|
|
81931
82550
|
return c2.json({ tried_path: path, anchor, matches: [] });
|
|
81932
82551
|
}
|
|
@@ -83435,6 +84054,11 @@ Learn more:
|
|
|
83435
84054
|
const metadata = program2.command("metadata").description("Metadata: keys, search.");
|
|
83436
84055
|
moveInto(metadata, registerListMetadataKeys, "keys");
|
|
83437
84056
|
moveInto(metadata, registerMetadataSearch, "search");
|
|
84057
|
+
const relation = program2.command("relation").description("Document relations: set, delete, list, neighbors.");
|
|
84058
|
+
registerRelationSet(relation);
|
|
84059
|
+
registerRelationDelete(relation);
|
|
84060
|
+
registerRelationList(relation);
|
|
84061
|
+
registerRelationNeighbors(relation);
|
|
83438
84062
|
const audit = program2.command("audit").description("Audit log: list.");
|
|
83439
84063
|
moveInto(audit, registerGetAuditLog, "list");
|
|
83440
84064
|
const config2 = program2.command("config").description("Runtime config: list, get, set.");
|