chapterhouse 0.9.2 → 0.10.0
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/README.md +1 -1
- package/dist/api/auth.js +11 -1
- package/dist/api/auth.test.js +29 -0
- package/dist/api/errors.js +23 -0
- package/dist/api/route-coverage.test.js +61 -21
- package/dist/api/routes/agents.js +472 -0
- package/dist/api/routes/memory.js +299 -0
- package/dist/api/routes/projects.js +170 -0
- package/dist/api/routes/sessions.js +347 -0
- package/dist/api/routes/system.js +82 -0
- package/dist/api/routes/wiki.js +455 -0
- package/dist/api/routes/wiki.test.js +49 -0
- package/dist/api/send-json.js +16 -0
- package/dist/api/send-json.test.js +18 -0
- package/dist/api/server-runtime.js +45 -3
- package/dist/api/server.js +34 -1764
- package/dist/api/server.test.js +239 -8
- package/dist/api/sse-hub.js +37 -0
- package/dist/cli.js +1 -1
- package/dist/config.js +151 -58
- package/dist/config.test.js +29 -0
- package/dist/copilot/okr-mapper.js +2 -11
- package/dist/copilot/orchestrator.js +358 -352
- package/dist/copilot/orchestrator.test.js +139 -4
- package/dist/copilot/prompt-date.js +2 -1
- package/dist/copilot/session-manager.js +25 -23
- package/dist/copilot/session-manager.test.js +35 -1
- package/dist/copilot/standup.js +2 -2
- package/dist/copilot/task-event-log.js +7 -1
- package/dist/copilot/task-event-log.test.js +13 -0
- package/dist/copilot/tools/agent.js +608 -0
- package/dist/copilot/tools/index.js +19 -0
- package/dist/copilot/tools/memory.js +678 -0
- package/dist/copilot/tools/models.js +2 -0
- package/dist/copilot/tools/okr.js +171 -0
- package/dist/copilot/tools/wiki.js +333 -0
- package/dist/copilot/tools-deps.js +4 -0
- package/dist/copilot/tools.agent.test.js +10 -8
- package/dist/copilot/tools.inventory.test.js +76 -0
- package/dist/copilot/tools.js +1 -1780
- package/dist/copilot/tools.okr.test.js +31 -0
- package/dist/copilot/tools.wiki.test.js +6 -3
- package/dist/copilot/turn-event-log.js +31 -4
- package/dist/copilot/turn-event-log.test.js +24 -2
- package/dist/copilot/workiq-installer.test.js +2 -2
- package/dist/daemon-install.js +3 -2
- package/dist/daemon.js +9 -17
- package/dist/integrations/ado-client.js +90 -9
- package/dist/integrations/ado-client.test.js +56 -0
- package/dist/integrations/team-push.js +1 -0
- package/dist/integrations/team-push.test.js +6 -0
- package/dist/integrations/teams-notify.js +1 -0
- package/dist/integrations/teams-notify.test.js +5 -0
- package/dist/memory/active-scope.test.js +0 -1
- package/dist/memory/checkpoint.js +89 -72
- package/dist/memory/checkpoint.test.js +23 -3
- package/dist/memory/eot.js +87 -85
- package/dist/memory/eot.test.js +71 -3
- package/dist/memory/hooks.js +2 -4
- package/dist/memory/housekeeping-scheduler.js +1 -1
- package/dist/memory/housekeeping-scheduler.test.js +1 -2
- package/dist/memory/housekeeping.js +100 -3
- package/dist/memory/housekeeping.test.js +33 -2
- package/dist/memory/reflect.test.js +2 -0
- package/dist/memory/scope-lock.js +26 -0
- package/dist/memory/scope-lock.test.js +118 -0
- package/dist/memory/scopes.test.js +0 -1
- package/dist/mode-context.js +58 -5
- package/dist/mode-context.test.js +68 -0
- package/dist/paths.js +1 -0
- package/dist/setup.js +3 -2
- package/dist/shared/api-schemas.js +48 -5
- package/dist/store/connection.js +96 -0
- package/dist/store/db.js +5 -1498
- package/dist/store/db.test.js +182 -1
- package/dist/store/migrations.js +460 -0
- package/dist/store/repositories/memory.js +281 -0
- package/dist/store/repositories/okr.js +3 -0
- package/dist/store/repositories/projects.js +5 -0
- package/dist/store/repositories/sessions.js +284 -0
- package/dist/store/repositories/wiki.js +60 -0
- package/dist/store/schema.js +501 -0
- package/dist/util/logger.js +3 -2
- package/dist/wiki/consolidation.js +50 -9
- package/dist/wiki/consolidation.test.js +45 -0
- package/dist/wiki/frontmatter.js +43 -13
- package/dist/wiki/frontmatter.test.js +24 -0
- package/dist/wiki/fs.js +16 -4
- package/dist/wiki/fs.test.js +84 -0
- package/dist/wiki/index-manager.js +30 -2
- package/dist/wiki/index-manager.test.js +43 -12
- package/dist/wiki/ingest.js +1 -1
- package/dist/wiki/lock.js +11 -1
- package/dist/wiki/log-manager.js +2 -7
- package/dist/wiki/migrate.js +44 -17
- package/dist/wiki/project-registry.js +10 -5
- package/dist/wiki/project-registry.test.js +14 -0
- package/dist/wiki/scheduler.js +1 -1
- package/dist/wiki/seed-team-wiki.js +2 -1
- package/dist/wiki/team-sync.js +31 -6
- package/dist/wiki/team-sync.test.js +81 -0
- package/package.json +1 -1
- package/web/dist/assets/WikiEdit-BZXAdarz.js +30 -0
- package/web/dist/assets/WikiEdit-BZXAdarz.js.map +1 -0
- package/web/dist/assets/WikiGraph-KrCYco4v.js +2 -0
- package/web/dist/assets/WikiGraph-KrCYco4v.js.map +1 -0
- package/web/dist/assets/index-CUm2Wbuh.js +250 -0
- package/web/dist/assets/index-CUm2Wbuh.js.map +1 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-iQrv3lQN.js +0 -286
- package/web/dist/assets/index-iQrv3lQN.js.map +0 -1
package/dist/config.js
CHANGED
|
@@ -18,6 +18,8 @@ function loadRuntimeEnv() {
|
|
|
18
18
|
loadRuntimeEnv();
|
|
19
19
|
const configSchema = z.object({
|
|
20
20
|
NODE_ENV: z.string().optional(),
|
|
21
|
+
PATH: z.string().optional(),
|
|
22
|
+
CHAPTERHOUSE_DISABLE_DOTENV: z.string().optional(),
|
|
21
23
|
CHAPTERHOUSE_MODE: z.string().optional(),
|
|
22
24
|
API_HOST: z.string().optional(),
|
|
23
25
|
API_PORT: z.string().optional(),
|
|
@@ -34,6 +36,7 @@ const configSchema = z.object({
|
|
|
34
36
|
ENTRA_AUTH_ENABLED: z.string().optional(),
|
|
35
37
|
CORS_ALLOWED_ORIGINS: z.string().optional(),
|
|
36
38
|
API_TOKEN: z.string().optional(),
|
|
39
|
+
LOG_LEVEL: z.string().optional(),
|
|
37
40
|
TEAM_CHAPTERHOUSE_URL: z.string().optional(),
|
|
38
41
|
TEAM_CHAPTERHOUSE_TOKEN: z.string().optional(),
|
|
39
42
|
TEAM_WIKI_CACHE_TTL_MINUTES: z.string().optional(),
|
|
@@ -43,6 +46,7 @@ const configSchema = z.object({
|
|
|
43
46
|
TEAMS_NOTIFICATIONS_ENABLED: z.string().optional(),
|
|
44
47
|
COPILOT_TOKEN: z.string().optional(),
|
|
45
48
|
GITHUB_TOKEN: z.string().optional(),
|
|
49
|
+
TELEGRAM_BOT_TOKEN: z.string().optional(),
|
|
46
50
|
API_RATE_LIMIT_WINDOW_MS: z.string().optional(),
|
|
47
51
|
API_RATE_LIMIT_GENERAL_MAX: z.string().optional(),
|
|
48
52
|
API_RATE_LIMIT_AUTH_MAX: z.string().optional(),
|
|
@@ -50,7 +54,20 @@ const configSchema = z.object({
|
|
|
50
54
|
CHAPTERHOUSE_SSE_BUFFER_CAPACITY: z.string().optional(),
|
|
51
55
|
CHAPTERHOUSE_SSE_REPLAY_LIMIT: z.string().optional(),
|
|
52
56
|
CHAPTERHOUSE_WORKIQ_AUTO_INSTALL: z.string().optional(),
|
|
57
|
+
CHAPTERHOUSE_SELF_EDIT: z.string().optional(),
|
|
58
|
+
CHAPTERHOUSE_OPEN_BROWSER: z.string().optional(),
|
|
59
|
+
CHAPTERHOUSE_RESTARTED: z.string().optional(),
|
|
60
|
+
CHAPTERHOUSE_SHUTDOWN_TIMEOUT_MS: z.string().optional(),
|
|
53
61
|
CHAPTERHOUSE_CHAT_SSE: z.string().optional(),
|
|
62
|
+
CHAPTERHOUSE_INJECT_DATE: z.string().optional(),
|
|
63
|
+
CHAPTERHOUSE_SESSION_AGENT_NAME: z.string().optional(),
|
|
64
|
+
CHAPTERHOUSE_AGENT_NAME: z.string().optional(),
|
|
65
|
+
COPILOT_AGENT_NAME: z.string().optional(),
|
|
66
|
+
AGENT_NAME: z.string().optional(),
|
|
67
|
+
CHAPTERHOUSE_SESSION_IDLE_TTL_MS: z.string().optional(),
|
|
68
|
+
CHAPTERHOUSE_SESSION_MAX_ACTIVE: z.string().optional(),
|
|
69
|
+
CHAPTERHOUSE_ORCHESTRATOR_TIMEOUT_MS: z.string().optional(),
|
|
70
|
+
CHAPTERHOUSE_JSON_LIMIT: z.string().optional(),
|
|
54
71
|
CHAPTERHOUSE_MEMORY_CHECKPOINT_ENABLED: z.string().optional(),
|
|
55
72
|
CHAPTERHOUSE_MEMORY_CHECKPOINT_TURNS: z.string().optional(),
|
|
56
73
|
CHAPTERHOUSE_MEMORY_CHECKPOINT_ON_SCOPE_CHANGE: z.string().optional(),
|
|
@@ -58,9 +75,12 @@ const configSchema = z.object({
|
|
|
58
75
|
CHAPTERHOUSE_MEMORY_INJECT: z.string().optional(),
|
|
59
76
|
CHAPTERHOUSE_MEMORY_AUTO_ACCEPT: z.string().optional(),
|
|
60
77
|
CHAPTERHOUSE_MEMORY_EOT_HOOK_ENABLED: z.string().optional(),
|
|
78
|
+
CHAPTERHOUSE_MEMORY_EOT_FRICTION_ENABLED: z.string().optional(),
|
|
61
79
|
CHAPTERHOUSE_MEMORY_HOOKS_ENABLED: z.string().optional(),
|
|
62
80
|
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_ENABLED: z.string().optional(),
|
|
63
81
|
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_TURNS: z.string().optional(),
|
|
82
|
+
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD: z.string().optional(),
|
|
83
|
+
CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD: z.string().optional(),
|
|
64
84
|
CHAPTERHOUSE_MEMORY_DECAY_DAYS: z.string().optional(),
|
|
65
85
|
CHAPTERHOUSE_MEMORY_INBOX_RETENTION_DAYS: z.string().optional(),
|
|
66
86
|
CHAPTERHOUSE_MEMORY_TIERING_ENABLED: z.string().optional(),
|
|
@@ -68,6 +88,7 @@ const configSchema = z.object({
|
|
|
68
88
|
CHAPTERHOUSE_MEMORY_HOT_AGE_DAYS: z.string().optional(),
|
|
69
89
|
CHAPTERHOUSE_PKB_CONSOLIDATION_ENABLED: z.string().optional(),
|
|
70
90
|
CHAPTERHOUSE_PKB_CONSOLIDATION_HOUR: z.string().optional(),
|
|
91
|
+
CHAPTERHOUSE_PKB_TRUTH_REWRITE_BUDGET: z.string().optional(),
|
|
71
92
|
});
|
|
72
93
|
export const DEFAULT_MODEL = "claude-sonnet-4.6";
|
|
73
94
|
export const DEFAULT_TEAM_WIKI_CACHE_TTL_MINUTES = 60;
|
|
@@ -82,13 +103,18 @@ export const DEFAULT_API_RATE_LIMIT_AUTH_MAX = 10;
|
|
|
82
103
|
export const DEFAULT_API_RATE_LIMIT_SSE_MAX_CONNECTIONS = 5;
|
|
83
104
|
export const DEFAULT_SSE_BUFFER_CAPACITY = 2_000;
|
|
84
105
|
export const DEFAULT_SSE_REPLAY_LIMIT = 10_000;
|
|
106
|
+
export const DEFAULT_JSON_BODY_LIMIT = "2mb";
|
|
107
|
+
export const DEFAULT_PKB_TRUTH_REWRITE_BUDGET = 18;
|
|
85
108
|
function parseZeroOneEnv(name, rawValue, defaultValue) {
|
|
86
109
|
const normalized = rawValue?.trim();
|
|
87
110
|
if (!normalized) {
|
|
88
111
|
return defaultValue;
|
|
89
112
|
}
|
|
113
|
+
if (normalized === "true" || normalized === "false") {
|
|
114
|
+
return normalized === "true";
|
|
115
|
+
}
|
|
90
116
|
if (normalized !== "0" && normalized !== "1") {
|
|
91
|
-
throw new Error(`${name} must be '0' or '
|
|
117
|
+
throw new Error(`${name} must be '0', '1', 'true', or 'false', got: "${rawValue}"`);
|
|
92
118
|
}
|
|
93
119
|
return normalized === "1";
|
|
94
120
|
}
|
|
@@ -143,6 +169,17 @@ function parsePositiveNumberEnv(name, rawValue, defaultValue) {
|
|
|
143
169
|
}
|
|
144
170
|
return parsed;
|
|
145
171
|
}
|
|
172
|
+
function parseUnitIntervalEnv(name, rawValue, defaultValue) {
|
|
173
|
+
const normalized = rawValue?.trim();
|
|
174
|
+
if (!normalized) {
|
|
175
|
+
return defaultValue;
|
|
176
|
+
}
|
|
177
|
+
const parsed = Number(normalized);
|
|
178
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
|
|
179
|
+
throw new Error(`${name} must be a number between 0 and 1, got: "${rawValue}"`);
|
|
180
|
+
}
|
|
181
|
+
return parsed;
|
|
182
|
+
}
|
|
146
183
|
function parseHourEnv(name, rawValue, defaultValue) {
|
|
147
184
|
const normalized = rawValue?.trim();
|
|
148
185
|
if (!normalized) {
|
|
@@ -308,12 +345,20 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
308
345
|
const memoryCheckpointTurns = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_CHECKPOINT_TURNS", raw.CHAPTERHOUSE_MEMORY_CHECKPOINT_TURNS, 5);
|
|
309
346
|
const memoryCheckpointMinTurnsForScopeFire = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_CHECKPOINT_MIN_TURNS_FOR_SCOPE_FIRE", raw.CHAPTERHOUSE_MEMORY_CHECKPOINT_MIN_TURNS_FOR_SCOPE_FIRE, 2);
|
|
310
347
|
const memoryHousekeepingTurns = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_HOUSEKEEPING_TURNS", raw.CHAPTERHOUSE_MEMORY_HOUSEKEEPING_TURNS, 50);
|
|
348
|
+
const memoryHousekeepingSimilarityThreshold = parseUnitIntervalEnv("CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD", raw.CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD, 0.8);
|
|
349
|
+
const memoryCheckpointDuplicateThreshold = parseUnitIntervalEnv("CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD", raw.CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD, 0.85);
|
|
311
350
|
const memoryDecayDays = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_DECAY_DAYS", raw.CHAPTERHOUSE_MEMORY_DECAY_DAYS, 30);
|
|
312
351
|
const memoryInboxRetentionDays = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_INBOX_RETENTION_DAYS", raw.CHAPTERHOUSE_MEMORY_INBOX_RETENTION_DAYS, 7);
|
|
313
352
|
const memoryHotRecallBoost = parsePositiveNumberEnv("CHAPTERHOUSE_MEMORY_HOT_RECALL_BOOST", raw.CHAPTERHOUSE_MEMORY_HOT_RECALL_BOOST, 1.5);
|
|
314
353
|
const memoryHotAgeDays = parsePositiveIntegerEnv("CHAPTERHOUSE_MEMORY_HOT_AGE_DAYS", raw.CHAPTERHOUSE_MEMORY_HOT_AGE_DAYS, 30);
|
|
315
354
|
const pkbConsolidationEnabled = parseBooleanEnv("CHAPTERHOUSE_PKB_CONSOLIDATION_ENABLED", raw.CHAPTERHOUSE_PKB_CONSOLIDATION_ENABLED, true);
|
|
316
355
|
const pkbConsolidationHour = parseHourEnv("CHAPTERHOUSE_PKB_CONSOLIDATION_HOUR", raw.CHAPTERHOUSE_PKB_CONSOLIDATION_HOUR, 3);
|
|
356
|
+
const jsonBodyLimit = raw.CHAPTERHOUSE_JSON_LIMIT?.trim() || DEFAULT_JSON_BODY_LIMIT;
|
|
357
|
+
const shutdownTimeoutMs = parsePositiveIntegerEnv("CHAPTERHOUSE_SHUTDOWN_TIMEOUT_MS", raw.CHAPTERHOUSE_SHUTDOWN_TIMEOUT_MS, 60_000);
|
|
358
|
+
const sessionIdleTtlMs = parsePositiveIntegerEnv("CHAPTERHOUSE_SESSION_IDLE_TTL_MS", raw.CHAPTERHOUSE_SESSION_IDLE_TTL_MS, 1_800_000);
|
|
359
|
+
const sessionMaxActive = parsePositiveIntegerEnv("CHAPTERHOUSE_SESSION_MAX_ACTIVE", raw.CHAPTERHOUSE_SESSION_MAX_ACTIVE, 20);
|
|
360
|
+
const orchestratorTimeoutMs = parsePositiveIntegerEnv("CHAPTERHOUSE_ORCHESTRATOR_TIMEOUT_MS", raw.CHAPTERHOUSE_ORCHESTRATOR_TIMEOUT_MS, 1_800_000);
|
|
361
|
+
const pkbTruthRewriteBudget = parsePositiveIntegerEnv("CHAPTERHOUSE_PKB_TRUTH_REWRITE_BUDGET", raw.CHAPTERHOUSE_PKB_TRUTH_REWRITE_BUDGET, DEFAULT_PKB_TRUTH_REWRITE_BUDGET);
|
|
317
362
|
if (effectiveEntraAuthEnabled && (!effectiveEntraTenantId || !effectiveEntraClientId)) {
|
|
318
363
|
throw new Error("ENTRA_AUTH_ENABLED=true requires ENTRA_TENANT_ID and ENTRA_CLIENT_ID");
|
|
319
364
|
}
|
|
@@ -323,7 +368,9 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
323
368
|
return {
|
|
324
369
|
nodeEnv,
|
|
325
370
|
isProduction,
|
|
371
|
+
disableDotenv: raw.CHAPTERHOUSE_DISABLE_DOTENV === "1",
|
|
326
372
|
chapterhouseMode: parsedMode,
|
|
373
|
+
explicitChapterhouseMode: raw.CHAPTERHOUSE_MODE?.trim() || "",
|
|
327
374
|
apiHost: parsedHost,
|
|
328
375
|
apiPort: parsedPort,
|
|
329
376
|
standupTime: parsedStandupTime,
|
|
@@ -332,16 +379,18 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
332
379
|
adoProject: raw.ADO_PROJECT?.trim() || DEFAULT_ADO_PROJECT,
|
|
333
380
|
adoPat: raw.ADO_PAT?.trim() || "",
|
|
334
381
|
workerTimeoutMs: parsedWorkerTimeout,
|
|
382
|
+
shellPath: raw.PATH?.trim() || "",
|
|
335
383
|
entraTenantId: effectiveEntraTenantId,
|
|
336
384
|
entraClientId: effectiveEntraClientId,
|
|
337
385
|
entraRequiredRole: effectiveEntraRequiredRole,
|
|
338
386
|
entraTeamLeadId: effectiveEntraTeamLeadId,
|
|
339
387
|
entraAuthEnabled: effectiveEntraAuthEnabled,
|
|
388
|
+
apiToken,
|
|
340
389
|
standaloneMode,
|
|
341
390
|
corsAllowedOrigins: parseCorsAllowedOrigins(raw.CORS_ALLOWED_ORIGINS),
|
|
342
391
|
copilotModel: raw.COPILOT_MODEL || DEFAULT_MODEL,
|
|
343
392
|
copilotAuthToken: raw.COPILOT_TOKEN?.trim() || raw.GITHUB_TOKEN?.trim() || "",
|
|
344
|
-
selfEditEnabled:
|
|
393
|
+
selfEditEnabled: raw.CHAPTERHOUSE_SELF_EDIT === "1",
|
|
345
394
|
teamChapterhouseUrl: parseOptionalUrl("TEAM_CHAPTERHOUSE_URL", raw.TEAM_CHAPTERHOUSE_URL),
|
|
346
395
|
teamChapterhouseToken: raw.TEAM_CHAPTERHOUSE_TOKEN?.trim() || "",
|
|
347
396
|
teamWikiCacheTtlMinutes: parsedTeamWikiCacheTtlMinutes,
|
|
@@ -356,7 +405,23 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
356
405
|
sseBufferCapacity,
|
|
357
406
|
sseReplayLimit,
|
|
358
407
|
workiqAutoInstall: parseBooleanEnv("CHAPTERHOUSE_WORKIQ_AUTO_INSTALL", raw.CHAPTERHOUSE_WORKIQ_AUTO_INSTALL, true),
|
|
408
|
+
logLevel: raw.LOG_LEVEL?.trim() || undefined,
|
|
409
|
+
shutdownTimeoutMs,
|
|
410
|
+
telegramBotTokenConfigured: Boolean(raw.TELEGRAM_BOT_TOKEN?.trim()),
|
|
411
|
+
openBrowserOnStart: raw.CHAPTERHOUSE_OPEN_BROWSER === "1",
|
|
412
|
+
restarted: raw.CHAPTERHOUSE_RESTARTED === "1",
|
|
413
|
+
injectDate: raw.CHAPTERHOUSE_INJECT_DATE !== "0",
|
|
414
|
+
agentNameCandidates: [
|
|
415
|
+
raw.CHAPTERHOUSE_SESSION_AGENT_NAME,
|
|
416
|
+
raw.CHAPTERHOUSE_AGENT_NAME,
|
|
417
|
+
raw.COPILOT_AGENT_NAME,
|
|
418
|
+
raw.AGENT_NAME,
|
|
419
|
+
].map((value) => value?.trim() || "").filter(Boolean),
|
|
420
|
+
sessionIdleTtlMs,
|
|
421
|
+
sessionMaxActive,
|
|
422
|
+
orchestratorTimeoutMs,
|
|
359
423
|
chatSseEnabled: parseZeroOneEnv("CHAPTERHOUSE_CHAT_SSE", raw.CHAPTERHOUSE_CHAT_SSE, true),
|
|
424
|
+
jsonBodyLimit,
|
|
360
425
|
memoryCheckpointEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_CHECKPOINT_ENABLED", raw.CHAPTERHOUSE_MEMORY_CHECKPOINT_ENABLED, true),
|
|
361
426
|
memoryCheckpointTurns,
|
|
362
427
|
memoryCheckpointOnScopeChange: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_CHECKPOINT_ON_SCOPE_CHANGE", raw.CHAPTERHOUSE_MEMORY_CHECKPOINT_ON_SCOPE_CHANGE, true),
|
|
@@ -364,9 +429,12 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
364
429
|
memoryInjectEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_INJECT", raw.CHAPTERHOUSE_MEMORY_INJECT, true),
|
|
365
430
|
memoryAutoAcceptEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_AUTO_ACCEPT", raw.CHAPTERHOUSE_MEMORY_AUTO_ACCEPT, true),
|
|
366
431
|
memoryEndOfTaskHookEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_EOT_HOOK_ENABLED", raw.CHAPTERHOUSE_MEMORY_EOT_HOOK_ENABLED, true),
|
|
432
|
+
memoryEndOfTaskFrictionEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_EOT_FRICTION_ENABLED", raw.CHAPTERHOUSE_MEMORY_EOT_FRICTION_ENABLED, false),
|
|
367
433
|
memoryHooksEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_HOOKS_ENABLED", raw.CHAPTERHOUSE_MEMORY_HOOKS_ENABLED, true),
|
|
368
434
|
memoryHousekeepingEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_HOUSEKEEPING_ENABLED", raw.CHAPTERHOUSE_MEMORY_HOUSEKEEPING_ENABLED, true),
|
|
369
435
|
memoryHousekeepingTurns,
|
|
436
|
+
memoryHousekeepingSimilarityThreshold,
|
|
437
|
+
memoryCheckpointDuplicateThreshold,
|
|
370
438
|
memoryDecayDays,
|
|
371
439
|
memoryInboxRetentionDays,
|
|
372
440
|
memoryTieringEnabled: parseZeroOneEnv("CHAPTERHOUSE_MEMORY_TIERING_ENABLED", raw.CHAPTERHOUSE_MEMORY_TIERING_ENABLED, true),
|
|
@@ -374,75 +442,100 @@ export function parseRuntimeConfig(env, options = {}) {
|
|
|
374
442
|
memoryHotAgeDays,
|
|
375
443
|
pkbConsolidationEnabled,
|
|
376
444
|
pkbConsolidationHour,
|
|
445
|
+
pkbTruthRewriteBudget,
|
|
377
446
|
modeCompatibilityWarnings,
|
|
378
447
|
};
|
|
379
448
|
}
|
|
380
449
|
const runtimeConfig = parseRuntimeConfig(process.env);
|
|
381
450
|
let _copilotModel = runtimeConfig.copilotModel;
|
|
451
|
+
let _adoPatOverride;
|
|
452
|
+
function currentRuntimeConfig() {
|
|
453
|
+
return parseRuntimeConfig(process.env);
|
|
454
|
+
}
|
|
382
455
|
export const config = {
|
|
383
|
-
nodeEnv
|
|
384
|
-
isProduction
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
456
|
+
get nodeEnv() { return currentRuntimeConfig().nodeEnv; },
|
|
457
|
+
get isProduction() { return currentRuntimeConfig().isProduction; },
|
|
458
|
+
get disableDotenv() { return currentRuntimeConfig().disableDotenv; },
|
|
459
|
+
get chapterhouseMode() { return currentRuntimeConfig().chapterhouseMode; },
|
|
460
|
+
get explicitChapterhouseMode() { return currentRuntimeConfig().explicitChapterhouseMode; },
|
|
461
|
+
get apiHost() { return currentRuntimeConfig().apiHost; },
|
|
462
|
+
get apiPort() { return currentRuntimeConfig().apiPort; },
|
|
463
|
+
get standupTime() { return currentRuntimeConfig().standupTime; },
|
|
464
|
+
get adoOrg() { return currentRuntimeConfig().adoOrg; },
|
|
465
|
+
get adoProject() { return currentRuntimeConfig().adoProject; },
|
|
466
|
+
get adoPat() { return _adoPatOverride ?? currentRuntimeConfig().adoPat; },
|
|
467
|
+
set adoPat(value) { _adoPatOverride = value; },
|
|
392
468
|
get ADO_ORG() {
|
|
393
|
-
return
|
|
469
|
+
return currentRuntimeConfig().adoOrg;
|
|
394
470
|
},
|
|
395
471
|
get ADO_PROJECT() {
|
|
396
|
-
return
|
|
472
|
+
return currentRuntimeConfig().adoProject;
|
|
397
473
|
},
|
|
398
|
-
workerTimeoutMs
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
474
|
+
get workerTimeoutMs() { return currentRuntimeConfig().workerTimeoutMs; },
|
|
475
|
+
get shellPath() { return currentRuntimeConfig().shellPath; },
|
|
476
|
+
get entraTenantId() { return currentRuntimeConfig().entraTenantId; },
|
|
477
|
+
get entraClientId() { return currentRuntimeConfig().entraClientId; },
|
|
478
|
+
get entraRequiredRole() { return currentRuntimeConfig().entraRequiredRole; },
|
|
479
|
+
get entraTeamLeadId() { return currentRuntimeConfig().entraTeamLeadId; },
|
|
480
|
+
get entraAuthEnabled() { return currentRuntimeConfig().entraAuthEnabled; },
|
|
481
|
+
get apiToken() { return currentRuntimeConfig().apiToken; },
|
|
482
|
+
get standaloneMode() { return currentRuntimeConfig().standaloneMode; },
|
|
483
|
+
get corsAllowedOrigins() { return currentRuntimeConfig().corsAllowedOrigins; },
|
|
484
|
+
get teamChapterhouseUrl() { return currentRuntimeConfig().teamChapterhouseUrl; },
|
|
485
|
+
get teamChapterhouseToken() { return currentRuntimeConfig().teamChapterhouseToken; },
|
|
486
|
+
get teamWikiCacheTtlMinutes() { return currentRuntimeConfig().teamWikiCacheTtlMinutes; },
|
|
487
|
+
get teamWikiPaths() { return currentRuntimeConfig().teamWikiPaths; },
|
|
488
|
+
get wikiEntityCategories() { return currentRuntimeConfig().wikiEntityCategories; },
|
|
489
|
+
get teamsWebhookUrl() { return currentRuntimeConfig().teamsWebhookUrl; },
|
|
490
|
+
get teamsNotificationsEnabled() { return currentRuntimeConfig().teamsNotificationsEnabled; },
|
|
491
|
+
get apiRateLimitWindowMs() { return currentRuntimeConfig().apiRateLimitWindowMs; },
|
|
492
|
+
get apiRateLimitGeneralMax() { return currentRuntimeConfig().apiRateLimitGeneralMax; },
|
|
493
|
+
get apiRateLimitAuthMax() { return currentRuntimeConfig().apiRateLimitAuthMax; },
|
|
494
|
+
get apiRateLimitSseMaxConnections() { return currentRuntimeConfig().apiRateLimitSseMaxConnections; },
|
|
495
|
+
get sseBufferCapacity() { return currentRuntimeConfig().sseBufferCapacity; },
|
|
496
|
+
get sseReplayLimit() { return currentRuntimeConfig().sseReplayLimit; },
|
|
497
|
+
get workiqAutoInstall() { return currentRuntimeConfig().workiqAutoInstall; },
|
|
498
|
+
get logLevel() { return currentRuntimeConfig().logLevel; },
|
|
499
|
+
get shutdownTimeoutMs() { return currentRuntimeConfig().shutdownTimeoutMs; },
|
|
500
|
+
get telegramBotTokenConfigured() { return currentRuntimeConfig().telegramBotTokenConfigured; },
|
|
501
|
+
get openBrowserOnStart() { return currentRuntimeConfig().openBrowserOnStart; },
|
|
502
|
+
get restarted() { return currentRuntimeConfig().restarted; },
|
|
503
|
+
get injectDate() { return currentRuntimeConfig().injectDate; },
|
|
504
|
+
get agentNameCandidates() { return currentRuntimeConfig().agentNameCandidates; },
|
|
505
|
+
get sessionIdleTtlMs() { return currentRuntimeConfig().sessionIdleTtlMs; },
|
|
506
|
+
get sessionMaxActive() { return currentRuntimeConfig().sessionMaxActive; },
|
|
507
|
+
get orchestratorTimeoutMs() { return currentRuntimeConfig().orchestratorTimeoutMs; },
|
|
508
|
+
get chatSseEnabled() { return currentRuntimeConfig().chatSseEnabled; },
|
|
509
|
+
get jsonBodyLimit() { return currentRuntimeConfig().jsonBodyLimit; },
|
|
510
|
+
get memoryCheckpointEnabled() { return currentRuntimeConfig().memoryCheckpointEnabled; },
|
|
511
|
+
get memoryCheckpointTurns() { return currentRuntimeConfig().memoryCheckpointTurns; },
|
|
512
|
+
get memoryCheckpointOnScopeChange() { return currentRuntimeConfig().memoryCheckpointOnScopeChange; },
|
|
513
|
+
get memoryCheckpointMinTurnsForScopeFire() { return currentRuntimeConfig().memoryCheckpointMinTurnsForScopeFire; },
|
|
514
|
+
get memoryInjectEnabled() { return currentRuntimeConfig().memoryInjectEnabled; },
|
|
515
|
+
get memoryAutoAcceptEnabled() { return currentRuntimeConfig().memoryAutoAcceptEnabled; },
|
|
516
|
+
get memoryEndOfTaskHookEnabled() { return currentRuntimeConfig().memoryEndOfTaskHookEnabled; },
|
|
517
|
+
get memoryEndOfTaskFrictionEnabled() { return currentRuntimeConfig().memoryEndOfTaskFrictionEnabled; },
|
|
518
|
+
get memoryHooksEnabled() { return currentRuntimeConfig().memoryHooksEnabled; },
|
|
519
|
+
get memoryHousekeepingEnabled() { return currentRuntimeConfig().memoryHousekeepingEnabled; },
|
|
520
|
+
get memoryHousekeepingTurns() { return currentRuntimeConfig().memoryHousekeepingTurns; },
|
|
521
|
+
get memoryHousekeepingSimilarityThreshold() { return currentRuntimeConfig().memoryHousekeepingSimilarityThreshold; },
|
|
522
|
+
get memoryCheckpointDuplicateThreshold() { return currentRuntimeConfig().memoryCheckpointDuplicateThreshold; },
|
|
523
|
+
get memoryDecayDays() { return currentRuntimeConfig().memoryDecayDays; },
|
|
524
|
+
get memoryInboxRetentionDays() { return currentRuntimeConfig().memoryInboxRetentionDays; },
|
|
525
|
+
get memoryTieringEnabled() { return currentRuntimeConfig().memoryTieringEnabled; },
|
|
526
|
+
get memoryHotRecallBoost() { return currentRuntimeConfig().memoryHotRecallBoost; },
|
|
527
|
+
get memoryHotAgeDays() { return currentRuntimeConfig().memoryHotAgeDays; },
|
|
528
|
+
get pkbConsolidationEnabled() { return currentRuntimeConfig().pkbConsolidationEnabled; },
|
|
529
|
+
get pkbConsolidationHour() { return currentRuntimeConfig().pkbConsolidationHour; },
|
|
530
|
+
get pkbTruthRewriteBudget() { return currentRuntimeConfig().pkbTruthRewriteBudget; },
|
|
438
531
|
get PKB_CONSOLIDATION_ENABLED() {
|
|
439
|
-
return
|
|
532
|
+
return currentRuntimeConfig().pkbConsolidationEnabled;
|
|
440
533
|
},
|
|
441
534
|
get PKB_CONSOLIDATION_HOUR() {
|
|
442
|
-
return
|
|
535
|
+
return currentRuntimeConfig().pkbConsolidationHour;
|
|
443
536
|
},
|
|
444
|
-
modeCompatibilityWarnings
|
|
445
|
-
copilotAuthToken
|
|
537
|
+
get modeCompatibilityWarnings() { return currentRuntimeConfig().modeCompatibilityWarnings; },
|
|
538
|
+
get copilotAuthToken() { return currentRuntimeConfig().copilotAuthToken; },
|
|
446
539
|
get copilotModel() {
|
|
447
540
|
return _copilotModel;
|
|
448
541
|
},
|
|
@@ -450,7 +543,7 @@ export const config = {
|
|
|
450
543
|
_copilotModel = model;
|
|
451
544
|
},
|
|
452
545
|
get selfEditEnabled() {
|
|
453
|
-
return
|
|
546
|
+
return currentRuntimeConfig().selfEditEnabled;
|
|
454
547
|
},
|
|
455
548
|
};
|
|
456
549
|
/** Update or append an env var in ~/.chapterhouse/.env */
|
package/dist/config.test.js
CHANGED
|
@@ -112,6 +112,19 @@ test("defaults chat SSE on and still honors explicit CHAPTERHOUSE_CHAT_SSE overr
|
|
|
112
112
|
assert.equal(parsedDisabled.chatSseEnabled, false);
|
|
113
113
|
assert.equal(parsedEnabled.chatSseEnabled, true);
|
|
114
114
|
});
|
|
115
|
+
test("parses configurable JSON body and consolidation truth rewrite limits", async () => {
|
|
116
|
+
const configModule = await import("./config.js");
|
|
117
|
+
assert.equal(typeof configModule.parseRuntimeConfig, "function", "parseRuntimeConfig should be exported");
|
|
118
|
+
const parsedDefault = configModule.parseRuntimeConfig({});
|
|
119
|
+
const parsedExplicit = configModule.parseRuntimeConfig({
|
|
120
|
+
CHAPTERHOUSE_JSON_LIMIT: "8mb",
|
|
121
|
+
CHAPTERHOUSE_PKB_TRUTH_REWRITE_BUDGET: "7",
|
|
122
|
+
});
|
|
123
|
+
assert.equal(parsedDefault.jsonBodyLimit, "2mb");
|
|
124
|
+
assert.equal(parsedDefault.pkbTruthRewriteBudget, 18);
|
|
125
|
+
assert.equal(parsedExplicit.jsonBodyLimit, "8mb");
|
|
126
|
+
assert.equal(parsedExplicit.pkbTruthRewriteBudget, 7);
|
|
127
|
+
});
|
|
115
128
|
test("defaults memory checkpoint turns to 5 and parses integer overrides", async () => {
|
|
116
129
|
const configModule = await import("./config.js");
|
|
117
130
|
assert.equal(typeof configModule.parseRuntimeConfig, "function", "parseRuntimeConfig should be exported");
|
|
@@ -197,15 +210,31 @@ test("parses memory housekeeping config defaults and overrides", async () => {
|
|
|
197
210
|
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_TURNS: "12",
|
|
198
211
|
CHAPTERHOUSE_MEMORY_DECAY_DAYS: "45",
|
|
199
212
|
CHAPTERHOUSE_MEMORY_INBOX_RETENTION_DAYS: "14",
|
|
213
|
+
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD: "0.91",
|
|
214
|
+
CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD: "0.72",
|
|
200
215
|
});
|
|
201
216
|
assert.equal(parsedDefault.memoryHousekeepingEnabled, true);
|
|
202
217
|
assert.equal(parsedDefault.memoryHousekeepingTurns, 50);
|
|
203
218
|
assert.equal(parsedDefault.memoryDecayDays, 30);
|
|
204
219
|
assert.equal(parsedDefault.memoryInboxRetentionDays, 7);
|
|
220
|
+
assert.equal(parsedDefault.memoryHousekeepingSimilarityThreshold, 0.8);
|
|
221
|
+
assert.equal(parsedDefault.memoryCheckpointDuplicateThreshold, 0.85);
|
|
205
222
|
assert.equal(parsedOverride.memoryHousekeepingEnabled, false);
|
|
206
223
|
assert.equal(parsedOverride.memoryHousekeepingTurns, 12);
|
|
207
224
|
assert.equal(parsedOverride.memoryDecayDays, 45);
|
|
208
225
|
assert.equal(parsedOverride.memoryInboxRetentionDays, 14);
|
|
226
|
+
assert.equal(parsedOverride.memoryHousekeepingSimilarityThreshold, 0.91);
|
|
227
|
+
assert.equal(parsedOverride.memoryCheckpointDuplicateThreshold, 0.72);
|
|
228
|
+
});
|
|
229
|
+
test("rejects memory similarity thresholds outside the 0..1 range", async () => {
|
|
230
|
+
const configModule = await import("./config.js");
|
|
231
|
+
assert.equal(typeof configModule.parseRuntimeConfig, "function", "parseRuntimeConfig should be exported");
|
|
232
|
+
assert.throws(() => configModule.parseRuntimeConfig({
|
|
233
|
+
CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD: "1.1",
|
|
234
|
+
}), /CHAPTERHOUSE_MEMORY_HOUSEKEEPING_SIMILARITY_THRESHOLD must be a number between 0 and 1/);
|
|
235
|
+
assert.throws(() => configModule.parseRuntimeConfig({
|
|
236
|
+
CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD: "-0.1",
|
|
237
|
+
}), /CHAPTERHOUSE_MEMORY_CHECKPOINT_DUPLICATE_THRESHOLD must be a number between 0 and 1/);
|
|
209
238
|
});
|
|
210
239
|
test("defaults automatic proposal acceptance on and still honors explicit CHAPTERHOUSE_MEMORY_AUTO_ACCEPT overrides", async () => {
|
|
211
240
|
const configModule = await import("./config.js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import { getChapterhouseHome } from "../paths.js";
|
|
4
4
|
const STOP_WORDS = new Set([
|
|
5
5
|
"about", "after", "against", "been", "from", "into", "just", "that", "their", "them",
|
|
6
6
|
"then", "they", "this", "today", "work", "worked", "yesterday",
|
|
@@ -8,11 +8,9 @@ const STOP_WORDS = new Set([
|
|
|
8
8
|
const MIN_HISTORY_CONFIDENCE = 2;
|
|
9
9
|
export class OKRMapper {
|
|
10
10
|
teamWikiSync;
|
|
11
|
-
_adoClient;
|
|
12
11
|
learnedMappings;
|
|
13
12
|
constructor(teamWikiSync, _adoClient) {
|
|
14
13
|
this.teamWikiSync = teamWikiSync;
|
|
15
|
-
this._adoClient = _adoClient;
|
|
16
14
|
this.learnedMappings = loadLearnedMappings();
|
|
17
15
|
}
|
|
18
16
|
recordConfirmedMapping(activity, krId) {
|
|
@@ -181,14 +179,7 @@ function saveLearnedMappings(store) {
|
|
|
181
179
|
writeFileSync(join(wikiDir, ".okr-memory.json"), `${JSON.stringify(store, null, 2)}\n`);
|
|
182
180
|
}
|
|
183
181
|
function getWikiDir() {
|
|
184
|
-
|
|
185
|
-
if (!configuredHome) {
|
|
186
|
-
return join(homedir(), ".chapterhouse", "wiki");
|
|
187
|
-
}
|
|
188
|
-
const chapterhouseHome = configuredHome.endsWith(".chapterhouse")
|
|
189
|
-
? configuredHome
|
|
190
|
-
: join(configuredHome, ".chapterhouse");
|
|
191
|
-
return join(chapterhouseHome, "wiki");
|
|
182
|
+
return join(getChapterhouseHome(), "wiki");
|
|
192
183
|
}
|
|
193
184
|
function getOkrMemoryPath() {
|
|
194
185
|
return join(getWikiDir(), ".okr-memory.json");
|