@askexenow/exe-os 0.9.112 → 0.9.113
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 +9 -7
- package/dist/bin/agentic-ontology-backfill.js +54 -11
- package/dist/bin/agentic-reflection-backfill.js +29 -1
- package/dist/bin/agentic-semantic-label.js +29 -1
- package/dist/bin/backfill-conversations.js +53 -10
- package/dist/bin/backfill-responses.js +54 -11
- package/dist/bin/backfill-vectors.js +29 -1
- package/dist/bin/bulk-sync-postgres.js +55 -12
- package/dist/bin/cleanup-stale-review-tasks.js +75 -15
- package/dist/bin/cli.js +293 -76
- package/dist/bin/exe-agent-config.js +7 -1
- package/dist/bin/exe-agent.js +28 -2
- package/dist/bin/exe-assign.js +54 -11
- package/dist/bin/exe-boot.js +481 -147
- package/dist/bin/exe-call.js +45 -4
- package/dist/bin/exe-cloud.js +93 -15
- package/dist/bin/exe-dispatch.js +369 -24
- package/dist/bin/exe-doctor.js +53 -10
- package/dist/bin/exe-export-behaviors.js +54 -11
- package/dist/bin/exe-forget.js +54 -11
- package/dist/bin/exe-gateway.js +128 -23
- package/dist/bin/exe-heartbeat.js +75 -15
- package/dist/bin/exe-kill.js +54 -11
- package/dist/bin/exe-launch-agent.js +70 -12
- package/dist/bin/exe-new-employee.js +175 -7
- package/dist/bin/exe-pending-messages.js +75 -15
- package/dist/bin/exe-pending-notifications.js +75 -15
- package/dist/bin/exe-pending-reviews.js +75 -15
- package/dist/bin/exe-rename.js +54 -11
- package/dist/bin/exe-review.js +54 -11
- package/dist/bin/exe-search.js +54 -11
- package/dist/bin/exe-session-cleanup.js +491 -146
- package/dist/bin/exe-settings.js +10 -4
- package/dist/bin/exe-start-codex.js +524 -245
- package/dist/bin/exe-start-opencode.js +534 -165
- package/dist/bin/exe-status.js +75 -15
- package/dist/bin/exe-support.js +1 -1
- package/dist/bin/exe-team.js +54 -11
- package/dist/bin/git-sweep.js +369 -24
- package/dist/bin/graph-backfill.js +54 -11
- package/dist/bin/graph-export.js +54 -11
- package/dist/bin/install.js +62 -4
- package/dist/bin/intercom-check.js +491 -146
- package/dist/bin/pre-publish.js +13 -1
- package/dist/bin/scan-tasks.js +369 -24
- package/dist/bin/setup.js +91 -13
- package/dist/bin/shard-migrate.js +54 -11
- package/dist/bin/stack-update.js +1 -1
- package/dist/bin/update.js +3 -3
- package/dist/gateway/index.js +128 -23
- package/dist/hooks/bug-report-worker.js +128 -23
- package/dist/hooks/codex-stop-task-finalizer.js +512 -140
- package/dist/hooks/commit-complete.js +369 -24
- package/dist/hooks/error-recall.js +54 -11
- package/dist/hooks/ingest.js +4575 -252
- package/dist/hooks/instructions-loaded.js +54 -11
- package/dist/hooks/notification.js +54 -11
- package/dist/hooks/post-compact.js +75 -15
- package/dist/hooks/post-tool-combined.js +75 -15
- package/dist/hooks/pre-compact.js +449 -104
- package/dist/hooks/pre-tool-use.js +90 -15
- package/dist/hooks/prompt-submit.js +129 -24
- package/dist/hooks/session-end.js +451 -109
- package/dist/hooks/session-start.js +104 -16
- package/dist/hooks/stop.js +74 -14
- package/dist/hooks/subagent-stop.js +75 -15
- package/dist/hooks/summary-worker.js +73 -7
- package/dist/index.js +128 -23
- package/dist/lib/agent-config.js +16 -1
- package/dist/lib/cloud-sync.js +38 -1
- package/dist/lib/consolidation.js +16 -1
- package/dist/lib/database.js +16 -0
- package/dist/lib/db.js +16 -0
- package/dist/lib/device-registry.js +16 -0
- package/dist/lib/employee-templates.js +29 -3
- package/dist/lib/employees.js +16 -1
- package/dist/lib/exe-daemon.js +268 -42
- package/dist/lib/hybrid-search.js +54 -11
- package/dist/lib/license.js +3 -3
- package/dist/lib/messaging.js +21 -4
- package/dist/lib/schedules.js +29 -1
- package/dist/lib/skill-learning.js +458 -70
- package/dist/lib/status-brief.js +14 -1
- package/dist/lib/store.js +54 -11
- package/dist/lib/tasks.js +393 -91
- package/dist/lib/tmux-routing.js +316 -14
- package/dist/mcp/server.js +169 -30
- package/dist/mcp/tools/create-task.js +75 -13
- package/dist/mcp/tools/deactivate-behavior.js +33 -24
- package/dist/mcp/tools/list-tasks.js +21 -4
- package/dist/mcp/tools/send-message.js +21 -4
- package/dist/mcp/tools/update-task.js +390 -91
- package/dist/runtime/index.js +446 -101
- package/dist/tui/App.js +208 -54
- package/package.json +1 -1
|
@@ -3260,6 +3260,22 @@ async function ensureSchema() {
|
|
|
3260
3260
|
} catch (e) {
|
|
3261
3261
|
logCatchDebug("migration", e);
|
|
3262
3262
|
}
|
|
3263
|
+
try {
|
|
3264
|
+
await client.execute({
|
|
3265
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3266
|
+
args: []
|
|
3267
|
+
});
|
|
3268
|
+
} catch (e) {
|
|
3269
|
+
logCatchDebug("migration", e);
|
|
3270
|
+
}
|
|
3271
|
+
try {
|
|
3272
|
+
await client.execute({
|
|
3273
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3274
|
+
args: []
|
|
3275
|
+
});
|
|
3276
|
+
} catch (e) {
|
|
3277
|
+
logCatchDebug("migration", e);
|
|
3278
|
+
}
|
|
3263
3279
|
}
|
|
3264
3280
|
async function disposeDatabase() {
|
|
3265
3281
|
if (_walCheckpointTimer) {
|
|
@@ -3610,7 +3626,7 @@ var init_license = __esm({
|
|
|
3610
3626
|
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
3611
3627
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
3612
3628
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
3613
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
3629
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
3614
3630
|
}
|
|
3615
3631
|
});
|
|
3616
3632
|
|
|
@@ -3663,6 +3679,18 @@ function extractRootExe(name) {
|
|
|
3663
3679
|
const parts = name.split("-").filter(Boolean);
|
|
3664
3680
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
3665
3681
|
}
|
|
3682
|
+
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
3683
|
+
if (!existsSync12(SESSION_CACHE)) {
|
|
3684
|
+
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3685
|
+
}
|
|
3686
|
+
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3687
|
+
const filePath = path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3688
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3689
|
+
parentExe: rootExe,
|
|
3690
|
+
dispatchedBy: dispatchedBy || rootExe,
|
|
3691
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3692
|
+
}));
|
|
3693
|
+
}
|
|
3666
3694
|
function getParentExe(sessionKey) {
|
|
3667
3695
|
try {
|
|
3668
3696
|
const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
@@ -3672,11 +3700,12 @@ function getParentExe(sessionKey) {
|
|
|
3672
3700
|
}
|
|
3673
3701
|
}
|
|
3674
3702
|
function resolveExeSession() {
|
|
3703
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
3704
|
+
const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3705
|
+
if (fromEnv) return fromEnv;
|
|
3706
|
+
}
|
|
3675
3707
|
const mySession = getMySession();
|
|
3676
3708
|
if (!mySession) {
|
|
3677
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
3678
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3679
|
-
}
|
|
3680
3709
|
return null;
|
|
3681
3710
|
}
|
|
3682
3711
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -3691,6 +3720,10 @@ function resolveExeSession() {
|
|
|
3691
3720
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
3692
3721
|
`
|
|
3693
3722
|
);
|
|
3723
|
+
try {
|
|
3724
|
+
registerParentExe(key, fromSessionName);
|
|
3725
|
+
} catch {
|
|
3726
|
+
}
|
|
3694
3727
|
candidate = fromSessionName;
|
|
3695
3728
|
} else {
|
|
3696
3729
|
candidate = fromCache;
|
|
@@ -4919,11 +4952,17 @@ var init_platform_procedures = __esm({
|
|
|
4919
4952
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
4920
4953
|
},
|
|
4921
4954
|
{
|
|
4922
|
-
title: "
|
|
4955
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4923
4956
|
domain: "workflow",
|
|
4924
4957
|
priority: "p1",
|
|
4925
4958
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
4926
4959
|
},
|
|
4960
|
+
{
|
|
4961
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
4962
|
+
domain: "identity",
|
|
4963
|
+
priority: "p0",
|
|
4964
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
4965
|
+
},
|
|
4927
4966
|
{
|
|
4928
4967
|
title: "Single dispatch path \u2014 create_task only",
|
|
4929
4968
|
domain: "workflow",
|
|
@@ -4957,6 +4996,12 @@ var init_platform_procedures = __esm({
|
|
|
4957
4996
|
priority: "p0",
|
|
4958
4997
|
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
4959
4998
|
},
|
|
4999
|
+
{
|
|
5000
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
5001
|
+
domain: "security",
|
|
5002
|
+
priority: "p0",
|
|
5003
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
5004
|
+
},
|
|
4960
5005
|
{
|
|
4961
5006
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4962
5007
|
domain: "support",
|
|
@@ -5242,10 +5287,24 @@ function stableId(memoryId, type, content) {
|
|
|
5242
5287
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
5243
5288
|
}
|
|
5244
5289
|
function cleanText(text) {
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5290
|
+
let cleaned = text.replace(
|
|
5291
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
5292
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
5293
|
+
);
|
|
5294
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
5295
|
+
return cleaned;
|
|
5296
|
+
}
|
|
5297
|
+
function splitSegments(text) {
|
|
5298
|
+
const cleaned = cleanText(text);
|
|
5299
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
5300
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5301
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
5302
|
+
if (lines.length > 0) return lines;
|
|
5303
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5304
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
return segments;
|
|
5249
5308
|
}
|
|
5250
5309
|
function inferCardType(sentence, toolName) {
|
|
5251
5310
|
const lower = sentence.toLowerCase();
|
|
@@ -5277,12 +5336,12 @@ function predicateFor(type) {
|
|
|
5277
5336
|
}
|
|
5278
5337
|
}
|
|
5279
5338
|
function extractMemoryCards(row) {
|
|
5280
|
-
const
|
|
5339
|
+
const segments = splitSegments(row.raw_text);
|
|
5281
5340
|
const cards = [];
|
|
5282
|
-
for (const sentence of
|
|
5341
|
+
for (const sentence of segments) {
|
|
5283
5342
|
const type = inferCardType(sentence, row.tool_name);
|
|
5284
5343
|
const subject = extractSubject(sentence, row.agent_id);
|
|
5285
|
-
const content = sentence.length >
|
|
5344
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
5286
5345
|
cards.push({
|
|
5287
5346
|
id: stableId(row.id, type, content),
|
|
5288
5347
|
memory_id: row.id,
|
|
@@ -5378,13 +5437,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
5378
5437
|
last_accessed: String(row.timestamp)
|
|
5379
5438
|
}));
|
|
5380
5439
|
}
|
|
5381
|
-
var MAX_CARDS_PER_MEMORY,
|
|
5440
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
5382
5441
|
var init_memory_cards = __esm({
|
|
5383
5442
|
"src/lib/memory-cards.ts"() {
|
|
5384
5443
|
"use strict";
|
|
5385
5444
|
init_database();
|
|
5386
|
-
MAX_CARDS_PER_MEMORY =
|
|
5387
|
-
|
|
5445
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
5446
|
+
MAX_SEGMENT_CHARS = 500;
|
|
5447
|
+
MIN_SEGMENT_CHARS = 20;
|
|
5388
5448
|
}
|
|
5389
5449
|
});
|
|
5390
5450
|
|
|
@@ -3260,6 +3260,22 @@ async function ensureSchema() {
|
|
|
3260
3260
|
} catch (e) {
|
|
3261
3261
|
logCatchDebug("migration", e);
|
|
3262
3262
|
}
|
|
3263
|
+
try {
|
|
3264
|
+
await client.execute({
|
|
3265
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3266
|
+
args: []
|
|
3267
|
+
});
|
|
3268
|
+
} catch (e) {
|
|
3269
|
+
logCatchDebug("migration", e);
|
|
3270
|
+
}
|
|
3271
|
+
try {
|
|
3272
|
+
await client.execute({
|
|
3273
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3274
|
+
args: []
|
|
3275
|
+
});
|
|
3276
|
+
} catch (e) {
|
|
3277
|
+
logCatchDebug("migration", e);
|
|
3278
|
+
}
|
|
3263
3279
|
}
|
|
3264
3280
|
async function disposeDatabase() {
|
|
3265
3281
|
if (_walCheckpointTimer) {
|
|
@@ -3610,7 +3626,7 @@ var init_license = __esm({
|
|
|
3610
3626
|
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
3611
3627
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
3612
3628
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
3613
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
3629
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
3614
3630
|
}
|
|
3615
3631
|
});
|
|
3616
3632
|
|
|
@@ -3663,6 +3679,18 @@ function extractRootExe(name) {
|
|
|
3663
3679
|
const parts = name.split("-").filter(Boolean);
|
|
3664
3680
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
3665
3681
|
}
|
|
3682
|
+
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
3683
|
+
if (!existsSync12(SESSION_CACHE)) {
|
|
3684
|
+
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3685
|
+
}
|
|
3686
|
+
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3687
|
+
const filePath = path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3688
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3689
|
+
parentExe: rootExe,
|
|
3690
|
+
dispatchedBy: dispatchedBy || rootExe,
|
|
3691
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3692
|
+
}));
|
|
3693
|
+
}
|
|
3666
3694
|
function getParentExe(sessionKey) {
|
|
3667
3695
|
try {
|
|
3668
3696
|
const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
@@ -3672,11 +3700,12 @@ function getParentExe(sessionKey) {
|
|
|
3672
3700
|
}
|
|
3673
3701
|
}
|
|
3674
3702
|
function resolveExeSession() {
|
|
3703
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
3704
|
+
const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3705
|
+
if (fromEnv) return fromEnv;
|
|
3706
|
+
}
|
|
3675
3707
|
const mySession = getMySession();
|
|
3676
3708
|
if (!mySession) {
|
|
3677
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
3678
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3679
|
-
}
|
|
3680
3709
|
return null;
|
|
3681
3710
|
}
|
|
3682
3711
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -3691,6 +3720,10 @@ function resolveExeSession() {
|
|
|
3691
3720
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
3692
3721
|
`
|
|
3693
3722
|
);
|
|
3723
|
+
try {
|
|
3724
|
+
registerParentExe(key, fromSessionName);
|
|
3725
|
+
} catch {
|
|
3726
|
+
}
|
|
3694
3727
|
candidate = fromSessionName;
|
|
3695
3728
|
} else {
|
|
3696
3729
|
candidate = fromCache;
|
|
@@ -4958,11 +4991,17 @@ var init_platform_procedures = __esm({
|
|
|
4958
4991
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
4959
4992
|
},
|
|
4960
4993
|
{
|
|
4961
|
-
title: "
|
|
4994
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4962
4995
|
domain: "workflow",
|
|
4963
4996
|
priority: "p1",
|
|
4964
4997
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
4965
4998
|
},
|
|
4999
|
+
{
|
|
5000
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
5001
|
+
domain: "identity",
|
|
5002
|
+
priority: "p0",
|
|
5003
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
5004
|
+
},
|
|
4966
5005
|
{
|
|
4967
5006
|
title: "Single dispatch path \u2014 create_task only",
|
|
4968
5007
|
domain: "workflow",
|
|
@@ -4996,6 +5035,12 @@ var init_platform_procedures = __esm({
|
|
|
4996
5035
|
priority: "p0",
|
|
4997
5036
|
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
4998
5037
|
},
|
|
5038
|
+
{
|
|
5039
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
5040
|
+
domain: "security",
|
|
5041
|
+
priority: "p0",
|
|
5042
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
5043
|
+
},
|
|
4999
5044
|
{
|
|
5000
5045
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
5001
5046
|
domain: "support",
|
|
@@ -5281,10 +5326,24 @@ function stableId(memoryId, type, content) {
|
|
|
5281
5326
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
5282
5327
|
}
|
|
5283
5328
|
function cleanText(text) {
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5329
|
+
let cleaned = text.replace(
|
|
5330
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
5331
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
5332
|
+
);
|
|
5333
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
5334
|
+
return cleaned;
|
|
5335
|
+
}
|
|
5336
|
+
function splitSegments(text) {
|
|
5337
|
+
const cleaned = cleanText(text);
|
|
5338
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
5339
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5340
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
5341
|
+
if (lines.length > 0) return lines;
|
|
5342
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5343
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
return segments;
|
|
5288
5347
|
}
|
|
5289
5348
|
function inferCardType(sentence, toolName) {
|
|
5290
5349
|
const lower = sentence.toLowerCase();
|
|
@@ -5316,12 +5375,12 @@ function predicateFor(type) {
|
|
|
5316
5375
|
}
|
|
5317
5376
|
}
|
|
5318
5377
|
function extractMemoryCards(row) {
|
|
5319
|
-
const
|
|
5378
|
+
const segments = splitSegments(row.raw_text);
|
|
5320
5379
|
const cards = [];
|
|
5321
|
-
for (const sentence of
|
|
5380
|
+
for (const sentence of segments) {
|
|
5322
5381
|
const type = inferCardType(sentence, row.tool_name);
|
|
5323
5382
|
const subject = extractSubject(sentence, row.agent_id);
|
|
5324
|
-
const content = sentence.length >
|
|
5383
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
5325
5384
|
cards.push({
|
|
5326
5385
|
id: stableId(row.id, type, content),
|
|
5327
5386
|
memory_id: row.id,
|
|
@@ -5417,13 +5476,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
5417
5476
|
last_accessed: String(row.timestamp)
|
|
5418
5477
|
}));
|
|
5419
5478
|
}
|
|
5420
|
-
var MAX_CARDS_PER_MEMORY,
|
|
5479
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
5421
5480
|
var init_memory_cards = __esm({
|
|
5422
5481
|
"src/lib/memory-cards.ts"() {
|
|
5423
5482
|
"use strict";
|
|
5424
5483
|
init_database();
|
|
5425
|
-
MAX_CARDS_PER_MEMORY =
|
|
5426
|
-
|
|
5484
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
5485
|
+
MAX_SEGMENT_CHARS = 500;
|
|
5486
|
+
MIN_SEGMENT_CHARS = 20;
|
|
5427
5487
|
}
|
|
5428
5488
|
});
|
|
5429
5489
|
|
package/dist/bin/exe-rename.js
CHANGED
|
@@ -3104,6 +3104,22 @@ async function ensureSchema() {
|
|
|
3104
3104
|
} catch (e) {
|
|
3105
3105
|
logCatchDebug("migration", e);
|
|
3106
3106
|
}
|
|
3107
|
+
try {
|
|
3108
|
+
await client.execute({
|
|
3109
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3110
|
+
args: []
|
|
3111
|
+
});
|
|
3112
|
+
} catch (e) {
|
|
3113
|
+
logCatchDebug("migration", e);
|
|
3114
|
+
}
|
|
3115
|
+
try {
|
|
3116
|
+
await client.execute({
|
|
3117
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3118
|
+
args: []
|
|
3119
|
+
});
|
|
3120
|
+
} catch (e) {
|
|
3121
|
+
logCatchDebug("migration", e);
|
|
3122
|
+
}
|
|
3107
3123
|
}
|
|
3108
3124
|
async function disposeDatabase() {
|
|
3109
3125
|
if (_walCheckpointTimer) {
|
|
@@ -3206,11 +3222,17 @@ var init_platform_procedures = __esm({
|
|
|
3206
3222
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
3207
3223
|
},
|
|
3208
3224
|
{
|
|
3209
|
-
title: "
|
|
3225
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
3210
3226
|
domain: "workflow",
|
|
3211
3227
|
priority: "p1",
|
|
3212
3228
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
3213
3229
|
},
|
|
3230
|
+
{
|
|
3231
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
3232
|
+
domain: "identity",
|
|
3233
|
+
priority: "p0",
|
|
3234
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
3235
|
+
},
|
|
3214
3236
|
{
|
|
3215
3237
|
title: "Single dispatch path \u2014 create_task only",
|
|
3216
3238
|
domain: "workflow",
|
|
@@ -3244,6 +3266,12 @@ var init_platform_procedures = __esm({
|
|
|
3244
3266
|
priority: "p0",
|
|
3245
3267
|
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
3246
3268
|
},
|
|
3269
|
+
{
|
|
3270
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
3271
|
+
domain: "security",
|
|
3272
|
+
priority: "p0",
|
|
3273
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
3274
|
+
},
|
|
3247
3275
|
{
|
|
3248
3276
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
3249
3277
|
domain: "support",
|
|
@@ -4550,10 +4578,24 @@ function stableId(memoryId, type, content) {
|
|
|
4550
4578
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4551
4579
|
}
|
|
4552
4580
|
function cleanText(text) {
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4581
|
+
let cleaned = text.replace(
|
|
4582
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
4583
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
4584
|
+
);
|
|
4585
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4586
|
+
return cleaned;
|
|
4587
|
+
}
|
|
4588
|
+
function splitSegments(text) {
|
|
4589
|
+
const cleaned = cleanText(text);
|
|
4590
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
4591
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4592
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
4593
|
+
if (lines.length > 0) return lines;
|
|
4594
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4595
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
return segments;
|
|
4557
4599
|
}
|
|
4558
4600
|
function inferCardType(sentence, toolName) {
|
|
4559
4601
|
const lower = sentence.toLowerCase();
|
|
@@ -4585,12 +4627,12 @@ function predicateFor(type) {
|
|
|
4585
4627
|
}
|
|
4586
4628
|
}
|
|
4587
4629
|
function extractMemoryCards(row) {
|
|
4588
|
-
const
|
|
4630
|
+
const segments = splitSegments(row.raw_text);
|
|
4589
4631
|
const cards = [];
|
|
4590
|
-
for (const sentence of
|
|
4632
|
+
for (const sentence of segments) {
|
|
4591
4633
|
const type = inferCardType(sentence, row.tool_name);
|
|
4592
4634
|
const subject = extractSubject(sentence, row.agent_id);
|
|
4593
|
-
const content = sentence.length >
|
|
4635
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
4594
4636
|
cards.push({
|
|
4595
4637
|
id: stableId(row.id, type, content),
|
|
4596
4638
|
memory_id: row.id,
|
|
@@ -4686,13 +4728,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
4686
4728
|
last_accessed: String(row.timestamp)
|
|
4687
4729
|
}));
|
|
4688
4730
|
}
|
|
4689
|
-
var MAX_CARDS_PER_MEMORY,
|
|
4731
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
4690
4732
|
var init_memory_cards = __esm({
|
|
4691
4733
|
"src/lib/memory-cards.ts"() {
|
|
4692
4734
|
"use strict";
|
|
4693
4735
|
init_database();
|
|
4694
|
-
MAX_CARDS_PER_MEMORY =
|
|
4695
|
-
|
|
4736
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
4737
|
+
MAX_SEGMENT_CHARS = 500;
|
|
4738
|
+
MIN_SEGMENT_CHARS = 20;
|
|
4696
4739
|
}
|
|
4697
4740
|
});
|
|
4698
4741
|
|
package/dist/bin/exe-review.js
CHANGED
|
@@ -3263,6 +3263,22 @@ async function ensureSchema() {
|
|
|
3263
3263
|
} catch (e) {
|
|
3264
3264
|
logCatchDebug("migration", e);
|
|
3265
3265
|
}
|
|
3266
|
+
try {
|
|
3267
|
+
await client.execute({
|
|
3268
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3269
|
+
args: []
|
|
3270
|
+
});
|
|
3271
|
+
} catch (e) {
|
|
3272
|
+
logCatchDebug("migration", e);
|
|
3273
|
+
}
|
|
3274
|
+
try {
|
|
3275
|
+
await client.execute({
|
|
3276
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3277
|
+
args: []
|
|
3278
|
+
});
|
|
3279
|
+
} catch (e) {
|
|
3280
|
+
logCatchDebug("migration", e);
|
|
3281
|
+
}
|
|
3266
3282
|
}
|
|
3267
3283
|
async function disposeDatabase() {
|
|
3268
3284
|
if (_walCheckpointTimer) {
|
|
@@ -4386,11 +4402,17 @@ var init_platform_procedures = __esm({
|
|
|
4386
4402
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
4387
4403
|
},
|
|
4388
4404
|
{
|
|
4389
|
-
title: "
|
|
4405
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4390
4406
|
domain: "workflow",
|
|
4391
4407
|
priority: "p1",
|
|
4392
4408
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
4393
4409
|
},
|
|
4410
|
+
{
|
|
4411
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
4412
|
+
domain: "identity",
|
|
4413
|
+
priority: "p0",
|
|
4414
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
4415
|
+
},
|
|
4394
4416
|
{
|
|
4395
4417
|
title: "Single dispatch path \u2014 create_task only",
|
|
4396
4418
|
domain: "workflow",
|
|
@@ -4424,6 +4446,12 @@ var init_platform_procedures = __esm({
|
|
|
4424
4446
|
priority: "p0",
|
|
4425
4447
|
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
4426
4448
|
},
|
|
4449
|
+
{
|
|
4450
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
4451
|
+
domain: "security",
|
|
4452
|
+
priority: "p0",
|
|
4453
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
4454
|
+
},
|
|
4427
4455
|
{
|
|
4428
4456
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4429
4457
|
domain: "support",
|
|
@@ -4709,10 +4737,24 @@ function stableId(memoryId, type, content) {
|
|
|
4709
4737
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4710
4738
|
}
|
|
4711
4739
|
function cleanText(text) {
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4740
|
+
let cleaned = text.replace(
|
|
4741
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
4742
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
4743
|
+
);
|
|
4744
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4745
|
+
return cleaned;
|
|
4746
|
+
}
|
|
4747
|
+
function splitSegments(text) {
|
|
4748
|
+
const cleaned = cleanText(text);
|
|
4749
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
4750
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4751
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
4752
|
+
if (lines.length > 0) return lines;
|
|
4753
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4754
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4757
|
+
return segments;
|
|
4716
4758
|
}
|
|
4717
4759
|
function inferCardType(sentence, toolName) {
|
|
4718
4760
|
const lower = sentence.toLowerCase();
|
|
@@ -4744,12 +4786,12 @@ function predicateFor(type) {
|
|
|
4744
4786
|
}
|
|
4745
4787
|
}
|
|
4746
4788
|
function extractMemoryCards(row) {
|
|
4747
|
-
const
|
|
4789
|
+
const segments = splitSegments(row.raw_text);
|
|
4748
4790
|
const cards = [];
|
|
4749
|
-
for (const sentence of
|
|
4791
|
+
for (const sentence of segments) {
|
|
4750
4792
|
const type = inferCardType(sentence, row.tool_name);
|
|
4751
4793
|
const subject = extractSubject(sentence, row.agent_id);
|
|
4752
|
-
const content = sentence.length >
|
|
4794
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
4753
4795
|
cards.push({
|
|
4754
4796
|
id: stableId(row.id, type, content),
|
|
4755
4797
|
memory_id: row.id,
|
|
@@ -4845,13 +4887,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
4845
4887
|
last_accessed: String(row.timestamp)
|
|
4846
4888
|
}));
|
|
4847
4889
|
}
|
|
4848
|
-
var MAX_CARDS_PER_MEMORY,
|
|
4890
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
4849
4891
|
var init_memory_cards = __esm({
|
|
4850
4892
|
"src/lib/memory-cards.ts"() {
|
|
4851
4893
|
"use strict";
|
|
4852
4894
|
init_database();
|
|
4853
|
-
MAX_CARDS_PER_MEMORY =
|
|
4854
|
-
|
|
4895
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
4896
|
+
MAX_SEGMENT_CHARS = 500;
|
|
4897
|
+
MIN_SEGMENT_CHARS = 20;
|
|
4855
4898
|
}
|
|
4856
4899
|
});
|
|
4857
4900
|
|