@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/bin/gezeld.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;
|
|
@@ -14094,15 +14153,13 @@ import { createLogger as createLogger4 } from "@bendyline/gezel";
|
|
|
14094
14153
|
// src/model-profile/behaviors/fabrication-detect-claim-without-tool.ts
|
|
14095
14154
|
var PROJECT_CREATION_VERBS = [
|
|
14096
14155
|
"created",
|
|
14097
|
-
"initiated",
|
|
14098
14156
|
"initialized",
|
|
14099
14157
|
"set\\s+up",
|
|
14100
14158
|
"spun\\s+up",
|
|
14101
|
-
"started",
|
|
14102
14159
|
"made",
|
|
14103
|
-
"bootstrapped"
|
|
14104
|
-
"kicked\\s+off"
|
|
14160
|
+
"bootstrapped"
|
|
14105
14161
|
].join("|");
|
|
14162
|
+
var PROJECT_WORK_START_VERBS = ["initiated", "started", "kicked\\s+off"].join("|");
|
|
14106
14163
|
var TASK_CREATION_VERBS = ["created", "added", "queued", "set\\s+up"].join("|");
|
|
14107
14164
|
var GEZEL_CREATION_VERBS = [
|
|
14108
14165
|
"created",
|
|
@@ -14163,6 +14220,18 @@ var CLAIM_RULES = [
|
|
|
14163
14220
|
claim: "recruited a voorman",
|
|
14164
14221
|
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."
|
|
14165
14222
|
},
|
|
14223
|
+
{
|
|
14224
|
+
// Ambiguous kickoff verbs only become a container-creation claim when
|
|
14225
|
+
// the prose explicitly says this is a new/separate project. Otherwise
|
|
14226
|
+
// the next rule treats them as starting work in the current project.
|
|
14227
|
+
pattern: new RegExp(
|
|
14228
|
+
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`,
|
|
14229
|
+
"i"
|
|
14230
|
+
),
|
|
14231
|
+
requiredTools: ["start_project"],
|
|
14232
|
+
claim: "created a project",
|
|
14233
|
+
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."
|
|
14234
|
+
},
|
|
14166
14235
|
{
|
|
14167
14236
|
pattern: new RegExp(
|
|
14168
14237
|
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
|
|
@@ -14184,6 +14253,15 @@ var CLAIM_RULES = [
|
|
|
14184
14253
|
claim: "created a project",
|
|
14185
14254
|
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."
|
|
14186
14255
|
},
|
|
14256
|
+
{
|
|
14257
|
+
pattern: new RegExp(
|
|
14258
|
+
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`,
|
|
14259
|
+
"i"
|
|
14260
|
+
),
|
|
14261
|
+
requiredTools: ["invoke_craftbook", "create_task", "start_project"],
|
|
14262
|
+
claim: "started work in the current project",
|
|
14263
|
+
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."
|
|
14264
|
+
},
|
|
14187
14265
|
{
|
|
14188
14266
|
pattern: new RegExp(
|
|
14189
14267
|
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`,
|
|
@@ -15106,13 +15184,26 @@ var BUILD_REQUEST_RE = new RegExp(
|
|
|
15106
15184
|
function looksLikeNewBuildRequest(text) {
|
|
15107
15185
|
return BUILD_REQUEST_RE.test(text);
|
|
15108
15186
|
}
|
|
15187
|
+
function explicitlyRequestsSeparateProject(text) {
|
|
15188
|
+
return /\b(?:new|fresh|separate|another|dedicated)\s+(?:(?:standalone|independent)\s+)?(?:project|workspace)\b/i.test(
|
|
15189
|
+
text
|
|
15190
|
+
) || /\b(?:as|in|into|under|for)\s+(?:a|an)\s+(?:new|fresh|separate|another|dedicated)\s+(?:project|workspace)\b/i.test(
|
|
15191
|
+
text
|
|
15192
|
+
);
|
|
15193
|
+
}
|
|
15109
15194
|
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.)';
|
|
15110
15195
|
var PromptMeesterBuildPrelude = {
|
|
15111
15196
|
id: "prompt.meester-build-prelude",
|
|
15112
15197
|
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`.',
|
|
15113
15198
|
userPromptPrelude(ctx) {
|
|
15114
15199
|
if (!ctx.isMeester) return null;
|
|
15200
|
+
if (ctx.messageOrigin !== "direct-user") return null;
|
|
15201
|
+
if (/^\s*\[Answer to:/i.test(ctx.userText)) return null;
|
|
15115
15202
|
if (!looksLikeNewBuildRequest(ctx.userText)) return null;
|
|
15203
|
+
if (ctx.projectId !== "default" && !explicitlyRequestsSeparateProject(ctx.userText)) {
|
|
15204
|
+
return null;
|
|
15205
|
+
}
|
|
15206
|
+
if (!ctx.availableToolNames.includes("start_project")) return null;
|
|
15116
15207
|
return MEESTER_BUILD_PRELUDE;
|
|
15117
15208
|
}
|
|
15118
15209
|
};
|
|
@@ -18161,6 +18252,12 @@ var AnthropicCliSession = class extends StreamingSessionBase {
|
|
|
18161
18252
|
providerState() {
|
|
18162
18253
|
return this.claudeSessionIdCache ? { claudeCliSessionId: this.claudeSessionIdCache } : {};
|
|
18163
18254
|
}
|
|
18255
|
+
getRegisteredToolNames() {
|
|
18256
|
+
const context = this.deps.context;
|
|
18257
|
+
return [
|
|
18258
|
+
.../* @__PURE__ */ new Set([...context.allowedBuiltinTools ?? [], ...context.allowedMcpTools ?? []])
|
|
18259
|
+
];
|
|
18260
|
+
}
|
|
18164
18261
|
async disconnect() {
|
|
18165
18262
|
this.aborted = true;
|
|
18166
18263
|
try {
|
|
@@ -19709,6 +19806,10 @@ var AnthropicSession = class extends StreamingSessionBase {
|
|
|
19709
19806
|
* resolves and persisted on `ChatMessage.reasoning`.
|
|
19710
19807
|
*/
|
|
19711
19808
|
lastTurnReasoning = "";
|
|
19809
|
+
getRegisteredToolNames() {
|
|
19810
|
+
const bridgeNames = this.deps.bridges.isEmpty() ? [] : this.deps.bridges.getAnthropicTools().map((tool) => tool.name);
|
|
19811
|
+
return [.../* @__PURE__ */ new Set([...bridgeNames, ...this.externalToolNames])];
|
|
19812
|
+
}
|
|
19712
19813
|
capturedToolCalls() {
|
|
19713
19814
|
return [...this.capturedCalls];
|
|
19714
19815
|
}
|
|
@@ -33330,7 +33431,7 @@ var PROJECT_MACRO_INTERCEPT_CAP = 2;
|
|
|
33330
33431
|
var PROJECT_MACRO_FAILURE_CAP = 2;
|
|
33331
33432
|
function deriveProjectMacroClosing(firstResult) {
|
|
33332
33433
|
const projectMatch = firstResult.match(/Started (?:project|job) "([^"]+)"/);
|
|
33333
|
-
const leadMatch = firstResult.match(/Recruited (\S+) as (voorman|
|
|
33434
|
+
const leadMatch = firstResult.match(/Recruited (\S+) as (voorman|builder|lead)/i);
|
|
33334
33435
|
const projectName = projectMatch?.[1];
|
|
33335
33436
|
const leadName = leadMatch?.[1];
|
|
33336
33437
|
const leadRole = leadMatch?.[2];
|
|
@@ -37282,6 +37383,10 @@ var OpenAISession = class extends StreamingSessionBase {
|
|
|
37282
37383
|
capturedToolCalls() {
|
|
37283
37384
|
return [...this.capturedCalls];
|
|
37284
37385
|
}
|
|
37386
|
+
getRegisteredToolNames() {
|
|
37387
|
+
const bridgeNames = this.deps.bridges.isEmpty() ? [] : this.deps.bridges.getOpenAITools().map((tool) => tool.name);
|
|
37388
|
+
return [.../* @__PURE__ */ new Set([...bridgeNames, ...this.externalToolNames])];
|
|
37389
|
+
}
|
|
37285
37390
|
async sendAndWait(prompt, opts) {
|
|
37286
37391
|
return runInQueue(this.deps.queue, opts?.queue, () => this.sendAndWaitInner(prompt, opts));
|
|
37287
37392
|
}
|
|
@@ -40199,14 +40304,15 @@ async function evalCheck(c, ws, deps) {
|
|
|
40199
40304
|
}
|
|
40200
40305
|
async function evalCheckInner(c, ws, deps) {
|
|
40201
40306
|
const usesArtifact = c.artifact === true;
|
|
40202
|
-
const
|
|
40307
|
+
const artifactReader = {
|
|
40203
40308
|
read: ws.readArtifact ?? (async () => null),
|
|
40204
40309
|
list: ws.listArtifacts ?? (async () => []),
|
|
40205
40310
|
// Carry the byte reader across the artifact swap; without it a
|
|
40206
40311
|
// `verifyImageBytes` check on an artifact deliverable would report
|
|
40207
40312
|
// "no binary reads" even though the surface supports them.
|
|
40208
40313
|
...ws.readArtifactBytes ? { readBytes: ws.readArtifactBytes.bind(ws) } : {}
|
|
40209
|
-
}
|
|
40314
|
+
};
|
|
40315
|
+
const reader = usesArtifact ? artifactReader : ws;
|
|
40210
40316
|
switch (c.kind) {
|
|
40211
40317
|
case "minBytes": {
|
|
40212
40318
|
const r = await fileMinBytes(reader, c.file, c.bytes);
|
|
@@ -40634,7 +40740,12 @@ ${hint}` : ""}`,
|
|
|
40634
40740
|
};
|
|
40635
40741
|
}
|
|
40636
40742
|
case "markdownHeadingsMatch": {
|
|
40637
|
-
const result = await markdownHeadingsMatch(
|
|
40743
|
+
const result = await markdownHeadingsMatch(
|
|
40744
|
+
reader,
|
|
40745
|
+
c.file,
|
|
40746
|
+
c.outlineFile,
|
|
40747
|
+
c.outlineArtifact ? artifactReader : ws
|
|
40748
|
+
);
|
|
40638
40749
|
return {
|
|
40639
40750
|
ok: result.ok,
|
|
40640
40751
|
detail: result.detail,
|
|
@@ -42549,6 +42660,11 @@ function filterPromptToolDirectives(args) {
|
|
|
42549
42660
|
if (rejectedLines.size === 0) return args.prompt;
|
|
42550
42661
|
return args.prompt.split("\n").filter((_, index) => !rejectedLines.has(index + 1)).join("\n").replace(/\n{4,}/g, "\n\n\n");
|
|
42551
42662
|
}
|
|
42663
|
+
function capabilitySafeCorrectivePrompt(args) {
|
|
42664
|
+
const filtered = filterPromptToolDirectives(args).trim();
|
|
42665
|
+
if (filtered) return filtered;
|
|
42666
|
+
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.";
|
|
42667
|
+
}
|
|
42552
42668
|
|
|
42553
42669
|
// src/chat/provider-capabilities.ts
|
|
42554
42670
|
function providerUsesManagedMcpBridge(name) {
|
|
@@ -46387,6 +46503,21 @@ function sameFromBucket(a, b) {
|
|
|
46387
46503
|
if (!a || !b) return false;
|
|
46388
46504
|
return a.gezelId === b.gezelId;
|
|
46389
46505
|
}
|
|
46506
|
+
function resolveTurnMessageOrigin(opts) {
|
|
46507
|
+
if (opts?.messageOrigin) return opts.messageOrigin;
|
|
46508
|
+
if (opts?.from) return "cross-gezel";
|
|
46509
|
+
if (opts?.ambient || opts?.nudge || opts?.lane === "background") return "background-nudge";
|
|
46510
|
+
return "direct-user";
|
|
46511
|
+
}
|
|
46512
|
+
function liveTurnToolNames(session) {
|
|
46513
|
+
const names = /* @__PURE__ */ new Set();
|
|
46514
|
+
for (const name of session?.getRegisteredToolNames?.() ?? []) {
|
|
46515
|
+
names.add(name);
|
|
46516
|
+
const qualified = name.match(/^mcp__.+?__(.+)$/)?.[1];
|
|
46517
|
+
if (qualified && qualified !== "*") names.add(qualified);
|
|
46518
|
+
}
|
|
46519
|
+
return [...names];
|
|
46520
|
+
}
|
|
46390
46521
|
async function resolveCatalogParameterSize(catalog, catalogId) {
|
|
46391
46522
|
if (!catalogId) return void 0;
|
|
46392
46523
|
try {
|
|
@@ -47788,6 +47919,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
47788
47919
|
coalescable: false,
|
|
47789
47920
|
lane: void 0,
|
|
47790
47921
|
ambient: false,
|
|
47922
|
+
messageOrigin: "direct-user",
|
|
47791
47923
|
continuationMaxTokens: void 0,
|
|
47792
47924
|
hidden: false,
|
|
47793
47925
|
nudge: false,
|
|
@@ -48093,11 +48225,14 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48093
48225
|
const full = await this.store.getSession(args.gezelId, active.id);
|
|
48094
48226
|
if (full) return full;
|
|
48095
48227
|
}
|
|
48228
|
+
const parsedTaskRef = parseTaskRef2(args.taskRef);
|
|
48229
|
+
const task = parsedTaskRef ? await this.store.readTask(parsedTaskRef.projectId, parsedTaskRef.num).catch(() => null) : null;
|
|
48096
48230
|
return this.createSession({
|
|
48097
48231
|
gezelId: args.gezelId,
|
|
48098
48232
|
projectId: args.projectId,
|
|
48099
48233
|
taskRef: args.taskRef,
|
|
48100
|
-
...args.stepId ? { stepId: args.stepId } : {}
|
|
48234
|
+
...args.stepId ? { stepId: args.stepId } : {},
|
|
48235
|
+
...task?.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: task.roleBasedNameOnlyMode } : {}
|
|
48101
48236
|
});
|
|
48102
48237
|
}
|
|
48103
48238
|
/** Late-bind the fitness manager (see the field's docblock). */
|
|
@@ -48224,6 +48359,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48224
48359
|
*/
|
|
48225
48360
|
async startHandoffSession(args) {
|
|
48226
48361
|
const dispatchConfig = await this.store.readConfig();
|
|
48362
|
+
const roleBasedNameOnlyMode = args.roleBasedNameOnlyMode ?? dispatchConfig.roleBasedNameOnlyMode ?? false;
|
|
48227
48363
|
const dispatchGezel = await this.store.getGezel(args.gezelId);
|
|
48228
48364
|
const dispatchProviderName = await this.resolveProviderName(
|
|
48229
48365
|
args.gezelId,
|
|
@@ -48272,6 +48408,7 @@ ${JSON.stringify(run.output, null, 2)}`;
|
|
|
48272
48408
|
projectId: args.projectId,
|
|
48273
48409
|
taskRef: args.taskRef,
|
|
48274
48410
|
stepId: dispatchStepId,
|
|
48411
|
+
roleBasedNameOnlyMode,
|
|
48275
48412
|
...args.nightShift ? { nightShift: true } : {},
|
|
48276
48413
|
...routed && args.capabilityFloor ? {
|
|
48277
48414
|
routedModel: {
|
|
@@ -48328,9 +48465,15 @@ ${stepArc}
|
|
|
48328
48465
|
}
|
|
48329
48466
|
}
|
|
48330
48467
|
const selfHandoff = args.fromGezelId !== void 0 && args.fromGezelId === args.gezelId;
|
|
48331
|
-
const
|
|
48468
|
+
const previousGezel = !selfHandoff && args.fromGezelId ? await this.store.getGezel(args.fromGezelId).catch(() => null) : null;
|
|
48469
|
+
const fromGezelDisplayName = previousGezel ? displayName2(
|
|
48470
|
+
{ name: previousGezel.name, roleBasedName: previousGezel.roleBasedName },
|
|
48471
|
+
roleBasedNameOnlyMode
|
|
48472
|
+
) : roleBasedNameOnlyMode ? void 0 : args.fromGezelName;
|
|
48473
|
+
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.`;
|
|
48332
48474
|
this.trackBackground(
|
|
48333
48475
|
this.sendWithBusyRetry(session.id, seed, {
|
|
48476
|
+
messageOrigin: "system",
|
|
48334
48477
|
...args.lane ? { lane: args.lane } : {},
|
|
48335
48478
|
...args.ambient ? { ambient: true } : {}
|
|
48336
48479
|
}).catch((err) => {
|
|
@@ -49176,11 +49319,10 @@ ${stepArc}
|
|
|
49176
49319
|
log52.info(
|
|
49177
49320
|
`[questions] delivering answer to session ${args.sessionId.slice(0, 8)} (gezel ${session.gezelId}, project ${session.projectId})`
|
|
49178
49321
|
);
|
|
49179
|
-
await this.sendWithBusyRetry(
|
|
49180
|
-
|
|
49181
|
-
args.
|
|
49182
|
-
|
|
49183
|
-
);
|
|
49322
|
+
await this.sendWithBusyRetry(args.sessionId, args.seed, {
|
|
49323
|
+
messageOrigin: "question-answer",
|
|
49324
|
+
...args.coalescable ? { coalescable: true } : {}
|
|
49325
|
+
});
|
|
49184
49326
|
}
|
|
49185
49327
|
/**
|
|
49186
49328
|
* System-authored reaction seed into a gezel's live (gezel, project)
|
|
@@ -49206,6 +49348,7 @@ ${stepArc}
|
|
|
49206
49348
|
this.send(session.id, args.seed, {
|
|
49207
49349
|
coalescable: true,
|
|
49208
49350
|
lane: "background",
|
|
49351
|
+
messageOrigin: "system",
|
|
49209
49352
|
...leanReactionCap ? { continuationMaxTokens: leanReactionCap } : {},
|
|
49210
49353
|
...args.hidden ? { hidden: true } : {}
|
|
49211
49354
|
}).catch((err) => {
|
|
@@ -49680,12 +49823,13 @@ ${stepArc}
|
|
|
49680
49823
|
throw new Error("engagement-off: AI is disabled in settings; re-enable to send");
|
|
49681
49824
|
}
|
|
49682
49825
|
const existingQueue = this.pendingSends.get(sessionId2);
|
|
49826
|
+
const messageOrigin = resolveTurnMessageOrigin(opts);
|
|
49683
49827
|
const shouldQueue = this.inflight.has(sessionId2) || existingQueue !== void 0 && existingQueue.length > 0;
|
|
49684
49828
|
if (shouldQueue) {
|
|
49685
49829
|
return new Promise((resolve19, reject) => {
|
|
49686
49830
|
const q2 = this.pendingSends.get(sessionId2) ?? [];
|
|
49687
49831
|
const tail = q2.length > 0 ? q2[q2.length - 1] : void 0;
|
|
49688
|
-
const canMerge = opts?.coalescable === true && opts?.nudge !== true && tail?.coalescable === true && tail.nudge !== true && sameFromBucket(tail.from, opts.from);
|
|
49832
|
+
const canMerge = opts?.coalescable === true && opts?.nudge !== true && tail?.coalescable === true && tail.nudge !== true && tail.messageOrigin === messageOrigin && sameFromBucket(tail.from, opts.from);
|
|
49689
49833
|
if (canMerge && tail) {
|
|
49690
49834
|
tail.userText = `${tail.userText}
|
|
49691
49835
|
|
|
@@ -49712,6 +49856,7 @@ ${userText}`;
|
|
|
49712
49856
|
coalescable: opts?.coalescable === true,
|
|
49713
49857
|
lane: opts?.lane,
|
|
49714
49858
|
ambient: opts?.ambient === true,
|
|
49859
|
+
messageOrigin,
|
|
49715
49860
|
continuationMaxTokens: opts?.continuationMaxTokens,
|
|
49716
49861
|
hidden: opts?.hidden === true,
|
|
49717
49862
|
nudge: opts?.nudge === true,
|
|
@@ -49728,7 +49873,7 @@ ${userText}`;
|
|
|
49728
49873
|
return this.runSendAndDrain(
|
|
49729
49874
|
sessionId2,
|
|
49730
49875
|
userText,
|
|
49731
|
-
opts?.nudge ? { ...opts, nudge: false } : opts
|
|
49876
|
+
opts?.nudge ? { ...opts, nudge: false, messageOrigin } : { ...opts, messageOrigin }
|
|
49732
49877
|
);
|
|
49733
49878
|
}
|
|
49734
49879
|
/**
|
|
@@ -49827,7 +49972,7 @@ ${userText}`;
|
|
|
49827
49972
|
if (next.nudge) {
|
|
49828
49973
|
while (q2.length > 0) {
|
|
49829
49974
|
const peek = q2[0];
|
|
49830
|
-
if (!peek.nudge || peek.hidden !== next.hidden || !sameFromBucket(peek.from, next.from)) {
|
|
49975
|
+
if (!peek.nudge || peek.hidden !== next.hidden || peek.messageOrigin !== next.messageOrigin || !sameFromBucket(peek.from, next.from)) {
|
|
49831
49976
|
break;
|
|
49832
49977
|
}
|
|
49833
49978
|
q2.shift();
|
|
@@ -49850,6 +49995,7 @@ ${peek.userText}`;
|
|
|
49850
49995
|
if (next.continuationMaxTokens) runOpts.continuationMaxTokens = next.continuationMaxTokens;
|
|
49851
49996
|
if (next.hidden) runOpts.hidden = true;
|
|
49852
49997
|
if (next.nudge) runOpts.nudge = true;
|
|
49998
|
+
runOpts.messageOrigin = next.messageOrigin;
|
|
49853
49999
|
void this.runSendAndDrain(sessionId2, next.userText, runOpts).then((msg) => {
|
|
49854
50000
|
for (const w of next.waiters) {
|
|
49855
50001
|
try {
|
|
@@ -50180,6 +50326,18 @@ ${peek.userText}`;
|
|
|
50180
50326
|
try {
|
|
50181
50327
|
let lastAssistantMessage = null;
|
|
50182
50328
|
let promptForTurn = spliceIntoText(userText, pendingDigests);
|
|
50329
|
+
const correctivePromptForLiveRoster = (prompt, source) => {
|
|
50330
|
+
const safe = capabilitySafeCorrectivePrompt({
|
|
50331
|
+
prompt,
|
|
50332
|
+
availableTools: liveTurnToolNames(liveSession)
|
|
50333
|
+
});
|
|
50334
|
+
if (safe !== prompt.trim()) {
|
|
50335
|
+
log52.warn(
|
|
50336
|
+
`session ${sessionId2}: filtered ${source} corrective against the live tool roster`
|
|
50337
|
+
);
|
|
50338
|
+
}
|
|
50339
|
+
return safe;
|
|
50340
|
+
};
|
|
50183
50341
|
const freshGameState = await this.refreshLeanGameState(state.record, userText);
|
|
50184
50342
|
if (freshGameState) {
|
|
50185
50343
|
promptForTurn = `${freshGameState}
|
|
@@ -50190,7 +50348,8 @@ ${promptForTurn}`;
|
|
|
50190
50348
|
this.taskBudget.reset(state.record.taskRef);
|
|
50191
50349
|
this.pendingBudgetNudge.delete(state.record.taskRef);
|
|
50192
50350
|
}
|
|
50193
|
-
const
|
|
50351
|
+
const messageOrigin = resolveTurnMessageOrigin(opts);
|
|
50352
|
+
const preludeForTurn = await this.resolveUserPromptPrelude(state, userText, messageOrigin);
|
|
50194
50353
|
if (preludeForTurn) {
|
|
50195
50354
|
promptForTurn = `${preludeForTurn.text}
|
|
50196
50355
|
|
|
@@ -50213,7 +50372,7 @@ ${promptForTurn}`;
|
|
|
50213
50372
|
}
|
|
50214
50373
|
if (state.record.taskRef && this.pendingBudgetNudge.has(state.record.taskRef)) {
|
|
50215
50374
|
this.pendingBudgetNudge.delete(state.record.taskRef);
|
|
50216
|
-
promptForTurn = `${TASK_BUDGET_NUDGE}
|
|
50375
|
+
promptForTurn = `${correctivePromptForLiveRoster(TASK_BUDGET_NUDGE, "task-budget")}
|
|
50217
50376
|
|
|
50218
50377
|
${promptForTurn}`;
|
|
50219
50378
|
log52.info(
|
|
@@ -50222,6 +50381,7 @@ ${promptForTurn}`;
|
|
|
50222
50381
|
}
|
|
50223
50382
|
let continuations = 0;
|
|
50224
50383
|
const maxContinuations = resolveContinuationBudget(state);
|
|
50384
|
+
let voormanIdleNudged = false;
|
|
50225
50385
|
const toolsAcrossContinuations = [];
|
|
50226
50386
|
let compactionsThisSend = 0;
|
|
50227
50387
|
let keurmeesterConsultedThisSend = false;
|
|
@@ -50485,6 +50645,7 @@ ${state.aboutSnapshot}`);
|
|
|
50485
50645
|
const detectorVerdict = runPostTurnDetectors(state, {
|
|
50486
50646
|
sessionId: sessionId2,
|
|
50487
50647
|
isMeester: cfgForDetector?.meesterGezelId === state.record.gezelId,
|
|
50648
|
+
messageOrigin,
|
|
50488
50649
|
userText,
|
|
50489
50650
|
drained: toolsAcrossContinuations,
|
|
50490
50651
|
assistantContent: assistantMessage.content,
|
|
@@ -50498,7 +50659,10 @@ ${state.aboutSnapshot}`);
|
|
|
50498
50659
|
this.events.publish(scope, { type: "warning", message: warningMessage });
|
|
50499
50660
|
}
|
|
50500
50661
|
if (detectorVerdict?.promptForNextTurn) {
|
|
50501
|
-
detectorReprompt =
|
|
50662
|
+
detectorReprompt = correctivePromptForLiveRoster(
|
|
50663
|
+
detectorVerdict.promptForNextTurn,
|
|
50664
|
+
"post-turn detector"
|
|
50665
|
+
);
|
|
50502
50666
|
}
|
|
50503
50667
|
const advanceOutcome = await this.maybeAutoAdvanceOnObservableProgress(
|
|
50504
50668
|
state,
|
|
@@ -50649,7 +50813,10 @@ ${state.aboutSnapshot}`);
|
|
|
50649
50813
|
log52.info(
|
|
50650
50814
|
`session ${sessionId2}: keurmeester intervention applied (case ${consult.caseId}) \u2014 granting one recovery continuation`
|
|
50651
50815
|
);
|
|
50652
|
-
promptForTurn =
|
|
50816
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50817
|
+
consult.correctivePrompt,
|
|
50818
|
+
"keurmeester"
|
|
50819
|
+
);
|
|
50653
50820
|
continue;
|
|
50654
50821
|
}
|
|
50655
50822
|
}
|
|
@@ -50667,7 +50834,10 @@ ${state.aboutSnapshot}`);
|
|
|
50667
50834
|
log52.info(
|
|
50668
50835
|
`session ${sessionId2}: ${detectorVerdict?.reason ?? "detector"} \u2014 re-prompting`
|
|
50669
50836
|
);
|
|
50670
|
-
promptForTurn =
|
|
50837
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50838
|
+
detectorReprompt,
|
|
50839
|
+
detectorVerdict ? "post-turn detector" : "deliverable salvage"
|
|
50840
|
+
);
|
|
50671
50841
|
continue;
|
|
50672
50842
|
}
|
|
50673
50843
|
if (advanceOutcome.gateRejected && !advanceOutcome.gateRejected.paused && advanceOutcome.gateRejected.fingerprint !== state.lastGateNudgeFingerprint && !drained.some((d) => d.name === "ask_user_question" && d.success)) {
|
|
@@ -50677,7 +50847,10 @@ ${state.aboutSnapshot}`);
|
|
|
50677
50847
|
log52.info(
|
|
50678
50848
|
`session ${sessionId2}: ${advanceOutcome.gateRejected.taskRef} step "${advanceOutcome.gateRejected.stepId}" gate rejected \u2014 re-prompting with the verdict${stage > 0 ? ` (escalation stage ${stage})` : ""}`
|
|
50679
50849
|
);
|
|
50680
|
-
promptForTurn =
|
|
50850
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50851
|
+
stage >= 1 ? advanceOutcome.gateRejected.message : buildGateRejectionNudge(advanceOutcome.gateRejected.message),
|
|
50852
|
+
"task-gate"
|
|
50853
|
+
);
|
|
50681
50854
|
continue;
|
|
50682
50855
|
}
|
|
50683
50856
|
if (deliverableOutcome.deliverableRejected?.stopRetrying) {
|
|
@@ -50728,7 +50901,10 @@ ${state.aboutSnapshot}`);
|
|
|
50728
50901
|
log52.info(
|
|
50729
50902
|
`session ${sessionId2}: keurmeester intervention applied on deliverable plateau (case ${consult.caseId}) \u2014 granting one recovery continuation`
|
|
50730
50903
|
);
|
|
50731
|
-
promptForTurn =
|
|
50904
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50905
|
+
consult.correctivePrompt,
|
|
50906
|
+
"keurmeester deliverable-plateau"
|
|
50907
|
+
);
|
|
50732
50908
|
continue;
|
|
50733
50909
|
}
|
|
50734
50910
|
}
|
|
@@ -50752,7 +50928,10 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50752
50928
|
...dRej.filePath ? { filePath: dRej.filePath } : {},
|
|
50753
50929
|
failingVerdict: dRej.message
|
|
50754
50930
|
});
|
|
50755
|
-
promptForTurn =
|
|
50931
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50932
|
+
clampNudge ?? (dStage >= 1 ? dRej.message : buildGateRejectionNudge(dRej.message)),
|
|
50933
|
+
"deliverable-gate"
|
|
50934
|
+
);
|
|
50756
50935
|
continue;
|
|
50757
50936
|
}
|
|
50758
50937
|
if (advanceOutcome.unmetEditGate && (looksStalled(finalContent) || claimsCompletion(finalContent)) && !drained.some((d) => d.name === "ask_user_question" && d.success)) {
|
|
@@ -50760,7 +50939,10 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50760
50939
|
log52.info(
|
|
50761
50940
|
`session ${sessionId2}: ${advanceOutcome.unmetEditGate.taskRef} edit gate unmet (${advanceOutcome.unmetEditGate.file} not written) but reply claims progress \u2014 nudging to edit`
|
|
50762
50941
|
);
|
|
50763
|
-
promptForTurn =
|
|
50942
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
50943
|
+
buildDeliverableEditNudge(advanceOutcome.unmetEditGate.file),
|
|
50944
|
+
"deliverable-edit"
|
|
50945
|
+
);
|
|
50764
50946
|
continue;
|
|
50765
50947
|
}
|
|
50766
50948
|
const unresolvedToolFailures = unresolvedFailedToolCalls(drained);
|
|
@@ -50804,7 +50986,7 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50804
50986
|
// the hot path synchronous for the common non-voorman case.
|
|
50805
50987
|
// Also requires `proactive` — voorman idle nudges advance
|
|
50806
50988
|
// project work past what the user asked for.
|
|
50807
|
-
isProactiveAllowed(nudgeConfig) && state.record.providerName !== "copilot"
|
|
50989
|
+
isProactiveAllowed(nudgeConfig) && state.record.providerName !== "copilot" && !voormanIdleNudged
|
|
50808
50990
|
) {
|
|
50809
50991
|
voormanIdleVerdict = await this.didVoormanIdleStall(state.record, drained, sessionId2);
|
|
50810
50992
|
if (voormanIdleVerdict !== null) {
|
|
@@ -50822,15 +51004,19 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
50822
51004
|
);
|
|
50823
51005
|
break;
|
|
50824
51006
|
}
|
|
51007
|
+
if (stallReason === "voorman-idle") voormanIdleNudged = true;
|
|
50825
51008
|
continuations++;
|
|
50826
51009
|
log52.info(
|
|
50827
|
-
`session ${sessionId2}: response looks stalled (${stallReason}) \u2014
|
|
51010
|
+
`session ${sessionId2}: response looks stalled (${stallReason}) \u2014 requesting one recovery pass`
|
|
51011
|
+
);
|
|
51012
|
+
promptForTurn = correctivePromptForLiveRoster(
|
|
51013
|
+
stallReason === "voorman-idle" ? buildContinuationNudge(
|
|
51014
|
+
finalContent,
|
|
51015
|
+
state.record.messages,
|
|
51016
|
+
voormanIdleVerdict === "nothing-built" ? VOORMAN_NOT_DONE_NUDGE : VOORMAN_IDLE_NUDGE
|
|
51017
|
+
) : stallReason === "tool-only" ? CLOSING_SUMMARY_NUDGE : stallReason === "tool-read-only" ? READ_ONLY_PROGRESS_NUDGE : stallReason === "tool-failed" ? buildFailedToolRecoveryNudge(unresolvedToolFailures) : buildContinuationNudge(finalContent, state.record.messages),
|
|
51018
|
+
`stall-${stallReason}`
|
|
50828
51019
|
);
|
|
50829
|
-
promptForTurn = stallReason === "voorman-idle" ? buildContinuationNudge(
|
|
50830
|
-
finalContent,
|
|
50831
|
-
state.record.messages,
|
|
50832
|
-
voormanIdleVerdict === "nothing-built" ? VOORMAN_NOT_DONE_NUDGE : VOORMAN_IDLE_NUDGE
|
|
50833
|
-
) : stallReason === "tool-only" ? CLOSING_SUMMARY_NUDGE : stallReason === "tool-read-only" ? READ_ONLY_PROGRESS_NUDGE : stallReason === "tool-failed" ? buildFailedToolRecoveryNudge(unresolvedToolFailures) : buildContinuationNudge(finalContent, state.record.messages);
|
|
50834
51020
|
continue;
|
|
50835
51021
|
}
|
|
50836
51022
|
}
|
|
@@ -51396,7 +51582,7 @@ ${rej.message.split("\n").slice(0, 4).join("\n")}`;
|
|
|
51396
51582
|
return null;
|
|
51397
51583
|
}
|
|
51398
51584
|
const tasks = await this.store.listProjectTasks(record.projectId).catch(() => []);
|
|
51399
|
-
if (tasks.length
|
|
51585
|
+
if (tasks.length === 0 || !tasks.some((t) => t.status === "active")) {
|
|
51400
51586
|
return null;
|
|
51401
51587
|
}
|
|
51402
51588
|
const workspaceFiles = await this.store.listProjectWorkspaceRecursive(record.projectId).catch(() => []);
|
|
@@ -54147,7 +54333,7 @@ ${baseSystem}` : baseSystem;
|
|
|
54147
54333
|
return { modelId };
|
|
54148
54334
|
}
|
|
54149
54335
|
}
|
|
54150
|
-
async resolveUserPromptPrelude(state, userText) {
|
|
54336
|
+
async resolveUserPromptPrelude(state, userText, messageOrigin) {
|
|
54151
54337
|
const profile = state.profile;
|
|
54152
54338
|
if (!profile) return null;
|
|
54153
54339
|
const cfg = await this.store.readConfig().catch(() => null);
|
|
@@ -54156,6 +54342,9 @@ ${baseSystem}` : baseSystem;
|
|
|
54156
54342
|
...modelCtxFromProfile(profile, state),
|
|
54157
54343
|
sessionId: state.record.id,
|
|
54158
54344
|
isMeester,
|
|
54345
|
+
projectId: state.record.projectId,
|
|
54346
|
+
messageOrigin,
|
|
54347
|
+
availableToolNames: liveTurnToolNames(state.session),
|
|
54159
54348
|
userText,
|
|
54160
54349
|
drained: [],
|
|
54161
54350
|
assistantContent: "",
|
|
@@ -55476,6 +55665,7 @@ Allow **${info.toolName}** this time?`,
|
|
|
55476
55665
|
GEZEL_SESSION_ID: record.id,
|
|
55477
55666
|
GEZEL_HOME: this.home,
|
|
55478
55667
|
GEZEL_EXECUTION_DENSITY: executionDensity,
|
|
55668
|
+
GEZEL_ROLE_BASED_NAME_ONLY_MODE: record.roleBasedNameOnlyMode ?? globalConfig.roleBasedNameOnlyMode ?? false ? "1" : "0",
|
|
55479
55669
|
...record.expectedDeliverable ? { GEZEL_EXPECTED_DELIVERABLE: JSON.stringify(record.expectedDeliverable) } : {},
|
|
55480
55670
|
...record.stepId ? { GEZEL_STEP_ID: record.stepId } : {},
|
|
55481
55671
|
// Scope task: lets the MCP task tools default to / recover toward
|
|
@@ -55915,6 +56105,9 @@ function runPostTurnDetectors(state, args) {
|
|
|
55915
56105
|
...modelCtxFromProfile(profile, state),
|
|
55916
56106
|
sessionId: args.sessionId,
|
|
55917
56107
|
isMeester: args.isMeester,
|
|
56108
|
+
projectId: state.record.projectId,
|
|
56109
|
+
messageOrigin: args.messageOrigin,
|
|
56110
|
+
availableToolNames: liveTurnToolNames(state.session),
|
|
55918
56111
|
userText: args.userText,
|
|
55919
56112
|
drained: args.drained,
|
|
55920
56113
|
assistantContent: args.assistantContent,
|
|
@@ -56447,13 +56640,18 @@ Drop conversational filler, pleasantries, and verbatim tool outputs (just note "
|
|
|
56447
56640
|
Earlier conversation:
|
|
56448
56641
|
|
|
56449
56642
|
`;
|
|
56450
|
-
var VOORMAN_IDLE_NUDGE =
|
|
56643
|
+
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.";
|
|
56451
56644
|
var BOOTSTRAP_WORKSPACE_FILES = /* @__PURE__ */ new Set([
|
|
56452
56645
|
"package.json",
|
|
56646
|
+
"package-lock.json",
|
|
56647
|
+
"pnpm-lock.yaml",
|
|
56648
|
+
"yarn.lock",
|
|
56649
|
+
"bun.lock",
|
|
56650
|
+
"bun.lockb",
|
|
56453
56651
|
"tsconfig.json",
|
|
56454
56652
|
".gitignore"
|
|
56455
56653
|
]);
|
|
56456
|
-
var VOORMAN_NOT_DONE_NUDGE = "
|
|
56654
|
+
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.";
|
|
56457
56655
|
var READ_ONLY_MCP_TOOLS = /* @__PURE__ */ new Set([
|
|
56458
56656
|
"search_memory",
|
|
56459
56657
|
"list_memories",
|
|
@@ -75777,6 +75975,7 @@ ${p.content.trim()}`).join("\n\n---\n\n");
|
|
|
75777
75975
|
async createProject(input, opts) {
|
|
75778
75976
|
const release2 = await this.acquireProjectCreationLock();
|
|
75779
75977
|
try {
|
|
75978
|
+
if (input.workingDir) this.assertSafeWorkingDir(input.workingDir);
|
|
75780
75979
|
const id = opts?.id ?? await this.uniqueProjectId(slugify(input.name) || randomUUID10().slice(0, 8));
|
|
75781
75980
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
75782
75981
|
throw new Error(`invalid project id "${id}"`);
|
|
@@ -75800,14 +75999,22 @@ ${p.content.trim()}`).join("\n\n---\n\n");
|
|
|
75800
75999
|
projectName: input.name
|
|
75801
76000
|
});
|
|
75802
76001
|
}
|
|
76002
|
+
let github = input.github?.url ? { url: input.github.url } : void 0;
|
|
76003
|
+
if (input.workingDir) {
|
|
76004
|
+
github = await autoDetectGitHubLink(input.workingDir, github) ?? github;
|
|
76005
|
+
}
|
|
75803
76006
|
const project = {
|
|
75804
76007
|
id,
|
|
75805
76008
|
name: input.name,
|
|
75806
76009
|
description: input.description,
|
|
75807
76010
|
...input.workingDir ? { workingDir: input.workingDir } : {},
|
|
76011
|
+
// Opening an existing folder is an intake action, not a declaration
|
|
76012
|
+
// that its objectives are ready for active supervision. Keep the
|
|
76013
|
+
// Meester quiet until the user explicitly opts this project back in.
|
|
76014
|
+
...input.workingDir ? { nudgeConfig: { enabled: false } } : {},
|
|
75808
76015
|
...input.mode && input.mode !== "crew" ? { mode: input.mode } : {},
|
|
75809
76016
|
...input.indexingEnabled !== void 0 ? { indexingEnabled: input.indexingEnabled } : {},
|
|
75810
|
-
...
|
|
76017
|
+
...github ? { github } : {},
|
|
75811
76018
|
createdAt: nowIso5(),
|
|
75812
76019
|
updatedAt: nowIso5()
|
|
75813
76020
|
};
|
|
@@ -80259,6 +80466,7 @@ var TaskManager = class {
|
|
|
80259
80466
|
...cron ? { cron } : {},
|
|
80260
80467
|
...nightShift ? { nightShift } : {},
|
|
80261
80468
|
...fanout ? { fanout } : {},
|
|
80469
|
+
...input.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: input.roleBasedNameOnlyMode } : {},
|
|
80262
80470
|
createdAt: now,
|
|
80263
80471
|
updatedAt: now,
|
|
80264
80472
|
createdBy: input.createdBy ?? { kind: "user" }
|
|
@@ -82253,6 +82461,7 @@ Fix one of these, then set the task active again:
|
|
|
82253
82461
|
...parent.nightShift?.enabled ? { nightShift: { enabled: true } } : {},
|
|
82254
82462
|
activeStepId,
|
|
82255
82463
|
parentTaskRef: parent.ref,
|
|
82464
|
+
...parent.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: parent.roleBasedNameOnlyMode } : {},
|
|
82256
82465
|
createdAt: now,
|
|
82257
82466
|
updatedAt: now,
|
|
82258
82467
|
createdBy: parent.createdBy
|
|
@@ -96153,19 +96362,19 @@ function memoryRoutes(ctx) {
|
|
|
96153
96362
|
const app = new Hono37();
|
|
96154
96363
|
app.post("/search", async (c) => {
|
|
96155
96364
|
const body = await c.req.json();
|
|
96156
|
-
const
|
|
96365
|
+
const outcome = await ctx.memory.searchAllDetailed(
|
|
96157
96366
|
body.gezelId,
|
|
96158
96367
|
body.projectId,
|
|
96159
96368
|
body.query,
|
|
96160
96369
|
body.topK ?? 10
|
|
96161
96370
|
);
|
|
96162
|
-
return c.json(
|
|
96371
|
+
return c.json(outcome);
|
|
96163
96372
|
});
|
|
96164
96373
|
app.post("/save", async (c) => {
|
|
96165
96374
|
const body = await c.req.json();
|
|
96166
96375
|
const kind = isMemoryKind(body.kind) ? body.kind : "fact";
|
|
96167
96376
|
const outcome = await ctx.memory.save(body.scope, body.id, body.text, kind);
|
|
96168
|
-
return c.json({ ok: true,
|
|
96377
|
+
return c.json({ ok: true, ...outcome });
|
|
96169
96378
|
});
|
|
96170
96379
|
app.get("/recent", async (c) => {
|
|
96171
96380
|
const scope = c.req.query("scope") ?? "gezel";
|
|
@@ -101014,6 +101223,7 @@ import {
|
|
|
101014
101223
|
projectGezelId as projectGezelId2,
|
|
101015
101224
|
skillToCraftbookDoc
|
|
101016
101225
|
} from "@bendyline/gezel";
|
|
101226
|
+
init_ensure();
|
|
101017
101227
|
init_install();
|
|
101018
101228
|
|
|
101019
101229
|
// src/workspace/instruction-scanner.ts
|
|
@@ -101196,6 +101406,30 @@ async function translateShellBlock(chat, skillName, scriptName, code) {
|
|
|
101196
101406
|
// src/workspace/import-sync.ts
|
|
101197
101407
|
var log110 = createLogger114("import-sync");
|
|
101198
101408
|
var VOORMAN_TEMPLATE_ID = "voorman";
|
|
101409
|
+
var BUILDER_TEMPLATE_ID = "builder";
|
|
101410
|
+
async function ensureFolderProjectBuilder(deps, projectId) {
|
|
101411
|
+
const { store, catalog } = deps;
|
|
101412
|
+
if (!projectId || projectId === "default") return {};
|
|
101413
|
+
const project = await store.getProject(projectId).catch(() => null);
|
|
101414
|
+
if (!project || project.mode !== "solo" || !project.workingDir) return {};
|
|
101415
|
+
if (project.voormanGezelId) return {};
|
|
101416
|
+
const gezels = await store.listGezels().catch(() => []);
|
|
101417
|
+
const existing = gezels.find(
|
|
101418
|
+
(gezel) => gezel.templateId === BUILDER_TEMPLATE_ID || gezel.role?.trim().toLowerCase() === BUILDER_TEMPLATE_ID
|
|
101419
|
+
);
|
|
101420
|
+
const recruited = existing ? null : await recruitFromTemplate(store, catalog, BUILDER_TEMPLATE_ID).catch((err) => {
|
|
101421
|
+
log110.warn(`[import-sync] ${projectId}: Builder recruit failed: ${describe6(err)}`);
|
|
101422
|
+
return null;
|
|
101423
|
+
});
|
|
101424
|
+
const builder = existing ?? recruited;
|
|
101425
|
+
if (!builder) return {};
|
|
101426
|
+
await store.updateProject(projectId, {
|
|
101427
|
+
voormanGezelId: builder.id,
|
|
101428
|
+
voormanAutoAssignedAt: nowIso12()
|
|
101429
|
+
});
|
|
101430
|
+
log110.info(`[import-sync] ${projectId}: assigned ${builder.id} as Builder`);
|
|
101431
|
+
return recruited ? { createdGezel: recruited } : {};
|
|
101432
|
+
}
|
|
101199
101433
|
async function syncProjectImports(deps, projectId, instructions, skills) {
|
|
101200
101434
|
const { store } = deps;
|
|
101201
101435
|
const gate = await store.assertWorkspaceWritable(projectId).catch(() => null);
|
|
@@ -101324,16 +101558,20 @@ async function findExistingVoorman(store) {
|
|
|
101324
101558
|
return match?.id ?? null;
|
|
101325
101559
|
}
|
|
101326
101560
|
async function recruitVoorman(store, catalog) {
|
|
101327
|
-
|
|
101328
|
-
|
|
101561
|
+
return recruitFromTemplate(store, catalog, VOORMAN_TEMPLATE_ID);
|
|
101562
|
+
}
|
|
101563
|
+
async function recruitFromTemplate(store, catalog, templateId) {
|
|
101564
|
+
const template = await resolveGildeTemplateForRole(catalog, templateId).catch(() => null);
|
|
101565
|
+
if (!template || template.templateId !== templateId) return null;
|
|
101329
101566
|
const { name, gender } = pickRandomNameWithGender4();
|
|
101330
101567
|
const created = await store.createGezel({
|
|
101331
101568
|
name,
|
|
101332
|
-
role:
|
|
101569
|
+
role: template.role,
|
|
101333
101570
|
gender,
|
|
101334
|
-
about:
|
|
101335
|
-
templateId
|
|
101336
|
-
templateVersion:
|
|
101571
|
+
about: template.about,
|
|
101572
|
+
templateId,
|
|
101573
|
+
templateVersion: template.templateVersion,
|
|
101574
|
+
...template.frontmatter ? { frontmatter: template.frontmatter } : {}
|
|
101337
101575
|
});
|
|
101338
101576
|
return { id: created.id, name: created.name };
|
|
101339
101577
|
}
|
|
@@ -101808,6 +102046,7 @@ async function resolveActor(ctx, gezelIdHeader) {
|
|
|
101808
102046
|
}
|
|
101809
102047
|
function projectTaskRoutes(ctx) {
|
|
101810
102048
|
const app = new Hono55();
|
|
102049
|
+
const inflightCraftbookInvocations = /* @__PURE__ */ new Map();
|
|
101811
102050
|
app.get("/:projectId/tasks", async (c) => {
|
|
101812
102051
|
const projectId = c.req.param("projectId");
|
|
101813
102052
|
const filter = ListFilterSchema.parse({
|
|
@@ -101823,10 +102062,31 @@ function projectTaskRoutes(ctx) {
|
|
|
101823
102062
|
});
|
|
101824
102063
|
app.post("/:projectId/tasks", async (c) => {
|
|
101825
102064
|
const projectId = c.req.param("projectId");
|
|
101826
|
-
const { dispatchEntry, ...body } = CreateTaskRequestSchema.parse(
|
|
102065
|
+
const { dispatchEntry, craftbookInvocationKey, ...body } = CreateTaskRequestSchema.parse(
|
|
102066
|
+
await c.req.json()
|
|
102067
|
+
);
|
|
101827
102068
|
let task;
|
|
101828
102069
|
try {
|
|
101829
|
-
|
|
102070
|
+
if (craftbookInvocationKey) {
|
|
102071
|
+
const existing = (await ctx.tasks.list({ projectId })).find(
|
|
102072
|
+
(candidate) => candidate.origin?.kind === "craftbook-invocation" && candidate.origin.key === craftbookInvocationKey && (candidate.status === "draft" || candidate.status === "active" || candidate.status === "paused")
|
|
102073
|
+
);
|
|
102074
|
+
if (existing) return c.json(existing);
|
|
102075
|
+
const inflightKey = `${projectId}:${craftbookInvocationKey}`;
|
|
102076
|
+
const pending5 = inflightCraftbookInvocations.get(inflightKey);
|
|
102077
|
+
if (pending5) return c.json(await pending5);
|
|
102078
|
+
const create = ctx.tasks.create(projectId, body, {
|
|
102079
|
+
origin: { kind: "craftbook-invocation", key: craftbookInvocationKey }
|
|
102080
|
+
});
|
|
102081
|
+
inflightCraftbookInvocations.set(inflightKey, create);
|
|
102082
|
+
try {
|
|
102083
|
+
task = await create;
|
|
102084
|
+
} finally {
|
|
102085
|
+
inflightCraftbookInvocations.delete(inflightKey);
|
|
102086
|
+
}
|
|
102087
|
+
} else {
|
|
102088
|
+
task = await ctx.tasks.create(projectId, body);
|
|
102089
|
+
}
|
|
101830
102090
|
} catch (err) {
|
|
101831
102091
|
if (err instanceof CraftbookSetupRequiredError) {
|
|
101832
102092
|
return c.json(
|
|
@@ -104272,12 +104532,13 @@ function projectRoutes(ctx) {
|
|
|
104272
104532
|
app.post("/", async (c) => {
|
|
104273
104533
|
const body = CreateProjectRequestSchema.parse(await c.req.json());
|
|
104274
104534
|
const created = await ctx.store.createProject(body);
|
|
104275
|
-
const
|
|
104535
|
+
const ensureLead = body.workingDir && body.mode === "solo" ? ensureFolderProjectBuilder : ensureProjectVoorman;
|
|
104536
|
+
const ensured2 = await ensureLead(
|
|
104276
104537
|
{ store: ctx.store, chat: ctx.chat, home: ctx.home, catalog: ctx.catalog },
|
|
104277
104538
|
created.id
|
|
104278
104539
|
).catch((err) => {
|
|
104279
104540
|
const message = err instanceof Error ? err.message : String(err);
|
|
104280
|
-
log114.warn(`[projects] ensure-
|
|
104541
|
+
log114.warn(`[projects] ensure-lead failed for ${created.id}: ${message}`);
|
|
104281
104542
|
return {};
|
|
104282
104543
|
});
|
|
104283
104544
|
if (ensured2.createdGezel) {
|
|
@@ -104800,6 +105061,31 @@ function projectRoutes(ctx) {
|
|
|
104800
105061
|
return c.json({ error: "not found" }, 404);
|
|
104801
105062
|
}
|
|
104802
105063
|
});
|
|
105064
|
+
app.post("/:id/reveal-reference", async (c) => {
|
|
105065
|
+
const id = c.req.param("id");
|
|
105066
|
+
const request = ReferenceFileLocationRequestSchema.parse({
|
|
105067
|
+
kind: c.req.query("kind"),
|
|
105068
|
+
path: c.req.query("path")
|
|
105069
|
+
});
|
|
105070
|
+
const base = request.kind === "artifact" ? ctx.store.projectArtifactsDir(id) : request.kind === "workspace" ? await ctx.store.projectWorkspaceDir(id) : ctx.store.documentsDir();
|
|
105071
|
+
const joined = safeJoin(base, request.path);
|
|
105072
|
+
if (!joined || !await realpathContained(base, joined)) {
|
|
105073
|
+
return c.json({ error: "path traversal" }, 400);
|
|
105074
|
+
}
|
|
105075
|
+
let path2;
|
|
105076
|
+
try {
|
|
105077
|
+
const file = await stat36(joined);
|
|
105078
|
+
if (!file.isFile()) return c.json({ error: "not found" }, 404);
|
|
105079
|
+
path2 = await realpath8(joined);
|
|
105080
|
+
} catch {
|
|
105081
|
+
return c.json({ error: "not found" }, 404);
|
|
105082
|
+
}
|
|
105083
|
+
const { execFile: execFile8 } = await import("child_process");
|
|
105084
|
+
const launcher = process.platform === "darwin" ? { cmd: "open", args: ["-R", path2] } : process.platform === "win32" ? { cmd: "explorer", args: ["/select,", path2] } : { cmd: "xdg-open", args: [dirname44(path2)] };
|
|
105085
|
+
execFile8(launcher.cmd, launcher.args, { windowsHide: true }, () => {
|
|
105086
|
+
});
|
|
105087
|
+
return c.json(ReferenceFileLocationResponseSchema.parse({ path: path2 }));
|
|
105088
|
+
});
|
|
104803
105089
|
app.get("/:id/artifacts", async (c) => {
|
|
104804
105090
|
const id = c.req.param("id");
|
|
104805
105091
|
const subpath = c.req.query("path") ?? "";
|
|
@@ -116254,7 +116540,10 @@ function opaqueServerErrors(log189, onUnexpectedHttpError) {
|
|
|
116254
116540
|
const raw = await prior.clone().text().catch(() => "");
|
|
116255
116541
|
try {
|
|
116256
116542
|
const parsed = JSON.parse(raw);
|
|
116257
|
-
if (parsed.error === "internal_error" && typeof parsed.requestId === "string")
|
|
116543
|
+
if (parsed.error === "internal_error" && typeof parsed.requestId === "string") {
|
|
116544
|
+
c.header("x-request-id", parsed.requestId);
|
|
116545
|
+
return;
|
|
116546
|
+
}
|
|
116258
116547
|
if ((parsed.error === "machine_engine_unavailable" || parsed.error === "capacity_denied") && Object.keys(parsed).length === 1) {
|
|
116259
116548
|
return;
|
|
116260
116549
|
}
|
|
@@ -125165,8 +125454,8 @@ var MemoryManager = class {
|
|
|
125165
125454
|
* that text dedups, so we accept the race rather than lock.
|
|
125166
125455
|
*
|
|
125167
125456
|
* Degraded mode (embeddings disabled): markdown is still appended (it is
|
|
125168
|
-
* the source of truth and the
|
|
125169
|
-
*
|
|
125457
|
+
* the source of truth) and the outcome reports deferred indexing. The health
|
|
125458
|
+
* monitor self-heals the derived index once embeddings recover.
|
|
125170
125459
|
*/
|
|
125171
125460
|
async save(scope, id, text, kind = DEFAULT_MEMORY_KIND) {
|
|
125172
125461
|
const trimmed = text.trim();
|
|
@@ -125181,9 +125470,19 @@ var MemoryManager = class {
|
|
|
125181
125470
|
vector = await embed(trimmed);
|
|
125182
125471
|
} catch (err) {
|
|
125183
125472
|
await this.store.appendMemory(scope, id, trimmed, kind);
|
|
125184
|
-
|
|
125473
|
+
log155.warn(
|
|
125474
|
+
`[memory] saved ${scope}/${id} to Markdown; semantic indexing deferred: ${describeError3(err)}`
|
|
125475
|
+
);
|
|
125476
|
+
return deferredIndexOutcome();
|
|
125477
|
+
}
|
|
125478
|
+
let top;
|
|
125479
|
+
try {
|
|
125480
|
+
top = (await searchByVector(indexDir, vector, 1))[0];
|
|
125481
|
+
} catch (error) {
|
|
125482
|
+
log155.warn(
|
|
125483
|
+
`[memory] vector dedup unavailable for ${scope}/${id}; continuing save: ${describeError3(error)}`
|
|
125484
|
+
);
|
|
125185
125485
|
}
|
|
125186
|
-
const top = (await searchByVector(indexDir, vector, 1))[0];
|
|
125187
125486
|
if (top && top.score >= this.dedupThreshold) {
|
|
125188
125487
|
log155.info(
|
|
125189
125488
|
`[memory] dup-skip (${top.score.toFixed(2)} vs "${top.text.slice(0, 40)}") ${scope}/${id}: ${trimmed.slice(0, 60)}`
|
|
@@ -125191,20 +125490,27 @@ var MemoryManager = class {
|
|
|
125191
125490
|
return { status: "duplicate", match: { text: top.text, score: top.score, via: "vector" } };
|
|
125192
125491
|
}
|
|
125193
125492
|
await this.store.appendMemory(scope, id, trimmed, kind);
|
|
125194
|
-
|
|
125195
|
-
|
|
125196
|
-
|
|
125197
|
-
|
|
125198
|
-
|
|
125199
|
-
|
|
125200
|
-
|
|
125201
|
-
|
|
125202
|
-
|
|
125203
|
-
|
|
125204
|
-
|
|
125205
|
-
|
|
125493
|
+
try {
|
|
125494
|
+
await addToIndex(
|
|
125495
|
+
indexDir,
|
|
125496
|
+
{
|
|
125497
|
+
text: trimmed,
|
|
125498
|
+
scope,
|
|
125499
|
+
id,
|
|
125500
|
+
day: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
125501
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
125502
|
+
kind
|
|
125503
|
+
},
|
|
125504
|
+
vector
|
|
125505
|
+
);
|
|
125506
|
+
} catch (error) {
|
|
125507
|
+
log155.warn(
|
|
125508
|
+
`[memory] saved ${scope}/${id} to Markdown; semantic index write deferred: ${describeError3(error)}`
|
|
125509
|
+
);
|
|
125510
|
+
return deferredIndexOutcome();
|
|
125511
|
+
}
|
|
125206
125512
|
log155.info(`[memory] saved ${scope}/${id} [${kind}]: ${trimmed.slice(0, 60)}`);
|
|
125207
|
-
return { status: "saved" };
|
|
125513
|
+
return { status: "saved", indexed: true };
|
|
125208
125514
|
}
|
|
125209
125515
|
/**
|
|
125210
125516
|
* Exact-text match against today's and yesterday's daily files. Two days
|
|
@@ -125226,7 +125532,15 @@ var MemoryManager = class {
|
|
|
125226
125532
|
}
|
|
125227
125533
|
async search(scope, id, query, topK = 10) {
|
|
125228
125534
|
const indexDir = this.store.memoryIndexDir(scope, id);
|
|
125229
|
-
return
|
|
125535
|
+
if (!this.hasIndex(scope, id)) return this.searchLexical(scope, id, query, topK);
|
|
125536
|
+
try {
|
|
125537
|
+
return await searchIndex(indexDir, query, topK);
|
|
125538
|
+
} catch (error) {
|
|
125539
|
+
log155.warn(
|
|
125540
|
+
`[memory] semantic search failed for ${scope}/${id}; using lexical fallback: ${describeError3(error)}`
|
|
125541
|
+
);
|
|
125542
|
+
return this.searchLexical(scope, id, query, topK);
|
|
125543
|
+
}
|
|
125230
125544
|
}
|
|
125231
125545
|
/**
|
|
125232
125546
|
* Like {@link search} but with a precomputed query embedding — lets the
|
|
@@ -125255,11 +125569,64 @@ var MemoryManager = class {
|
|
|
125255
125569
|
return existsSync28(join103(this.store.memoryIndexDir(scope, id), "mem.db"));
|
|
125256
125570
|
}
|
|
125257
125571
|
async searchAll(gezelId, projectId, query, topK = 10) {
|
|
125258
|
-
|
|
125259
|
-
|
|
125260
|
-
|
|
125572
|
+
return (await this.searchAllDetailed(gezelId, projectId, query, topK)).results;
|
|
125573
|
+
}
|
|
125574
|
+
/**
|
|
125575
|
+
* Search both scopes with one query embedding. Missing indexes fall back to
|
|
125576
|
+
* the daily Markdown source; an unavailable/corrupt semantic cache does the
|
|
125577
|
+
* same and reports a degraded mode instead of turning an optional feature
|
|
125578
|
+
* into an HTTP 500.
|
|
125579
|
+
*/
|
|
125580
|
+
async searchAllDetailed(gezelId, projectId, query, topK = 10) {
|
|
125581
|
+
const gezelIndexed = this.hasIndex("gezel", gezelId);
|
|
125582
|
+
const projectIndexed = this.hasIndex("project", projectId);
|
|
125583
|
+
if (!gezelIndexed && !projectIndexed) {
|
|
125584
|
+
return {
|
|
125585
|
+
results: await this.searchAllLexical(gezelId, projectId, query, topK),
|
|
125586
|
+
mode: "lexical"
|
|
125587
|
+
};
|
|
125588
|
+
}
|
|
125589
|
+
try {
|
|
125590
|
+
const vector = await embedQuery(query);
|
|
125591
|
+
const [gezelResults, projectResults] = await Promise.all([
|
|
125592
|
+
gezelIndexed ? this.searchVector("gezel", gezelId, vector, topK) : this.searchLexical("gezel", gezelId, query, topK),
|
|
125593
|
+
projectIndexed ? this.searchVector("project", projectId, vector, topK) : this.searchLexical("project", projectId, query, topK)
|
|
125594
|
+
]);
|
|
125595
|
+
return {
|
|
125596
|
+
results: rankSearchResults([...gezelResults, ...projectResults], topK),
|
|
125597
|
+
mode: gezelIndexed && projectIndexed ? "semantic" : "hybrid"
|
|
125598
|
+
};
|
|
125599
|
+
} catch (error) {
|
|
125600
|
+
log155.warn(
|
|
125601
|
+
`[memory] semantic search unavailable; using daily-memory lexical fallback: ${describeError3(error)}`
|
|
125602
|
+
);
|
|
125603
|
+
return {
|
|
125604
|
+
results: await this.searchAllLexical(gezelId, projectId, query, topK),
|
|
125605
|
+
mode: "lexical",
|
|
125606
|
+
degraded: {
|
|
125607
|
+
code: "semantic_search_unavailable",
|
|
125608
|
+
message: "Semantic memory search is temporarily unavailable; searched saved memory text directly instead."
|
|
125609
|
+
}
|
|
125610
|
+
};
|
|
125611
|
+
}
|
|
125612
|
+
}
|
|
125613
|
+
async searchAllLexical(gezelId, projectId, query, topK) {
|
|
125614
|
+
const [gezelResults, projectResults] = await Promise.all([
|
|
125615
|
+
this.searchLexical("gezel", gezelId, query, topK),
|
|
125616
|
+
this.searchLexical("project", projectId, query, topK)
|
|
125261
125617
|
]);
|
|
125262
|
-
return [...
|
|
125618
|
+
return rankSearchResults([...gezelResults, ...projectResults], topK);
|
|
125619
|
+
}
|
|
125620
|
+
async searchLexical(scope, id, query, topK) {
|
|
125621
|
+
const entries = await this.allEntries(scope, id);
|
|
125622
|
+
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 }) => ({
|
|
125623
|
+
text: entry.text,
|
|
125624
|
+
score,
|
|
125625
|
+
day: entry.day,
|
|
125626
|
+
scope: entry.scope,
|
|
125627
|
+
id: entry.id,
|
|
125628
|
+
kind: entry.kind ?? DEFAULT_MEMORY_KIND
|
|
125629
|
+
}));
|
|
125263
125630
|
}
|
|
125264
125631
|
async listDays(scope, id) {
|
|
125265
125632
|
return this.store.listMemoryDays(scope, id);
|
|
@@ -125324,6 +125691,36 @@ var MemoryManager = class {
|
|
|
125324
125691
|
return entries.length;
|
|
125325
125692
|
}
|
|
125326
125693
|
};
|
|
125694
|
+
function rankSearchResults(results, topK) {
|
|
125695
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
125696
|
+
}
|
|
125697
|
+
function deferredIndexOutcome() {
|
|
125698
|
+
return {
|
|
125699
|
+
status: "saved",
|
|
125700
|
+
indexed: false,
|
|
125701
|
+
degraded: {
|
|
125702
|
+
code: "semantic_index_unavailable",
|
|
125703
|
+
message: "Memory was saved, but semantic indexing is temporarily unavailable."
|
|
125704
|
+
}
|
|
125705
|
+
};
|
|
125706
|
+
}
|
|
125707
|
+
function lexicalScore(query, text) {
|
|
125708
|
+
const normalizedQuery = query.trim().toLocaleLowerCase();
|
|
125709
|
+
const normalizedText = text.toLocaleLowerCase();
|
|
125710
|
+
if (!normalizedQuery || !normalizedText) return 0;
|
|
125711
|
+
if (normalizedText.includes(normalizedQuery)) return 1;
|
|
125712
|
+
const queryTokens = new Set(normalizedQuery.match(/[\p{L}\p{N}_-]+/gu) ?? []);
|
|
125713
|
+
if (queryTokens.size === 0) return 0;
|
|
125714
|
+
const textTokens = new Set(normalizedText.match(/[\p{L}\p{N}_-]+/gu) ?? []);
|
|
125715
|
+
let matches = 0;
|
|
125716
|
+
for (const token of queryTokens) {
|
|
125717
|
+
if (textTokens.has(token)) matches++;
|
|
125718
|
+
}
|
|
125719
|
+
return matches / queryTokens.size;
|
|
125720
|
+
}
|
|
125721
|
+
function describeError3(error) {
|
|
125722
|
+
return error instanceof Error ? error.message : String(error);
|
|
125723
|
+
}
|
|
125327
125724
|
|
|
125328
125725
|
// src/models/install-jobs.ts
|
|
125329
125726
|
import { createLogger as createLogger166 } from "@bendyline/gezel";
|
|
@@ -128732,7 +129129,7 @@ var VideoModelManager = class {
|
|
|
128732
129129
|
await rm43(finalPath, { force: true });
|
|
128733
129130
|
await rename17(partialPath, finalPath);
|
|
128734
129131
|
} catch (err) {
|
|
128735
|
-
yield { type: "error", error: `rename failed for ${file.name}: ${
|
|
129132
|
+
yield { type: "error", error: `rename failed for ${file.name}: ${describeError4(err)}` };
|
|
128736
129133
|
return;
|
|
128737
129134
|
}
|
|
128738
129135
|
}
|
|
@@ -128891,7 +129288,7 @@ var VideoModelSelector = class {
|
|
|
128891
129288
|
return (id ? await this.models.resolveModel(id) : null) ?? await this.models.resolveDefaultModel();
|
|
128892
129289
|
}
|
|
128893
129290
|
};
|
|
128894
|
-
function
|
|
129291
|
+
function describeError4(err) {
|
|
128895
129292
|
return err instanceof Error ? err.message : String(err);
|
|
128896
129293
|
}
|
|
128897
129294
|
function isSafeId3(id) {
|
|
@@ -133222,6 +133619,7 @@ var TaskRunner = class {
|
|
|
133222
133619
|
...handoff.fromGezelName ? { fromGezelName: handoff.fromGezelName } : {},
|
|
133223
133620
|
...handoff.fromGezelId ? { fromGezelId: handoff.fromGezelId } : {},
|
|
133224
133621
|
...handoff.kind ? { kind: handoff.kind } : {},
|
|
133622
|
+
...task.roleBasedNameOnlyMode !== void 0 ? { roleBasedNameOnlyMode: task.roleBasedNameOnlyMode } : {},
|
|
133225
133623
|
lane,
|
|
133226
133624
|
...isNight ? { ambient: true } : {},
|
|
133227
133625
|
...isNight ? { nightShift: true } : {},
|
|
@@ -133735,6 +134133,10 @@ Step "${step.name}" (\`${step.id}\`) was re-driven ${maxRedrives}\xD7 without pr
|
|
|
133735
134133
|
} catch {
|
|
133736
134134
|
}
|
|
133737
134135
|
const activeTasks = projectTasks.filter((t) => t.status === "active");
|
|
134136
|
+
if (projectTasks.length === 0) {
|
|
134137
|
+
trace("skip \u2014 project has no tasks to advance");
|
|
134138
|
+
return;
|
|
134139
|
+
}
|
|
133738
134140
|
if (projectTasks.length > 0 && activeTasks.length === 0) {
|
|
133739
134141
|
if (projectTasks.some((t) => t.status === "draft")) {
|
|
133740
134142
|
trace("skip \u2014 only draft task(s) await activation; not nudging or stabilizing");
|
|
@@ -137476,7 +137878,7 @@ Address these, then the gate re-checks automatically.`,
|
|
|
137476
137878
|
try {
|
|
137477
137879
|
const existing = await tasks.listChildren(task.ref).catch(() => []);
|
|
137478
137880
|
if (existing.length === 0) {
|
|
137479
|
-
const raw = await store.readProjectWorkspaceFile(projectId, spawn14.overFile).catch(() => null);
|
|
137881
|
+
const raw = await (spawn14.overArtifact ? store.readProjectArtifact(projectId, spawn14.overFile) : store.readProjectWorkspaceFile(projectId, spawn14.overFile)).catch(() => null);
|
|
137480
137882
|
const items = raw ? extractSpawnItems(raw, spawn14.itemsPath) : [];
|
|
137481
137883
|
if (items.length === 0) {
|
|
137482
137884
|
log188.warn(
|
|
@@ -137505,7 +137907,7 @@ Address these, then the gate re-checks automatically.`,
|
|
|
137505
137907
|
|
|
137506
137908
|
${kids.map((k) => `- ${k.ref}: ${k.title}`).join("\n")}
|
|
137507
137909
|
`;
|
|
137508
|
-
await store.writeProjectWorkspaceFile(projectId, advanceFile, manifest).catch((err) => log188.warn(`[fanout] ${task.ref}: could not write ${advanceFile}:`, err));
|
|
137910
|
+
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));
|
|
137509
137911
|
}
|
|
137510
137912
|
const nextStep = newStep.advanceWhen?.goto ?? newStep.next;
|
|
137511
137913
|
if (nextStep) {
|