@bendyline/gezel-service 1.0.3 → 1.0.4
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/bin/gezeld.js +486 -84
- package/dist/handboek-content/whats-new/1.26226.md +89 -0
- package/dist/index.d.ts +45 -2
- package/dist/index.js +486 -84
- package/dist/memory/embed-worker.js +22 -3
- package/dist/ui/assets/{TerminalCodeEditor-CXspNipu.js → TerminalCodeEditor-BuMcfTS4.js} +2 -2
- package/dist/ui/assets/{_.contribution-Bi8h5rS7.js → _.contribution-CZO2XAKt.js} +1 -1
- package/dist/ui/assets/{chunk-6N2J7C2B-Du7clJkV.js → chunk-6N2J7C2B-BNHR_rFP.js} +1 -1
- package/dist/ui/assets/chunk-ILCJ3WFD-CUnKgI_I.js +4 -0
- package/dist/ui/assets/chunk-S5PCVMKU-i2wfHmvU.js +6 -0
- package/dist/ui/assets/{chunk-WATAOG4Y-BnCgSncI.js → chunk-WATAOG4Y-BbL-tDgQ.js} +1 -1
- package/dist/ui/assets/{cpp.contribution-CIgWElWw.js → cpp.contribution-BJzhk0Zj.js} +1 -1
- package/dist/ui/assets/{csharp.contribution-DDiJzXzB.js → csharp.contribution-BR9K2qKj.js} +1 -1
- package/dist/ui/assets/{css.contribution-Dc5E_mNx.js → css.contribution-CfkVmdah.js} +1 -1
- package/dist/ui/assets/{cssMode-BN_VZB6O.js → cssMode-MMeGUmV2.js} +1 -1
- package/dist/ui/assets/dist-8uH4DcHx.js +2 -0
- package/dist/ui/assets/{dist-D4PZf1Q3.js → dist-CFOmf7nD.js} +2 -2
- package/dist/ui/assets/{dockerfile.contribution-BQsaSuAJ.js → dockerfile.contribution-IZMl57B5.js} +1 -1
- package/dist/ui/assets/docx-BEJpkI6I.js +2 -0
- package/dist/ui/assets/extract-UTAOG7LV-BY3SCkzz.js +1 -0
- package/dist/ui/assets/{go.contribution-CPvqBST7.js → go.contribution-BxCBwhZs.js} +1 -1
- package/dist/ui/assets/{handlebars-DJvRMy-I.js → handlebars-CreIkams.js} +1 -1
- package/dist/ui/assets/handlebars.contribution-BGlyL-dm.js +2 -0
- package/dist/ui/assets/{html-Becff5XU.js → html-BSrz1IKi.js} +1 -1
- package/dist/ui/assets/html.contribution-CucOMFQ_.js +2 -0
- package/dist/ui/assets/{htmlMode-BFmyC6t-.js → htmlMode-DRG7XY5Z.js} +1 -1
- package/dist/ui/assets/{index-w_CaRVtV.js → index-Bqu-32S3.js} +177 -172
- package/dist/ui/assets/infer-D6e75m-s.js +2 -0
- package/dist/ui/assets/{ini.contribution-DFSSA0eY.js → ini.contribution-CGX5OdXM.js} +1 -1
- package/dist/ui/assets/{java.contribution-Bdvvskrf.js → java.contribution-CVhfJ_us.js} +1 -1
- package/dist/ui/assets/{javascript-DByfaclN.js → javascript-QelFp9t5.js} +1 -1
- package/dist/ui/assets/javascript.contribution--no0ijCu.js +2 -0
- package/dist/ui/assets/{jsonMode-CxkV6dJT.js → jsonMode-T4Ss3lDu.js} +1 -1
- package/dist/ui/assets/{kotlin.contribution-D8eqi2Fi.js → kotlin.contribution-DxFbGDYA.js} +1 -1
- package/dist/ui/assets/layouts-2A7QNF6Y-CWQp8HDd.js +1 -0
- package/dist/ui/assets/{less.contribution-DFRb86Ld.js → less.contribution-g9R8XRZf.js} +1 -1
- package/dist/ui/assets/{lua.contribution-BgktkcsF.js → lua.contribution-YqDsEy8Z.js} +1 -1
- package/dist/ui/assets/{markdown.contribution-BKqBKD_g.js → markdown.contribution-DboXnPnx.js} +1 -1
- package/dist/ui/assets/{monaco-CyhM025v.js → monaco-BdFw56DI.js} +3 -3
- package/dist/ui/assets/{monaco-base-hW9ht_BG.js → monaco-base-DrP3D13F.js} +1 -1
- package/dist/ui/assets/{monaco-setup-Cquhh1OE.js → monaco-setup-QyF22y9h.js} +1 -1
- package/dist/ui/assets/{monaco.contribution-D9-bPyBf.js → monaco.contribution-BkqIxESv.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-Cle0Lbgx.js → monaco.contribution-CMzPFHtO.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-Dl8lHLi5.js → monaco.contribution-FA_ESP-W.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-BVrZ1Anc.js → monaco.contribution-XEpc63ty.js} +2 -2
- package/dist/ui/assets/{php.contribution-CcYxMawn.js → php.contribution-rnpik0Kk.js} +1 -1
- package/dist/ui/assets/pptx-DZdEoDP9.js +6 -0
- package/dist/ui/assets/{python-DivQov6J.js → python-CF7X5t9Q.js} +1 -1
- package/dist/ui/assets/python.contribution-CyJGCfSq.js +2 -0
- package/dist/ui/assets/{ruby.contribution-DNudSRrU.js → ruby.contribution-4ZyPGu2E.js} +1 -1
- package/dist/ui/assets/{rust.contribution-BqG2lQpP.js → rust.contribution-Cl_B3X2G.js} +1 -1
- package/dist/ui/assets/{scss.contribution-DDxPnF-K.js → scss.contribution-BO02gVLZ.js} +1 -1
- package/dist/ui/assets/{shell.contribution-Q7wVL7zv.js → shell.contribution-Dn9Y0uHs.js} +1 -1
- package/dist/ui/assets/{sql.contribution-B9ndj3QH.js → sql.contribution-Bog_5Rc8.js} +1 -1
- package/dist/ui/assets/{swift.contribution-D_FDdL6S.js → swift.contribution-CfiAr7AX.js} +1 -1
- package/dist/ui/assets/{terminal-monaco-setup-BdF0mUfG.js → terminal-monaco-setup-B-EnkGiy.js} +1 -1
- package/dist/ui/assets/{tsMode-JVR2Jo5q.js → tsMode-B2WuLuPL.js} +1 -1
- package/dist/ui/assets/{typescript-1ZOjdUnd.js → typescript-Bv_J1tKT.js} +1 -1
- package/dist/ui/assets/typescript.contribution-CM0XQCYi.js +2 -0
- package/dist/ui/assets/xlsx-DDBRN-IU.js +4 -0
- package/dist/ui/assets/{xml-DrdFGpo2.js → xml-DMV-f4tm.js} +1 -1
- package/dist/ui/assets/xml.contribution-QqmOB9gT.js +2 -0
- package/dist/ui/assets/{yaml-DYQPB5Mj.js → yaml-Bb6mZXY5.js} +1 -1
- package/dist/ui/assets/yaml.contribution-DCDnWhHR.js +2 -0
- package/dist/ui/index.html +10 -10
- package/package.json +11 -11
- package/dist/ui/assets/chunk-ILCJ3WFD-fHFoZ9wm.js +0 -4
- package/dist/ui/assets/chunk-S5PCVMKU-DopU3Q9j.js +0 -6
- package/dist/ui/assets/dist-BwDZUtiH.js +0 -2
- package/dist/ui/assets/docx-IZY6hX8A.js +0 -2
- package/dist/ui/assets/extract-UTAOG7LV-BZ_L7lLL.js +0 -1
- package/dist/ui/assets/handlebars.contribution-BNbstxN6.js +0 -2
- package/dist/ui/assets/html.contribution-CPDzzJ0M.js +0 -2
- package/dist/ui/assets/infer-v-bCXeT9.js +0 -2
- package/dist/ui/assets/javascript.contribution-CPCuprn0.js +0 -2
- package/dist/ui/assets/layouts-2A7QNF6Y-D94iKLLQ.js +0 -1
- package/dist/ui/assets/pptx-CsdVR0xn.js +0 -6
- package/dist/ui/assets/python.contribution-CiRaN0sm.js +0 -2
- package/dist/ui/assets/typescript.contribution-_s-8TvIE.js +0 -2
- package/dist/ui/assets/xlsx-CdLmEC42.js +0 -4
- package/dist/ui/assets/xml.contribution-DUPYAKAC.js +0 -2
- package/dist/ui/assets/yaml.contribution-CRBo99nF.js +0 -2
package/dist/index.js
CHANGED
|
@@ -320,6 +320,13 @@ function queryInstruction() {
|
|
|
320
320
|
if (/bge-/i.test(model)) return "Represent this sentence for searching relevant passages: ";
|
|
321
321
|
return "";
|
|
322
322
|
}
|
|
323
|
+
function isRetryablePipelineLoadFailure(error) {
|
|
324
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
325
|
+
const code = error?.code ?? "";
|
|
326
|
+
return /(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|UND_ERR_|fetch failed|network(?: request)? failed|socket hang up|timed?\s*out|HTTP\s+(?:408|425|429|5\d\d)|TLS|SSL|certificate)/i.test(
|
|
327
|
+
`${code} ${message}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
323
330
|
async function loadPipeline() {
|
|
324
331
|
if (!pipelinePromise) {
|
|
325
332
|
pipelinePromise = (async () => {
|
|
@@ -333,7 +340,11 @@ async function loadPipeline() {
|
|
|
333
340
|
} catch (err) {
|
|
334
341
|
const missing = isMissingModule(err, TRANSFORMERS_MODULE);
|
|
335
342
|
const message = missing ? "Local memory embeddings are an optional npm feature. Install @huggingface/transformers@^3.8.1 alongside @bendyline/gezel-service (see the service README)." : err instanceof Error ? err.message : String(err);
|
|
336
|
-
throw new PipelineLoadError(
|
|
343
|
+
throw new PipelineLoadError(
|
|
344
|
+
message,
|
|
345
|
+
missing,
|
|
346
|
+
!missing && isRetryablePipelineLoadFailure(err)
|
|
347
|
+
);
|
|
337
348
|
}
|
|
338
349
|
})();
|
|
339
350
|
pipelinePromise.catch(() => {
|
|
@@ -374,10 +385,17 @@ var init_embed_core = __esm({
|
|
|
374
385
|
* damaged runtime.
|
|
375
386
|
*/
|
|
376
387
|
optionalPeerMissing;
|
|
377
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Network/model-registry failures can clear without a process restart. The
|
|
390
|
+
* host uses this bit to apply a short retry cooldown instead of permanently
|
|
391
|
+
* disabling embeddings after one failed first-use download.
|
|
392
|
+
*/
|
|
393
|
+
retryable;
|
|
394
|
+
constructor(message, optionalPeerMissing = false, retryable = false) {
|
|
378
395
|
super(message);
|
|
379
396
|
this.name = "PipelineLoadError";
|
|
380
397
|
this.optionalPeerMissing = optionalPeerMissing;
|
|
398
|
+
this.retryable = retryable;
|
|
381
399
|
}
|
|
382
400
|
};
|
|
383
401
|
pipelinePromise = null;
|
|
@@ -388,6 +406,7 @@ var init_embed_core = __esm({
|
|
|
388
406
|
var embeddings_exports = {};
|
|
389
407
|
__export(embeddings_exports, {
|
|
390
408
|
EmbeddingsDisabledError: () => EmbeddingsDisabledError,
|
|
409
|
+
EmbeddingsUnavailableError: () => EmbeddingsUnavailableError,
|
|
391
410
|
embed: () => embed,
|
|
392
411
|
embedBatch: () => embedBatch,
|
|
393
412
|
embedQuery: () => embedQuery,
|
|
@@ -400,7 +419,7 @@ function disabledByEnv() {
|
|
|
400
419
|
return raw === "1" || raw?.toLowerCase() === "true";
|
|
401
420
|
}
|
|
402
421
|
function embeddingsDisabledReason() {
|
|
403
|
-
return disabledByEnv() ? ENV_DISABLED_REASON : disabledReason;
|
|
422
|
+
return disabledByEnv() ? ENV_DISABLED_REASON : disabledReason ?? currentUnavailableReason();
|
|
404
423
|
}
|
|
405
424
|
function workerEntry() {
|
|
406
425
|
if (process.env.VITEST) return null;
|
|
@@ -436,7 +455,12 @@ function onMessage(msg) {
|
|
|
436
455
|
pending.delete(msg.id);
|
|
437
456
|
if (msg.error) {
|
|
438
457
|
if (msg.fatal) markDisabled(msg.error, msg.optionalPeerMissing ?? false);
|
|
439
|
-
|
|
458
|
+
if (msg.retryable) {
|
|
459
|
+
markTemporarilyUnavailable(msg.error);
|
|
460
|
+
p.reject(new EmbeddingsUnavailableError(unavailableReason ?? msg.error));
|
|
461
|
+
} else {
|
|
462
|
+
p.reject(new Error(msg.error));
|
|
463
|
+
}
|
|
440
464
|
return;
|
|
441
465
|
}
|
|
442
466
|
p.resolve(msg.vectors ?? []);
|
|
@@ -469,12 +493,31 @@ async function embedInProcess(texts) {
|
|
|
469
493
|
return await runEmbed(texts);
|
|
470
494
|
} catch (err) {
|
|
471
495
|
if (err instanceof PipelineLoadError) {
|
|
496
|
+
if (err.retryable) {
|
|
497
|
+
markTemporarilyUnavailable(err.message);
|
|
498
|
+
throw new EmbeddingsUnavailableError(unavailableReason ?? err.message);
|
|
499
|
+
}
|
|
472
500
|
markDisabled(err.message, err.optionalPeerMissing);
|
|
473
501
|
throw new EmbeddingsDisabledError(disabledReason ?? err.message);
|
|
474
502
|
}
|
|
475
503
|
throw err;
|
|
476
504
|
}
|
|
477
505
|
}
|
|
506
|
+
function currentUnavailableReason() {
|
|
507
|
+
if (!unavailableReason) return null;
|
|
508
|
+
if (Date.now() < unavailableUntil) return unavailableReason;
|
|
509
|
+
unavailableReason = null;
|
|
510
|
+
unavailableUntil = 0;
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
function markTemporarilyUnavailable(message) {
|
|
514
|
+
unavailableReason = firstLine(message);
|
|
515
|
+
unavailableUntil = Date.now() + EMBEDDING_RETRY_COOLDOWN_MS;
|
|
516
|
+
log10.warn(
|
|
517
|
+
`[memory] embedding model load failed; semantic search will retry after ${Math.ceil(EMBEDDING_RETRY_COOLDOWN_MS / 1e3)}s.`
|
|
518
|
+
);
|
|
519
|
+
log10.warn("[memory] underlying transient error:", message);
|
|
520
|
+
}
|
|
478
521
|
function markDisabled(message, optionalPeerMissing = false) {
|
|
479
522
|
if (disabledReason) return;
|
|
480
523
|
disabledReason = firstLine(message);
|
|
@@ -490,11 +533,14 @@ function markDisabled(message, optionalPeerMissing = false) {
|
|
|
490
533
|
async function embedMany(texts) {
|
|
491
534
|
if (disabledByEnv()) throw new EmbeddingsDisabledError(ENV_DISABLED_REASON);
|
|
492
535
|
if (disabledReason) throw new EmbeddingsDisabledError(disabledReason);
|
|
536
|
+
const temporaryReason = currentUnavailableReason();
|
|
537
|
+
if (temporaryReason) throw new EmbeddingsUnavailableError(temporaryReason);
|
|
493
538
|
const w = ensureWorker();
|
|
494
539
|
if (w) {
|
|
495
540
|
try {
|
|
496
541
|
return await sendToWorker(w, texts);
|
|
497
542
|
} catch (err) {
|
|
543
|
+
if (err instanceof EmbeddingsUnavailableError) throw err;
|
|
498
544
|
if (disabledReason) throw new EmbeddingsDisabledError(disabledReason);
|
|
499
545
|
log10.warn(`[memory] embed via worker failed; retrying in-process: ${describe(err)}`);
|
|
500
546
|
}
|
|
@@ -519,7 +565,7 @@ async function embedBatch(texts) {
|
|
|
519
565
|
if (texts.length === 0) return [];
|
|
520
566
|
return embedMany(texts);
|
|
521
567
|
}
|
|
522
|
-
var log10, EmbeddingsDisabledError, disabledReason, ENV_DISABLED_REASON, worker, workerUsable, crashCount, nextId, pending;
|
|
568
|
+
var log10, EmbeddingsDisabledError, EmbeddingsUnavailableError, disabledReason, unavailableReason, unavailableUntil, EMBEDDING_RETRY_COOLDOWN_MS, ENV_DISABLED_REASON, worker, workerUsable, crashCount, nextId, pending;
|
|
523
569
|
var init_embeddings = __esm({
|
|
524
570
|
"src/memory/embeddings.ts"() {
|
|
525
571
|
"use strict";
|
|
@@ -528,12 +574,25 @@ var init_embeddings = __esm({
|
|
|
528
574
|
log10 = createLogger10("memory");
|
|
529
575
|
EmbeddingsDisabledError = class extends Error {
|
|
530
576
|
code = "EMBEDDINGS_DISABLED";
|
|
577
|
+
retryable = false;
|
|
531
578
|
constructor(reason) {
|
|
532
579
|
super(`memory embeddings disabled: ${reason}`);
|
|
533
580
|
this.name = "EmbeddingsDisabledError";
|
|
534
581
|
}
|
|
535
582
|
};
|
|
583
|
+
EmbeddingsUnavailableError = class extends EmbeddingsDisabledError {
|
|
584
|
+
code = "EMBEDDINGS_UNAVAILABLE";
|
|
585
|
+
retryable = true;
|
|
586
|
+
constructor(reason) {
|
|
587
|
+
super(reason);
|
|
588
|
+
this.name = "EmbeddingsUnavailableError";
|
|
589
|
+
this.message = `memory embeddings temporarily unavailable: ${reason}`;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
536
592
|
disabledReason = null;
|
|
593
|
+
unavailableReason = null;
|
|
594
|
+
unavailableUntil = 0;
|
|
595
|
+
EMBEDDING_RETRY_COOLDOWN_MS = 6e4;
|
|
537
596
|
ENV_DISABLED_REASON = "disabled by GEZEL_DISABLE_EMBEDDINGS";
|
|
538
597
|
worker = null;
|
|
539
598
|
workerUsable = true;
|
|
@@ -14085,15 +14144,13 @@ import { createLogger as createLogger4 } from "@bendyline/gezel";
|
|
|
14085
14144
|
// src/model-profile/behaviors/fabrication-detect-claim-without-tool.ts
|
|
14086
14145
|
var PROJECT_CREATION_VERBS = [
|
|
14087
14146
|
"created",
|
|
14088
|
-
"initiated",
|
|
14089
14147
|
"initialized",
|
|
14090
14148
|
"set\\s+up",
|
|
14091
14149
|
"spun\\s+up",
|
|
14092
|
-
"started",
|
|
14093
14150
|
"made",
|
|
14094
|
-
"bootstrapped"
|
|
14095
|
-
"kicked\\s+off"
|
|
14151
|
+
"bootstrapped"
|
|
14096
14152
|
].join("|");
|
|
14153
|
+
var PROJECT_WORK_START_VERBS = ["initiated", "started", "kicked\\s+off"].join("|");
|
|
14097
14154
|
var TASK_CREATION_VERBS = ["created", "added", "queued", "set\\s+up"].join("|");
|
|
14098
14155
|
var GEZEL_CREATION_VERBS = [
|
|
14099
14156
|
"created",
|
|
@@ -14154,6 +14211,18 @@ var CLAIM_RULES = [
|
|
|
14154
14211
|
claim: "recruited a voorman",
|
|
14155
14212
|
nudge: "You told the user you recruited a voorman, but you did not call `create_gezel`, `ensure_gezel`, or `start_project` this turn. Call the right one now, and only report recruitment after it succeeds."
|
|
14156
14213
|
},
|
|
14214
|
+
{
|
|
14215
|
+
// Ambiguous kickoff verbs only become a container-creation claim when
|
|
14216
|
+
// the prose explicitly says this is a new/separate project. Otherwise
|
|
14217
|
+
// the next rule treats them as starting work in the current project.
|
|
14218
|
+
pattern: new RegExp(
|
|
14219
|
+
String.raw`\bI(?:'ve|\s+have|\s+just|\s+already)?\s+(?:` + PROJECT_WORK_START_VERBS + String.raw`)\s+(?:the|a|an)\s+(?:new|fresh|separate|another|dedicated)\s+project\b`,
|
|
14220
|
+
"i"
|
|
14221
|
+
),
|
|
14222
|
+
requiredTools: ["start_project"],
|
|
14223
|
+
claim: "created a project",
|
|
14224
|
+
nudge: "You told the user you started a new project, but you did not call `start_project` this turn. Call it now with the user-intended name and project brief, or correct the claim."
|
|
14225
|
+
},
|
|
14157
14226
|
{
|
|
14158
14227
|
pattern: new RegExp(
|
|
14159
14228
|
String.raw`\bI(?:'ve|\s+have|\s+just|\s+already)?\s+(?:` + PROJECT_CREATION_VERBS + String.raw`)\s+(?:the|a|an)\s+` + // Optional name placed between "the" and "project". Forms
|
|
@@ -14175,6 +14244,15 @@ var CLAIM_RULES = [
|
|
|
14175
14244
|
claim: "created a project",
|
|
14176
14245
|
nudge: "You told the user you created the project, but you did not call `start_project` this turn. Call it now with the user-intended name and a real `about` + `missionObjectives` derived from their request."
|
|
14177
14246
|
},
|
|
14247
|
+
{
|
|
14248
|
+
pattern: new RegExp(
|
|
14249
|
+
String.raw`\bI(?:'ve|\s+have|\s+just|\s+already)?\s+(?:` + PROJECT_WORK_START_VERBS + String.raw`)\s+(?:(?:work|the\s+work)\s+(?:on|for)\s+)?(?:the|this|that|our|your|a|an)\s+project\b`,
|
|
14250
|
+
"i"
|
|
14251
|
+
),
|
|
14252
|
+
requiredTools: ["invoke_craftbook", "create_task", "start_project"],
|
|
14253
|
+
claim: "started work in the current project",
|
|
14254
|
+
nudge: "You told the user project work started, but no project-local action succeeded this turn. Use `invoke_craftbook` for a selected procedure, `create_task` for an ad-hoc task, or `start_project` only when the user explicitly requested a separate project. Do not repeat the kickoff claim until the action returns successfully."
|
|
14255
|
+
},
|
|
14178
14256
|
{
|
|
14179
14257
|
pattern: new RegExp(
|
|
14180
14258
|
String.raw`\bI(?:'ve|\s+have|\s+just|\s+already)?\s+(?:` + GEZEL_CREATION_VERBS + String.raw`)\s+(?:the|a|an)\s+(?:new\s+)?gezel\b`,
|
|
@@ -15097,13 +15175,26 @@ var BUILD_REQUEST_RE = new RegExp(
|
|
|
15097
15175
|
function looksLikeNewBuildRequest(text) {
|
|
15098
15176
|
return BUILD_REQUEST_RE.test(text);
|
|
15099
15177
|
}
|
|
15178
|
+
function explicitlyRequestsSeparateProject(text) {
|
|
15179
|
+
return /\b(?:new|fresh|separate|another|dedicated)\s+(?:(?:standalone|independent)\s+)?(?:project|workspace)\b/i.test(
|
|
15180
|
+
text
|
|
15181
|
+
) || /\b(?:as|in|into|under|for)\s+(?:a|an)\s+(?:new|fresh|separate|another|dedicated)\s+(?:project|workspace)\b/i.test(
|
|
15182
|
+
text
|
|
15183
|
+
);
|
|
15184
|
+
}
|
|
15100
15185
|
var MEESTER_BUILD_PRELUDE = '(System note for this turn: the user is asking for a new substantive build. Make ONE tool call:\n \u2022 `start_project({ name, about, missionObjectives, taskDescription })`. Creates a fresh project, selects an appropriate lead/team for the effective execution mode, creates the kickoff task, and hands it off (the work starts in a task-scoped session). Use this for every "build me a website / game / app / dashboard" request, from a single-file prototype through multimodal work. `taskDescription` must ask the lead to ship the actual requested deliverable, not to create a plan. For browser games/sites, name `index.html` and the acceptance criteria (workspace-relative path; do not prefix `workspace/`).\nAfter the macro returns, your turn is done \u2014 tell the user the lead is on it. Do NOT call `create_gezel`, `update_project`, `create_task`, or `message_gezel` separately \u2014 the macro handles them. Do NOT reuse the existing "Default" project; the macro creates a fresh dedicated one.)';
|
|
15101
15186
|
var PromptMeesterBuildPrelude = {
|
|
15102
15187
|
id: "prompt.meester-build-prelude",
|
|
15103
15188
|
description: 'Prepends a system note to the user prompt when the active gezel is the Meester and the message looks like a "build me X" request, anchoring the first-call expectation on `start_project`.',
|
|
15104
15189
|
userPromptPrelude(ctx) {
|
|
15105
15190
|
if (!ctx.isMeester) return null;
|
|
15191
|
+
if (ctx.messageOrigin !== "direct-user") return null;
|
|
15192
|
+
if (/^\s*\[Answer to:/i.test(ctx.userText)) return null;
|
|
15106
15193
|
if (!looksLikeNewBuildRequest(ctx.userText)) return null;
|
|
15194
|
+
if (ctx.projectId !== "default" && !explicitlyRequestsSeparateProject(ctx.userText)) {
|
|
15195
|
+
return null;
|
|
15196
|
+
}
|
|
15197
|
+
if (!ctx.availableToolNames.includes("start_project")) return null;
|
|
15107
15198
|
return MEESTER_BUILD_PRELUDE;
|
|
15108
15199
|
}
|
|
15109
15200
|
};
|
|
@@ -18152,6 +18243,12 @@ var AnthropicCliSession = class extends StreamingSessionBase {
|
|
|
18152
18243
|
providerState() {
|
|
18153
18244
|
return this.claudeSessionIdCache ? { claudeCliSessionId: this.claudeSessionIdCache } : {};
|
|
18154
18245
|
}
|
|
18246
|
+
getRegisteredToolNames() {
|
|
18247
|
+
const context = this.deps.context;
|
|
18248
|
+
return [
|
|
18249
|
+
.../* @__PURE__ */ new Set([...context.allowedBuiltinTools ?? [], ...context.allowedMcpTools ?? []])
|
|
18250
|
+
];
|
|
18251
|
+
}
|
|
18155
18252
|
async disconnect() {
|
|
18156
18253
|
this.aborted = true;
|
|
18157
18254
|
try {
|
|
@@ -19700,6 +19797,10 @@ var AnthropicSession = class extends StreamingSessionBase {
|
|
|
19700
19797
|
* resolves and persisted on `ChatMessage.reasoning`.
|
|
19701
19798
|
*/
|
|
19702
19799
|
lastTurnReasoning = "";
|
|
19800
|
+
getRegisteredToolNames() {
|
|
19801
|
+
const bridgeNames = this.deps.bridges.isEmpty() ? [] : this.deps.bridges.getAnthropicTools().map((tool) => tool.name);
|
|
19802
|
+
return [.../* @__PURE__ */ new Set([...bridgeNames, ...this.externalToolNames])];
|
|
19803
|
+
}
|
|
19703
19804
|
capturedToolCalls() {
|
|
19704
19805
|
return [...this.capturedCalls];
|
|
19705
19806
|
}
|
|
@@ -33321,7 +33422,7 @@ var PROJECT_MACRO_INTERCEPT_CAP = 2;
|
|
|
33321
33422
|
var PROJECT_MACRO_FAILURE_CAP = 2;
|
|
33322
33423
|
function deriveProjectMacroClosing(firstResult) {
|
|
33323
33424
|
const projectMatch = firstResult.match(/Started (?:project|job) "([^"]+)"/);
|
|
33324
|
-
const leadMatch = firstResult.match(/Recruited (\S+) as (voorman|
|
|
33425
|
+
const leadMatch = firstResult.match(/Recruited (\S+) as (voorman|builder|lead)/i);
|
|
33325
33426
|
const projectName = projectMatch?.[1];
|
|
33326
33427
|
const leadName = leadMatch?.[1];
|
|
33327
33428
|
const leadRole = leadMatch?.[2];
|
|
@@ -37273,6 +37374,10 @@ var OpenAISession = class extends StreamingSessionBase {
|
|
|
37273
37374
|
capturedToolCalls() {
|
|
37274
37375
|
return [...this.capturedCalls];
|
|
37275
37376
|
}
|
|
37377
|
+
getRegisteredToolNames() {
|
|
37378
|
+
const bridgeNames = this.deps.bridges.isEmpty() ? [] : this.deps.bridges.getOpenAITools().map((tool) => tool.name);
|
|
37379
|
+
return [.../* @__PURE__ */ new Set([...bridgeNames, ...this.externalToolNames])];
|
|
37380
|
+
}
|
|
37276
37381
|
async sendAndWait(prompt, opts) {
|
|
37277
37382
|
return runInQueue(this.deps.queue, opts?.queue, () => this.sendAndWaitInner(prompt, opts));
|
|
37278
37383
|
}
|
|
@@ -40190,14 +40295,15 @@ async function evalCheck(c, ws, deps) {
|
|
|
40190
40295
|
}
|
|
40191
40296
|
async function evalCheckInner(c, ws, deps) {
|
|
40192
40297
|
const usesArtifact = c.artifact === true;
|
|
40193
|
-
const
|
|
40298
|
+
const artifactReader = {
|
|
40194
40299
|
read: ws.readArtifact ?? (async () => null),
|
|
40195
40300
|
list: ws.listArtifacts ?? (async () => []),
|
|
40196
40301
|
// Carry the byte reader across the artifact swap; without it a
|
|
40197
40302
|
// `verifyImageBytes` check on an artifact deliverable would report
|
|
40198
40303
|
// "no binary reads" even though the surface supports them.
|
|
40199
40304
|
...ws.readArtifactBytes ? { readBytes: ws.readArtifactBytes.bind(ws) } : {}
|
|
40200
|
-
}
|
|
40305
|
+
};
|
|
40306
|
+
const reader = usesArtifact ? artifactReader : ws;
|
|
40201
40307
|
switch (c.kind) {
|
|
40202
40308
|
case "minBytes": {
|
|
40203
40309
|
const r = await fileMinBytes(reader, c.file, c.bytes);
|
|
@@ -40625,7 +40731,12 @@ ${hint}` : ""}`,
|
|
|
40625
40731
|
};
|
|
40626
40732
|
}
|
|
40627
40733
|
case "markdownHeadingsMatch": {
|
|
40628
|
-
const result = await markdownHeadingsMatch(
|
|
40734
|
+
const result = await markdownHeadingsMatch(
|
|
40735
|
+
reader,
|
|
40736
|
+
c.file,
|
|
40737
|
+
c.outlineFile,
|
|
40738
|
+
c.outlineArtifact ? artifactReader : ws
|
|
40739
|
+
);
|
|
40629
40740
|
return {
|
|
40630
40741
|
ok: result.ok,
|
|
40631
40742
|
detail: result.detail,
|
|
@@ -42540,6 +42651,11 @@ function filterPromptToolDirectives(args) {
|
|
|
42540
42651
|
if (rejectedLines.size === 0) return args.prompt;
|
|
42541
42652
|
return args.prompt.split("\n").filter((_, index) => !rejectedLines.has(index + 1)).join("\n").replace(/\n{4,}/g, "\n\n\n");
|
|
42542
42653
|
}
|
|
42654
|
+
function capabilitySafeCorrectivePrompt(args) {
|
|
42655
|
+
const filtered = filterPromptToolDirectives(args).trim();
|
|
42656
|
+
if (filtered) return filtered;
|
|
42657
|
+
return "Your previous reply claimed an action succeeded without live evidence. Use only an appropriate action tool visible in your current roster, or explain that the action cannot be performed here. Do not repeat the success claim until an available action returns successfully.";
|
|
42658
|
+
}
|
|
42543
42659
|
|
|
42544
42660
|
// src/chat/provider-capabilities.ts
|
|
42545
42661
|
function providerUsesManagedMcpBridge(name) {
|
|
@@ -46378,6 +46494,21 @@ function sameFromBucket(a, b) {
|
|
|
46378
46494
|
if (!a || !b) return false;
|
|
46379
46495
|
return a.gezelId === b.gezelId;
|
|
46380
46496
|
}
|
|
46497
|
+
function resolveTurnMessageOrigin(opts) {
|
|
46498
|
+
if (opts?.messageOrigin) return opts.messageOrigin;
|
|
46499
|
+
if (opts?.from) return "cross-gezel";
|
|
46500
|
+
if (opts?.ambient || opts?.nudge || opts?.lane === "background") return "background-nudge";
|
|
46501
|
+
return "direct-user";
|
|
46502
|
+
}
|
|
46503
|
+
function liveTurnToolNames(session) {
|
|
46504
|
+
const names = /* @__PURE__ */ new Set();
|
|
46505
|
+
for (const name of session?.getRegisteredToolNames?.() ?? []) {
|
|
46506
|
+
names.add(name);
|
|
46507
|
+
const qualified = name.match(/^mcp__.+?__(.+)$/)?.[1];
|
|
46508
|
+
if (qualified && qualified !== "*") names.add(qualified);
|
|
46509
|
+
}
|
|
46510
|
+
return [...names];
|
|
46511
|
+
}
|
|
46381
46512
|
async function resolveCatalogParameterSize(catalog, catalogId) {
|
|
46382
46513
|
if (!catalogId) return void 0;
|
|
46383
46514
|
try {
|
|
@@ -47779,6 +47910,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
47779
47910
|
coalescable: false,
|
|
47780
47911
|
lane: void 0,
|
|
47781
47912
|
ambient: false,
|
|
47913
|
+
messageOrigin: "direct-user",
|
|
47782
47914
|
continuationMaxTokens: void 0,
|
|
47783
47915
|
hidden: false,
|
|
47784
47916
|
nudge: false,
|
|
@@ -48084,11 +48216,14 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48084
48216
|
const full = await this.store.getSession(args.gezelId, active.id);
|
|
48085
48217
|
if (full) return full;
|
|
48086
48218
|
}
|
|
48219
|
+
const parsedTaskRef = parseTaskRef2(args.taskRef);
|
|
48220
|
+
const task = parsedTaskRef ? await this.store.readTask(parsedTaskRef.projectId, parsedTaskRef.num).catch(() => null) : null;
|
|
48087
48221
|
return this.createSession({
|
|
48088
48222
|
gezelId: args.gezelId,
|
|
48089
48223
|
projectId: args.projectId,
|
|
48090
48224
|
taskRef: args.taskRef,
|
|
48091
|
-
...args.stepId ? { stepId: args.stepId } : {}
|
|
48225
|
+
...args.stepId ? { stepId: args.stepId } : {},
|
|
48226
|
+
...task?.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: task.roleBasedNameOnlyMode } : {}
|
|
48092
48227
|
});
|
|
48093
48228
|
}
|
|
48094
48229
|
/** Late-bind the fitness manager (see the field's docblock). */
|
|
@@ -48215,6 +48350,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48215
48350
|
*/
|
|
48216
48351
|
async startHandoffSession(args) {
|
|
48217
48352
|
const dispatchConfig = await this.store.readConfig();
|
|
48353
|
+
const roleBasedNameOnlyMode = args.roleBasedNameOnlyMode ?? dispatchConfig.roleBasedNameOnlyMode ?? false;
|
|
48218
48354
|
const dispatchGezel = await this.store.getGezel(args.gezelId);
|
|
48219
48355
|
const dispatchProviderName = await this.resolveProviderName(
|
|
48220
48356
|
args.gezelId,
|
|
@@ -48263,6 +48399,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48263
48399
|
projectId: args.projectId,
|
|
48264
48400
|
taskRef: args.taskRef,
|
|
48265
48401
|
stepId: dispatchStepId,
|
|
48402
|
+
roleBasedNameOnlyMode,
|
|
48266
48403
|
...args.nightShift ? { nightShift: true } : {},
|
|
48267
48404
|
...routed && args.capabilityFloor ? {
|
|
48268
48405
|
routedModel: {
|
|
@@ -48319,9 +48456,15 @@ ${stepArc}
|
|
|
48319
48456
|
}
|
|
48320
48457
|
}
|
|
48321
48458
|
const selfHandoff = args.fromGezelId !== void 0 && args.fromGezelId === args.gezelId;
|
|
48322
|
-
const
|
|
48459
|
+
const previousGezel = !selfHandoff && args.fromGezelId ? await this.store.getGezel(args.fromGezelId).catch(() => null) : null;
|
|
48460
|
+
const fromGezelDisplayName = previousGezel ? displayName2(
|
|
48461
|
+
{ name: previousGezel.name, roleBasedName: previousGezel.roleBasedName },
|
|
48462
|
+
roleBasedNameOnlyMode
|
|
48463
|
+
) : roleBasedNameOnlyMode ? void 0 : args.fromGezelName;
|
|
48464
|
+
const seed = args.kind === "entry" ? `${entryPreface}You've been assigned task ${args.taskRef} (step \`${dispatchStepId}\`). Follow the step instructions already in your prompt \u2014 make the first tool call they name this turn. Append focused notes with \`write_task_note\` as you go. When the step is done, call \`advance_task_step\` to hand off to whoever's next.` : selfHandoff ? `Task ${args.taskRef} has advanced to the next step \u2014 \`${dispatchStepId}\`, which is yours as well. Please continue: follow the step instructions already in your prompt \u2014 make the first tool call they name this turn. Append focused notes with \`write_task_note\` as you go so the next gezel can pick up where you left off. When the step is done, call \`advance_task_step\` to hand off to whoever's next.` : `${fromGezelDisplayName ? `${fromGezelDisplayName} has` : "The previous step has been completed and"} handed step \`${dispatchStepId}\` of task ${args.taskRef} to you. Follow the step instructions already in your prompt \u2014 make the first tool call they name this turn. Append focused notes with \`write_task_note\` as you go so the next gezel can pick up where you left off. When the step is done, call \`advance_task_step\` to hand off to whoever's next.`;
|
|
48323
48465
|
this.trackBackground(
|
|
48324
48466
|
this.sendWithBusyRetry(session.id, seed, {
|
|
48467
|
+
messageOrigin: "system",
|
|
48325
48468
|
...args.lane ? { lane: args.lane } : {},
|
|
48326
48469
|
...args.ambient ? { ambient: true } : {}
|
|
48327
48470
|
}).catch((err) => {
|
|
@@ -49167,11 +49310,10 @@ ${stepArc}
|
|
|
49167
49310
|
log52.info(
|
|
49168
49311
|
`[questions] delivering answer to session ${args.sessionId.slice(0, 8)} (gezel ${session.gezelId}, project ${session.projectId})`
|
|
49169
49312
|
);
|
|
49170
|
-
await this.sendWithBusyRetry(
|
|
49171
|
-
|
|
49172
|
-
args.
|
|
49173
|
-
|
|
49174
|
-
);
|
|
49313
|
+
await this.sendWithBusyRetry(args.sessionId, args.seed, {
|
|
49314
|
+
messageOrigin: "question-answer",
|
|
49315
|
+
...args.coalescable ? { coalescable: true } : {}
|
|
49316
|
+
});
|
|
49175
49317
|
}
|
|
49176
49318
|
/**
|
|
49177
49319
|
* System-authored reaction seed into a gezel's live (gezel, project)
|
|
@@ -49197,6 +49339,7 @@ ${stepArc}
|
|
|
49197
49339
|
this.send(session.id, args.seed, {
|
|
49198
49340
|
coalescable: true,
|
|
49199
49341
|
lane: "background",
|
|
49342
|
+
messageOrigin: "system",
|
|
49200
49343
|
...leanReactionCap ? { continuationMaxTokens: leanReactionCap } : {},
|
|
49201
49344
|
...args.hidden ? { hidden: true } : {}
|
|
49202
49345
|
}).catch((err) => {
|
|
@@ -49671,12 +49814,13 @@ ${stepArc}
|
|
|
49671
49814
|
throw new Error("engagement-off: AI is disabled in settings; re-enable to send");
|
|
49672
49815
|
}
|
|
49673
49816
|
const existingQueue = this.pendingSends.get(sessionId2);
|
|
49817
|
+
const messageOrigin = resolveTurnMessageOrigin(opts);
|
|
49674
49818
|
const shouldQueue = this.inflight.has(sessionId2) || existingQueue !== void 0 && existingQueue.length > 0;
|
|
49675
49819
|
if (shouldQueue) {
|
|
49676
49820
|
return new Promise((resolve18, reject) => {
|
|
49677
49821
|
const q2 = this.pendingSends.get(sessionId2) ?? [];
|
|
49678
49822
|
const tail = q2.length > 0 ? q2[q2.length - 1] : void 0;
|
|
49679
|
-
const canMerge = opts?.coalescable === true && opts?.nudge !== true && tail?.coalescable === true && tail.nudge !== true && sameFromBucket(tail.from, opts.from);
|
|
49823
|
+
const canMerge = opts?.coalescable === true && opts?.nudge !== true && tail?.coalescable === true && tail.nudge !== true && tail.messageOrigin === messageOrigin && sameFromBucket(tail.from, opts.from);
|
|
49680
49824
|
if (canMerge && tail) {
|
|
49681
49825
|
tail.userText = `${tail.userText}
|
|
49682
49826
|
|
|
@@ -49703,6 +49847,7 @@ ${userText}`;
|
|
|
49703
49847
|
coalescable: opts?.coalescable === true,
|
|
49704
49848
|
lane: opts?.lane,
|
|
49705
49849
|
ambient: opts?.ambient === true,
|
|
49850
|
+
messageOrigin,
|
|
49706
49851
|
continuationMaxTokens: opts?.continuationMaxTokens,
|
|
49707
49852
|
hidden: opts?.hidden === true,
|
|
49708
49853
|
nudge: opts?.nudge === true,
|
|
@@ -49719,7 +49864,7 @@ ${userText}`;
|
|
|
49719
49864
|
return this.runSendAndDrain(
|
|
49720
49865
|
sessionId2,
|
|
49721
49866
|
userText,
|
|
49722
|
-
opts?.nudge ? { ...opts, nudge: false } : opts
|
|
49867
|
+
opts?.nudge ? { ...opts, nudge: false, messageOrigin } : { ...opts, messageOrigin }
|
|
49723
49868
|
);
|
|
49724
49869
|
}
|
|
49725
49870
|
/**
|
|
@@ -49818,7 +49963,7 @@ ${userText}`;
|
|
|
49818
49963
|
if (next.nudge) {
|
|
49819
49964
|
while (q2.length > 0) {
|
|
49820
49965
|
const peek = q2[0];
|
|
49821
|
-
if (!peek.nudge || peek.hidden !== next.hidden || !sameFromBucket(peek.from, next.from)) {
|
|
49966
|
+
if (!peek.nudge || peek.hidden !== next.hidden || peek.messageOrigin !== next.messageOrigin || !sameFromBucket(peek.from, next.from)) {
|
|
49822
49967
|
break;
|
|
49823
49968
|
}
|
|
49824
49969
|
q2.shift();
|
|
@@ -49841,6 +49986,7 @@ ${peek.userText}`;
|
|
|
49841
49986
|
if (next.continuationMaxTokens) runOpts.continuationMaxTokens = next.continuationMaxTokens;
|
|
49842
49987
|
if (next.hidden) runOpts.hidden = true;
|
|
49843
49988
|
if (next.nudge) runOpts.nudge = true;
|
|
49989
|
+
runOpts.messageOrigin = next.messageOrigin;
|
|
49844
49990
|
void this.runSendAndDrain(sessionId2, next.userText, runOpts).then((msg) => {
|
|
49845
49991
|
for (const w of next.waiters) {
|
|
49846
49992
|
try {
|
|
@@ -50171,6 +50317,18 @@ ${peek.userText}`;
|
|
|
50171
50317
|
try {
|
|
50172
50318
|
let lastAssistantMessage = null;
|
|
50173
50319
|
let promptForTurn = spliceIntoText(userText, pendingDigests);
|
|
50320
|
+
const correctivePromptForLiveRoster = (prompt, source) => {
|
|
50321
|
+
const safe = capabilitySafeCorrectivePrompt({
|
|
50322
|
+
prompt,
|
|
50323
|
+
availableTools: liveTurnToolNames(liveSession)
|
|
50324
|
+
});
|
|
50325
|
+
if (safe !== prompt.trim()) {
|
|
50326
|
+
log52.warn(
|
|
50327
|
+
`session ${sessionId2}: filtered ${source} corrective against the live tool roster`
|
|
50328
|
+
);
|
|
50329
|
+
}
|
|
50330
|
+
return safe;
|
|
50331
|
+
};
|
|
50174
50332
|
const freshGameState = await this.refreshLeanGameState(state.record, userText);
|
|
50175
50333
|
if (freshGameState) {
|
|
50176
50334
|
promptForTurn = `${freshGameState}
|
|
@@ -50181,7 +50339,8 @@ ${promptForTurn}`;
|
|
|
50181
50339
|
this.taskBudget.reset(state.record.taskRef);
|
|
50182
50340
|
this.pendingBudgetNudge.delete(state.record.taskRef);
|
|
50183
50341
|
}
|
|
50184
|
-
const
|
|
50342
|
+
const messageOrigin = resolveTurnMessageOrigin(opts);
|
|
50343
|
+
const preludeForTurn = await this.resolveUserPromptPrelude(state, userText, messageOrigin);
|
|
50185
50344
|
if (preludeForTurn) {
|
|
50186
50345
|
promptForTurn = `${preludeForTurn.text}
|
|
50187
50346
|
|
|
@@ -50204,7 +50363,7 @@ ${promptForTurn}`;
|
|
|
50204
50363
|
}
|
|
50205
50364
|
if (state.record.taskRef && this.pendingBudgetNudge.has(state.record.taskRef)) {
|
|
50206
50365
|
this.pendingBudgetNudge.delete(state.record.taskRef);
|
|
50207
|
-
promptForTurn = `${TASK_BUDGET_NUDGE}
|
|
50366
|
+
promptForTurn = `${correctivePromptForLiveRoster(TASK_BUDGET_NUDGE, "task-budget")}
|
|
50208
50367
|
|
|
50209
50368
|
${promptForTurn}`;
|
|
50210
50369
|
log52.info(
|
|
@@ -50213,6 +50372,7 @@ ${promptForTurn}`;
|
|
|
50213
50372
|
}
|
|
50214
50373
|
let continuations = 0;
|
|
50215
50374
|
const maxContinuations = resolveContinuationBudget(state);
|
|
50375
|
+
let voormanIdleNudged = false;
|
|
50216
50376
|
const toolsAcrossContinuations = [];
|
|
50217
50377
|
let compactionsThisSend = 0;
|
|
50218
50378
|
let keurmeesterConsultedThisSend = false;
|
|
@@ -50476,6 +50636,7 @@ ${state.aboutSnapshot}`);
|
|
|
50476
50636
|
const detectorVerdict = runPostTurnDetectors(state, {
|
|
50477
50637
|
sessionId: sessionId2,
|
|
50478
50638
|
isMeester: cfgForDetector?.meesterGezelId === state.record.gezelId,
|
|
50639
|
+
messageOrigin,
|
|
50479
50640
|
userText,
|
|
50480
50641
|
drained: toolsAcrossContinuations,
|
|
50481
50642
|
assistantContent: assistantMessage.content,
|
|
@@ -50489,7 +50650,10 @@ ${state.aboutSnapshot}`);
|
|
|
50489
50650
|
this.events.publish(scope, { type: "warning", message: warningMessage });
|
|
50490
50651
|
}
|
|
50491
50652
|
if (detectorVerdict?.promptForNextTurn) {
|
|
50492
|
-
detectorReprompt =
|
|
50653
|
+
detectorReprompt = correctivePromptForLiveRoster(
|
|
50654
|
+
detectorVerdict.promptForNextTurn,
|
|
50655
|
+
"post-turn detector"
|
|
50656
|
+
);
|
|
50493
50657
|
}
|
|
50494
50658
|
const advanceOutcome = await this.maybeAutoAdvanceOnObservableProgress(
|
|
50495
50659
|
state,
|
|
@@ -50640,7 +50804,10 @@ ${state.aboutSnapshot}`);
|
|
|
50640
50804
|
log52.info(
|
|
50641
50805
|
`session ${sessionId2}: keurmeester intervention applied (case ${consult.caseId}) \u2014 granting one recovery continuation`
|
|
50642
50806
|
);
|
|
50643
|
-
promptForTurn =
|
|
50807
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50808
|
+
consult.correctivePrompt,
|
|
50809
|
+
"keurmeester"
|
|
50810
|
+
);
|
|
50644
50811
|
continue;
|
|
50645
50812
|
}
|
|
50646
50813
|
}
|
|
@@ -50658,7 +50825,10 @@ ${state.aboutSnapshot}`);
|
|
|
50658
50825
|
log52.info(
|
|
50659
50826
|
`session ${sessionId2}: ${detectorVerdict?.reason ?? "detector"} \u2014 re-prompting`
|
|
50660
50827
|
);
|
|
50661
|
-
promptForTurn =
|
|
50828
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50829
|
+
detectorReprompt,
|
|
50830
|
+
detectorVerdict ? "post-turn detector" : "deliverable salvage"
|
|
50831
|
+
);
|
|
50662
50832
|
continue;
|
|
50663
50833
|
}
|
|
50664
50834
|
if (advanceOutcome.gateRejected && !advanceOutcome.gateRejected.paused && advanceOutcome.gateRejected.fingerprint !== state.lastGateNudgeFingerprint && !drained.some((d) => d.name === "ask_user_question" && d.success)) {
|
|
@@ -50668,7 +50838,10 @@ ${state.aboutSnapshot}`);
|
|
|
50668
50838
|
log52.info(
|
|
50669
50839
|
`session ${sessionId2}: ${advanceOutcome.gateRejected.taskRef} step "${advanceOutcome.gateRejected.stepId}" gate rejected \u2014 re-prompting with the verdict${stage > 0 ? ` (escalation stage ${stage})` : ""}`
|
|
50670
50840
|
);
|
|
50671
|
-
promptForTurn =
|
|
50841
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50842
|
+
stage >= 1 ? advanceOutcome.gateRejected.message : buildGateRejectionNudge(advanceOutcome.gateRejected.message),
|
|
50843
|
+
"task-gate"
|
|
50844
|
+
);
|
|
50672
50845
|
continue;
|
|
50673
50846
|
}
|
|
50674
50847
|
if (deliverableOutcome.deliverableRejected?.stopRetrying) {
|
|
@@ -50719,7 +50892,10 @@ ${state.aboutSnapshot}`);
|
|
|
50719
50892
|
log52.info(
|
|
50720
50893
|
`session ${sessionId2}: keurmeester intervention applied on deliverable plateau (case ${consult.caseId}) \u2014 granting one recovery continuation`
|
|
50721
50894
|
);
|
|
50722
|
-
promptForTurn =
|
|
50895
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50896
|
+
consult.correctivePrompt,
|
|
50897
|
+
"keurmeester deliverable-plateau"
|
|
50898
|
+
);
|
|
50723
50899
|
continue;
|
|
50724
50900
|
}
|
|
50725
50901
|
}
|
|
@@ -50743,7 +50919,10 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50743
50919
|
...dRej.filePath ? { filePath: dRej.filePath } : {},
|
|
50744
50920
|
failingVerdict: dRej.message
|
|
50745
50921
|
});
|
|
50746
|
-
promptForTurn =
|
|
50922
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50923
|
+
clampNudge ?? (dStage >= 1 ? dRej.message : buildGateRejectionNudge(dRej.message)),
|
|
50924
|
+
"deliverable-gate"
|
|
50925
|
+
);
|
|
50747
50926
|
continue;
|
|
50748
50927
|
}
|
|
50749
50928
|
if (advanceOutcome.unmetEditGate && (looksStalled(finalContent) || claimsCompletion(finalContent)) && !drained.some((d) => d.name === "ask_user_question" && d.success)) {
|
|
@@ -50751,7 +50930,10 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50751
50930
|
log52.info(
|
|
50752
50931
|
`session ${sessionId2}: ${advanceOutcome.unmetEditGate.taskRef} edit gate unmet (${advanceOutcome.unmetEditGate.file} not written) but reply claims progress \u2014 nudging to edit`
|
|
50753
50932
|
);
|
|
50754
|
-
promptForTurn =
|
|
50933
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50934
|
+
buildDeliverableEditNudge(advanceOutcome.unmetEditGate.file),
|
|
50935
|
+
"deliverable-edit"
|
|
50936
|
+
);
|
|
50755
50937
|
continue;
|
|
50756
50938
|
}
|
|
50757
50939
|
const unresolvedToolFailures = unresolvedFailedToolCalls(drained);
|
|
@@ -50795,7 +50977,7 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50795
50977
|
// the hot path synchronous for the common non-voorman case.
|
|
50796
50978
|
// Also requires `proactive` — voorman idle nudges advance
|
|
50797
50979
|
// project work past what the user asked for.
|
|
50798
|
-
isProactiveAllowed(nudgeConfig) && state.record.providerName !== "copilot"
|
|
50980
|
+
isProactiveAllowed(nudgeConfig) && state.record.providerName !== "copilot" && !voormanIdleNudged
|
|
50799
50981
|
) {
|
|
50800
50982
|
voormanIdleVerdict = await this.didVoormanIdleStall(state.record, drained, sessionId2);
|
|
50801
50983
|
if (voormanIdleVerdict !== null) {
|
|
@@ -50813,15 +50995,19 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50813
50995
|
);
|
|
50814
50996
|
break;
|
|
50815
50997
|
}
|
|
50998
|
+
if (stallReason === "voorman-idle") voormanIdleNudged = true;
|
|
50816
50999
|
continuations++;
|
|
50817
51000
|
log52.info(
|
|
50818
|
-
`session ${sessionId2}: response looks stalled (${stallReason}) \u2014
|
|
51001
|
+
`session ${sessionId2}: response looks stalled (${stallReason}) \u2014 requesting one recovery pass`
|
|
51002
|
+
);
|
|
51003
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
51004
|
+
stallReason === "voorman-idle" ? buildContinuationNudge(
|
|
51005
|
+
finalContent,
|
|
51006
|
+
state.record.messages,
|
|
51007
|
+
voormanIdleVerdict === "nothing-built" ? VOORMAN_NOT_DONE_NUDGE : VOORMAN_IDLE_NUDGE
|
|
51008
|
+
) : stallReason === "tool-only" ? CLOSING_SUMMARY_NUDGE : stallReason === "tool-read-only" ? READ_ONLY_PROGRESS_NUDGE : stallReason === "tool-failed" ? buildFailedToolRecoveryNudge(unresolvedToolFailures) : buildContinuationNudge(finalContent, state.record.messages),
|
|
51009
|
+
`stall-${stallReason}`
|
|
50819
51010
|
);
|
|
50820
|
-
promptForTurn = stallReason === "voorman-idle" ? buildContinuationNudge(
|
|
50821
|
-
finalContent,
|
|
50822
|
-
state.record.messages,
|
|
50823
|
-
voormanIdleVerdict === "nothing-built" ? VOORMAN_NOT_DONE_NUDGE : VOORMAN_IDLE_NUDGE
|
|
50824
|
-
) : stallReason === "tool-only" ? CLOSING_SUMMARY_NUDGE : stallReason === "tool-read-only" ? READ_ONLY_PROGRESS_NUDGE : stallReason === "tool-failed" ? buildFailedToolRecoveryNudge(unresolvedToolFailures) : buildContinuationNudge(finalContent, state.record.messages);
|
|
50825
51011
|
continue;
|
|
50826
51012
|
}
|
|
50827
51013
|
}
|
|
@@ -51387,7 +51573,7 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
51387
51573
|
return null;
|
|
51388
51574
|
}
|
|
51389
51575
|
const tasks = await this.store.listProjectTasks(record.projectId).catch(() => []);
|
|
51390
|
-
if (tasks.length
|
|
51576
|
+
if (tasks.length === 0 || !tasks.some((t) => t.status === "active")) {
|
|
51391
51577
|
return null;
|
|
51392
51578
|
}
|
|
51393
51579
|
const workspaceFiles = await this.store.listProjectWorkspaceRecursive(record.projectId).catch(() => []);
|
|
@@ -54138,7 +54324,7 @@ ${baseSystem}` : baseSystem;
|
|
|
54138
54324
|
return { modelId };
|
|
54139
54325
|
}
|
|
54140
54326
|
}
|
|
54141
|
-
async resolveUserPromptPrelude(state, userText) {
|
|
54327
|
+
async resolveUserPromptPrelude(state, userText, messageOrigin) {
|
|
54142
54328
|
const profile = state.profile;
|
|
54143
54329
|
if (!profile) return null;
|
|
54144
54330
|
const cfg = await this.store.readConfig().catch(() => null);
|
|
@@ -54147,6 +54333,9 @@ ${baseSystem}` : baseSystem;
|
|
|
54147
54333
|
...modelCtxFromProfile(profile, state),
|
|
54148
54334
|
sessionId: state.record.id,
|
|
54149
54335
|
isMeester,
|
|
54336
|
+
projectId: state.record.projectId,
|
|
54337
|
+
messageOrigin,
|
|
54338
|
+
availableToolNames: liveTurnToolNames(state.session),
|
|
54150
54339
|
userText,
|
|
54151
54340
|
drained: [],
|
|
54152
54341
|
assistantContent: "",
|
|
@@ -55467,6 +55656,7 @@ Allow **${info.toolName}** this time?`,
|
|
|
55467
55656
|
GEZEL_SESSION_ID: record.id,
|
|
55468
55657
|
GEZEL_HOME: this.home,
|
|
55469
55658
|
GEZEL_EXECUTION_DENSITY: executionDensity,
|
|
55659
|
+
GEZEL_ROLE_BASED_NAME_ONLY_MODE: record.roleBasedNameOnlyMode ?? globalConfig.roleBasedNameOnlyMode ?? false ? "1" : "0",
|
|
55470
55660
|
...record.expectedDeliverable ? { GEZEL_EXPECTED_DELIVERABLE: JSON.stringify(record.expectedDeliverable) } : {},
|
|
55471
55661
|
...record.stepId ? { GEZEL_STEP_ID: record.stepId } : {},
|
|
55472
55662
|
// Scope task: lets the MCP task tools default to / recover toward
|
|
@@ -55906,6 +56096,9 @@ function runPostTurnDetectors(state, args) {
|
|
|
55906
56096
|
...modelCtxFromProfile(profile, state),
|
|
55907
56097
|
sessionId: args.sessionId,
|
|
55908
56098
|
isMeester: args.isMeester,
|
|
56099
|
+
projectId: state.record.projectId,
|
|
56100
|
+
messageOrigin: args.messageOrigin,
|
|
56101
|
+
availableToolNames: liveTurnToolNames(state.session),
|
|
55909
56102
|
userText: args.userText,
|
|
55910
56103
|
drained: args.drained,
|
|
55911
56104
|
assistantContent: args.assistantContent,
|
|
@@ -56438,13 +56631,18 @@ Drop conversational filler, pleasantries, and verbatim tool outputs (just note "
|
|
|
56438
56631
|
Earlier conversation:
|
|
56439
56632
|
|
|
56440
56633
|
`;
|
|
56441
|
-
var VOORMAN_IDLE_NUDGE =
|
|
56634
|
+
var VOORMAN_IDLE_NUDGE = "Before you finish, make one quick project check: is there concrete work already in flight that this turn should move? If yes, take the natural next action with the most relevant available tool \u2014 advance a ready step, message or assign the right gezel, or surface a real blocker. If no \u2014 because the project is complete, stable, or waiting on the user \u2014 say that once in one short sentence and end the turn. Do not invent work or call a tool merely to satisfy this check. Do not re-verify or promise future action.";
|
|
56442
56635
|
var BOOTSTRAP_WORKSPACE_FILES = /* @__PURE__ */ new Set([
|
|
56443
56636
|
"package.json",
|
|
56637
|
+
"package-lock.json",
|
|
56638
|
+
"pnpm-lock.yaml",
|
|
56639
|
+
"yarn.lock",
|
|
56640
|
+
"bun.lock",
|
|
56641
|
+
"bun.lockb",
|
|
56444
56642
|
"tsconfig.json",
|
|
56445
56643
|
".gitignore"
|
|
56446
56644
|
]);
|
|
56447
|
-
var VOORMAN_NOT_DONE_NUDGE = "
|
|
56645
|
+
var VOORMAN_NOT_DONE_NUDGE = "One project-state check before you finish: an active task remains, but the workspace still contains only setup files, so no deliverable has been built yet. If the user only asked for status or conversation, answer accurately and stop; a tool is not required. If this turn is supposed to move the active work, take one natural next action: message or assign the specialist who owns the deliverable, advance a genuinely ready step, or surface a real blocker with `ask_user_question`. Do not invent work or call a tool merely to appear busy, and do not describe an active empty project as done or stable.";
|
|
56448
56646
|
var READ_ONLY_MCP_TOOLS = /* @__PURE__ */ new Set([
|
|
56449
56647
|
"search_memory",
|
|
56450
56648
|
"list_memories",
|
|
@@ -75768,6 +75966,7 @@ ${p.content.trim()}`).join("\n\n---\n\n");
|
|
|
75768
75966
|
async createProject(input, opts) {
|
|
75769
75967
|
const release2 = await this.acquireProjectCreationLock();
|
|
75770
75968
|
try {
|
|
75969
|
+
if (input.workingDir) this.assertSafeWorkingDir(input.workingDir);
|
|
75771
75970
|
const id = opts?.id ?? await this.uniqueProjectId(slugify(input.name) || randomUUID10().slice(0, 8));
|
|
75772
75971
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
75773
75972
|
throw new Error(`invalid project id "${id}"`);
|
|
@@ -75791,14 +75990,22 @@ ${p.content.trim()}`).join("\n\n---\n\n");
|
|
|
75791
75990
|
projectName: input.name
|
|
75792
75991
|
});
|
|
75793
75992
|
}
|
|
75993
|
+
let github = input.github?.url ? { url: input.github.url } : void 0;
|
|
75994
|
+
if (input.workingDir) {
|
|
75995
|
+
github = await autoDetectGitHubLink(input.workingDir, github) ?? github;
|
|
75996
|
+
}
|
|
75794
75997
|
const project = {
|
|
75795
75998
|
id,
|
|
75796
75999
|
name: input.name,
|
|
75797
76000
|
description: input.description,
|
|
75798
76001
|
...input.workingDir ? { workingDir: input.workingDir } : {},
|
|
76002
|
+
// Opening an existing folder is an intake action, not a declaration
|
|
76003
|
+
// that its objectives are ready for active supervision. Keep the
|
|
76004
|
+
// Meester quiet until the user explicitly opts this project back in.
|
|
76005
|
+
...input.workingDir ? { nudgeConfig: { enabled: false } } : {},
|
|
75799
76006
|
...input.mode && input.mode !== "crew" ? { mode: input.mode } : {},
|
|
75800
76007
|
...input.indexingEnabled !== void 0 ? { indexingEnabled: input.indexingEnabled } : {},
|
|
75801
|
-
...
|
|
76008
|
+
...github ? { github } : {},
|
|
75802
76009
|
createdAt: nowIso5(),
|
|
75803
76010
|
updatedAt: nowIso5()
|
|
75804
76011
|
};
|
|
@@ -80250,6 +80457,7 @@ var TaskManager = class {
|
|
|
80250
80457
|
...cron ? { cron } : {},
|
|
80251
80458
|
...nightShift ? { nightShift } : {},
|
|
80252
80459
|
...fanout ? { fanout } : {},
|
|
80460
|
+
...input.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: input.roleBasedNameOnlyMode } : {},
|
|
80253
80461
|
createdAt: now,
|
|
80254
80462
|
updatedAt: now,
|
|
80255
80463
|
createdBy: input.createdBy ?? { kind: "user" }
|
|
@@ -82244,6 +82452,7 @@ Fix one of these, then set the task active again:
|
|
|
82244
82452
|
...parent.nightShift?.enabled ? { nightShift: { enabled: true } } : {},
|
|
82245
82453
|
activeStepId,
|
|
82246
82454
|
parentTaskRef: parent.ref,
|
|
82455
|
+
...parent.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: parent.roleBasedNameOnlyMode } : {},
|
|
82247
82456
|
createdAt: now,
|
|
82248
82457
|
updatedAt: now,
|
|
82249
82458
|
createdBy: parent.createdBy
|
|
@@ -96144,19 +96353,19 @@ function memoryRoutes(ctx) {
|
|
|
96144
96353
|
const app = new Hono37();
|
|
96145
96354
|
app.post("/search", async (c) => {
|
|
96146
96355
|
const body = await c.req.json();
|
|
96147
|
-
const
|
|
96356
|
+
const outcome = await ctx.memory.searchAllDetailed(
|
|
96148
96357
|
body.gezelId,
|
|
96149
96358
|
body.projectId,
|
|
96150
96359
|
body.query,
|
|
96151
96360
|
body.topK ?? 10
|
|
96152
96361
|
);
|
|
96153
|
-
return c.json(
|
|
96362
|
+
return c.json(outcome);
|
|
96154
96363
|
});
|
|
96155
96364
|
app.post("/save", async (c) => {
|
|
96156
96365
|
const body = await c.req.json();
|
|
96157
96366
|
const kind = isMemoryKind(body.kind) ? body.kind : "fact";
|
|
96158
96367
|
const outcome = await ctx.memory.save(body.scope, body.id, body.text, kind);
|
|
96159
|
-
return c.json({ ok: true,
|
|
96368
|
+
return c.json({ ok: true, ...outcome });
|
|
96160
96369
|
});
|
|
96161
96370
|
app.get("/recent", async (c) => {
|
|
96162
96371
|
const scope = c.req.query("scope") ?? "gezel";
|
|
@@ -101005,6 +101214,7 @@ import {
|
|
|
101005
101214
|
projectGezelId as projectGezelId2,
|
|
101006
101215
|
skillToCraftbookDoc
|
|
101007
101216
|
} from "@bendyline/gezel";
|
|
101217
|
+
init_ensure();
|
|
101008
101218
|
init_install();
|
|
101009
101219
|
|
|
101010
101220
|
// src/workspace/instruction-scanner.ts
|
|
@@ -101187,6 +101397,30 @@ async function translateShellBlock(chat, skillName, scriptName, code) {
|
|
|
101187
101397
|
// src/workspace/import-sync.ts
|
|
101188
101398
|
var log110 = createLogger114("import-sync");
|
|
101189
101399
|
var VOORMAN_TEMPLATE_ID = "voorman";
|
|
101400
|
+
var BUILDER_TEMPLATE_ID = "builder";
|
|
101401
|
+
async function ensureFolderProjectBuilder(deps, projectId) {
|
|
101402
|
+
const { store, catalog } = deps;
|
|
101403
|
+
if (!projectId || projectId === "default") return {};
|
|
101404
|
+
const project = await store.getProject(projectId).catch(() => null);
|
|
101405
|
+
if (!project || project.mode !== "solo" || !project.workingDir) return {};
|
|
101406
|
+
if (project.voormanGezelId) return {};
|
|
101407
|
+
const gezels = await store.listGezels().catch(() => []);
|
|
101408
|
+
const existing = gezels.find(
|
|
101409
|
+
(gezel) => gezel.templateId === BUILDER_TEMPLATE_ID || gezel.role?.trim().toLowerCase() === BUILDER_TEMPLATE_ID
|
|
101410
|
+
);
|
|
101411
|
+
const recruited = existing ? null : await recruitFromTemplate(store, catalog, BUILDER_TEMPLATE_ID).catch((err) => {
|
|
101412
|
+
log110.warn(`[import-sync] ${projectId}: Builder recruit failed: ${describe6(err)}`);
|
|
101413
|
+
return null;
|
|
101414
|
+
});
|
|
101415
|
+
const builder = existing ?? recruited;
|
|
101416
|
+
if (!builder) return {};
|
|
101417
|
+
await store.updateProject(projectId, {
|
|
101418
|
+
voormanGezelId: builder.id,
|
|
101419
|
+
voormanAutoAssignedAt: nowIso12()
|
|
101420
|
+
});
|
|
101421
|
+
log110.info(`[import-sync] ${projectId}: assigned ${builder.id} as Builder`);
|
|
101422
|
+
return recruited ? { createdGezel: recruited } : {};
|
|
101423
|
+
}
|
|
101190
101424
|
async function syncProjectImports(deps, projectId, instructions, skills) {
|
|
101191
101425
|
const { store } = deps;
|
|
101192
101426
|
const gate = await store.assertWorkspaceWritable(projectId).catch(() => null);
|
|
@@ -101315,16 +101549,20 @@ async function findExistingVoorman(store) {
|
|
|
101315
101549
|
return match?.id ?? null;
|
|
101316
101550
|
}
|
|
101317
101551
|
async function recruitVoorman(store, catalog) {
|
|
101318
|
-
|
|
101319
|
-
|
|
101552
|
+
return recruitFromTemplate(store, catalog, VOORMAN_TEMPLATE_ID);
|
|
101553
|
+
}
|
|
101554
|
+
async function recruitFromTemplate(store, catalog, templateId) {
|
|
101555
|
+
const template = await resolveGildeTemplateForRole(catalog, templateId).catch(() => null);
|
|
101556
|
+
if (!template || template.templateId !== templateId) return null;
|
|
101320
101557
|
const { name, gender } = pickRandomNameWithGender4();
|
|
101321
101558
|
const created = await store.createGezel({
|
|
101322
101559
|
name,
|
|
101323
|
-
role:
|
|
101560
|
+
role: template.role,
|
|
101324
101561
|
gender,
|
|
101325
|
-
about:
|
|
101326
|
-
templateId
|
|
101327
|
-
templateVersion:
|
|
101562
|
+
about: template.about,
|
|
101563
|
+
templateId,
|
|
101564
|
+
templateVersion: template.templateVersion,
|
|
101565
|
+
...template.frontmatter ? { frontmatter: template.frontmatter } : {}
|
|
101328
101566
|
});
|
|
101329
101567
|
return { id: created.id, name: created.name };
|
|
101330
101568
|
}
|
|
@@ -101799,6 +102037,7 @@ async function resolveActor(ctx, gezelIdHeader) {
|
|
|
101799
102037
|
}
|
|
101800
102038
|
function projectTaskRoutes(ctx) {
|
|
101801
102039
|
const app = new Hono55();
|
|
102040
|
+
const inflightCraftbookInvocations = /* @__PURE__ */ new Map();
|
|
101802
102041
|
app.get("/:projectId/tasks", async (c) => {
|
|
101803
102042
|
const projectId = c.req.param("projectId");
|
|
101804
102043
|
const filter = ListFilterSchema.parse({
|
|
@@ -101814,10 +102053,31 @@ function projectTaskRoutes(ctx) {
|
|
|
101814
102053
|
});
|
|
101815
102054
|
app.post("/:projectId/tasks", async (c) => {
|
|
101816
102055
|
const projectId = c.req.param("projectId");
|
|
101817
|
-
const { dispatchEntry, ...body } = CreateTaskRequestSchema.parse(
|
|
102056
|
+
const { dispatchEntry, craftbookInvocationKey, ...body } = CreateTaskRequestSchema.parse(
|
|
102057
|
+
await c.req.json()
|
|
102058
|
+
);
|
|
101818
102059
|
let task;
|
|
101819
102060
|
try {
|
|
101820
|
-
|
|
102061
|
+
if (craftbookInvocationKey) {
|
|
102062
|
+
const existing = (await ctx.tasks.list({ projectId })).find(
|
|
102063
|
+
(candidate) => candidate.origin?.kind === "craftbook-invocation" && candidate.origin.key === craftbookInvocationKey && (candidate.status === "draft" || candidate.status === "active" || candidate.status === "paused")
|
|
102064
|
+
);
|
|
102065
|
+
if (existing) return c.json(existing);
|
|
102066
|
+
const inflightKey = `${projectId}:${craftbookInvocationKey}`;
|
|
102067
|
+
const pending5 = inflightCraftbookInvocations.get(inflightKey);
|
|
102068
|
+
if (pending5) return c.json(await pending5);
|
|
102069
|
+
const create = ctx.tasks.create(projectId, body, {
|
|
102070
|
+
origin: { kind: "craftbook-invocation", key: craftbookInvocationKey }
|
|
102071
|
+
});
|
|
102072
|
+
inflightCraftbookInvocations.set(inflightKey, create);
|
|
102073
|
+
try {
|
|
102074
|
+
task = await create;
|
|
102075
|
+
} finally {
|
|
102076
|
+
inflightCraftbookInvocations.delete(inflightKey);
|
|
102077
|
+
}
|
|
102078
|
+
} else {
|
|
102079
|
+
task = await ctx.tasks.create(projectId, body);
|
|
102080
|
+
}
|
|
101821
102081
|
} catch (err) {
|
|
101822
102082
|
if (err instanceof CraftbookSetupRequiredError) {
|
|
101823
102083
|
return c.json(
|
|
@@ -104263,12 +104523,13 @@ function projectRoutes(ctx) {
|
|
|
104263
104523
|
app.post("/", async (c) => {
|
|
104264
104524
|
const body = CreateProjectRequestSchema.parse(await c.req.json());
|
|
104265
104525
|
const created = await ctx.store.createProject(body);
|
|
104266
|
-
const
|
|
104526
|
+
const ensureLead = body.workingDir && body.mode === "solo" ? ensureFolderProjectBuilder : ensureProjectVoorman;
|
|
104527
|
+
const ensured2 = await ensureLead(
|
|
104267
104528
|
{ store: ctx.store, chat: ctx.chat, home: ctx.home, catalog: ctx.catalog },
|
|
104268
104529
|
created.id
|
|
104269
104530
|
).catch((err) => {
|
|
104270
104531
|
const message = err instanceof Error ? err.message : String(err);
|
|
104271
|
-
log114.warn(`[projects] ensure-
|
|
104532
|
+
log114.warn(`[projects] ensure-lead failed for ${created.id}: ${message}`);
|
|
104272
104533
|
return {};
|
|
104273
104534
|
});
|
|
104274
104535
|
if (ensured2.createdGezel) {
|
|
@@ -104791,6 +105052,31 @@ function projectRoutes(ctx) {
|
|
|
104791
105052
|
return c.json({ error: "not found" }, 404);
|
|
104792
105053
|
}
|
|
104793
105054
|
});
|
|
105055
|
+
app.post("/:id/reveal-reference", async (c) => {
|
|
105056
|
+
const id = c.req.param("id");
|
|
105057
|
+
const request = ReferenceFileLocationRequestSchema.parse({
|
|
105058
|
+
kind: c.req.query("kind"),
|
|
105059
|
+
path: c.req.query("path")
|
|
105060
|
+
});
|
|
105061
|
+
const base = request.kind === "artifact" ? ctx.store.projectArtifactsDir(id) : request.kind === "workspace" ? await ctx.store.projectWorkspaceDir(id) : ctx.store.documentsDir();
|
|
105062
|
+
const joined = safeJoin(base, request.path);
|
|
105063
|
+
if (!joined || !await realpathContained(base, joined)) {
|
|
105064
|
+
return c.json({ error: "path traversal" }, 400);
|
|
105065
|
+
}
|
|
105066
|
+
let path2;
|
|
105067
|
+
try {
|
|
105068
|
+
const file = await stat36(joined);
|
|
105069
|
+
if (!file.isFile()) return c.json({ error: "not found" }, 404);
|
|
105070
|
+
path2 = await realpath8(joined);
|
|
105071
|
+
} catch {
|
|
105072
|
+
return c.json({ error: "not found" }, 404);
|
|
105073
|
+
}
|
|
105074
|
+
const { execFile: execFile8 } = await import("child_process");
|
|
105075
|
+
const launcher = process.platform === "darwin" ? { cmd: "open", args: ["-R", path2] } : process.platform === "win32" ? { cmd: "explorer", args: ["/select,", path2] } : { cmd: "xdg-open", args: [dirname44(path2)] };
|
|
105076
|
+
execFile8(launcher.cmd, launcher.args, { windowsHide: true }, () => {
|
|
105077
|
+
});
|
|
105078
|
+
return c.json(ReferenceFileLocationResponseSchema.parse({ path: path2 }));
|
|
105079
|
+
});
|
|
104794
105080
|
app.get("/:id/artifacts", async (c) => {
|
|
104795
105081
|
const id = c.req.param("id");
|
|
104796
105082
|
const subpath = c.req.query("path") ?? "";
|
|
@@ -116245,7 +116531,10 @@ function opaqueServerErrors(log189, onUnexpectedHttpError) {
|
|
|
116245
116531
|
const raw = await prior.clone().text().catch(() => "");
|
|
116246
116532
|
try {
|
|
116247
116533
|
const parsed = JSON.parse(raw);
|
|
116248
|
-
if (parsed.error === "internal_error" && typeof parsed.requestId === "string")
|
|
116534
|
+
if (parsed.error === "internal_error" && typeof parsed.requestId === "string") {
|
|
116535
|
+
c.header("x-request-id", parsed.requestId);
|
|
116536
|
+
return;
|
|
116537
|
+
}
|
|
116249
116538
|
if ((parsed.error === "machine_engine_unavailable" || parsed.error === "capacity_denied") && Object.keys(parsed).length === 1) {
|
|
116250
116539
|
return;
|
|
116251
116540
|
}
|
|
@@ -125156,8 +125445,8 @@ var MemoryManager = class {
|
|
|
125156
125445
|
* that text dedups, so we accept the race rather than lock.
|
|
125157
125446
|
*
|
|
125158
125447
|
* Degraded mode (embeddings disabled): markdown is still appended (it is
|
|
125159
|
-
* the source of truth and the
|
|
125160
|
-
*
|
|
125448
|
+
* the source of truth) and the outcome reports deferred indexing. The health
|
|
125449
|
+
* monitor self-heals the derived index once embeddings recover.
|
|
125161
125450
|
*/
|
|
125162
125451
|
async save(scope, id, text, kind = DEFAULT_MEMORY_KIND) {
|
|
125163
125452
|
const trimmed = text.trim();
|
|
@@ -125172,9 +125461,19 @@ var MemoryManager = class {
|
|
|
125172
125461
|
vector = await embed(trimmed);
|
|
125173
125462
|
} catch (err) {
|
|
125174
125463
|
await this.store.appendMemory(scope, id, trimmed, kind);
|
|
125175
|
-
|
|
125464
|
+
log155.warn(
|
|
125465
|
+
`[memory] saved ${scope}/${id} to Markdown; semantic indexing deferred: ${describeError3(err)}`
|
|
125466
|
+
);
|
|
125467
|
+
return deferredIndexOutcome();
|
|
125468
|
+
}
|
|
125469
|
+
let top;
|
|
125470
|
+
try {
|
|
125471
|
+
top = (await searchByVector(indexDir, vector, 1))[0];
|
|
125472
|
+
} catch (error) {
|
|
125473
|
+
log155.warn(
|
|
125474
|
+
`[memory] vector dedup unavailable for ${scope}/${id}; continuing save: ${describeError3(error)}`
|
|
125475
|
+
);
|
|
125176
125476
|
}
|
|
125177
|
-
const top = (await searchByVector(indexDir, vector, 1))[0];
|
|
125178
125477
|
if (top && top.score >= this.dedupThreshold) {
|
|
125179
125478
|
log155.info(
|
|
125180
125479
|
`[memory] dup-skip (${top.score.toFixed(2)} vs "${top.text.slice(0, 40)}") ${scope}/${id}: ${trimmed.slice(0, 60)}`
|
|
@@ -125182,20 +125481,27 @@ var MemoryManager = class {
|
|
|
125182
125481
|
return { status: "duplicate", match: { text: top.text, score: top.score, via: "vector" } };
|
|
125183
125482
|
}
|
|
125184
125483
|
await this.store.appendMemory(scope, id, trimmed, kind);
|
|
125185
|
-
|
|
125186
|
-
|
|
125187
|
-
|
|
125188
|
-
|
|
125189
|
-
|
|
125190
|
-
|
|
125191
|
-
|
|
125192
|
-
|
|
125193
|
-
|
|
125194
|
-
|
|
125195
|
-
|
|
125196
|
-
|
|
125484
|
+
try {
|
|
125485
|
+
await addToIndex(
|
|
125486
|
+
indexDir,
|
|
125487
|
+
{
|
|
125488
|
+
text: trimmed,
|
|
125489
|
+
scope,
|
|
125490
|
+
id,
|
|
125491
|
+
day: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
125492
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
125493
|
+
kind
|
|
125494
|
+
},
|
|
125495
|
+
vector
|
|
125496
|
+
);
|
|
125497
|
+
} catch (error) {
|
|
125498
|
+
log155.warn(
|
|
125499
|
+
`[memory] saved ${scope}/${id} to Markdown; semantic index write deferred: ${describeError3(error)}`
|
|
125500
|
+
);
|
|
125501
|
+
return deferredIndexOutcome();
|
|
125502
|
+
}
|
|
125197
125503
|
log155.info(`[memory] saved ${scope}/${id} [${kind}]: ${trimmed.slice(0, 60)}`);
|
|
125198
|
-
return { status: "saved" };
|
|
125504
|
+
return { status: "saved", indexed: true };
|
|
125199
125505
|
}
|
|
125200
125506
|
/**
|
|
125201
125507
|
* Exact-text match against today's and yesterday's daily files. Two days
|
|
@@ -125217,7 +125523,15 @@ var MemoryManager = class {
|
|
|
125217
125523
|
}
|
|
125218
125524
|
async search(scope, id, query, topK = 10) {
|
|
125219
125525
|
const indexDir = this.store.memoryIndexDir(scope, id);
|
|
125220
|
-
return
|
|
125526
|
+
if (!this.hasIndex(scope, id)) return this.searchLexical(scope, id, query, topK);
|
|
125527
|
+
try {
|
|
125528
|
+
return await searchIndex(indexDir, query, topK);
|
|
125529
|
+
} catch (error) {
|
|
125530
|
+
log155.warn(
|
|
125531
|
+
`[memory] semantic search failed for ${scope}/${id}; using lexical fallback: ${describeError3(error)}`
|
|
125532
|
+
);
|
|
125533
|
+
return this.searchLexical(scope, id, query, topK);
|
|
125534
|
+
}
|
|
125221
125535
|
}
|
|
125222
125536
|
/**
|
|
125223
125537
|
* Like {@link search} but with a precomputed query embedding — lets the
|
|
@@ -125246,11 +125560,64 @@ var MemoryManager = class {
|
|
|
125246
125560
|
return existsSync28(join103(this.store.memoryIndexDir(scope, id), "mem.db"));
|
|
125247
125561
|
}
|
|
125248
125562
|
async searchAll(gezelId, projectId, query, topK = 10) {
|
|
125249
|
-
|
|
125250
|
-
|
|
125251
|
-
|
|
125563
|
+
return (await this.searchAllDetailed(gezelId, projectId, query, topK)).results;
|
|
125564
|
+
}
|
|
125565
|
+
/**
|
|
125566
|
+
* Search both scopes with one query embedding. Missing indexes fall back to
|
|
125567
|
+
* the daily Markdown source; an unavailable/corrupt semantic cache does the
|
|
125568
|
+
* same and reports a degraded mode instead of turning an optional feature
|
|
125569
|
+
* into an HTTP 500.
|
|
125570
|
+
*/
|
|
125571
|
+
async searchAllDetailed(gezelId, projectId, query, topK = 10) {
|
|
125572
|
+
const gezelIndexed = this.hasIndex("gezel", gezelId);
|
|
125573
|
+
const projectIndexed = this.hasIndex("project", projectId);
|
|
125574
|
+
if (!gezelIndexed && !projectIndexed) {
|
|
125575
|
+
return {
|
|
125576
|
+
results: await this.searchAllLexical(gezelId, projectId, query, topK),
|
|
125577
|
+
mode: "lexical"
|
|
125578
|
+
};
|
|
125579
|
+
}
|
|
125580
|
+
try {
|
|
125581
|
+
const vector = await embedQuery(query);
|
|
125582
|
+
const [gezelResults, projectResults] = await Promise.all([
|
|
125583
|
+
gezelIndexed ? this.searchVector("gezel", gezelId, vector, topK) : this.searchLexical("gezel", gezelId, query, topK),
|
|
125584
|
+
projectIndexed ? this.searchVector("project", projectId, vector, topK) : this.searchLexical("project", projectId, query, topK)
|
|
125585
|
+
]);
|
|
125586
|
+
return {
|
|
125587
|
+
results: rankSearchResults([...gezelResults, ...projectResults], topK),
|
|
125588
|
+
mode: gezelIndexed && projectIndexed ? "semantic" : "hybrid"
|
|
125589
|
+
};
|
|
125590
|
+
} catch (error) {
|
|
125591
|
+
log155.warn(
|
|
125592
|
+
`[memory] semantic search unavailable; using daily-memory lexical fallback: ${describeError3(error)}`
|
|
125593
|
+
);
|
|
125594
|
+
return {
|
|
125595
|
+
results: await this.searchAllLexical(gezelId, projectId, query, topK),
|
|
125596
|
+
mode: "lexical",
|
|
125597
|
+
degraded: {
|
|
125598
|
+
code: "semantic_search_unavailable",
|
|
125599
|
+
message: "Semantic memory search is temporarily unavailable; searched saved memory text directly instead."
|
|
125600
|
+
}
|
|
125601
|
+
};
|
|
125602
|
+
}
|
|
125603
|
+
}
|
|
125604
|
+
async searchAllLexical(gezelId, projectId, query, topK) {
|
|
125605
|
+
const [gezelResults, projectResults] = await Promise.all([
|
|
125606
|
+
this.searchLexical("gezel", gezelId, query, topK),
|
|
125607
|
+
this.searchLexical("project", projectId, query, topK)
|
|
125252
125608
|
]);
|
|
125253
|
-
return [...
|
|
125609
|
+
return rankSearchResults([...gezelResults, ...projectResults], topK);
|
|
125610
|
+
}
|
|
125611
|
+
async searchLexical(scope, id, query, topK) {
|
|
125612
|
+
const entries = await this.allEntries(scope, id);
|
|
125613
|
+
return entries.map((entry) => ({ entry, score: lexicalScore(query, entry.text) })).filter((candidate) => candidate.score > 0).sort((a, b) => b.score - a.score || b.entry.at.localeCompare(a.entry.at)).slice(0, topK).map(({ entry, score }) => ({
|
|
125614
|
+
text: entry.text,
|
|
125615
|
+
score,
|
|
125616
|
+
day: entry.day,
|
|
125617
|
+
scope: entry.scope,
|
|
125618
|
+
id: entry.id,
|
|
125619
|
+
kind: entry.kind ?? DEFAULT_MEMORY_KIND
|
|
125620
|
+
}));
|
|
125254
125621
|
}
|
|
125255
125622
|
async listDays(scope, id) {
|
|
125256
125623
|
return this.store.listMemoryDays(scope, id);
|
|
@@ -125315,6 +125682,36 @@ var MemoryManager = class {
|
|
|
125315
125682
|
return entries.length;
|
|
125316
125683
|
}
|
|
125317
125684
|
};
|
|
125685
|
+
function rankSearchResults(results, topK) {
|
|
125686
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
125687
|
+
}
|
|
125688
|
+
function deferredIndexOutcome() {
|
|
125689
|
+
return {
|
|
125690
|
+
status: "saved",
|
|
125691
|
+
indexed: false,
|
|
125692
|
+
degraded: {
|
|
125693
|
+
code: "semantic_index_unavailable",
|
|
125694
|
+
message: "Memory was saved, but semantic indexing is temporarily unavailable."
|
|
125695
|
+
}
|
|
125696
|
+
};
|
|
125697
|
+
}
|
|
125698
|
+
function lexicalScore(query, text) {
|
|
125699
|
+
const normalizedQuery = query.trim().toLocaleLowerCase();
|
|
125700
|
+
const normalizedText = text.toLocaleLowerCase();
|
|
125701
|
+
if (!normalizedQuery || !normalizedText) return 0;
|
|
125702
|
+
if (normalizedText.includes(normalizedQuery)) return 1;
|
|
125703
|
+
const queryTokens = new Set(normalizedQuery.match(/[\p{L}\p{N}_-]+/gu) ?? []);
|
|
125704
|
+
if (queryTokens.size === 0) return 0;
|
|
125705
|
+
const textTokens = new Set(normalizedText.match(/[\p{L}\p{N}_-]+/gu) ?? []);
|
|
125706
|
+
let matches = 0;
|
|
125707
|
+
for (const token of queryTokens) {
|
|
125708
|
+
if (textTokens.has(token)) matches++;
|
|
125709
|
+
}
|
|
125710
|
+
return matches / queryTokens.size;
|
|
125711
|
+
}
|
|
125712
|
+
function describeError3(error) {
|
|
125713
|
+
return error instanceof Error ? error.message : String(error);
|
|
125714
|
+
}
|
|
125318
125715
|
|
|
125319
125716
|
// src/models/install-jobs.ts
|
|
125320
125717
|
import { createLogger as createLogger166 } from "@bendyline/gezel";
|
|
@@ -128723,7 +129120,7 @@ var VideoModelManager = class {
|
|
|
128723
129120
|
await rm43(finalPath, { force: true });
|
|
128724
129121
|
await rename17(partialPath, finalPath);
|
|
128725
129122
|
} catch (err) {
|
|
128726
|
-
yield { type: "error", error: `rename failed for ${file.name}: ${
|
|
129123
|
+
yield { type: "error", error: `rename failed for ${file.name}: ${describeError4(err)}` };
|
|
128727
129124
|
return;
|
|
128728
129125
|
}
|
|
128729
129126
|
}
|
|
@@ -128882,7 +129279,7 @@ var VideoModelSelector = class {
|
|
|
128882
129279
|
return (id ? await this.models.resolveModel(id) : null) ?? await this.models.resolveDefaultModel();
|
|
128883
129280
|
}
|
|
128884
129281
|
};
|
|
128885
|
-
function
|
|
129282
|
+
function describeError4(err) {
|
|
128886
129283
|
return err instanceof Error ? err.message : String(err);
|
|
128887
129284
|
}
|
|
128888
129285
|
function isSafeId3(id) {
|
|
@@ -133213,6 +133610,7 @@ var TaskRunner = class {
|
|
|
133213
133610
|
...handoff.fromGezelName ? { fromGezelName: handoff.fromGezelName } : {},
|
|
133214
133611
|
...handoff.fromGezelId ? { fromGezelId: handoff.fromGezelId } : {},
|
|
133215
133612
|
...handoff.kind ? { kind: handoff.kind } : {},
|
|
133613
|
+
...task.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: task.roleBasedNameOnlyMode } : {},
|
|
133216
133614
|
lane,
|
|
133217
133615
|
...isNight ? { ambient: true } : {},
|
|
133218
133616
|
...isNight ? { nightShift: true } : {},
|
|
@@ -133726,6 +134124,10 @@ Step "${step.name}" (\`${step.id}\`) was re-driven ${maxRedrives}\xD7 without pr
|
|
|
133726
134124
|
} catch {
|
|
133727
134125
|
}
|
|
133728
134126
|
const activeTasks = projectTasks.filter((t) => t.status === "active");
|
|
134127
|
+
if (projectTasks.length === 0) {
|
|
134128
|
+
trace("skip \u2014 project has no tasks to advance");
|
|
134129
|
+
return;
|
|
134130
|
+
}
|
|
133729
134131
|
if (projectTasks.length > 0 && activeTasks.length === 0) {
|
|
133730
134132
|
if (projectTasks.some((t) => t.status === "draft")) {
|
|
133731
134133
|
trace("skip \u2014 only draft task(s) await activation; not nudging or stabilizing");
|
|
@@ -137467,7 +137869,7 @@ Address these, then the gate re-checks automatically.`,
|
|
|
137467
137869
|
try {
|
|
137468
137870
|
const existing = await tasks.listChildren(task.ref).catch(() => []);
|
|
137469
137871
|
if (existing.length === 0) {
|
|
137470
|
-
const raw = await store.readProjectWorkspaceFile(projectId, spawn14.overFile).catch(() => null);
|
|
137872
|
+
const raw = await (spawn14.overArtifact ? store.readProjectArtifact(projectId, spawn14.overFile) : store.readProjectWorkspaceFile(projectId, spawn14.overFile)).catch(() => null);
|
|
137471
137873
|
const items = raw ? extractSpawnItems(raw, spawn14.itemsPath) : [];
|
|
137472
137874
|
if (items.length === 0) {
|
|
137473
137875
|
log188.warn(
|
|
@@ -137496,7 +137898,7 @@ Address these, then the gate re-checks automatically.`,
|
|
|
137496
137898
|
|
|
137497
137899
|
${kids.map((k) => `- ${k.ref}: ${k.title}`).join("\n")}
|
|
137498
137900
|
`;
|
|
137499
|
-
await store.writeProjectWorkspaceFile(projectId, advanceFile, manifest).catch((err) => log188.warn(`[fanout] ${task.ref}: could not write ${advanceFile}:`, err));
|
|
137901
|
+
await (newStep.advanceWhen?.artifact ? store.writeProjectArtifact(projectId, advanceFile, manifest) : store.writeProjectWorkspaceFile(projectId, advanceFile, manifest)).catch((err) => log188.warn(`[fanout] ${task.ref}: could not write ${advanceFile}:`, err));
|
|
137500
137902
|
}
|
|
137501
137903
|
const nextStep = newStep.advanceWhen?.goto ?? newStep.next;
|
|
137502
137904
|
if (nextStep) {
|