@lucern/mcp 0.3.0-alpha.5 → 0.3.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +877 -883
- package/dist/cli.js.map +1 -1
- package/dist/gateway.js +751 -317
- package/dist/gateway.js.map +1 -1
- package/dist/hosted-route.js +808 -890
- package/dist/hosted-route.js.map +1 -1
- package/dist/index.js +914 -888
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +505 -161
- package/dist/runtime.js.map +1 -1
- package/package.json +7 -7
package/dist/gateway.js
CHANGED
|
@@ -4865,6 +4865,11 @@ var TENANT_CLIENT_INSTALLABLE_PACKAGES = [
|
|
|
4865
4865
|
role: "sdk_dependency",
|
|
4866
4866
|
directTenantImport: false
|
|
4867
4867
|
},
|
|
4868
|
+
{
|
|
4869
|
+
packageName: "@lucern/graph-sync",
|
|
4870
|
+
role: "host_addon_runtime",
|
|
4871
|
+
directTenantImport: true
|
|
4872
|
+
},
|
|
4868
4873
|
{
|
|
4869
4874
|
packageName: "@lucern/identity",
|
|
4870
4875
|
role: "component_runtime",
|
|
@@ -4984,8 +4989,11 @@ function compactRecord(input) {
|
|
|
4984
4989
|
Object.entries(input).filter(([, value]) => value !== void 0)
|
|
4985
4990
|
);
|
|
4986
4991
|
}
|
|
4992
|
+
function isRecord(value) {
|
|
4993
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4994
|
+
}
|
|
4987
4995
|
function recordValue(value) {
|
|
4988
|
-
return
|
|
4996
|
+
return isRecord(value) ? value : {};
|
|
4989
4997
|
}
|
|
4990
4998
|
var createEvidenceProjection = defineProjection({
|
|
4991
4999
|
contractName: "create_evidence",
|
|
@@ -5691,9 +5699,16 @@ var ADD_WORKTREE = {
|
|
|
5691
5699
|
},
|
|
5692
5700
|
projectId: {
|
|
5693
5701
|
type: "string",
|
|
5694
|
-
description: "Legacy topicId alias"
|
|
5702
|
+
description: "Legacy topicId alias or resolver hint"
|
|
5703
|
+
},
|
|
5704
|
+
topicId: {
|
|
5705
|
+
type: "string",
|
|
5706
|
+
description: "Optional topic scope hint for resolver validation"
|
|
5707
|
+
},
|
|
5708
|
+
topicHint: {
|
|
5709
|
+
type: "string",
|
|
5710
|
+
description: "Natural-language topic hint for automatic topic resolution"
|
|
5695
5711
|
},
|
|
5696
|
-
topicId: { type: "string", description: "Optional topic scope hint" },
|
|
5697
5712
|
branchId: {
|
|
5698
5713
|
type: "string",
|
|
5699
5714
|
description: "The branch this worktree investigates"
|
|
@@ -5791,6 +5806,22 @@ var ADD_WORKTREE = {
|
|
|
5791
5806
|
type: "string",
|
|
5792
5807
|
description: "Optional domain pack whose shaping hooks should influence generated questions and tasks"
|
|
5793
5808
|
},
|
|
5809
|
+
tags: {
|
|
5810
|
+
type: "array",
|
|
5811
|
+
description: "Additional topic-resolution tags for the worktree"
|
|
5812
|
+
},
|
|
5813
|
+
touchedPaths: {
|
|
5814
|
+
type: "array",
|
|
5815
|
+
description: "File paths used as topic-resolution signals"
|
|
5816
|
+
},
|
|
5817
|
+
sourceRef: {
|
|
5818
|
+
type: "string",
|
|
5819
|
+
description: "Source reference used as a topic-resolution signal"
|
|
5820
|
+
},
|
|
5821
|
+
sourceKind: {
|
|
5822
|
+
type: "string",
|
|
5823
|
+
description: "Source kind used as a topic-resolution signal"
|
|
5824
|
+
},
|
|
5794
5825
|
campaign: {
|
|
5795
5826
|
type: "number",
|
|
5796
5827
|
description: "Top-level pipeline campaign number. Campaigns define the outer execution slice."
|
|
@@ -5828,7 +5859,7 @@ var ADD_WORKTREE = {
|
|
|
5828
5859
|
description: "Timestamp when worktree metadata was last reconciled"
|
|
5829
5860
|
}
|
|
5830
5861
|
},
|
|
5831
|
-
required: ["title"
|
|
5862
|
+
required: ["title"],
|
|
5832
5863
|
response: {
|
|
5833
5864
|
description: "The created worktree",
|
|
5834
5865
|
fields: {
|
|
@@ -7531,18 +7562,60 @@ var CREATE_TASK = {
|
|
|
7531
7562
|
name: "create_task",
|
|
7532
7563
|
description: "Create an execution task tied to the reasoning state. Like `git task` \u2014 tracks concrete work items (calls to make, data to gather, analyses to run) linked to questions, beliefs, or worktrees.",
|
|
7533
7564
|
parameters: {
|
|
7534
|
-
title: { type: "string", description: "Task
|
|
7565
|
+
title: { type: "string", description: "Task title" },
|
|
7535
7566
|
topicId: { type: "string", description: "Topic scope" },
|
|
7567
|
+
description: {
|
|
7568
|
+
type: "string",
|
|
7569
|
+
description: "Long-form task description"
|
|
7570
|
+
},
|
|
7536
7571
|
taskType: {
|
|
7537
7572
|
type: "string",
|
|
7538
|
-
description: "
|
|
7539
|
-
enum: [
|
|
7573
|
+
description: "Task taxonomy",
|
|
7574
|
+
enum: [
|
|
7575
|
+
"general",
|
|
7576
|
+
"find_evidence",
|
|
7577
|
+
"verify_claim",
|
|
7578
|
+
"research",
|
|
7579
|
+
"review",
|
|
7580
|
+
"interview",
|
|
7581
|
+
"analysis",
|
|
7582
|
+
"track_metrics"
|
|
7583
|
+
]
|
|
7584
|
+
},
|
|
7585
|
+
priority: {
|
|
7586
|
+
type: "string",
|
|
7587
|
+
description: "Priority",
|
|
7588
|
+
enum: ["urgent", "high", "medium", "low"]
|
|
7589
|
+
},
|
|
7590
|
+
status: {
|
|
7591
|
+
type: "string",
|
|
7592
|
+
description: "Initial status (defaults to todo)",
|
|
7593
|
+
enum: ["todo", "in_progress", "blocked", "done"]
|
|
7594
|
+
},
|
|
7595
|
+
linkedWorktreeId: {
|
|
7596
|
+
type: "string",
|
|
7597
|
+
description: "Worktree this task belongs to"
|
|
7598
|
+
},
|
|
7599
|
+
linkedBeliefId: {
|
|
7600
|
+
type: "string",
|
|
7601
|
+
description: "Belief this task supports"
|
|
7540
7602
|
},
|
|
7541
7603
|
linkedQuestionId: {
|
|
7542
7604
|
type: "string",
|
|
7543
7605
|
description: "Question this task addresses"
|
|
7544
7606
|
},
|
|
7545
|
-
|
|
7607
|
+
assigneeId: {
|
|
7608
|
+
type: "string",
|
|
7609
|
+
description: "Principal assigned to the task"
|
|
7610
|
+
},
|
|
7611
|
+
dueDate: {
|
|
7612
|
+
type: "number",
|
|
7613
|
+
description: "Due date as epoch milliseconds"
|
|
7614
|
+
},
|
|
7615
|
+
tags: {
|
|
7616
|
+
type: "array",
|
|
7617
|
+
description: "Free-form string tags"
|
|
7618
|
+
}
|
|
7546
7619
|
},
|
|
7547
7620
|
required: ["title"],
|
|
7548
7621
|
response: {
|
|
@@ -9625,9 +9698,7 @@ function mcpContractFromArgsSchema(base, args, contractName) {
|
|
|
9625
9698
|
required: converted.filter(([, field]) => field.required).map(([fieldName]) => fieldName)
|
|
9626
9699
|
};
|
|
9627
9700
|
}
|
|
9628
|
-
|
|
9629
|
-
return contract;
|
|
9630
|
-
}
|
|
9701
|
+
var defineFunctionContract = (contract) => contract;
|
|
9631
9702
|
function authUserId(context) {
|
|
9632
9703
|
return context.userId ?? context.principalId ?? "lucern-agent";
|
|
9633
9704
|
}
|
|
@@ -9781,6 +9852,9 @@ var observationContextArgs = z.object({
|
|
|
9781
9852
|
limit: z.number().optional().describe("Maximum observations to return."),
|
|
9782
9853
|
status: z.string().optional().describe("Observation status filter.")
|
|
9783
9854
|
});
|
|
9855
|
+
function isRecord2(value) {
|
|
9856
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
9857
|
+
}
|
|
9784
9858
|
var observationInput = (input, context) => withUserId(
|
|
9785
9859
|
compactRecord4({
|
|
9786
9860
|
projectId: input.projectId,
|
|
@@ -9835,8 +9909,8 @@ var contextContracts = [
|
|
|
9835
9909
|
kind: "mutation",
|
|
9836
9910
|
inputProjection: observationInput,
|
|
9837
9911
|
outputProjection: (output, input) => ({
|
|
9838
|
-
...output
|
|
9839
|
-
observationId: output
|
|
9912
|
+
...isRecord2(output) ? output : {},
|
|
9913
|
+
observationId: isRecord2(output) ? output.nodeId : void 0,
|
|
9840
9914
|
observationType: input.observationType
|
|
9841
9915
|
})
|
|
9842
9916
|
},
|
|
@@ -11317,10 +11391,11 @@ var worktreeDecisionGateInputSchema = z.object({
|
|
|
11317
11391
|
decidedBy: z.string().optional().describe("Actor that decided the gate verdict.")
|
|
11318
11392
|
}).passthrough().describe("Decision gate contract for worktree activation or exit.");
|
|
11319
11393
|
var addWorktreeArgs = z.object({
|
|
11320
|
-
title: z.string().
|
|
11394
|
+
title: z.string().describe("Human-readable worktree name or objective."),
|
|
11321
11395
|
name: z.string().optional().describe("Storage-name alias for callers that already use backend naming."),
|
|
11322
|
-
topicId: z.string().describe("
|
|
11323
|
-
projectId: z.string().optional().describe("Legacy topicId alias."),
|
|
11396
|
+
topicId: z.string().optional().describe("Optional primary topic scope hint for resolver validation."),
|
|
11397
|
+
projectId: z.string().optional().describe("Legacy topicId alias/hint."),
|
|
11398
|
+
topicHint: z.string().optional().describe("Natural-language topic hint for automatic topic resolution."),
|
|
11324
11399
|
branchId: z.string().optional().describe("Legacy branch identifier for compatibility with workflow callers."),
|
|
11325
11400
|
objective: z.string().optional().describe("Reasoning objective this worktree is intended to resolve."),
|
|
11326
11401
|
hypothesis: z.string().optional().describe("Testable claim this worktree investigates."),
|
|
@@ -11345,6 +11420,10 @@ var addWorktreeArgs = z.object({
|
|
|
11345
11420
|
autoShape: z.boolean().optional().describe("Whether to invoke inquiry auto-shaping during creation."),
|
|
11346
11421
|
autoFixPolicy: autoFixPolicyInputSchema.optional(),
|
|
11347
11422
|
domainPackId: z.string().optional().describe("Domain pack whose shaping hooks should influence the worktree."),
|
|
11423
|
+
tags: z.array(z.string()).optional().describe("Additional topic-resolution tags for the worktree."),
|
|
11424
|
+
touchedPaths: z.array(z.string()).optional().describe("File paths used as topic-resolution signals."),
|
|
11425
|
+
sourceRef: z.string().optional().describe("Source reference used as a topic-resolution signal."),
|
|
11426
|
+
sourceKind: z.string().optional().describe("Source kind used as a topic-resolution signal."),
|
|
11348
11427
|
campaign: z.number().optional().describe("Top-level pipeline campaign number."),
|
|
11349
11428
|
lane: z.string().optional().describe("Campaign lane for the worktree."),
|
|
11350
11429
|
laneOrderInCampaign: z.number().optional().describe("Ordering for this lane within its campaign."),
|
|
@@ -11674,8 +11753,46 @@ var worktreesContracts = [
|
|
|
11674
11753
|
args: openPullRequestArgs
|
|
11675
11754
|
})
|
|
11676
11755
|
];
|
|
11677
|
-
|
|
11678
|
-
|
|
11756
|
+
var taskPrioritySchema = z.enum(["urgent", "high", "medium", "low"]);
|
|
11757
|
+
var taskStatusSchema2 = z.enum(["todo", "in_progress", "blocked", "done"]);
|
|
11758
|
+
var taskTypeSchema = z.enum([
|
|
11759
|
+
"general",
|
|
11760
|
+
"find_evidence",
|
|
11761
|
+
"verify_claim",
|
|
11762
|
+
"research",
|
|
11763
|
+
"review",
|
|
11764
|
+
"interview",
|
|
11765
|
+
"analysis",
|
|
11766
|
+
"track_metrics"
|
|
11767
|
+
]);
|
|
11768
|
+
var createTaskArgs = z.object({
|
|
11769
|
+
title: z.string().describe("Task title."),
|
|
11770
|
+
topicId: z.string().optional().describe("Topic scope."),
|
|
11771
|
+
description: z.string().optional().describe("Long-form task description."),
|
|
11772
|
+
taskType: taskTypeSchema.optional().describe("Task taxonomy."),
|
|
11773
|
+
priority: taskPrioritySchema.optional().describe("Priority. Defaults to medium when omitted by the server."),
|
|
11774
|
+
status: taskStatusSchema2.optional().describe("Initial status. Defaults to todo."),
|
|
11775
|
+
linkedWorktreeId: z.string().optional().describe("Worktree this task belongs to."),
|
|
11776
|
+
linkedBeliefId: z.string().optional().describe("Belief this task supports."),
|
|
11777
|
+
linkedQuestionId: z.string().optional().describe("Question this task addresses."),
|
|
11778
|
+
assigneeId: z.string().optional().describe("Principal assigned to the task."),
|
|
11779
|
+
dueDate: z.number().optional().describe("Due date as epoch milliseconds."),
|
|
11780
|
+
tags: z.array(z.string()).optional().describe("Free-form tags.")
|
|
11781
|
+
});
|
|
11782
|
+
var createTaskInput = (input) => compactRecord4({
|
|
11783
|
+
title: input.title,
|
|
11784
|
+
topicId: input.topicId,
|
|
11785
|
+
description: input.description,
|
|
11786
|
+
taskType: input.taskType,
|
|
11787
|
+
priority: input.priority ?? "medium",
|
|
11788
|
+
status: input.status ?? "todo",
|
|
11789
|
+
linkedWorktreeId: input.linkedWorktreeId,
|
|
11790
|
+
linkedBeliefId: input.linkedBeliefId,
|
|
11791
|
+
linkedQuestionId: input.linkedQuestionId,
|
|
11792
|
+
assigneeId: input.assigneeId,
|
|
11793
|
+
dueDate: input.dueDate,
|
|
11794
|
+
tags: input.tags
|
|
11795
|
+
});
|
|
11679
11796
|
var taskInput = (input) => compactRecord4({
|
|
11680
11797
|
...input,
|
|
11681
11798
|
taskId: input.taskId ?? input.id
|
|
@@ -11707,8 +11824,10 @@ var tasksContracts = [
|
|
|
11707
11824
|
convex: {
|
|
11708
11825
|
module: "tasks",
|
|
11709
11826
|
functionName: "create",
|
|
11710
|
-
kind: "mutation"
|
|
11711
|
-
|
|
11827
|
+
kind: "mutation",
|
|
11828
|
+
inputProjection: createTaskInput
|
|
11829
|
+
},
|
|
11830
|
+
args: createTaskArgs
|
|
11712
11831
|
}),
|
|
11713
11832
|
surfaceContract({
|
|
11714
11833
|
name: "list_tasks",
|
|
@@ -12826,9 +12945,12 @@ var ALL_FUNCTION_CONTRACTS = [
|
|
|
12826
12945
|
...legacyContracts
|
|
12827
12946
|
];
|
|
12828
12947
|
assertSurfaceCoverage(ALL_FUNCTION_CONTRACTS);
|
|
12829
|
-
new Map(
|
|
12948
|
+
var FUNCTION_CONTRACTS_BY_NAME = new Map(
|
|
12830
12949
|
ALL_FUNCTION_CONTRACTS.map((contract) => [contract.name, contract])
|
|
12831
12950
|
);
|
|
12951
|
+
FUNCTION_CONTRACTS_BY_NAME.get.bind(
|
|
12952
|
+
FUNCTION_CONTRACTS_BY_NAME
|
|
12953
|
+
);
|
|
12832
12954
|
|
|
12833
12955
|
// ../contracts/src/text-matching.contract.ts
|
|
12834
12956
|
var TOKEN_SPLIT_REGEX = /[^a-z0-9]+/;
|
|
@@ -13873,15 +13995,31 @@ function defaultSuggestionForCode(code) {
|
|
|
13873
13995
|
return void 0;
|
|
13874
13996
|
}
|
|
13875
13997
|
}
|
|
13998
|
+
function createGatewaySuccessBody(payload, args) {
|
|
13999
|
+
const body = {};
|
|
14000
|
+
body.success = true;
|
|
14001
|
+
body.data = payload;
|
|
14002
|
+
body.correlationId = args.correlationId;
|
|
14003
|
+
body.policyTraceId = args.policyTraceId ?? null;
|
|
14004
|
+
body.idempotentReplay = args.idempotentReplay ?? false;
|
|
14005
|
+
return body;
|
|
14006
|
+
}
|
|
14007
|
+
function createGatewayErrorBody(args, safeMessage) {
|
|
14008
|
+
const body = {};
|
|
14009
|
+
body.success = false;
|
|
14010
|
+
body.error = safeMessage;
|
|
14011
|
+
body.code = args.code;
|
|
14012
|
+
body.invariant = args.invariant ?? defaultInvariantForCode(args.code) ?? null;
|
|
14013
|
+
body.suggestion = args.suggestion ?? defaultSuggestionForCode(args.code) ?? null;
|
|
14014
|
+
body.details = args.details;
|
|
14015
|
+
body.correlationId = args.correlationId;
|
|
14016
|
+
body.policyTraceId = args.policyTraceId ?? null;
|
|
14017
|
+
return body;
|
|
14018
|
+
}
|
|
13876
14019
|
function successResponse(payload, args) {
|
|
14020
|
+
const body = createGatewaySuccessBody(payload, args);
|
|
13877
14021
|
return Response.json(
|
|
13878
|
-
|
|
13879
|
-
success: true,
|
|
13880
|
-
data: payload,
|
|
13881
|
-
correlationId: args.correlationId,
|
|
13882
|
-
policyTraceId: args.policyTraceId ?? null,
|
|
13883
|
-
idempotentReplay: args.idempotentReplay ?? false
|
|
13884
|
-
},
|
|
14022
|
+
body,
|
|
13885
14023
|
{
|
|
13886
14024
|
status: args.status ?? 200,
|
|
13887
14025
|
headers: buildHeaders({
|
|
@@ -13908,17 +14046,9 @@ function errorResponse(args) {
|
|
|
13908
14046
|
status: args.status,
|
|
13909
14047
|
code: args.code
|
|
13910
14048
|
});
|
|
14049
|
+
const body = createGatewayErrorBody(args, safeMessage);
|
|
13911
14050
|
return Response.json(
|
|
13912
|
-
|
|
13913
|
-
success: false,
|
|
13914
|
-
error: safeMessage,
|
|
13915
|
-
code: args.code,
|
|
13916
|
-
invariant: args.invariant ?? defaultInvariantForCode(args.code) ?? null,
|
|
13917
|
-
suggestion: args.suggestion ?? defaultSuggestionForCode(args.code) ?? null,
|
|
13918
|
-
details: args.details,
|
|
13919
|
-
correlationId: args.correlationId,
|
|
13920
|
-
policyTraceId: args.policyTraceId ?? null
|
|
13921
|
-
},
|
|
14051
|
+
body,
|
|
13922
14052
|
{
|
|
13923
14053
|
status: args.status,
|
|
13924
14054
|
headers
|
|
@@ -13967,6 +14097,42 @@ var api = makeProxy("api");
|
|
|
13967
14097
|
makeProxy("components");
|
|
13968
14098
|
makeProxy("internal");
|
|
13969
14099
|
|
|
14100
|
+
// ../server-core/src/debug.ts
|
|
14101
|
+
function formatUnknownError(error) {
|
|
14102
|
+
if (error instanceof Error) {
|
|
14103
|
+
const cause = error.cause;
|
|
14104
|
+
const message = `${error.name}: ${error.message}`;
|
|
14105
|
+
if (cause === void 0) {
|
|
14106
|
+
return message;
|
|
14107
|
+
}
|
|
14108
|
+
return `${message}; cause=${formatUnknownError(cause)}`;
|
|
14109
|
+
}
|
|
14110
|
+
if (typeof error === "string") {
|
|
14111
|
+
return error;
|
|
14112
|
+
}
|
|
14113
|
+
if (error === null) {
|
|
14114
|
+
return "null";
|
|
14115
|
+
}
|
|
14116
|
+
if (error === void 0) {
|
|
14117
|
+
return "undefined";
|
|
14118
|
+
}
|
|
14119
|
+
try {
|
|
14120
|
+
return JSON.stringify(error);
|
|
14121
|
+
} catch {
|
|
14122
|
+
return Object.prototype.toString.call(error);
|
|
14123
|
+
}
|
|
14124
|
+
}
|
|
14125
|
+
function isServerCoreFallbackDebugEnabled() {
|
|
14126
|
+
const env = globalThis.process?.env;
|
|
14127
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_SERVER_CORE_DEBUG === "1";
|
|
14128
|
+
}
|
|
14129
|
+
function debugServerCoreFallback(scope, message, context) {
|
|
14130
|
+
if (!isServerCoreFallbackDebugEnabled()) {
|
|
14131
|
+
return;
|
|
14132
|
+
}
|
|
14133
|
+
console.debug(`[${scope}] ${message}`, context ?? {});
|
|
14134
|
+
}
|
|
14135
|
+
|
|
13970
14136
|
// ../server-core/src/mcp-context-tools.ts
|
|
13971
14137
|
function requireMcpConvex(authContext, label) {
|
|
13972
14138
|
const convex = authContext.convex;
|
|
@@ -14890,6 +15056,9 @@ async function bisectBeliefConfidence(port, input) {
|
|
|
14890
15056
|
}
|
|
14891
15057
|
var DEFAULT_THRESHOLD = 0.35;
|
|
14892
15058
|
var TREE_MAX_DEPTH = 20;
|
|
15059
|
+
var BM25_K1 = 1.2;
|
|
15060
|
+
var BM25_B = 0.75;
|
|
15061
|
+
var BM25_NORMALIZATION = 8;
|
|
14893
15062
|
var METADATA_TOKEN_KEYS = [
|
|
14894
15063
|
"aliases",
|
|
14895
15064
|
"alias",
|
|
@@ -14942,35 +15111,44 @@ function readStringArray2(value) {
|
|
|
14942
15111
|
}
|
|
14943
15112
|
return value.map((entry) => readString2(entry)).filter((entry) => Boolean(entry));
|
|
14944
15113
|
}
|
|
15114
|
+
function isRecord3(value) {
|
|
15115
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15116
|
+
}
|
|
15117
|
+
function decodePrefixedIdOrNull(value) {
|
|
15118
|
+
const normalized = value.trim();
|
|
15119
|
+
const match = /^([a-z][a-z0-9]*)_(.+)$/.exec(normalized);
|
|
15120
|
+
if (!match) {
|
|
15121
|
+
return null;
|
|
15122
|
+
}
|
|
15123
|
+
return {
|
|
15124
|
+
prefix: match[1],
|
|
15125
|
+
value: match[2]
|
|
15126
|
+
};
|
|
15127
|
+
}
|
|
14945
15128
|
function asRecord2(value) {
|
|
14946
|
-
return
|
|
15129
|
+
return isRecord3(value) ? value : {};
|
|
14947
15130
|
}
|
|
14948
15131
|
function normalizeTopicId(value) {
|
|
14949
15132
|
const normalized = readString2(value);
|
|
14950
15133
|
if (!normalized) {
|
|
14951
15134
|
return void 0;
|
|
14952
15135
|
}
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
return decoded.prefix === "top" ? decoded.value : normalized;
|
|
14956
|
-
} catch {
|
|
14957
|
-
return normalized;
|
|
14958
|
-
}
|
|
15136
|
+
const decoded = decodePrefixedIdOrNull(normalized);
|
|
15137
|
+
return decoded?.prefix === "top" ? decoded.value : normalized;
|
|
14959
15138
|
}
|
|
14960
15139
|
function normalizeExternalId(value, prefix) {
|
|
14961
15140
|
const normalized = readString2(value);
|
|
14962
15141
|
if (!normalized) {
|
|
14963
15142
|
return void 0;
|
|
14964
15143
|
}
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
if (prefix && decoded.prefix !== prefix) {
|
|
14968
|
-
return normalized;
|
|
14969
|
-
}
|
|
14970
|
-
return decoded.value;
|
|
14971
|
-
} catch {
|
|
15144
|
+
const decoded = decodePrefixedIdOrNull(normalized);
|
|
15145
|
+
if (!decoded) {
|
|
14972
15146
|
return normalized;
|
|
14973
15147
|
}
|
|
15148
|
+
if (prefix && decoded.prefix !== prefix) {
|
|
15149
|
+
return normalized;
|
|
15150
|
+
}
|
|
15151
|
+
return decoded.value;
|
|
14974
15152
|
}
|
|
14975
15153
|
function normalizeToken(value) {
|
|
14976
15154
|
const normalized = value.toLowerCase().trim();
|
|
@@ -15049,15 +15227,83 @@ function collectTopicMetadataTokens(metadata) {
|
|
|
15049
15227
|
function topicNameSlug(name) {
|
|
15050
15228
|
return tokenize(name).join(" ");
|
|
15051
15229
|
}
|
|
15230
|
+
function topicTokenList(topic) {
|
|
15231
|
+
return [
|
|
15232
|
+
...tokenize(topic.name),
|
|
15233
|
+
...tokenize(topic.description),
|
|
15234
|
+
...tokenize(topic.type),
|
|
15235
|
+
...collectTopicMetadataTokens(topic.metadata ?? {}).flatMap(
|
|
15236
|
+
(value) => tokenize(value)
|
|
15237
|
+
)
|
|
15238
|
+
];
|
|
15239
|
+
}
|
|
15052
15240
|
function topicTokenSet(topic) {
|
|
15053
15241
|
const tokens = /* @__PURE__ */ new Set();
|
|
15054
|
-
addTokens(tokens,
|
|
15055
|
-
addTokens(tokens, tokenize(topic.description));
|
|
15056
|
-
addTokens(tokens, tokenize(topic.type));
|
|
15057
|
-
addTokens(tokens, collectTopicMetadataTokens(topic.metadata ?? {}));
|
|
15242
|
+
addTokens(tokens, topicTokenList(topic));
|
|
15058
15243
|
return tokens;
|
|
15059
15244
|
}
|
|
15245
|
+
function buildTopicScoreCorpus(topics2) {
|
|
15246
|
+
const documentFrequencyByToken = /* @__PURE__ */ new Map();
|
|
15247
|
+
let documentCount = 0;
|
|
15248
|
+
let totalLength = 0;
|
|
15249
|
+
for (const topic of topics2) {
|
|
15250
|
+
const tokens = topicTokenList(topic);
|
|
15251
|
+
const uniqueTokens = new Set(tokens);
|
|
15252
|
+
documentCount += 1;
|
|
15253
|
+
totalLength += tokens.length;
|
|
15254
|
+
for (const token of uniqueTokens) {
|
|
15255
|
+
documentFrequencyByToken.set(
|
|
15256
|
+
token,
|
|
15257
|
+
(documentFrequencyByToken.get(token) ?? 0) + 1
|
|
15258
|
+
);
|
|
15259
|
+
}
|
|
15260
|
+
}
|
|
15261
|
+
return {
|
|
15262
|
+
documentCount,
|
|
15263
|
+
averageDocumentLength: documentCount > 0 ? Math.max(1, totalLength / documentCount) : 1,
|
|
15264
|
+
documentFrequencyByToken
|
|
15265
|
+
};
|
|
15266
|
+
}
|
|
15267
|
+
function countTokens(tokens) {
|
|
15268
|
+
const counts = /* @__PURE__ */ new Map();
|
|
15269
|
+
for (const token of tokens) {
|
|
15270
|
+
counts.set(token, (counts.get(token) ?? 0) + 1);
|
|
15271
|
+
}
|
|
15272
|
+
return counts;
|
|
15273
|
+
}
|
|
15274
|
+
function bm25Score(topic, signals, corpus) {
|
|
15275
|
+
if (signals.allTokens.size === 0 || corpus.documentCount === 0) {
|
|
15276
|
+
return 0;
|
|
15277
|
+
}
|
|
15278
|
+
const documentTokens = topicTokenList(topic);
|
|
15279
|
+
if (documentTokens.length === 0) {
|
|
15280
|
+
return 0;
|
|
15281
|
+
}
|
|
15282
|
+
const counts = countTokens(documentTokens);
|
|
15283
|
+
const docLength = documentTokens.length;
|
|
15284
|
+
let score = 0;
|
|
15285
|
+
for (const token of signals.allTokens) {
|
|
15286
|
+
const termFrequency = counts.get(token) ?? 0;
|
|
15287
|
+
if (termFrequency === 0) {
|
|
15288
|
+
continue;
|
|
15289
|
+
}
|
|
15290
|
+
const documentFrequency = corpus.documentFrequencyByToken.get(token) ?? 0;
|
|
15291
|
+
const idf = Math.log(
|
|
15292
|
+
1 + (corpus.documentCount - documentFrequency + 0.5) / (documentFrequency + 0.5)
|
|
15293
|
+
);
|
|
15294
|
+
const denominator = termFrequency + BM25_K1 * (1 - BM25_B + BM25_B * (docLength / corpus.averageDocumentLength));
|
|
15295
|
+
score += idf * (termFrequency * (BM25_K1 + 1) / denominator);
|
|
15296
|
+
}
|
|
15297
|
+
return score / (score + BM25_NORMALIZATION);
|
|
15298
|
+
}
|
|
15060
15299
|
function scoreTopicMatch(topic, input) {
|
|
15300
|
+
return scoreTopicMatchWithCorpus(
|
|
15301
|
+
topic,
|
|
15302
|
+
input,
|
|
15303
|
+
buildTopicScoreCorpus([topic])
|
|
15304
|
+
);
|
|
15305
|
+
}
|
|
15306
|
+
function scoreTopicMatchWithCorpus(topic, input, corpus) {
|
|
15061
15307
|
const signals = buildSignalBag(input);
|
|
15062
15308
|
const topicTokens = topicTokenSet(topic);
|
|
15063
15309
|
if (signals.allTokens.size === 0 || topicTokens.size === 0) {
|
|
@@ -15071,6 +15317,7 @@ function scoreTopicMatch(topic, input) {
|
|
|
15071
15317
|
}
|
|
15072
15318
|
const union = (/* @__PURE__ */ new Set([...signals.allTokens, ...topicTokens])).size;
|
|
15073
15319
|
const jaccard = union > 0 ? intersection / union : 0;
|
|
15320
|
+
const bm25 = bm25Score(topic, signals, corpus);
|
|
15074
15321
|
const topicSlug = topicNameSlug(topic.name);
|
|
15075
15322
|
let boost = 0;
|
|
15076
15323
|
for (const token of signals.tagTokens) {
|
|
@@ -15091,7 +15338,7 @@ function scoreTopicMatch(topic, input) {
|
|
|
15091
15338
|
break;
|
|
15092
15339
|
}
|
|
15093
15340
|
}
|
|
15094
|
-
return Math.max(0, Math.min(1, jaccard + boost));
|
|
15341
|
+
return Math.max(0, Math.min(1, bm25 * 0.55 + jaccard * 0.45 + boost));
|
|
15095
15342
|
}
|
|
15096
15343
|
function normalizeTopicCandidate(value) {
|
|
15097
15344
|
const record = asRecord2(value);
|
|
@@ -15113,26 +15360,21 @@ function normalizeTopicCandidate(value) {
|
|
|
15113
15360
|
globalId: readString2(record.globalId)
|
|
15114
15361
|
};
|
|
15115
15362
|
}
|
|
15116
|
-
function topicMatchesScope(topic, tenantId, workspaceId) {
|
|
15117
|
-
if (topic.status === "archived") {
|
|
15118
|
-
return false;
|
|
15119
|
-
}
|
|
15120
|
-
if (tenantId && topic.tenantId && topic.tenantId !== tenantId) {
|
|
15121
|
-
return false;
|
|
15122
|
-
}
|
|
15123
|
-
if (workspaceId && topic.workspaceId && topic.workspaceId !== workspaceId) {
|
|
15124
|
-
return false;
|
|
15125
|
-
}
|
|
15126
|
-
return true;
|
|
15127
|
-
}
|
|
15128
15363
|
async function fetchTopicById(ctx, topicId) {
|
|
15129
15364
|
const normalizedTopicId = normalizeTopicId(topicId);
|
|
15130
15365
|
if (!normalizedTopicId) {
|
|
15131
15366
|
return null;
|
|
15132
15367
|
}
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
15368
|
+
let topic = null;
|
|
15369
|
+
try {
|
|
15370
|
+
topic = await getConvex(ctx).query(api.topics.get, {
|
|
15371
|
+
id: normalizedTopicId
|
|
15372
|
+
});
|
|
15373
|
+
} catch (error) {
|
|
15374
|
+
debugServerCoreFallback("topic-resolver", `fetchTopicById: topics.get(${normalizedTopicId})`, {
|
|
15375
|
+
error: formatUnknownError(error)
|
|
15376
|
+
});
|
|
15377
|
+
}
|
|
15136
15378
|
return normalizeTopicCandidate(topic);
|
|
15137
15379
|
}
|
|
15138
15380
|
function readRecordTopicId(value) {
|
|
@@ -15142,7 +15384,14 @@ function readRecordTopicId(value) {
|
|
|
15142
15384
|
);
|
|
15143
15385
|
}
|
|
15144
15386
|
async function fetchRecordTopicId(ctx, reference, args) {
|
|
15145
|
-
|
|
15387
|
+
let result = null;
|
|
15388
|
+
try {
|
|
15389
|
+
result = await getConvex(ctx).query(reference, args);
|
|
15390
|
+
} catch (error) {
|
|
15391
|
+
debugServerCoreFallback("topic-resolver", "fetchRecordTopicId", {
|
|
15392
|
+
error: formatUnknownError(error)
|
|
15393
|
+
});
|
|
15394
|
+
}
|
|
15146
15395
|
return readRecordTopicId(result);
|
|
15147
15396
|
}
|
|
15148
15397
|
async function resolveBeliefTopicId(ctx, beliefId) {
|
|
@@ -15185,12 +15434,9 @@ async function resolveTopicIdFromEvidenceTarget(ctx, targetId, targetType) {
|
|
|
15185
15434
|
if (targetType === "belief") {
|
|
15186
15435
|
return resolveBeliefTopicId(ctx, normalizedTargetId);
|
|
15187
15436
|
}
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
return resolveQuestionTopicId(ctx, normalizedTargetId);
|
|
15192
|
-
}
|
|
15193
|
-
} catch {
|
|
15437
|
+
const decoded = decodePrefixedIdOrNull(normalizedTargetId);
|
|
15438
|
+
if (decoded?.prefix === "que") {
|
|
15439
|
+
return resolveQuestionTopicId(ctx, normalizedTargetId);
|
|
15194
15440
|
}
|
|
15195
15441
|
return resolveBeliefTopicId(ctx, normalizedTargetId);
|
|
15196
15442
|
}
|
|
@@ -15202,7 +15448,9 @@ async function resolveCommonBeliefTopicId(ctx, beliefIds) {
|
|
|
15202
15448
|
return void 0;
|
|
15203
15449
|
}
|
|
15204
15450
|
const resolvedTopicIds = (await Promise.all(
|
|
15205
|
-
normalizedBeliefIds.map(
|
|
15451
|
+
normalizedBeliefIds.map(
|
|
15452
|
+
(beliefId) => resolveBeliefTopicId(ctx, beliefId)
|
|
15453
|
+
)
|
|
15206
15454
|
)).filter((topicId) => Boolean(topicId));
|
|
15207
15455
|
if (resolvedTopicIds.length !== normalizedBeliefIds.length) {
|
|
15208
15456
|
return void 0;
|
|
@@ -15211,17 +15459,31 @@ async function resolveCommonBeliefTopicId(ctx, beliefIds) {
|
|
|
15211
15459
|
}
|
|
15212
15460
|
async function fetchTopicTree(ctx) {
|
|
15213
15461
|
const convex = getConvex(ctx);
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15462
|
+
let tree = null;
|
|
15463
|
+
try {
|
|
15464
|
+
tree = await convex.query(api.topics.getTree, {
|
|
15465
|
+
rootId: ROOT_TOPIC_ID,
|
|
15466
|
+
maxDepth: TREE_MAX_DEPTH
|
|
15467
|
+
});
|
|
15468
|
+
} catch (error) {
|
|
15469
|
+
debugServerCoreFallback("topic-resolver", "fetchTopicTree: topics.getTree", {
|
|
15470
|
+
error: formatUnknownError(error)
|
|
15471
|
+
});
|
|
15472
|
+
}
|
|
15218
15473
|
const normalizedTree = Array.isArray(tree) ? tree.map((topic) => normalizeTopicCandidate(topic)).filter((topic) => Boolean(topic)) : [];
|
|
15219
15474
|
if (normalizedTree.length > 0) {
|
|
15220
15475
|
return normalizedTree;
|
|
15221
15476
|
}
|
|
15222
|
-
|
|
15223
|
-
|
|
15224
|
-
|
|
15477
|
+
let listed = [];
|
|
15478
|
+
try {
|
|
15479
|
+
listed = await convex.query(api.topics.list, {
|
|
15480
|
+
status: "active"
|
|
15481
|
+
});
|
|
15482
|
+
} catch (error) {
|
|
15483
|
+
debugServerCoreFallback("topic-resolver", "fetchTopicTree: topics.list fallback", {
|
|
15484
|
+
error: formatUnknownError(error)
|
|
15485
|
+
});
|
|
15486
|
+
}
|
|
15225
15487
|
return Array.isArray(listed) ? listed.map((topic) => normalizeTopicCandidate(topic)).filter((topic) => Boolean(topic)) : [];
|
|
15226
15488
|
}
|
|
15227
15489
|
function buildTopicMaps(topics2) {
|
|
@@ -15254,42 +15516,43 @@ function buildPath(topicId, byId) {
|
|
|
15254
15516
|
function titleCase(value) {
|
|
15255
15517
|
return value.replace(/\b[a-z]/g, (match) => match.toUpperCase());
|
|
15256
15518
|
}
|
|
15257
|
-
function compactWhitespace(value) {
|
|
15258
|
-
return value.replace(/\s+/g, " ").trim();
|
|
15259
|
-
}
|
|
15260
15519
|
function deriveTopicName(input, parentTopic) {
|
|
15261
15520
|
const textualHint = readString2(input.topicHint);
|
|
15262
15521
|
if (textualHint && tokenize(textualHint).length > 0) {
|
|
15263
|
-
return titleCase(
|
|
15522
|
+
return titleCase(textualHint.replace(/\s+/g, " ").trim()).slice(0, 60);
|
|
15264
15523
|
}
|
|
15265
15524
|
const firstTag = (input.tags ?? []).find((tag) => tokenize(tag).length > 0);
|
|
15266
15525
|
if (firstTag) {
|
|
15267
|
-
return titleCase(
|
|
15526
|
+
return titleCase(firstTag.replace(/\s+/g, " ").trim()).slice(0, 60);
|
|
15268
15527
|
}
|
|
15269
15528
|
const firstPathStem = (input.touchedPaths ?? []).map((filePath) => basenameStem(filePath)).find((stem) => stem && tokenize(stem).length > 0);
|
|
15270
15529
|
if (firstPathStem) {
|
|
15271
|
-
return titleCase(
|
|
15530
|
+
return titleCase(
|
|
15531
|
+
firstPathStem.replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim()
|
|
15532
|
+
).slice(0, 60);
|
|
15272
15533
|
}
|
|
15273
|
-
const summary =
|
|
15534
|
+
const summary = input.summary.replace(/\s+/g, " ").trim();
|
|
15274
15535
|
if (summary.length > 0) {
|
|
15275
15536
|
return titleCase(summary.slice(0, 60));
|
|
15276
15537
|
}
|
|
15277
15538
|
const sourceRef = readString2(input.sourceRef);
|
|
15278
15539
|
if (sourceRef) {
|
|
15279
|
-
return titleCase(
|
|
15540
|
+
return titleCase(
|
|
15541
|
+
sourceRef.replace(/[-_:/]+/g, " ").replace(/\s+/g, " ").trim()
|
|
15542
|
+
).slice(0, 60);
|
|
15280
15543
|
}
|
|
15281
|
-
return `${titleCase(parentTopic.name)} Subtopic
|
|
15544
|
+
return parentTopic ? `${titleCase(parentTopic.name)} Subtopic` : "Lucern";
|
|
15282
15545
|
}
|
|
15283
|
-
async function
|
|
15546
|
+
async function createTopic(ctx, input, parentTopic) {
|
|
15284
15547
|
const convex = getConvex(ctx);
|
|
15285
15548
|
const desiredTenantId = ctx.tenantId;
|
|
15286
15549
|
const desiredWorkspaceId = readString2(input.workspaceId) ?? ctx.workspaceId;
|
|
15287
15550
|
const createdBy = ctx.principalId ?? ctx.userId;
|
|
15288
15551
|
const created = await convex.mutation(api.topics.create, {
|
|
15289
15552
|
name: deriveTopicName(input, parentTopic),
|
|
15290
|
-
description:
|
|
15553
|
+
description: input.summary.replace(/\s+/g, " ").trim().slice(0, 280) || void 0,
|
|
15291
15554
|
type: "theme",
|
|
15292
|
-
parentTopicId: parentTopic.rawId,
|
|
15555
|
+
...parentTopic ? { parentTopicId: parentTopic.rawId } : {},
|
|
15293
15556
|
tenantId: desiredTenantId,
|
|
15294
15557
|
workspaceId: desiredWorkspaceId,
|
|
15295
15558
|
visibility: "team",
|
|
@@ -15306,10 +15569,18 @@ async function createChildTopic(ctx, parentTopic, input) {
|
|
|
15306
15569
|
const createdId = readString2(createdRecord.id) ?? readString2(createdRecord.topicId) ?? readString2(createdRecord._id);
|
|
15307
15570
|
const hydrated = await fetchTopicById(ctx, createdId);
|
|
15308
15571
|
if (!hydrated) {
|
|
15309
|
-
throw new Error(
|
|
15572
|
+
throw new Error(
|
|
15573
|
+
"[topic-resolver] Auto-created topic could not be reloaded."
|
|
15574
|
+
);
|
|
15310
15575
|
}
|
|
15311
15576
|
return hydrated;
|
|
15312
15577
|
}
|
|
15578
|
+
function createChildTopic(ctx, parentTopic, input) {
|
|
15579
|
+
return createTopic(ctx, input, parentTopic);
|
|
15580
|
+
}
|
|
15581
|
+
function createRootTopic(ctx, input) {
|
|
15582
|
+
return createTopic(ctx, input);
|
|
15583
|
+
}
|
|
15313
15584
|
function pushTrace(trace, topic, score) {
|
|
15314
15585
|
const existing = trace[trace.length - 1];
|
|
15315
15586
|
if (existing?.topicId === topic.rawId) {
|
|
@@ -15324,9 +15595,10 @@ function pushTrace(trace, topic, score) {
|
|
|
15324
15595
|
});
|
|
15325
15596
|
}
|
|
15326
15597
|
function pickBestTopic(topics2, input) {
|
|
15598
|
+
const corpus = buildTopicScoreCorpus(topics2);
|
|
15327
15599
|
const ranked = topics2.filter((topic) => topic.status !== "archived").map((topic) => ({
|
|
15328
15600
|
topic,
|
|
15329
|
-
score:
|
|
15601
|
+
score: scoreTopicMatchWithCorpus(topic, input, corpus)
|
|
15330
15602
|
})).sort((left, right) => {
|
|
15331
15603
|
if (right.score !== left.score) {
|
|
15332
15604
|
return right.score - left.score;
|
|
@@ -15342,27 +15614,31 @@ function pickFallbackRootTopic(topics2, input) {
|
|
|
15342
15614
|
return pickBestTopic(parentless, input) ?? pickBestTopic(topics2, input);
|
|
15343
15615
|
}
|
|
15344
15616
|
async function loadTopicUniverse(ctx, input) {
|
|
15345
|
-
const desiredTenantId = ctx.tenantId;
|
|
15346
|
-
const desiredWorkspaceId = readString2(input.workspaceId) ?? ctx.workspaceId;
|
|
15347
15617
|
const rawTopics = await fetchTopicTree(ctx);
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
const root = rawTopics.find((topic) => topic.rawId === ROOT_TOPIC_ID) ?? await fetchTopicById(ctx, ROOT_TOPIC_ID) ?? pickFallbackRootTopic(scopedTopics, input) ?? null;
|
|
15618
|
+
let candidatePool = rawTopics;
|
|
15619
|
+
let root = pickFallbackRootTopic(candidatePool, input) ?? candidatePool.find((topic) => !topic.parentTopicId) ?? candidatePool[0] ?? null;
|
|
15620
|
+
let rootCreated = false;
|
|
15352
15621
|
if (!root) {
|
|
15353
|
-
|
|
15622
|
+
if (input.autoCreate === false) {
|
|
15623
|
+
throw new Error(
|
|
15624
|
+
"[topic-resolver] No topics available for resolution."
|
|
15625
|
+
);
|
|
15626
|
+
}
|
|
15627
|
+
root = await createRootTopic(ctx, input);
|
|
15628
|
+
rootCreated = true;
|
|
15629
|
+
candidatePool = [root];
|
|
15354
15630
|
}
|
|
15355
|
-
const topics2 = rawTopics.filter(
|
|
15356
|
-
(topic) => topic.rawId === root.rawId || topicMatchesScope(topic, desiredTenantId, desiredWorkspaceId)
|
|
15357
|
-
);
|
|
15358
15631
|
const dedupedTopics = /* @__PURE__ */ new Map();
|
|
15359
15632
|
dedupedTopics.set(root.rawId, root);
|
|
15360
|
-
for (const topic of
|
|
15633
|
+
for (const topic of candidatePool) {
|
|
15361
15634
|
dedupedTopics.set(topic.rawId, topic);
|
|
15362
15635
|
}
|
|
15363
|
-
const { byId, childrenByParent } = buildTopicMaps([
|
|
15636
|
+
const { byId, childrenByParent } = buildTopicMaps([
|
|
15637
|
+
...dedupedTopics.values()
|
|
15638
|
+
]);
|
|
15364
15639
|
return {
|
|
15365
15640
|
root,
|
|
15641
|
+
rootCreated,
|
|
15366
15642
|
byId,
|
|
15367
15643
|
childrenByParent
|
|
15368
15644
|
};
|
|
@@ -15373,7 +15649,9 @@ async function validateTopicOrNull(ctx, topicId) {
|
|
|
15373
15649
|
return null;
|
|
15374
15650
|
}
|
|
15375
15651
|
const { byId } = await loadTopicUniverse(ctx, {
|
|
15376
|
-
summary: topic.name
|
|
15652
|
+
summary: topic.name,
|
|
15653
|
+
autoCreate: false
|
|
15654
|
+
});
|
|
15377
15655
|
if (!byId.has(topic.rawId)) {
|
|
15378
15656
|
byId.set(topic.rawId, topic);
|
|
15379
15657
|
}
|
|
@@ -15395,8 +15673,10 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15395
15673
|
const threshold = typeof input.threshold === "number" && Number.isFinite(input.threshold) ? Math.max(0, Math.min(1, input.threshold)) : DEFAULT_THRESHOLD;
|
|
15396
15674
|
const createThreshold = Math.max(0.5, Math.min(1, threshold + 0.15));
|
|
15397
15675
|
const autoCreate = input.autoCreate !== false;
|
|
15398
|
-
const { root, byId, childrenByParent } = await loadTopicUniverse(ctx, input);
|
|
15676
|
+
const { root, rootCreated, byId, childrenByParent } = await loadTopicUniverse(ctx, input);
|
|
15399
15677
|
const trace = [];
|
|
15678
|
+
const scoreCorpus = buildTopicScoreCorpus(byId.values());
|
|
15679
|
+
const scoreTopic = (topic) => scoreTopicMatchWithCorpus(topic, input, scoreCorpus);
|
|
15400
15680
|
const ownScore = /* @__PURE__ */ new Map();
|
|
15401
15681
|
const subtreeScore = /* @__PURE__ */ new Map();
|
|
15402
15682
|
const computeSubtreeScore = (topicId, visited) => {
|
|
@@ -15413,7 +15693,7 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15413
15693
|
return 0;
|
|
15414
15694
|
}
|
|
15415
15695
|
if (!ownScore.has(topicId)) {
|
|
15416
|
-
ownScore.set(topicId,
|
|
15696
|
+
ownScore.set(topicId, scoreTopic(topic));
|
|
15417
15697
|
}
|
|
15418
15698
|
let best = ownScore.get(topicId);
|
|
15419
15699
|
for (const child of childrenByParent.get(topicId) ?? []) {
|
|
@@ -15425,7 +15705,7 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15425
15705
|
};
|
|
15426
15706
|
computeSubtreeScore(root.rawId, /* @__PURE__ */ new Set());
|
|
15427
15707
|
let current = root;
|
|
15428
|
-
let currentScore = ownScore.get(root.rawId) ??
|
|
15708
|
+
let currentScore = ownScore.get(root.rawId) ?? scoreTopic(root);
|
|
15429
15709
|
pushTrace(trace, current, currentScore);
|
|
15430
15710
|
while (true) {
|
|
15431
15711
|
const children = (childrenByParent.get(current.rawId) ?? []).filter(
|
|
@@ -15436,7 +15716,7 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15436
15716
|
}
|
|
15437
15717
|
const rankedChildren = children.map((topic) => {
|
|
15438
15718
|
if (!ownScore.has(topic.rawId)) {
|
|
15439
|
-
ownScore.set(topic.rawId,
|
|
15719
|
+
ownScore.set(topic.rawId, scoreTopic(topic));
|
|
15440
15720
|
}
|
|
15441
15721
|
return {
|
|
15442
15722
|
topic,
|
|
@@ -15448,13 +15728,13 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15448
15728
|
break;
|
|
15449
15729
|
}
|
|
15450
15730
|
current = bestChild.topic;
|
|
15451
|
-
currentScore = ownScore.get(current.rawId) ??
|
|
15731
|
+
currentScore = ownScore.get(current.rawId) ?? scoreTopic(current);
|
|
15452
15732
|
pushTrace(trace, current, currentScore);
|
|
15453
15733
|
}
|
|
15454
|
-
let created =
|
|
15734
|
+
let created = rootCreated;
|
|
15455
15735
|
let resolvedTopic = current;
|
|
15456
15736
|
let finalScore = currentScore;
|
|
15457
|
-
if (autoCreate && finalScore < createThreshold) {
|
|
15737
|
+
if (autoCreate && !rootCreated && finalScore < createThreshold) {
|
|
15458
15738
|
const siblings = childrenByParent.get(current.rawId) ?? [];
|
|
15459
15739
|
const derivedName = deriveTopicName(input, current).toLowerCase();
|
|
15460
15740
|
const existingSibling = siblings.find(
|
|
@@ -15462,7 +15742,7 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15462
15742
|
);
|
|
15463
15743
|
if (existingSibling) {
|
|
15464
15744
|
resolvedTopic = existingSibling;
|
|
15465
|
-
finalScore =
|
|
15745
|
+
finalScore = scoreTopic(existingSibling);
|
|
15466
15746
|
pushTrace(trace, resolvedTopic, finalScore);
|
|
15467
15747
|
} else {
|
|
15468
15748
|
resolvedTopic = await createChildTopic(ctx, current, input);
|
|
@@ -15486,6 +15766,23 @@ async function resolveTopicForWrite(ctx, input) {
|
|
|
15486
15766
|
trace
|
|
15487
15767
|
};
|
|
15488
15768
|
}
|
|
15769
|
+
async function resolveTopicIdForWrite(ctx, input) {
|
|
15770
|
+
const explicitTopicId = normalizeTopicId(input.topicId);
|
|
15771
|
+
const explicit = await validateTopicOrNull(ctx, explicitTopicId);
|
|
15772
|
+
if (explicit) {
|
|
15773
|
+
return explicit;
|
|
15774
|
+
}
|
|
15775
|
+
if (explicitTopicId) {
|
|
15776
|
+
console.warn(
|
|
15777
|
+
`[topic-resolver] Explicit topicId "${explicitTopicId}" is invalid or stale. Falling back to hop-by-hop topic resolution.`
|
|
15778
|
+
);
|
|
15779
|
+
}
|
|
15780
|
+
return resolveTopicForWrite(ctx, {
|
|
15781
|
+
...input,
|
|
15782
|
+
topicHint: input.topicHint ?? explicitTopicId,
|
|
15783
|
+
autoCreate: explicitTopicId ? false : input.autoCreate
|
|
15784
|
+
});
|
|
15785
|
+
}
|
|
15489
15786
|
|
|
15490
15787
|
// ../server-core/src/beliefs.ts
|
|
15491
15788
|
function resolveBeliefNodeId(value) {
|
|
@@ -16454,39 +16751,47 @@ function resolveExternalId2(value) {
|
|
|
16454
16751
|
if (!value) {
|
|
16455
16752
|
return value;
|
|
16456
16753
|
}
|
|
16754
|
+
return resolveNodeId(value);
|
|
16755
|
+
}
|
|
16756
|
+
function resolveNodeId(value) {
|
|
16457
16757
|
try {
|
|
16458
16758
|
return decodePrefixedId(value).value;
|
|
16459
|
-
} catch {
|
|
16759
|
+
} catch (_error) {
|
|
16460
16760
|
return value;
|
|
16461
16761
|
}
|
|
16462
16762
|
}
|
|
16763
|
+
async function queryWithFallback(label, run, fallback) {
|
|
16764
|
+
try {
|
|
16765
|
+
return await run();
|
|
16766
|
+
} catch (error) {
|
|
16767
|
+
debugServerCoreFallback("edges", label, {
|
|
16768
|
+
error: formatUnknownError(error)
|
|
16769
|
+
});
|
|
16770
|
+
return fallback;
|
|
16771
|
+
}
|
|
16772
|
+
}
|
|
16463
16773
|
async function fetchNodeWithQuery(runQuery, id) {
|
|
16464
16774
|
if (!id.trim()) {
|
|
16465
16775
|
return null;
|
|
16466
16776
|
}
|
|
16467
|
-
const rawId = (
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
return id;
|
|
16472
|
-
}
|
|
16473
|
-
})();
|
|
16474
|
-
try {
|
|
16475
|
-
const byNodeId = await runQuery(api.epistemicNodes.get, {
|
|
16777
|
+
const rawId = resolveNodeId(id);
|
|
16778
|
+
const byNodeId = await queryWithFallback(
|
|
16779
|
+
`fetchNodeWithQuery local id lookup for ${id}`,
|
|
16780
|
+
() => runQuery(api.epistemicNodes.get, {
|
|
16476
16781
|
nodeId: rawId
|
|
16477
|
-
})
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16782
|
+
}),
|
|
16783
|
+
null
|
|
16784
|
+
);
|
|
16785
|
+
if (byNodeId) {
|
|
16786
|
+
return byNodeId;
|
|
16482
16787
|
}
|
|
16483
|
-
|
|
16484
|
-
|
|
16788
|
+
return await queryWithFallback(
|
|
16789
|
+
`fetchNodeWithQuery global id lookup for ${id}`,
|
|
16790
|
+
() => runQuery(api.epistemicNodes.getByGlobalId, {
|
|
16485
16791
|
globalId: id
|
|
16486
|
-
})
|
|
16487
|
-
|
|
16488
|
-
|
|
16489
|
-
}
|
|
16792
|
+
}),
|
|
16793
|
+
null
|
|
16794
|
+
);
|
|
16490
16795
|
}
|
|
16491
16796
|
function resolveTopicIdFromNode(node) {
|
|
16492
16797
|
const record = asRecord6(node);
|
|
@@ -16520,7 +16825,9 @@ async function ensureTopicAccessWithQuery2(runQuery, topicId, userId, contextLab
|
|
|
16520
16825
|
userId
|
|
16521
16826
|
});
|
|
16522
16827
|
if (allowed !== true) {
|
|
16523
|
-
throw new Error(
|
|
16828
|
+
throw new Error(
|
|
16829
|
+
`[edges] ${contextLabel} requires access to topic ${topicId}.`
|
|
16830
|
+
);
|
|
16524
16831
|
}
|
|
16525
16832
|
}
|
|
16526
16833
|
async function executeTraversal(runQuery, runAction, userId, input) {
|
|
@@ -16591,10 +16898,13 @@ function createGatewayEdgesPort(authContext) {
|
|
|
16591
16898
|
authContext.userId,
|
|
16592
16899
|
"list"
|
|
16593
16900
|
);
|
|
16594
|
-
const rows = await authContext.convex.query(
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16901
|
+
const rows = await authContext.convex.query(
|
|
16902
|
+
api.epistemicEdges.getBySourceNode,
|
|
16903
|
+
{
|
|
16904
|
+
sourceNodeId: args.sourceRawId,
|
|
16905
|
+
edgeType: args.edgeType
|
|
16906
|
+
}
|
|
16907
|
+
);
|
|
16598
16908
|
return Array.isArray(rows) ? rows.slice(0, args.limit ?? rows.length) : [];
|
|
16599
16909
|
},
|
|
16600
16910
|
traverseEdges(input) {
|
|
@@ -17357,17 +17667,11 @@ function normalizeGlobalIds(input) {
|
|
|
17357
17667
|
}
|
|
17358
17668
|
return [...ids];
|
|
17359
17669
|
}
|
|
17360
|
-
function normalizeGraphNode(value) {
|
|
17361
|
-
return asRecord8(value);
|
|
17362
|
-
}
|
|
17363
|
-
function normalizeGraphEdge(value) {
|
|
17364
|
-
return asRecord8(value);
|
|
17365
|
-
}
|
|
17366
17670
|
function normalizeNeighborhoodResult(value, maxDepth) {
|
|
17367
17671
|
const payload = asRecord8(value);
|
|
17368
17672
|
return {
|
|
17369
|
-
nodes: asRecordArray(payload.nodes).map(
|
|
17370
|
-
edges: asRecordArray(payload.edges).map(
|
|
17673
|
+
nodes: asRecordArray(payload.nodes).map(asRecord8),
|
|
17674
|
+
edges: asRecordArray(payload.edges).map(asRecord8),
|
|
17371
17675
|
depth: normalizeDepth(payload.depth, maxDepth)
|
|
17372
17676
|
};
|
|
17373
17677
|
}
|
|
@@ -17377,8 +17681,8 @@ function normalizeTraverseResult(value, input) {
|
|
|
17377
17681
|
startNode: readString9(payload.startNode) ?? input.startNode,
|
|
17378
17682
|
direction: normalizeDirection2(payload.direction ?? input.direction),
|
|
17379
17683
|
maxDepth: normalizeDepth(payload.maxDepth, input.maxDepth),
|
|
17380
|
-
nodes: asRecordArray(payload.nodes).map(
|
|
17381
|
-
edges: asRecordArray(payload.edges).map(
|
|
17684
|
+
nodes: asRecordArray(payload.nodes).map(asRecord8),
|
|
17685
|
+
edges: asRecordArray(payload.edges).map(asRecord8),
|
|
17382
17686
|
depth: normalizeDepth(payload.depth, input.maxDepth),
|
|
17383
17687
|
...readString9(payload.topicId) ?? readString9(input.topicId) ? { topicId: readString9(payload.topicId) ?? readString9(input.topicId) } : {}
|
|
17384
17688
|
};
|
|
@@ -17835,6 +18139,20 @@ async function answerQuestion(deps, input) {
|
|
|
17835
18139
|
}
|
|
17836
18140
|
|
|
17837
18141
|
// ../server-core/src/questions.ts
|
|
18142
|
+
function normalizePrefixedId(value, prefix) {
|
|
18143
|
+
if (!value) {
|
|
18144
|
+
return value;
|
|
18145
|
+
}
|
|
18146
|
+
try {
|
|
18147
|
+
const decoded = decodePrefixedId(value);
|
|
18148
|
+
if (prefix && decoded.prefix !== prefix) {
|
|
18149
|
+
return value;
|
|
18150
|
+
}
|
|
18151
|
+
return decoded.value;
|
|
18152
|
+
} catch (_error) {
|
|
18153
|
+
return value;
|
|
18154
|
+
}
|
|
18155
|
+
}
|
|
17838
18156
|
function normalizeAnswerConfidence2(value) {
|
|
17839
18157
|
if (value === "medium") {
|
|
17840
18158
|
return "moderate";
|
|
@@ -17855,26 +18173,18 @@ function readStringArray5(value) {
|
|
|
17855
18173
|
const items = value.map((entry) => readString11(entry)).filter((entry) => Boolean(entry));
|
|
17856
18174
|
return items.length > 0 ? items : void 0;
|
|
17857
18175
|
}
|
|
17858
|
-
function
|
|
17859
|
-
|
|
17860
|
-
return value;
|
|
17861
|
-
}
|
|
17862
|
-
try {
|
|
17863
|
-
const decoded = decodePrefixedId(value);
|
|
17864
|
-
if (prefix && decoded.prefix !== prefix) {
|
|
17865
|
-
return value;
|
|
17866
|
-
}
|
|
17867
|
-
return decoded.value;
|
|
17868
|
-
} catch {
|
|
17869
|
-
return value;
|
|
17870
|
-
}
|
|
18176
|
+
function isRecord4(value) {
|
|
18177
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17871
18178
|
}
|
|
17872
18179
|
async function resolveQuestionTopicIdWithGatewayAuth(authContext, questionId) {
|
|
17873
|
-
const question = await authContext.convex.query(
|
|
17874
|
-
|
|
17875
|
-
|
|
17876
|
-
|
|
17877
|
-
|
|
18180
|
+
const question = await authContext.convex.query(
|
|
18181
|
+
api.epistemicQuestions.getById,
|
|
18182
|
+
{
|
|
18183
|
+
questionId,
|
|
18184
|
+
nodeId: questionId
|
|
18185
|
+
}
|
|
18186
|
+
);
|
|
18187
|
+
return isRecord4(question) ? readString11(question.topicId) : void 0;
|
|
17878
18188
|
}
|
|
17879
18189
|
async function emitQuestionEventFromGatewayAuth(authContext, args) {
|
|
17880
18190
|
return emitDomainEvent(
|
|
@@ -17906,8 +18216,8 @@ function normalizeLatestAnswerRecord(questionId, answer) {
|
|
|
17906
18216
|
questionNodeId: questionId
|
|
17907
18217
|
};
|
|
17908
18218
|
}
|
|
17909
|
-
const record = answer;
|
|
17910
|
-
const metadata =
|
|
18219
|
+
const record = isRecord4(answer) ? answer : {};
|
|
18220
|
+
const metadata = isRecord4(record.metadata) ? record.metadata : {};
|
|
17911
18221
|
return {
|
|
17912
18222
|
nodeId: typeof record._id === "string" ? record._id : null,
|
|
17913
18223
|
globalId: typeof record.globalId === "string" ? record.globalId : null,
|
|
@@ -17946,10 +18256,13 @@ function createGatewayQuestionsPort(authContext) {
|
|
|
17946
18256
|
});
|
|
17947
18257
|
},
|
|
17948
18258
|
refineQuestion(input) {
|
|
17949
|
-
return authContext.convex.mutation(
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
18259
|
+
return authContext.convex.mutation(
|
|
18260
|
+
api.epistemicQuestions.updateQuestion,
|
|
18261
|
+
{
|
|
18262
|
+
questionId: input.questionRawId,
|
|
18263
|
+
question: input.text
|
|
18264
|
+
}
|
|
18265
|
+
);
|
|
17953
18266
|
},
|
|
17954
18267
|
updateQuestionStatus(input) {
|
|
17955
18268
|
return authContext.convex.mutation(api.epistemicQuestions.updateStatus, {
|
|
@@ -17992,10 +18305,13 @@ async function createQuestionFromGatewayAuth(authContext, input) {
|
|
|
17992
18305
|
sourceKind: "question",
|
|
17993
18306
|
autoCreate: input.topicId ? false : true
|
|
17994
18307
|
});
|
|
17995
|
-
const payload = await createQuestion(
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
18308
|
+
const payload = await createQuestion(
|
|
18309
|
+
createGatewayQuestionsPort(authContext),
|
|
18310
|
+
{
|
|
18311
|
+
...input,
|
|
18312
|
+
topicId: resolvedTopic.topicId
|
|
18313
|
+
}
|
|
18314
|
+
);
|
|
17999
18315
|
await emitQuestionEventFromGatewayAuth(authContext, {
|
|
18000
18316
|
topicId: payload.topicId ?? resolvedTopic.topicId,
|
|
18001
18317
|
type: "question.created",
|
|
@@ -18017,9 +18333,15 @@ function listQuestionsFromGatewayAuth(authContext, query) {
|
|
|
18017
18333
|
return listQuestions(createGatewayQuestionsPort(authContext), query);
|
|
18018
18334
|
}
|
|
18019
18335
|
async function answerQuestionFromGatewayAuth(authContext, input) {
|
|
18020
|
-
const payload = await answerQuestion(
|
|
18336
|
+
const payload = await answerQuestion(
|
|
18337
|
+
createGatewayQuestionsPort(authContext),
|
|
18338
|
+
input
|
|
18339
|
+
);
|
|
18021
18340
|
await emitQuestionEventFromGatewayAuth(authContext, {
|
|
18022
|
-
topicId: await resolveQuestionTopicIdWithGatewayAuth(
|
|
18341
|
+
topicId: await resolveQuestionTopicIdWithGatewayAuth(
|
|
18342
|
+
authContext,
|
|
18343
|
+
payload.questionId
|
|
18344
|
+
) ?? "",
|
|
18023
18345
|
type: "question.answered",
|
|
18024
18346
|
resourceId: payload.questionId,
|
|
18025
18347
|
data: {
|
|
@@ -18043,13 +18365,16 @@ async function getQuestionAnswerFromGatewayAuth(authContext, questionId) {
|
|
|
18043
18365
|
return normalizeLatestAnswerRecord(questionId, answer);
|
|
18044
18366
|
}
|
|
18045
18367
|
async function refineQuestionFromGatewayAuth(authContext, input) {
|
|
18046
|
-
const payload = await refineQuestion(
|
|
18368
|
+
const payload = await refineQuestion(
|
|
18369
|
+
createGatewayQuestionsPort(authContext),
|
|
18370
|
+
input
|
|
18371
|
+
);
|
|
18047
18372
|
await emitQuestionEventFromGatewayAuth(authContext, {
|
|
18048
18373
|
topicId: payload.topicId ?? "",
|
|
18049
18374
|
type: "question.refined",
|
|
18050
18375
|
resourceId: payload.id,
|
|
18051
18376
|
data: {
|
|
18052
|
-
previousText: typeof payload.previousText === "string" ? payload.previousText : void 0,
|
|
18377
|
+
previousText: isRecord4(payload) && typeof payload.previousText === "string" ? payload.previousText : void 0,
|
|
18053
18378
|
text: payload.text,
|
|
18054
18379
|
rationale: input.rationale
|
|
18055
18380
|
}
|
|
@@ -18057,7 +18382,10 @@ async function refineQuestionFromGatewayAuth(authContext, input) {
|
|
|
18057
18382
|
return payload;
|
|
18058
18383
|
}
|
|
18059
18384
|
async function archiveQuestionFromGatewayAuth(authContext, input) {
|
|
18060
|
-
const payload = await archiveQuestion(
|
|
18385
|
+
const payload = await archiveQuestion(
|
|
18386
|
+
createGatewayQuestionsPort(authContext),
|
|
18387
|
+
input
|
|
18388
|
+
);
|
|
18061
18389
|
await emitQuestionEventFromGatewayAuth(authContext, {
|
|
18062
18390
|
topicId: payload.topicId ?? "",
|
|
18063
18391
|
type: "question.archived",
|
|
@@ -18080,15 +18408,17 @@ async function updateQuestionStatusFromGatewayAuth(authContext, input) {
|
|
|
18080
18408
|
type: "question.status_updated",
|
|
18081
18409
|
resourceId: payload.id,
|
|
18082
18410
|
data: {
|
|
18083
|
-
previousStatus: typeof payload.previousStatus === "string" ? payload.previousStatus : void 0,
|
|
18084
|
-
newStatus: typeof payload.newStatus === "string" ? payload.newStatus : payload.status,
|
|
18411
|
+
previousStatus: isRecord4(payload) && typeof payload.previousStatus === "string" ? payload.previousStatus : void 0,
|
|
18412
|
+
newStatus: isRecord4(payload) && typeof payload.newStatus === "string" ? payload.newStatus : payload.status,
|
|
18085
18413
|
rationale: input.rationale
|
|
18086
18414
|
}
|
|
18087
18415
|
});
|
|
18088
18416
|
return payload;
|
|
18089
18417
|
}
|
|
18090
18418
|
function createQuestionsBatchFromGatewayAuth(authContext, input) {
|
|
18091
|
-
const linkedBeliefIds = input.questions.map((question) => question.linkedBeliefNodeId).filter(
|
|
18419
|
+
const linkedBeliefIds = input.questions.map((question) => question.linkedBeliefNodeId).filter(
|
|
18420
|
+
(questionId) => Boolean(readString11(questionId))
|
|
18421
|
+
);
|
|
18092
18422
|
const linkedWorktreeIds = [
|
|
18093
18423
|
...new Set(
|
|
18094
18424
|
input.questions.map((question) => question.linkedWorktreeId).filter(
|
|
@@ -18120,22 +18450,19 @@ function createQuestionsBatchFromGatewayAuth(authContext, input) {
|
|
|
18120
18450
|
sourceKind: "question_batch",
|
|
18121
18451
|
autoCreate: input.topicId ? false : true
|
|
18122
18452
|
})).topicId;
|
|
18123
|
-
return authContext.convex.mutation(
|
|
18124
|
-
|
|
18125
|
-
{
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
userId: authContext.userId
|
|
18137
|
-
}
|
|
18138
|
-
);
|
|
18453
|
+
return authContext.convex.mutation(api.epistemicQuestions.createBatch, {
|
|
18454
|
+
topicId: resolvedTopicId,
|
|
18455
|
+
questions: input.questions.map((question) => ({
|
|
18456
|
+
...question,
|
|
18457
|
+
linkedBeliefNodeId: normalizePrefixedId(
|
|
18458
|
+
question.linkedBeliefNodeId,
|
|
18459
|
+
"bel"
|
|
18460
|
+
),
|
|
18461
|
+
linkedWorktreeId: normalizePrefixedId(question.linkedWorktreeId, "wt")
|
|
18462
|
+
})),
|
|
18463
|
+
source: input.source,
|
|
18464
|
+
userId: authContext.userId
|
|
18465
|
+
});
|
|
18139
18466
|
})();
|
|
18140
18467
|
}
|
|
18141
18468
|
async function addQuestionFromGatewayAuth(authContext, input) {
|
|
@@ -18159,26 +18486,35 @@ async function addQuestionFromGatewayAuth(authContext, input) {
|
|
|
18159
18486
|
sourceKind: input.questionType ?? "question",
|
|
18160
18487
|
autoCreate: input.topicId ? false : true
|
|
18161
18488
|
})).topicId;
|
|
18162
|
-
const questionId = await authContext.convex.mutation(
|
|
18163
|
-
|
|
18164
|
-
|
|
18165
|
-
|
|
18166
|
-
|
|
18167
|
-
|
|
18168
|
-
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18176
|
-
|
|
18489
|
+
const questionId = await authContext.convex.mutation(
|
|
18490
|
+
api.epistemicQuestions.addQuestion,
|
|
18491
|
+
{
|
|
18492
|
+
topicId: resolvedTopicId,
|
|
18493
|
+
question: input.question ?? input.text ?? "",
|
|
18494
|
+
category: input.category,
|
|
18495
|
+
priority: input.priority,
|
|
18496
|
+
source: input.source,
|
|
18497
|
+
beliefId: normalizePrefixedId(
|
|
18498
|
+
input.beliefId ?? input.linkedBeliefId,
|
|
18499
|
+
"bel"
|
|
18500
|
+
),
|
|
18501
|
+
linkedWorktreeId: input.linkedWorktreeId,
|
|
18502
|
+
chatId: input.chatId,
|
|
18503
|
+
importance: input.importance,
|
|
18504
|
+
epistemicUnlock: input.epistemicUnlock,
|
|
18505
|
+
metadata: input.metadata,
|
|
18506
|
+
questionType: input.questionType,
|
|
18507
|
+
userId: authContext.userId
|
|
18508
|
+
}
|
|
18509
|
+
);
|
|
18177
18510
|
return getQuestionFromGatewayAuth(authContext, String(questionId));
|
|
18178
18511
|
}
|
|
18179
18512
|
async function updateQuestionPriorityFromGatewayAuth(authContext, input) {
|
|
18180
18513
|
await authContext.convex.mutation(api.epistemicQuestions.updatePriority, {
|
|
18181
|
-
nodeId:
|
|
18514
|
+
nodeId: normalizePrefixedId(
|
|
18515
|
+
input.id ?? input.nodeId ?? input.questionId,
|
|
18516
|
+
"que"
|
|
18517
|
+
) ?? "",
|
|
18182
18518
|
priority: input.priority,
|
|
18183
18519
|
userId: authContext.userId
|
|
18184
18520
|
});
|
|
@@ -18188,15 +18524,24 @@ async function updateQuestionPriorityFromGatewayAuth(authContext, input) {
|
|
|
18188
18524
|
);
|
|
18189
18525
|
}
|
|
18190
18526
|
function advanceQuestionToConvictionFromGatewayAuth(authContext, input) {
|
|
18191
|
-
return authContext.convex.mutation(
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
|
|
18195
|
-
|
|
18527
|
+
return authContext.convex.mutation(
|
|
18528
|
+
api.epistemicQuestions.advanceToConviction,
|
|
18529
|
+
{
|
|
18530
|
+
questionId: normalizePrefixedId(
|
|
18531
|
+
input.questionId ?? input.id ?? input.nodeId,
|
|
18532
|
+
"que"
|
|
18533
|
+
) ?? "",
|
|
18534
|
+
worktreeId: input.worktreeId,
|
|
18535
|
+
userId: authContext.userId
|
|
18536
|
+
}
|
|
18537
|
+
);
|
|
18196
18538
|
}
|
|
18197
18539
|
function updateQuestionConvictionFromGatewayAuth(authContext, input) {
|
|
18198
18540
|
return authContext.convex.mutation(api.epistemicQuestions.updateConviction, {
|
|
18199
|
-
questionId:
|
|
18541
|
+
questionId: normalizePrefixedId(
|
|
18542
|
+
input.questionId ?? input.id ?? input.nodeId,
|
|
18543
|
+
"que"
|
|
18544
|
+
) ?? "",
|
|
18200
18545
|
conviction: input.conviction,
|
|
18201
18546
|
answerCompleteness: input.answerCompleteness,
|
|
18202
18547
|
convictionRationale: input.convictionRationale,
|
|
@@ -18204,18 +18549,24 @@ function updateQuestionConvictionFromGatewayAuth(authContext, input) {
|
|
|
18204
18549
|
});
|
|
18205
18550
|
}
|
|
18206
18551
|
function finalizeQuestionConvictionFromGatewayAuth(authContext, input) {
|
|
18207
|
-
return authContext.convex.mutation(
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
|
|
18211
|
-
|
|
18212
|
-
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
|
|
18552
|
+
return authContext.convex.mutation(
|
|
18553
|
+
api.epistemicQuestions.finalizeConviction,
|
|
18554
|
+
{
|
|
18555
|
+
questionId: normalizePrefixedId(
|
|
18556
|
+
input.questionId ?? input.id ?? input.nodeId,
|
|
18557
|
+
"que"
|
|
18558
|
+
) ?? "",
|
|
18559
|
+
conviction: input.conviction,
|
|
18560
|
+
answer: input.answer,
|
|
18561
|
+
convictionRationale: input.convictionRationale,
|
|
18562
|
+
answerCompleteness: input.answerCompleteness,
|
|
18563
|
+
whatWeNeed: input.whatWeNeed,
|
|
18564
|
+
userId: authContext.userId
|
|
18565
|
+
}
|
|
18566
|
+
);
|
|
18216
18567
|
}
|
|
18217
18568
|
async function updateQuestionFromGatewayAuth(authContext, input) {
|
|
18218
|
-
const questionId =
|
|
18569
|
+
const questionId = normalizePrefixedId(input.questionId ?? input.id ?? input.nodeId, "que") ?? "";
|
|
18219
18570
|
await authContext.convex.mutation(api.epistemicQuestions.updateQuestion, {
|
|
18220
18571
|
questionId,
|
|
18221
18572
|
question: input.question ?? input.text,
|
|
@@ -18226,7 +18577,10 @@ async function updateQuestionFromGatewayAuth(authContext, input) {
|
|
|
18226
18577
|
}
|
|
18227
18578
|
function deleteQuestionFromGatewayAuth(authContext, input) {
|
|
18228
18579
|
return authContext.convex.mutation(api.epistemicQuestions.deleteQuestion, {
|
|
18229
|
-
questionId:
|
|
18580
|
+
questionId: normalizePrefixedId(
|
|
18581
|
+
input.questionId ?? input.id ?? input.nodeId,
|
|
18582
|
+
"que"
|
|
18583
|
+
) ?? "",
|
|
18230
18584
|
userId: authContext.userId
|
|
18231
18585
|
});
|
|
18232
18586
|
}
|
|
@@ -18267,7 +18621,7 @@ function matchesOptionalString(actual, expected) {
|
|
|
18267
18621
|
}
|
|
18268
18622
|
return readString12(actual) === expected;
|
|
18269
18623
|
}
|
|
18270
|
-
function
|
|
18624
|
+
function normalizeGraphNode(row) {
|
|
18271
18625
|
const record = asRecord10(row);
|
|
18272
18626
|
const nodeId = readString12(record.nodeId) ?? readString12(record._id);
|
|
18273
18627
|
const globalId = readString12(record.globalId);
|
|
@@ -18279,7 +18633,7 @@ function normalizeGraphNode2(row) {
|
|
|
18279
18633
|
...text ? { text, canonicalText: text } : {}
|
|
18280
18634
|
};
|
|
18281
18635
|
}
|
|
18282
|
-
function
|
|
18636
|
+
function normalizeGraphEdge(row) {
|
|
18283
18637
|
const record = asRecord10(row);
|
|
18284
18638
|
const edgeId = readString12(record.edgeId) ?? readString12(record._id);
|
|
18285
18639
|
return {
|
|
@@ -18294,13 +18648,13 @@ async function fetchGraphNodeByIdentifier(authContext, input) {
|
|
|
18294
18648
|
const node = await authContext.convex.query(api.epistemicNodes.get, {
|
|
18295
18649
|
nodeId: input.nodeId
|
|
18296
18650
|
});
|
|
18297
|
-
return node ?
|
|
18651
|
+
return node ? normalizeGraphNode(node) : null;
|
|
18298
18652
|
}
|
|
18299
18653
|
if (input.globalId) {
|
|
18300
18654
|
const node = await authContext.convex.query(api.epistemicNodes.getByGlobalId, {
|
|
18301
18655
|
globalId: input.globalId
|
|
18302
18656
|
});
|
|
18303
|
-
return node ?
|
|
18657
|
+
return node ? normalizeGraphNode(node) : null;
|
|
18304
18658
|
}
|
|
18305
18659
|
return null;
|
|
18306
18660
|
}
|
|
@@ -18538,7 +18892,7 @@ async function listGraphNodesFromGatewayAuth(authContext, input) {
|
|
|
18538
18892
|
userId: authContext.userId,
|
|
18539
18893
|
limit: normalizeLimit(input.limit, 250, 1e3)
|
|
18540
18894
|
});
|
|
18541
|
-
const nodes = asRecordArray2(rows).map(
|
|
18895
|
+
const nodes = asRecordArray2(rows).map(normalizeGraphNode).filter((node) => matchesOptionalString(node.nodeType, input.nodeType));
|
|
18542
18896
|
return { items: nodes, nodes, total: nodes.length };
|
|
18543
18897
|
}
|
|
18544
18898
|
async function listGraphEdgesFromGatewayAuth(authContext, input) {
|
|
@@ -18551,7 +18905,7 @@ async function listGraphEdgesFromGatewayAuth(authContext, input) {
|
|
|
18551
18905
|
userId: authContext.userId,
|
|
18552
18906
|
limit: normalizeLimit(input.limit, 500, 2e3)
|
|
18553
18907
|
});
|
|
18554
|
-
const edges = asRecordArray2(rows).map(
|
|
18908
|
+
const edges = asRecordArray2(rows).map(normalizeGraphEdge).filter((edge) => matchesOptionalString(edge.edgeId, input.edgeId)).filter((edge) => matchesOptionalString(edge.fromNodeId, input.fromNodeId)).filter((edge) => matchesOptionalString(edge.toNodeId, input.toNodeId)).filter((edge) => matchesOptionalString(edge.edgeType, input.edgeType));
|
|
18555
18909
|
return { items: edges, edges, total: edges.length };
|
|
18556
18910
|
}
|
|
18557
18911
|
|
|
@@ -20008,7 +20362,7 @@ function classifyCoverage(beliefs, questions, evidence) {
|
|
|
20008
20362
|
}
|
|
20009
20363
|
return "partial";
|
|
20010
20364
|
}
|
|
20011
|
-
async function
|
|
20365
|
+
async function createTopic2(deps, input) {
|
|
20012
20366
|
const created = await deps.createTopic({
|
|
20013
20367
|
name: requireString2(input.name, "name"),
|
|
20014
20368
|
description: readString18(input.description),
|
|
@@ -20195,24 +20549,29 @@ async function emitTopicEventFromGatewayAuth(authContext, args) {
|
|
|
20195
20549
|
}
|
|
20196
20550
|
);
|
|
20197
20551
|
}
|
|
20552
|
+
function normalizePrefixedId2(value) {
|
|
20553
|
+
try {
|
|
20554
|
+
const decoded = decodePrefixedId(value);
|
|
20555
|
+
return decoded.prefix === "top" ? decoded.value : value;
|
|
20556
|
+
} catch (_error) {
|
|
20557
|
+
return value;
|
|
20558
|
+
}
|
|
20559
|
+
}
|
|
20560
|
+
function isRecord5(value) {
|
|
20561
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
20562
|
+
}
|
|
20198
20563
|
function normalizeTopicEventId(topicId) {
|
|
20199
20564
|
const normalized = topicId.trim();
|
|
20200
20565
|
if (!normalized) {
|
|
20201
20566
|
return normalized;
|
|
20202
20567
|
}
|
|
20203
|
-
|
|
20204
|
-
const decoded = decodePrefixedId(normalized);
|
|
20205
|
-
return decoded.prefix === "top" ? decoded.value : normalized;
|
|
20206
|
-
} catch {
|
|
20207
|
-
return normalized;
|
|
20208
|
-
}
|
|
20568
|
+
return normalizePrefixedId2(normalized);
|
|
20209
20569
|
}
|
|
20210
20570
|
function readCanonicalTopicRawId(value) {
|
|
20211
|
-
if (!
|
|
20571
|
+
if (!isRecord5(value)) {
|
|
20212
20572
|
return void 0;
|
|
20213
20573
|
}
|
|
20214
|
-
const
|
|
20215
|
-
for (const candidate of [record._id, record.id, record.topicId, record.projectId]) {
|
|
20574
|
+
for (const candidate of [value._id, value.id, value.topicId, value.projectId]) {
|
|
20216
20575
|
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
20217
20576
|
return normalizeTopicEventId(candidate);
|
|
20218
20577
|
}
|
|
@@ -20291,7 +20650,10 @@ function createGatewayTopicsPort(authContext) {
|
|
|
20291
20650
|
};
|
|
20292
20651
|
}
|
|
20293
20652
|
async function createTopicFromGatewayAuth(authContext, input) {
|
|
20294
|
-
const payload = await
|
|
20653
|
+
const payload = await createTopic2(
|
|
20654
|
+
createGatewayTopicsPort(authContext),
|
|
20655
|
+
input
|
|
20656
|
+
);
|
|
20295
20657
|
await emitTopicEventFromGatewayAuth(authContext, {
|
|
20296
20658
|
topicId: normalizeTopicEventId(payload.topicId),
|
|
20297
20659
|
type: "topic.created",
|
|
@@ -20308,7 +20670,10 @@ async function createTopicFromGatewayAuth(authContext, input) {
|
|
|
20308
20670
|
return payload;
|
|
20309
20671
|
}
|
|
20310
20672
|
async function updateTopicFromGatewayAuth(authContext, input) {
|
|
20311
|
-
const payload = await updateTopic(
|
|
20673
|
+
const payload = await updateTopic(
|
|
20674
|
+
createGatewayTopicsPort(authContext),
|
|
20675
|
+
input
|
|
20676
|
+
);
|
|
20312
20677
|
await emitTopicEventFromGatewayAuth(authContext, {
|
|
20313
20678
|
topicId: normalizeTopicEventId(payload.topicId),
|
|
20314
20679
|
type: payload.status === "archived" ? "topic.archived" : "topic.updated",
|
|
@@ -20345,7 +20710,7 @@ async function removeTopicFromGatewayAuth(authContext, input) {
|
|
|
20345
20710
|
id: normalizedId
|
|
20346
20711
|
});
|
|
20347
20712
|
return {
|
|
20348
|
-
...payload,
|
|
20713
|
+
...isRecord5(payload) ? payload : {},
|
|
20349
20714
|
id: input.id
|
|
20350
20715
|
};
|
|
20351
20716
|
}
|
|
@@ -20979,7 +21344,7 @@ function toSubjectiveLogicOpinion(confidence) {
|
|
|
20979
21344
|
baseRate: 0.5
|
|
20980
21345
|
};
|
|
20981
21346
|
}
|
|
20982
|
-
function
|
|
21347
|
+
function normalizePrefixedId3(value, prefix) {
|
|
20983
21348
|
if (!value) {
|
|
20984
21349
|
return value;
|
|
20985
21350
|
}
|
|
@@ -20989,26 +21354,28 @@ function resolveExternalId5(value, prefix) {
|
|
|
20989
21354
|
return value;
|
|
20990
21355
|
}
|
|
20991
21356
|
return decoded.value;
|
|
20992
|
-
} catch {
|
|
21357
|
+
} catch (_error) {
|
|
20993
21358
|
return value;
|
|
20994
21359
|
}
|
|
20995
21360
|
}
|
|
21361
|
+
function isRecord6(value) {
|
|
21362
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
21363
|
+
}
|
|
20996
21364
|
function summarizeWorktreeCollection(rows) {
|
|
20997
21365
|
const worktrees2 = Array.isArray(rows) ? rows : [];
|
|
20998
21366
|
const lanes = {};
|
|
20999
21367
|
const campaigns = {};
|
|
21000
21368
|
for (const row of worktrees2) {
|
|
21001
|
-
if (!
|
|
21369
|
+
if (!isRecord6(row)) {
|
|
21002
21370
|
continue;
|
|
21003
21371
|
}
|
|
21004
|
-
const
|
|
21005
|
-
const lane = typeof record.lane === "string" && record.lane.trim().length > 0 ? record.lane.trim() : "unlaned";
|
|
21372
|
+
const lane = typeof row.lane === "string" && row.lane.trim().length > 0 ? row.lane.trim() : "unlaned";
|
|
21006
21373
|
lanes[lane] = (lanes[lane] ?? 0) + 1;
|
|
21007
|
-
const campaignValue = typeof
|
|
21374
|
+
const campaignValue = typeof row.campaign === "number" ? String(row.campaign) : "uncampaigned";
|
|
21008
21375
|
campaigns[campaignValue] = (campaigns[campaignValue] ?? 0) + 1;
|
|
21009
21376
|
}
|
|
21010
21377
|
return {
|
|
21011
|
-
worktrees: worktrees2,
|
|
21378
|
+
worktrees: worktrees2.filter(isRecord6),
|
|
21012
21379
|
total: worktrees2.length,
|
|
21013
21380
|
lanes,
|
|
21014
21381
|
campaigns
|
|
@@ -21068,7 +21435,7 @@ function readString20(value) {
|
|
|
21068
21435
|
return normalized.length > 0 ? normalized : void 0;
|
|
21069
21436
|
}
|
|
21070
21437
|
function withRequestedWorktreeId(payload, worktreeId) {
|
|
21071
|
-
if (!
|
|
21438
|
+
if (!isRecord6(payload)) {
|
|
21072
21439
|
return payload;
|
|
21073
21440
|
}
|
|
21074
21441
|
return {
|
|
@@ -21080,7 +21447,7 @@ async function resolveWorktreeTopicIdWithGatewayAuth(authContext, worktreeId) {
|
|
|
21080
21447
|
const worktree = await authContext.convex.query(api.worktrees.get, {
|
|
21081
21448
|
worktreeId
|
|
21082
21449
|
});
|
|
21083
|
-
return readString20(worktree
|
|
21450
|
+
return isRecord6(worktree) ? readString20(worktree.topicId) : void 0;
|
|
21084
21451
|
}
|
|
21085
21452
|
async function emitWorktreeEventFromGatewayAuth(authContext, args) {
|
|
21086
21453
|
return emitDomainEvent(
|
|
@@ -21124,8 +21491,30 @@ function createGatewayWorktreesPort(authContext) {
|
|
|
21124
21491
|
},
|
|
21125
21492
|
async createWorktree(input) {
|
|
21126
21493
|
const shouldAutoShape = input.autoShape === true || Boolean(input.domainPackId?.trim());
|
|
21127
|
-
const created = shouldAutoShape ? await authContext.convex.mutation(
|
|
21128
|
-
|
|
21494
|
+
const created = shouldAutoShape ? await authContext.convex.mutation(
|
|
21495
|
+
api.worktrees.createShaped,
|
|
21496
|
+
{
|
|
21497
|
+
...buildCreateMutationArgs(
|
|
21498
|
+
{
|
|
21499
|
+
...input,
|
|
21500
|
+
topicId: input.topicRawId,
|
|
21501
|
+
title: input.title,
|
|
21502
|
+
beliefIds: input.beliefRawIds,
|
|
21503
|
+
targetBeliefIds: input.targetBeliefRawIds,
|
|
21504
|
+
targetQuestionIds: input.targetQuestionRawIds
|
|
21505
|
+
},
|
|
21506
|
+
authContext.userId
|
|
21507
|
+
),
|
|
21508
|
+
...input.domainPackId?.trim() ? { domainPackId: input.domainPackId.trim() } : {},
|
|
21509
|
+
...typeof input.autoShape === "boolean" ? { autoShape: input.autoShape } : {},
|
|
21510
|
+
...Array.isArray(input.proofArtifacts) ? { proofArtifacts: input.proofArtifacts } : {},
|
|
21511
|
+
...input.staffingHint?.trim() ? { staffingHint: input.staffingHint.trim() } : {},
|
|
21512
|
+
...typeof input.lastReconciledAt === "number" ? { lastReconciledAt: input.lastReconciledAt } : {},
|
|
21513
|
+
...input.autoFixPolicy ? { autoFixPolicy: input.autoFixPolicy } : {}
|
|
21514
|
+
}
|
|
21515
|
+
) : await authContext.convex.mutation(
|
|
21516
|
+
api.worktrees.create,
|
|
21517
|
+
buildCreateMutationArgs(
|
|
21129
21518
|
{
|
|
21130
21519
|
...input,
|
|
21131
21520
|
topicId: input.topicRawId,
|
|
@@ -21135,26 +21524,10 @@ function createGatewayWorktreesPort(authContext) {
|
|
|
21135
21524
|
targetQuestionIds: input.targetQuestionRawIds
|
|
21136
21525
|
},
|
|
21137
21526
|
authContext.userId
|
|
21138
|
-
)
|
|
21139
|
-
|
|
21140
|
-
...typeof input.autoShape === "boolean" ? { autoShape: input.autoShape } : {},
|
|
21141
|
-
...Array.isArray(input.proofArtifacts) ? { proofArtifacts: input.proofArtifacts } : {},
|
|
21142
|
-
...input.staffingHint?.trim() ? { staffingHint: input.staffingHint.trim() } : {},
|
|
21143
|
-
...typeof input.lastReconciledAt === "number" ? { lastReconciledAt: input.lastReconciledAt } : {},
|
|
21144
|
-
...input.autoFixPolicy ? { autoFixPolicy: input.autoFixPolicy } : {}
|
|
21145
|
-
}) : await authContext.convex.mutation(api.worktrees.create, buildCreateMutationArgs(
|
|
21146
|
-
{
|
|
21147
|
-
...input,
|
|
21148
|
-
topicId: input.topicRawId,
|
|
21149
|
-
title: input.title,
|
|
21150
|
-
beliefIds: input.beliefRawIds,
|
|
21151
|
-
targetBeliefIds: input.targetBeliefRawIds,
|
|
21152
|
-
targetQuestionIds: input.targetQuestionRawIds
|
|
21153
|
-
},
|
|
21154
|
-
authContext.userId
|
|
21155
|
-
));
|
|
21527
|
+
)
|
|
21528
|
+
);
|
|
21156
21529
|
if (!shouldAutoShape && (Array.isArray(input.proofArtifacts) || input.staffingHint || typeof input.lastReconciledAt === "number" || input.autoFixPolicy)) {
|
|
21157
|
-
const createdRecord = created
|
|
21530
|
+
const createdRecord = isRecord6(created) ? created : {};
|
|
21158
21531
|
const worktreeId = typeof created === "string" ? created : typeof createdRecord.worktreeId === "string" ? createdRecord.worktreeId : "";
|
|
21159
21532
|
if (worktreeId) {
|
|
21160
21533
|
await authContext.convex.mutation(api.worktrees.updateMetadata, {
|
|
@@ -21185,14 +21558,17 @@ function createGatewayWorktreesPort(authContext) {
|
|
|
21185
21558
|
},
|
|
21186
21559
|
scoreBeliefOutcome(args) {
|
|
21187
21560
|
const opinion = toSubjectiveLogicOpinion(args.confidence);
|
|
21188
|
-
return authContext.convex.mutation(
|
|
21189
|
-
|
|
21190
|
-
|
|
21191
|
-
|
|
21192
|
-
|
|
21193
|
-
|
|
21194
|
-
|
|
21195
|
-
|
|
21561
|
+
return authContext.convex.mutation(
|
|
21562
|
+
api.epistemicBeliefs.modulateConfidence,
|
|
21563
|
+
{
|
|
21564
|
+
nodeId: args.beliefRawId,
|
|
21565
|
+
trigger: "worktree_outcome",
|
|
21566
|
+
rationale: args.rationale,
|
|
21567
|
+
userId: authContext.userId,
|
|
21568
|
+
triggeringWorktreeId: args.worktreeRawId,
|
|
21569
|
+
...opinion
|
|
21570
|
+
}
|
|
21571
|
+
);
|
|
21196
21572
|
},
|
|
21197
21573
|
updateWorktreeMetadata(input) {
|
|
21198
21574
|
return authContext.convex.mutation(api.worktrees.updateMetadata, {
|
|
@@ -21226,16 +21602,44 @@ function createGatewayWorktreesPort(authContext) {
|
|
|
21226
21602
|
removeBeliefIds: input.removeBeliefRawIds.map((id) => id)
|
|
21227
21603
|
} : {},
|
|
21228
21604
|
...input.removeQuestionRawIds?.length ? {
|
|
21229
|
-
removeQuestionIds: input.removeQuestionRawIds.map(
|
|
21605
|
+
removeQuestionIds: input.removeQuestionRawIds.map(
|
|
21606
|
+
(id) => id
|
|
21607
|
+
)
|
|
21230
21608
|
} : {}
|
|
21231
21609
|
});
|
|
21232
21610
|
}
|
|
21233
21611
|
};
|
|
21234
21612
|
}
|
|
21235
21613
|
async function createWorktreeFromGatewayAuth(authContext, input) {
|
|
21236
|
-
const
|
|
21614
|
+
const explicitTopicId = readString20(input.topicId);
|
|
21615
|
+
const resolvedTopic = await resolveTopicIdForWrite(authContext, {
|
|
21616
|
+
topicId: explicitTopicId,
|
|
21617
|
+
topicHint: readString20(input.topicHint) ?? explicitTopicId,
|
|
21618
|
+
workspaceId: authContext.workspaceId,
|
|
21619
|
+
summary: readString20(input.objective) ?? readString20(input.hypothesis) ?? readString20(input.rationale) ?? readString20(input.title) ?? "",
|
|
21620
|
+
tags: [
|
|
21621
|
+
...input.tags ?? [],
|
|
21622
|
+
input.lane,
|
|
21623
|
+
input.gate,
|
|
21624
|
+
input.worktreeType,
|
|
21625
|
+
input.domainPackId,
|
|
21626
|
+
input.confidenceImpact
|
|
21627
|
+
].filter((value) => Boolean(readString20(value))),
|
|
21628
|
+
touchedPaths: input.touchedPaths,
|
|
21629
|
+
sourceRef: readString20(input.sourceRef) ?? readString20(input.title),
|
|
21630
|
+
sourceKind: readString20(input.sourceKind) ?? "worktree",
|
|
21631
|
+
autoCreate: !explicitTopicId
|
|
21632
|
+
});
|
|
21633
|
+
const resolvedInput = {
|
|
21634
|
+
...input,
|
|
21635
|
+
topicId: resolvedTopic.topicId
|
|
21636
|
+
};
|
|
21637
|
+
const payload = await createWorktree(
|
|
21638
|
+
createGatewayWorktreesPort(authContext),
|
|
21639
|
+
resolvedInput
|
|
21640
|
+
);
|
|
21237
21641
|
await emitWorktreeEventFromGatewayAuth(authContext, {
|
|
21238
|
-
topicId: payload.topicId ??
|
|
21642
|
+
topicId: payload.topicId ?? resolvedInput.topicId,
|
|
21239
21643
|
type: "worktree.created",
|
|
21240
21644
|
resourceId: payload.worktreeId,
|
|
21241
21645
|
data: {
|
|
@@ -21269,15 +21673,21 @@ async function listAllWorktreesFromGatewayAuth(authContext, query = {}) {
|
|
|
21269
21673
|
...typeof query.campaign === "number" ? { campaign: query.campaign } : {},
|
|
21270
21674
|
...typeof query.limit === "number" ? { limit: query.limit } : {}
|
|
21271
21675
|
});
|
|
21272
|
-
return summarizeWorktreeCollection(rows);
|
|
21676
|
+
return summarizeWorktreeCollection(Array.isArray(rows) ? rows : []);
|
|
21273
21677
|
}
|
|
21274
21678
|
async function listCampaignsFromGatewayAuth(authContext, query = {}) {
|
|
21275
21679
|
return listCampaigns(createGatewayWorktreesPort(authContext), query);
|
|
21276
21680
|
}
|
|
21277
21681
|
async function activateWorktreeFromGatewayAuth(authContext, input) {
|
|
21278
|
-
const payload = await activateWorktree(
|
|
21682
|
+
const payload = await activateWorktree(
|
|
21683
|
+
createGatewayWorktreesPort(authContext),
|
|
21684
|
+
input
|
|
21685
|
+
);
|
|
21279
21686
|
await emitWorktreeEventFromGatewayAuth(authContext, {
|
|
21280
|
-
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21687
|
+
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21688
|
+
authContext,
|
|
21689
|
+
payload.worktreeId
|
|
21690
|
+
) ?? "",
|
|
21281
21691
|
type: "worktree.activated",
|
|
21282
21692
|
resourceId: payload.worktreeId,
|
|
21283
21693
|
data: {
|
|
@@ -21289,9 +21699,15 @@ async function activateWorktreeFromGatewayAuth(authContext, input) {
|
|
|
21289
21699
|
return payload;
|
|
21290
21700
|
}
|
|
21291
21701
|
async function updateWorktreeFromGatewayAuth(authContext, input) {
|
|
21292
|
-
const payload = await updateWorktree(
|
|
21702
|
+
const payload = await updateWorktree(
|
|
21703
|
+
createGatewayWorktreesPort(authContext),
|
|
21704
|
+
input
|
|
21705
|
+
);
|
|
21293
21706
|
await emitWorktreeEventFromGatewayAuth(authContext, {
|
|
21294
|
-
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21707
|
+
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21708
|
+
authContext,
|
|
21709
|
+
payload.worktreeId
|
|
21710
|
+
) ?? "",
|
|
21295
21711
|
type: "worktree.metadata_updated",
|
|
21296
21712
|
resourceId: payload.worktreeId,
|
|
21297
21713
|
data: {
|
|
@@ -21308,9 +21724,15 @@ async function updateWorktreeFromGatewayAuth(authContext, input) {
|
|
|
21308
21724
|
return payload;
|
|
21309
21725
|
}
|
|
21310
21726
|
async function mergeWorktreeFromGatewayAuth(authContext, input) {
|
|
21311
|
-
const payload = await mergeWorktree(
|
|
21727
|
+
const payload = await mergeWorktree(
|
|
21728
|
+
createGatewayWorktreesPort(authContext),
|
|
21729
|
+
input
|
|
21730
|
+
);
|
|
21312
21731
|
await emitWorktreeEventFromGatewayAuth(authContext, {
|
|
21313
|
-
topicId: await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21732
|
+
topicId: await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21733
|
+
authContext,
|
|
21734
|
+
payload.worktreeId
|
|
21735
|
+
) ?? "",
|
|
21314
21736
|
type: "worktree.merged",
|
|
21315
21737
|
resourceId: payload.worktreeId,
|
|
21316
21738
|
data: {
|
|
@@ -21330,7 +21752,10 @@ async function updateWorktreeTargetsFromGatewayAuth(authContext, input) {
|
|
|
21330
21752
|
input
|
|
21331
21753
|
);
|
|
21332
21754
|
await emitWorktreeEventFromGatewayAuth(authContext, {
|
|
21333
|
-
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21755
|
+
topicId: payload.topicId ?? await resolveWorktreeTopicIdWithGatewayAuth(
|
|
21756
|
+
authContext,
|
|
21757
|
+
payload.worktreeId
|
|
21758
|
+
) ?? "",
|
|
21334
21759
|
type: "worktree.targets_updated",
|
|
21335
21760
|
resourceId: payload.worktreeId,
|
|
21336
21761
|
data: {
|
|
@@ -21346,32 +21771,36 @@ async function updateWorktreeTargetsFromGatewayAuth(authContext, input) {
|
|
|
21346
21771
|
}
|
|
21347
21772
|
function completeWorktreeRecordFromGatewayAuth(authContext, input) {
|
|
21348
21773
|
return authContext.convex.mutation(api.worktrees.complete, {
|
|
21349
|
-
worktreeId:
|
|
21774
|
+
worktreeId: normalizePrefixedId3(input.worktreeId, "wt") ?? input.worktreeId,
|
|
21350
21775
|
keyFindings: input.keyFindings ?? [],
|
|
21351
21776
|
decisionsReached: input.decisionsReached ?? [],
|
|
21352
21777
|
nextSteps: input.nextSteps ?? [],
|
|
21353
21778
|
userId: authContext.userId
|
|
21354
|
-
}).then(
|
|
21779
|
+
}).then(
|
|
21780
|
+
(payload) => withRequestedWorktreeId(payload, input.worktreeId)
|
|
21781
|
+
);
|
|
21355
21782
|
}
|
|
21356
21783
|
function advanceWorktreePhaseFromGatewayAuth(authContext, input) {
|
|
21357
21784
|
return authContext.convex.mutation(api.worktrees.advancePhase, {
|
|
21358
|
-
worktreeId:
|
|
21785
|
+
worktreeId: normalizePrefixedId3(input.worktreeId, "wt") ?? input.worktreeId,
|
|
21359
21786
|
userId: authContext.userId
|
|
21360
21787
|
});
|
|
21361
21788
|
}
|
|
21362
21789
|
function setWorktreePhaseFromGatewayAuth(authContext, input) {
|
|
21363
21790
|
return authContext.convex.mutation(api.worktrees.setPhase, {
|
|
21364
|
-
worktreeId:
|
|
21791
|
+
worktreeId: normalizePrefixedId3(input.worktreeId, "wt") ?? input.worktreeId,
|
|
21365
21792
|
phase: input.phase,
|
|
21366
21793
|
userId: authContext.userId
|
|
21367
21794
|
});
|
|
21368
21795
|
}
|
|
21369
21796
|
function patchWorktreeStateFromGatewayAuth(authContext, input) {
|
|
21370
21797
|
return authContext.convex.mutation(api.worktrees.patchState, {
|
|
21371
|
-
worktreeId:
|
|
21798
|
+
worktreeId: normalizePrefixedId3(input.worktreeId, "wt") ?? input.worktreeId,
|
|
21372
21799
|
patch: input.patch,
|
|
21373
21800
|
userId: authContext.userId
|
|
21374
|
-
}).then(
|
|
21801
|
+
}).then(
|
|
21802
|
+
(payload) => withRequestedWorktreeId(payload, input.worktreeId)
|
|
21803
|
+
);
|
|
21375
21804
|
}
|
|
21376
21805
|
function bulkCreateWorktreesFromGatewayAuth(authContext, input) {
|
|
21377
21806
|
return authContext.convex.mutation(api.worktrees.bulkCreate, {
|
|
@@ -24815,6 +25244,7 @@ async function handleWorktreeCreate(args) {
|
|
|
24815
25244
|
const payload = await createWorktreeFromGatewayAuth(args.authContext, {
|
|
24816
25245
|
title: readString33(body.title) ?? readString33(body.name) ?? "",
|
|
24817
25246
|
topicId: readString33(body.topicId ?? body.projectId) ?? "",
|
|
25247
|
+
topicHint: readString33(body.topicHint),
|
|
24818
25248
|
objective: readString33(body.objective),
|
|
24819
25249
|
hypothesis: readString33(body.hypothesis),
|
|
24820
25250
|
rationale: readString33(body.rationale),
|
|
@@ -24835,6 +25265,10 @@ async function handleWorktreeCreate(args) {
|
|
|
24835
25265
|
} : void 0,
|
|
24836
25266
|
autoShape: typeof body.autoShape === "boolean" ? body.autoShape : void 0,
|
|
24837
25267
|
domainPackId: readString33(body.domainPackId),
|
|
25268
|
+
tags: readStringArray17(body.tags),
|
|
25269
|
+
touchedPaths: readStringArray17(body.touchedPaths),
|
|
25270
|
+
sourceRef: readString33(body.sourceRef),
|
|
25271
|
+
sourceKind: readString33(body.sourceKind),
|
|
24838
25272
|
campaign: readNumber22(body.campaign),
|
|
24839
25273
|
lane: readString33(body.lane),
|
|
24840
25274
|
laneOrderInCampaign: readNumber22(body.laneOrderInCampaign),
|