@cerefox/memory 1.0.5 → 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 +836 -198
- 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 +74 -12
- 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 +311 -17
- package/dist/server-assets/db/schema.sql +35 -2
- package/docs/guides/configuration.md +23 -5
- 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-Csj-6UHY.js +0 -125
- package/dist/frontend/assets/index-Csj-6UHY.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
|
|
@@ -25217,21 +25471,46 @@ function getMaxResponseBytes() {
|
|
|
25217
25471
|
const n = Number.parseInt(raw, 10);
|
|
25218
25472
|
return Number.isNaN(n) || n <= 0 ? MAX_RESPONSE_BYTES : n;
|
|
25219
25473
|
}
|
|
25220
|
-
function
|
|
25221
|
-
const
|
|
25222
|
-
const
|
|
25223
|
-
if (
|
|
25224
|
-
return
|
|
25225
|
-
|
|
25226
|
-
|
|
25474
|
+
function readEnv(name) {
|
|
25475
|
+
const g = globalThis;
|
|
25476
|
+
const fromProcess = g.process?.env?.[name];
|
|
25477
|
+
if (fromProcess !== undefined && fromProcess !== "")
|
|
25478
|
+
return fromProcess;
|
|
25479
|
+
try {
|
|
25480
|
+
const fromDeno = g.Deno?.env?.get(name);
|
|
25481
|
+
return fromDeno === "" ? undefined : fromDeno;
|
|
25482
|
+
} catch {
|
|
25483
|
+
return;
|
|
25484
|
+
}
|
|
25227
25485
|
}
|
|
25228
|
-
function
|
|
25229
|
-
const raw =
|
|
25230
|
-
if (raw === undefined
|
|
25486
|
+
function readUnitInterval(name) {
|
|
25487
|
+
const raw = readEnv(name);
|
|
25488
|
+
if (raw === undefined)
|
|
25231
25489
|
return;
|
|
25232
25490
|
const n = Number.parseFloat(raw);
|
|
25233
25491
|
return Number.isNaN(n) || n < 0 || n > 1 ? undefined : n;
|
|
25234
25492
|
}
|
|
25493
|
+
function getSearchAlpha() {
|
|
25494
|
+
return readUnitInterval("CEREFOX_SEARCH_ALPHA") ?? DEFAULT_SEARCH_ALPHA;
|
|
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
|
+
}
|
|
25507
|
+
function getMinSearchScore() {
|
|
25508
|
+
const fallback = readEnv("CEREFOX_EMBEDDER") === "local" ? DEFAULT_MIN_SEARCH_SCORE_LOCAL : DEFAULT_MIN_SEARCH_SCORE;
|
|
25509
|
+
return readUnitInterval("CEREFOX_MIN_SEARCH_SCORE") ?? fallback;
|
|
25510
|
+
}
|
|
25511
|
+
function getMinTermCoverage() {
|
|
25512
|
+
return readUnitInterval("CEREFOX_MIN_TERM_COVERAGE");
|
|
25513
|
+
}
|
|
25235
25514
|
function applyByteBudget(rows, maxBytes) {
|
|
25236
25515
|
const accepted = [];
|
|
25237
25516
|
let usedBytes = 0;
|
|
@@ -25259,7 +25538,7 @@ function logUsage(supabase, params) {
|
|
|
25259
25538
|
p_extra: params.extra ?? {}
|
|
25260
25539
|
})).catch(() => {});
|
|
25261
25540
|
}
|
|
25262
|
-
var MAX_RESPONSE_BYTES = 200000, DEFAULT_MIN_SEARCH_SCORE = 0.5, DEFAULT_MIN_SEARCH_SCORE_LOCAL = 0.6;
|
|
25541
|
+
var MAX_RESPONSE_BYTES = 200000, DEFAULT_MIN_SEARCH_SCORE = 0.5, DEFAULT_MIN_SEARCH_SCORE_LOCAL = 0.6, DEFAULT_SEARCH_ALPHA = 0.7;
|
|
25263
25542
|
|
|
25264
25543
|
// ../../_shared/mcp-tools/_projects.ts
|
|
25265
25544
|
async function ensureDocumentInProject(supabase, documentId, projectName) {
|
|
@@ -54918,6 +55197,204 @@ var init_types3 = __esm(() => {
|
|
|
54918
55197
|
};
|
|
54919
55198
|
});
|
|
54920
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
|
+
|
|
54921
55398
|
// ../../_shared/mcp-tools/get-document.ts
|
|
54922
55399
|
async function handler2(supabase, args, ctx) {
|
|
54923
55400
|
const document_id = args.document_id;
|
|
@@ -54973,11 +55450,11 @@ var init_get_document = __esm(() => {
|
|
|
54973
55450
|
});
|
|
54974
55451
|
|
|
54975
55452
|
// ../../_shared/mcp-tools/get-help-content.ts
|
|
54976
|
-
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;
|
|
54977
55454
|
var init_get_help_content = __esm(() => {
|
|
54978
55455
|
HELP_SECTIONS = {
|
|
54979
|
-
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) |",
|
|
54980
|
-
"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`.',
|
|
54981
55458
|
"Update Workflow (ID-based -- preferred)": `## Update Workflow (ID-based -- preferred)
|
|
54982
55459
|
|
|
54983
55460
|
\`\`\`
|
|
@@ -54989,7 +55466,7 @@ ingest(title="Same Title", content="...", document_id="abc123",
|
|
|
54989
55466
|
On a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.`,
|
|
54990
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```',
|
|
54991
55468
|
"Catch-Up Workflow": '## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```',
|
|
54992
|
-
"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.'
|
|
54993
55470
|
};
|
|
54994
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)"];
|
|
54995
55472
|
});
|
|
@@ -55577,10 +56054,12 @@ async function handler9(supabase, args, ctx) {
|
|
|
55577
56054
|
const project_name = args.project_name;
|
|
55578
56055
|
const match_count = args.match_count ?? 5;
|
|
55579
56056
|
const mode = args.mode ?? "docs";
|
|
55580
|
-
const alpha = args.alpha ??
|
|
55581
|
-
const min_score = args.min_score ??
|
|
56057
|
+
const alpha = args.alpha ?? getConfiguredSearchAlpha();
|
|
56058
|
+
const min_score = args.min_score ?? getConfiguredMinSearchScore();
|
|
55582
56059
|
const min_term_coverage = args.min_term_coverage ?? getMinTermCoverage();
|
|
55583
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 } : {};
|
|
55584
56063
|
const metadata_filter = args.metadata_filter ?? null;
|
|
55585
56064
|
const requested_max_bytes = args.max_bytes;
|
|
55586
56065
|
const ceiling = getMaxResponseBytes();
|
|
@@ -55621,10 +56100,10 @@ async function handler9(supabase, args, ctx) {
|
|
|
55621
56100
|
p_query_text: query,
|
|
55622
56101
|
p_query_embedding: embedding,
|
|
55623
56102
|
p_match_count: match_count,
|
|
55624
|
-
p_alpha: alpha,
|
|
55625
56103
|
p_use_upgrade: false,
|
|
55626
56104
|
p_project_id: projectId,
|
|
55627
|
-
|
|
56105
|
+
...alphaParam,
|
|
56106
|
+
...scoreParam,
|
|
55628
56107
|
...metaFilterParam,
|
|
55629
56108
|
...coverageParam
|
|
55630
56109
|
};
|
|
@@ -55634,9 +56113,9 @@ async function handler9(supabase, args, ctx) {
|
|
|
55634
56113
|
p_query_text: query,
|
|
55635
56114
|
p_query_embedding: embedding,
|
|
55636
56115
|
p_match_count: match_count,
|
|
55637
|
-
p_alpha: alpha,
|
|
55638
56116
|
p_project_id: projectId,
|
|
55639
|
-
|
|
56117
|
+
...alphaParam,
|
|
56118
|
+
...scoreParam,
|
|
55640
56119
|
...metaFilterParam,
|
|
55641
56120
|
...coverageParam
|
|
55642
56121
|
};
|
|
@@ -55805,6 +56284,7 @@ var init_set_document_projects = __esm(() => {
|
|
|
55805
56284
|
var ALL_TOOLS, TOOLS_BY_NAME;
|
|
55806
56285
|
var init_mcp_tools = __esm(() => {
|
|
55807
56286
|
init_audit_log();
|
|
56287
|
+
init_relations();
|
|
55808
56288
|
init_get_document();
|
|
55809
56289
|
init_get_help();
|
|
55810
56290
|
init_ingest();
|
|
@@ -55825,6 +56305,10 @@ var init_mcp_tools = __esm(() => {
|
|
|
55825
56305
|
listProjectsTool,
|
|
55826
56306
|
setDocumentProjectsTool,
|
|
55827
56307
|
auditLogTool,
|
|
56308
|
+
setRelationTool,
|
|
56309
|
+
deleteRelationTool,
|
|
56310
|
+
getRelationsTool,
|
|
56311
|
+
getNeighborsTool,
|
|
55828
56312
|
getHelpTool
|
|
55829
56313
|
];
|
|
55830
56314
|
TOOLS_BY_NAME = Object.fromEntries(ALL_TOOLS.map((t) => [t.name, t]));
|
|
@@ -69039,7 +69523,7 @@ var init_server3 = __esm(() => {
|
|
|
69039
69523
|
// src/bin/cerefox.ts
|
|
69040
69524
|
init_cli_core();
|
|
69041
69525
|
|
|
69042
|
-
// ../../node_modules/.bun/commander@
|
|
69526
|
+
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
|
|
69043
69527
|
var import__ = __toESM(require_commander(), 1);
|
|
69044
69528
|
var {
|
|
69045
69529
|
program,
|
|
@@ -69464,6 +69948,18 @@ var CONFIG_KEYS = [
|
|
|
69464
69948
|
{
|
|
69465
69949
|
key: "requestor_identity_format",
|
|
69466
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."
|
|
69467
69963
|
}
|
|
69468
69964
|
];
|
|
69469
69965
|
function action4(options) {
|
|
@@ -75006,8 +75502,8 @@ import { homedir as homedir6 } from "node:os";
|
|
|
75006
75502
|
import { join as join9 } from "node:path";
|
|
75007
75503
|
|
|
75008
75504
|
// ../../_shared/ef-meta/index.ts
|
|
75009
|
-
var EF_VERSION = "1.0.
|
|
75010
|
-
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";
|
|
75011
75507
|
|
|
75012
75508
|
// src/cli/util/checks.ts
|
|
75013
75509
|
init_config();
|
|
@@ -75654,11 +76150,17 @@ async function action15(options) {
|
|
|
75654
76150
|
process.exit(1);
|
|
75655
76151
|
}
|
|
75656
76152
|
if (!options.json) {
|
|
75657
|
-
|
|
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
|
+
}
|
|
75658
76158
|
}
|
|
76159
|
+
if (options.strict && warnCount > 0)
|
|
76160
|
+
process.exit(1);
|
|
75659
76161
|
}
|
|
75660
76162
|
function registerDoctor(program2) {
|
|
75661
|
-
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);
|
|
75662
76164
|
}
|
|
75663
76165
|
|
|
75664
76166
|
// src/cli/commands/get-audit-log.ts
|
|
@@ -75705,6 +76207,134 @@ function registerGetAuditLog(program2) {
|
|
|
75705
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);
|
|
75706
76208
|
}
|
|
75707
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
|
+
|
|
75708
76338
|
// src/cli/commands/get-doc.ts
|
|
75709
76339
|
init_cli_core();
|
|
75710
76340
|
init_cli_core();
|
|
@@ -77480,8 +78110,10 @@ async function action29(query, options) {
|
|
|
77480
78110
|
throw userError("Empty query.");
|
|
77481
78111
|
}
|
|
77482
78112
|
const matchCount = parsePositiveInt(options.matchCount, "--match-count", 5);
|
|
77483
|
-
const
|
|
77484
|
-
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 } : {};
|
|
77485
78117
|
const envCoverage = getMinTermCoverage();
|
|
77486
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 } : {};
|
|
77487
78119
|
const maxBytes = parseNonNegativeInt(options.maxBytes, "--max-bytes", getMaxResponseBytes());
|
|
@@ -77523,10 +78155,10 @@ async function action29(query, options) {
|
|
|
77523
78155
|
p_query_text: query,
|
|
77524
78156
|
p_query_embedding: embedding,
|
|
77525
78157
|
p_match_count: matchCount,
|
|
77526
|
-
p_alpha: alpha,
|
|
77527
78158
|
p_use_upgrade: false,
|
|
77528
78159
|
p_project_id: projectId,
|
|
77529
|
-
|
|
78160
|
+
...alphaParam,
|
|
78161
|
+
...scoreParam,
|
|
77530
78162
|
...metaFilterParam,
|
|
77531
78163
|
...coverageParam
|
|
77532
78164
|
};
|
|
@@ -77536,9 +78168,9 @@ async function action29(query, options) {
|
|
|
77536
78168
|
p_query_text: query,
|
|
77537
78169
|
p_query_embedding: embedding,
|
|
77538
78170
|
p_match_count: matchCount,
|
|
77539
|
-
p_alpha: alpha,
|
|
77540
78171
|
p_project_id: projectId,
|
|
77541
|
-
|
|
78172
|
+
...alphaParam,
|
|
78173
|
+
...scoreParam,
|
|
77542
78174
|
...metaFilterParam,
|
|
77543
78175
|
...coverageParam
|
|
77544
78176
|
};
|
|
@@ -77639,7 +78271,7 @@ async function action29(query, options) {
|
|
|
77639
78271
|
}
|
|
77640
78272
|
}
|
|
77641
78273
|
function registerSearch(program2) {
|
|
77642
|
-
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: 0.7)."
|
|
78274
|
+
program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: CEREFOX_SEARCH_ALPHA; else 0.7).").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE; else 0.5, or 0.6 with the local embedder).").option("--min-term-coverage <float>", "OR-fallback keyword matches must cover at least this fraction of the query's meaningful terms to count as confident hits (default: CEREFOX_MIN_TERM_COVERAGE; else the server default 0.5; needs schema ≥ 0.9.1).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(action29);
|
|
77643
78275
|
}
|
|
77644
78276
|
|
|
77645
78277
|
// src/cli/commands/self-update.ts
|
|
@@ -77722,7 +78354,8 @@ async function action30(options) {
|
|
|
77722
78354
|
stdio: "inherit"
|
|
77723
78355
|
});
|
|
77724
78356
|
if (result.status !== 0) {
|
|
77725
|
-
|
|
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(" ")}\``);
|
|
77726
78359
|
}
|
|
77727
78360
|
println("");
|
|
77728
78361
|
println(c.green(`✓ Upgraded to ${target}.`));
|
|
@@ -81440,7 +82073,7 @@ function logWebUsage(ctx, params) {
|
|
|
81440
82073
|
}
|
|
81441
82074
|
|
|
81442
82075
|
// src/web/routes/discovery.ts
|
|
81443
|
-
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;
|
|
81444
82077
|
var DOC_COLS = "id, title, source, source_path, content_hash, metadata, chunk_count, total_chars, review_status, created_at, updated_at, deleted_at";
|
|
81445
82078
|
function jsonByteLength(value) {
|
|
81446
82079
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -81643,7 +82276,7 @@ async function runSearch(ctx, opts) {
|
|
|
81643
82276
|
p_query_text: query,
|
|
81644
82277
|
p_query_embedding: embedding,
|
|
81645
82278
|
p_match_count: count,
|
|
81646
|
-
p_alpha:
|
|
82279
|
+
p_alpha: getSearchAlpha(),
|
|
81647
82280
|
p_use_upgrade: false,
|
|
81648
82281
|
p_project_id: projectId,
|
|
81649
82282
|
p_min_score: getMinSearchScore()
|
|
@@ -81659,7 +82292,7 @@ async function runSearch(ctx, opts) {
|
|
|
81659
82292
|
p_query_text: query,
|
|
81660
82293
|
p_query_embedding: embedding,
|
|
81661
82294
|
p_match_count: Math.min(count, 5),
|
|
81662
|
-
p_alpha:
|
|
82295
|
+
p_alpha: getSearchAlpha(),
|
|
81663
82296
|
p_project_id: projectId,
|
|
81664
82297
|
p_min_score: getMinSearchScore()
|
|
81665
82298
|
};
|
|
@@ -81912,7 +82545,7 @@ function registerDiscoveryRoutes(app, ctx) {
|
|
|
81912
82545
|
if (!path) {
|
|
81913
82546
|
return c2.json({ tried_path: "", anchor, matches: [] });
|
|
81914
82547
|
}
|
|
81915
|
-
if (
|
|
82548
|
+
if (UUID_RE4.test(path)) {
|
|
81916
82549
|
if (path === fromDocId) {
|
|
81917
82550
|
return c2.json({ tried_path: path, anchor, matches: [] });
|
|
81918
82551
|
}
|
|
@@ -83421,6 +84054,11 @@ Learn more:
|
|
|
83421
84054
|
const metadata = program2.command("metadata").description("Metadata: keys, search.");
|
|
83422
84055
|
moveInto(metadata, registerListMetadataKeys, "keys");
|
|
83423
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);
|
|
83424
84062
|
const audit = program2.command("audit").description("Audit log: list.");
|
|
83425
84063
|
moveInto(audit, registerGetAuditLog, "list");
|
|
83426
84064
|
const config2 = program2.command("config").description("Runtime config: list, get, set.");
|