dayloom 0.1.0-beta.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.
Files changed (123) hide show
  1. package/README.md +1146 -0
  2. package/dist/cli/daily.js +41 -0
  3. package/dist/cli/index.js +33 -0
  4. package/dist/cli/init.js +40 -0
  5. package/dist/cli/next.js +60 -0
  6. package/dist/cli/play.js +39 -0
  7. package/dist/cli/revise.js +41 -0
  8. package/dist/cli/settle.js +45 -0
  9. package/dist/daily/apply-plan.js +25 -0
  10. package/dist/daily/constants.js +16 -0
  11. package/dist/daily/dialogue-loop.js +147 -0
  12. package/dist/daily/finalize.js +23 -0
  13. package/dist/daily/guard.js +54 -0
  14. package/dist/daily/index.js +27 -0
  15. package/dist/daily/intent-router.js +65 -0
  16. package/dist/daily/mcp-gateway.js +5 -0
  17. package/dist/daily/mcp-tools.js +8 -0
  18. package/dist/daily/parse-assistant.js +38 -0
  19. package/dist/daily/parse-payload.js +10 -0
  20. package/dist/daily/player-context.js +85 -0
  21. package/dist/daily/project-plan.js +15 -0
  22. package/dist/daily/promptpile-loop.js +41 -0
  23. package/dist/daily/prompts.js +11 -0
  24. package/dist/daily/read-user-input.js +6 -0
  25. package/dist/daily/session.js +119 -0
  26. package/dist/daily/types.js +2 -0
  27. package/dist/daily/validate-plan.js +46 -0
  28. package/dist/i18n/detect.js +23 -0
  29. package/dist/i18n/index.js +22 -0
  30. package/dist/i18n/messages.js +149 -0
  31. package/dist/index.js +27 -0
  32. package/dist/init/apply-payload.js +18 -0
  33. package/dist/init/archive-transcript.js +28 -0
  34. package/dist/init/checklist.js +74 -0
  35. package/dist/init/cleanup.js +12 -0
  36. package/dist/init/constants.js +21 -0
  37. package/dist/init/errors.js +11 -0
  38. package/dist/init/finalize.js +35 -0
  39. package/dist/init/guard.js +31 -0
  40. package/dist/init/index.js +59 -0
  41. package/dist/init/interview-loop.js +103 -0
  42. package/dist/init/parse-assistant.js +50 -0
  43. package/dist/init/project-payload.js +78 -0
  44. package/dist/init/promptpile-run.js +80 -0
  45. package/dist/init/prompts.js +16 -0
  46. package/dist/init/read-user-input.js +44 -0
  47. package/dist/init/scaffold.js +66 -0
  48. package/dist/init/session.js +98 -0
  49. package/dist/init/types.js +2 -0
  50. package/dist/next/index.js +79 -0
  51. package/dist/next/inspect.js +90 -0
  52. package/dist/play/ai.js +11 -0
  53. package/dist/play/event-loop.js +244 -0
  54. package/dist/play/guard.js +14 -0
  55. package/dist/play/index.js +21 -0
  56. package/dist/play/parse-assistant.js +39 -0
  57. package/dist/play/player-context.js +20 -0
  58. package/dist/play/prompts.js +9 -0
  59. package/dist/play/session.js +14 -0
  60. package/dist/play/state.js +117 -0
  61. package/dist/play/types.js +2 -0
  62. package/dist/play/validate.js +156 -0
  63. package/dist/revise/apply-payload.js +58 -0
  64. package/dist/revise/bin-resolve.js +38 -0
  65. package/dist/revise/constants.js +17 -0
  66. package/dist/revise/dialogue-loop.js +116 -0
  67. package/dist/revise/diff.js +24 -0
  68. package/dist/revise/file-hash.js +27 -0
  69. package/dist/revise/finalize.js +23 -0
  70. package/dist/revise/guard.js +17 -0
  71. package/dist/revise/index.js +24 -0
  72. package/dist/revise/mcp-gateway.js +74 -0
  73. package/dist/revise/mcp-tools.js +91 -0
  74. package/dist/revise/parse-assistant.js +41 -0
  75. package/dist/revise/parse-payload.js +22 -0
  76. package/dist/revise/process-run.js +77 -0
  77. package/dist/revise/project-payload.js +62 -0
  78. package/dist/revise/promptpile-loop.js +41 -0
  79. package/dist/revise/prompts.js +16 -0
  80. package/dist/revise/read-user-input.js +35 -0
  81. package/dist/revise/session.js +119 -0
  82. package/dist/revise/types.js +2 -0
  83. package/dist/revise/validate-payload.js +47 -0
  84. package/dist/settle/ai.js +23 -0
  85. package/dist/settle/apply.js +58 -0
  86. package/dist/settle/context.js +69 -0
  87. package/dist/settle/derive.js +56 -0
  88. package/dist/settle/guard.js +71 -0
  89. package/dist/settle/index.js +105 -0
  90. package/dist/settle/parse-assistant.js +14 -0
  91. package/dist/settle/parse-payload.js +19 -0
  92. package/dist/settle/project.js +58 -0
  93. package/dist/settle/session.js +45 -0
  94. package/dist/settle/types.js +2 -0
  95. package/dist/settle/validate.js +100 -0
  96. package/dist/shared/filtered-stream-output.js +41 -0
  97. package/dist/shared/promptpile-stream.js +59 -0
  98. package/dist/shared/run-promptpile-with-stream.js +34 -0
  99. package/dist/utils/loading.js +54 -0
  100. package/package.json +39 -0
  101. package/prompts/README.md +39 -0
  102. package/prompts/choice.system.md +0 -0
  103. package/prompts/daily-dialogue.system.md +37 -0
  104. package/prompts/daily-finalize-plan.system.md +34 -0
  105. package/prompts/daily-intent-router.system.md +34 -0
  106. package/prompts/day-planner.system.md +0 -0
  107. package/prompts/day-summarizer.system.md +0 -0
  108. package/prompts/dialogue.system.md +0 -0
  109. package/prompts/diary-writer.system.md +0 -0
  110. package/prompts/event-runner.system.md +0 -0
  111. package/prompts/init-finalize.system.md +59 -0
  112. package/prompts/init-interviewer.system.md +37 -0
  113. package/prompts/memory-updater.system.md +0 -0
  114. package/prompts/next-day-seeder.system.md +0 -0
  115. package/prompts/play-event-dialogue.system.md +20 -0
  116. package/prompts/play-event-generator.system.md +19 -0
  117. package/prompts/play-event-resolver.system.md +26 -0
  118. package/prompts/play-replanner.system.md +21 -0
  119. package/prompts/revise-dialogue.system.md +22 -0
  120. package/prompts/revise-finalize.system.md +40 -0
  121. package/prompts/settle.system.md +28 -0
  122. package/prompts/spec.md +320 -0
  123. package/prompts/state-resolver.system.md +0 -0
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseExplicitDailyAction = parseExplicitDailyAction;
4
+ exports.parseDailyIntent = parseDailyIntent;
5
+ exports.validateDailyIntent = validateDailyIntent;
6
+ exports.effectiveDailyAction = effectiveDailyAction;
7
+ exports.routeDailyIntent = routeDailyIntent;
8
+ exports.fallbackDailyIntent = fallbackDailyIntent;
9
+ const promptpile_loop_1 = require("./promptpile-loop");
10
+ const session_1 = require("./session");
11
+ const ACTIONS = new Set(['continue', 'pending', 'start', 'cancel', 'exit']);
12
+ const MIN_CONFIDENCE = 0.8;
13
+ function parseExplicitDailyAction(input) {
14
+ const actions = {
15
+ '/pending': 'pending',
16
+ '/start': 'start',
17
+ '/cancel': 'cancel',
18
+ '/exit': 'exit',
19
+ '/help': 'help',
20
+ };
21
+ return actions[input.trim().toLowerCase()];
22
+ }
23
+ function parseDailyIntent(text) {
24
+ const match = text.match(/```(?:json\s+)?daily-intent\s*\n([\s\S]*?)```/i);
25
+ if (!match)
26
+ throw new Error('Assistant response missing daily-intent JSON block');
27
+ let parsed;
28
+ try {
29
+ parsed = JSON.parse(match[1].trim());
30
+ }
31
+ catch (error) {
32
+ throw new Error(`Failed to parse daily-intent JSON: ${error instanceof Error ? error.message : error}`);
33
+ }
34
+ validateDailyIntent(parsed);
35
+ return parsed;
36
+ }
37
+ function validateDailyIntent(intent) {
38
+ if (!intent || typeof intent !== 'object' || Array.isArray(intent))
39
+ throw new Error('Daily intent must be an object');
40
+ if (!ACTIONS.has(intent.action))
41
+ throw new Error(`Unsupported daily intent action: ${String(intent.action)}`);
42
+ if (typeof intent.confidence !== 'number' || !Number.isFinite(intent.confidence) || intent.confidence < 0 || intent.confidence > 1) {
43
+ throw new Error('Daily intent confidence must be between 0 and 1');
44
+ }
45
+ if (typeof intent.reason !== 'string' || !intent.reason.trim())
46
+ throw new Error('Daily intent reason must be non-empty');
47
+ }
48
+ function effectiveDailyAction(intent) {
49
+ return intent.confidence >= MIN_CONFIDENCE ? intent.action : 'continue';
50
+ }
51
+ async function routeDailyIntent(input, draft, latestAssistantReply, baseUrl, token, maxToolRounds, keepSession = false) {
52
+ const session = (0, session_1.createIntentSession)({ input, draft, latestAssistantReply });
53
+ try {
54
+ return parseDailyIntent(await (0, promptpile_loop_1.runPromptpileUntilText)(session, baseUrl, token, maxToolRounds, () => undefined, true));
55
+ }
56
+ finally {
57
+ if (keepSession)
58
+ process.stderr.write(`Daily intent session preserved at: ${session.root}\n`);
59
+ else
60
+ (0, session_1.cleanupSession)(session);
61
+ }
62
+ }
63
+ function fallbackDailyIntent(reason) {
64
+ return { action: 'continue', confidence: 0, reason };
65
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectOrStartGateway = void 0;
4
+ var mcp_gateway_1 = require("../revise/mcp-gateway");
5
+ Object.defineProperty(exports, "connectOrStartGateway", { enumerable: true, get: function () { return mcp_gateway_1.connectOrStartGateway; } });
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseAndAssertReadonlyCalls = exports.exportReadonlyTools = exports.executeReadonlyCalls = exports.assertAllowedPlayerContextRoot = void 0;
4
+ var mcp_tools_1 = require("../revise/mcp-tools");
5
+ Object.defineProperty(exports, "assertAllowedPlayerContextRoot", { enumerable: true, get: function () { return mcp_tools_1.assertAllowedWorldRoot; } });
6
+ Object.defineProperty(exports, "executeReadonlyCalls", { enumerable: true, get: function () { return mcp_tools_1.executeReadonlyCalls; } });
7
+ Object.defineProperty(exports, "exportReadonlyTools", { enumerable: true, get: function () { return mcp_tools_1.exportReadonlyTools; } });
8
+ Object.defineProperty(exports, "parseAndAssertReadonlyCalls", { enumerable: true, get: function () { return mcp_tools_1.parseAndAssertReadonlyCalls; } });
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDailyStatus = parseDailyStatus;
4
+ exports.parseDailyPlan = parseDailyPlan;
5
+ exports.stripDailyStatus = stripDailyStatus;
6
+ function extractBlock(text, label) {
7
+ const m = text.match(new RegExp('```(?:json\\s+)?' + label + '\\s*\\n([\\s\\S]*?)```', 'i'));
8
+ return m ? m[1].trim() : null;
9
+ }
10
+ function parseDailyStatus(text) {
11
+ const raw = extractBlock(text, 'daily-status');
12
+ if (!raw)
13
+ return undefined;
14
+ const parsed = JSON.parse(raw);
15
+ if (!parsed || typeof parsed !== 'object')
16
+ throw new Error('daily-status must be an object');
17
+ if (typeof parsed.user_intent !== 'string')
18
+ throw new Error('daily-status user_intent must be a string');
19
+ for (const key of ['known_context', 'constraints', 'open_questions']) {
20
+ if (!Array.isArray(parsed[key]) || parsed[key].some(item => typeof item !== 'string'))
21
+ throw new Error(`daily-status ${key} must be a string array`);
22
+ }
23
+ return parsed;
24
+ }
25
+ function parseDailyPlan(text) {
26
+ const raw = extractBlock(text, 'daily-plan');
27
+ if (!raw)
28
+ throw new Error('Assistant response missing daily-plan JSON block');
29
+ try {
30
+ return JSON.parse(raw);
31
+ }
32
+ catch (err) {
33
+ throw new Error(`Failed to parse daily-plan JSON: ${err instanceof Error ? err.message : err}`);
34
+ }
35
+ }
36
+ function stripDailyStatus(text) {
37
+ return text.replace(/```(?:json\s+)?daily-status\s*\n[\s\S]*?```/gi, '').trim();
38
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readDailyPlan = readDailyPlan;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ function readDailyPlan(filePath) {
9
+ return JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
10
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildPlayerContext = buildPlayerContext;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function buildPlayerContext(worldRoot, outputRoot) {
10
+ fs_1.default.rmSync(outputRoot, { recursive: true, force: true });
11
+ fs_1.default.mkdirSync(outputRoot, { recursive: true });
12
+ copyDirFiles(worldRoot, outputRoot, 'canon', ['premise.md', 'rules.md', 'style.md', 'user_role.md']);
13
+ copyProtagonist(worldRoot, outputRoot);
14
+ copyKnownCharacters(worldRoot, outputRoot);
15
+ copyKnownScenes(worldRoot, outputRoot);
16
+ copyDirFiles(worldRoot, outputRoot, 'memory', ['short_term.md', 'long_term.md', 'facts.yaml']);
17
+ writeRecentHistory(worldRoot, outputRoot);
18
+ return { root: outputRoot };
19
+ }
20
+ function copyProtagonist(worldRoot, outputRoot) {
21
+ const id = findProtagonistId(worldRoot);
22
+ const base = path_1.default.join(worldRoot, 'characters', id);
23
+ const chunks = [`# Protagonist\n\nID: ${id}\n`];
24
+ for (const file of ['profile.md', 'memory.md', 'timeline.md']) {
25
+ const filePath = path_1.default.join(base, file);
26
+ if (fs_1.default.existsSync(filePath))
27
+ chunks.push(`\n## ${file}\n\n${fs_1.default.readFileSync(filePath, 'utf8')}`);
28
+ }
29
+ writeFile(path_1.default.join(outputRoot, 'protagonist.md'), chunks.join('\n'));
30
+ }
31
+ function findProtagonistId(worldRoot) {
32
+ const charactersDir = path_1.default.join(worldRoot, 'characters');
33
+ const preferred = path_1.default.join(charactersDir, 'char_protagonist');
34
+ if (fs_1.default.existsSync(preferred))
35
+ return 'char_protagonist';
36
+ if (!fs_1.default.existsSync(charactersDir))
37
+ return 'char_protagonist';
38
+ const first = fs_1.default.readdirSync(charactersDir, { withFileTypes: true }).find(entry => entry.isDirectory())?.name;
39
+ return first ?? 'char_protagonist';
40
+ }
41
+ function copyKnownCharacters(worldRoot, outputRoot) {
42
+ const charactersDir = path_1.default.join(worldRoot, 'characters');
43
+ if (!fs_1.default.existsSync(charactersDir))
44
+ return;
45
+ for (const entry of fs_1.default.readdirSync(charactersDir, { withFileTypes: true })) {
46
+ if (!entry.isDirectory())
47
+ continue;
48
+ const src = path_1.default.join(charactersDir, entry.name, 'profile.md');
49
+ if (fs_1.default.existsSync(src))
50
+ copyFile(src, path_1.default.join(outputRoot, 'known-characters', entry.name, 'profile.md'));
51
+ }
52
+ }
53
+ function copyKnownScenes(worldRoot, outputRoot) {
54
+ const scenesDir = path_1.default.join(worldRoot, 'scenes');
55
+ if (!fs_1.default.existsSync(scenesDir))
56
+ return;
57
+ for (const entry of fs_1.default.readdirSync(scenesDir, { withFileTypes: true })) {
58
+ if (!entry.isDirectory())
59
+ continue;
60
+ const src = path_1.default.join(scenesDir, entry.name, 'profile.md');
61
+ if (fs_1.default.existsSync(src))
62
+ copyFile(src, path_1.default.join(outputRoot, 'known-scenes', entry.name, 'profile.md'));
63
+ }
64
+ }
65
+ function copyDirFiles(worldRoot, outputRoot, relDir, files) {
66
+ for (const file of files) {
67
+ const src = path_1.default.join(worldRoot, relDir, file);
68
+ if (fs_1.default.existsSync(src))
69
+ copyFile(src, path_1.default.join(outputRoot, relDir, file));
70
+ }
71
+ }
72
+ function writeRecentHistory(worldRoot, outputRoot) {
73
+ const daysDir = path_1.default.join(worldRoot, 'days');
74
+ const lines = ['# Recent History', ''];
75
+ if (fs_1.default.existsSync(daysDir)) {
76
+ for (const day of fs_1.default.readdirSync(daysDir).sort().slice(-7)) {
77
+ const diary = path_1.default.join(daysDir, day, 'diary.md');
78
+ if (fs_1.default.existsSync(diary))
79
+ lines.push(`## ${day}`, '', fs_1.default.readFileSync(diary, 'utf8').trim(), '');
80
+ }
81
+ }
82
+ writeFile(path_1.default.join(outputRoot, 'recent-history.md'), `${lines.join('\n').trim()}\n`);
83
+ }
84
+ function copyFile(src, dest) { writeFile(dest, fs_1.default.readFileSync(src, 'utf8')); }
85
+ function writeFile(filePath, content) { fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true }); fs_1.default.writeFileSync(filePath, content, 'utf8'); }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectDailyPlan = projectDailyPlan;
4
+ function projectDailyPlan(plan, transcript, lastCommittedDay = 'null') {
5
+ const dayDir = `days/${plan.day}`;
6
+ const files = [
7
+ { relativePath: `${dayDir}/meta.yaml`, content: [`day: ${plan.day}`, 'phase: planned', `created_at: ${new Date().toISOString()}`, ''].join('\n') },
8
+ { relativePath: `${dayDir}/plan.user.md`, content: `${plan.user_intent.trim()}\n` },
9
+ { relativePath: `${dayDir}/plan.initial.json`, content: `${JSON.stringify(plan, null, 2)}\n` },
10
+ { relativePath: 'current.yaml', content: [`day: ${plan.day}`, 'phase: planned', `last_committed_day: ${lastCommittedDay}`, ''].join('\n') },
11
+ ];
12
+ if (transcript !== undefined)
13
+ files.push({ relativePath: `${dayDir}/dialogue/plan-transcript.md`, content: transcript });
14
+ return files;
15
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runPromptpileUntilText = runPromptpileUntilText;
7
+ const path_1 = __importDefault(require("path"));
8
+ const bin_resolve_1 = require("../revise/bin-resolve");
9
+ const run_promptpile_with_stream_1 = require("../shared/run-promptpile-with-stream");
10
+ const mcp_tools_1 = require("./mcp-tools");
11
+ const session_1 = require("./session");
12
+ async function runPromptpileUntilText(session, baseUrl, token, maxToolRounds, onDelta = () => undefined, disableTools = false) {
13
+ for (let round = 0; round <= maxToolRounds; round += 1) {
14
+ const spawnConfig = (0, bin_resolve_1.getPromptpileSpawnConfig)();
15
+ const result = await (0, run_promptpile_with_stream_1.runPromptpileWithStream)({
16
+ command: spawnConfig.command,
17
+ args: [
18
+ ...spawnConfig.argvPrefix,
19
+ '--config', path_1.default.basename(session.promptpileConfig),
20
+ '-d', 'messages',
21
+ ...(disableTools ? ['--disable-tool'] : ['--tools-file', path_1.default.basename(session.toolsFile)]),
22
+ '--continue',
23
+ '--quiet'
24
+ ],
25
+ cwd: session.root,
26
+ quiet: true,
27
+ onDelta
28
+ });
29
+ if (result.error)
30
+ throw new Error('Failed to run ' + spawnConfig.displayName + ': ' + result.error.message);
31
+ if (result.status !== 0)
32
+ throw new Error('promptpile exited with code ' + result.status + ': ' + result.stderr.trim().slice(-500));
33
+ const callsFile = (0, session_1.getLatestCallsFile)(session.messagesDir);
34
+ if (!callsFile)
35
+ return (0, session_1.getLatestAssistantText)(session.messagesDir);
36
+ if (round === maxToolRounds)
37
+ throw new Error('AI exceeded the tool-call limit (' + maxToolRounds + ') for this turn');
38
+ await (0, mcp_tools_1.executeReadonlyCalls)(baseUrl, token, callsFile);
39
+ }
40
+ throw new Error('Unexpected promptpile loop exit');
41
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadDailyPrompt = loadDailyPrompt;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function loadDailyPrompt(name) {
10
+ return fs_1.default.readFileSync(path_1.default.resolve(__dirname, '..', '..', 'prompts', `${name}.system.md`), 'utf8');
11
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readDailyUserInput = exports.askYesNo = void 0;
4
+ var read_user_input_1 = require("../revise/read-user-input");
5
+ Object.defineProperty(exports, "askYesNo", { enumerable: true, get: function () { return read_user_input_1.askYesNo; } });
6
+ Object.defineProperty(exports, "readDailyUserInput", { enumerable: true, get: function () { return read_user_input_1.readReviseUserInput; } });
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createDailySession = createDailySession;
7
+ exports.createFinalizeSession = createFinalizeSession;
8
+ exports.createIntentSession = createIntentSession;
9
+ exports.emptyDraft = emptyDraft;
10
+ exports.readDraft = readDraft;
11
+ exports.writeDraft = writeDraft;
12
+ exports.cleanupSession = cleanupSession;
13
+ exports.appendUserMessage = appendUserMessage;
14
+ exports.getLatestAssistantText = getLatestAssistantText;
15
+ exports.getLatestCallsFile = getLatestCallsFile;
16
+ exports.buildTranscript = buildTranscript;
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const os_1 = __importDefault(require("os"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const constants_1 = require("./constants");
21
+ const prompts_1 = require("./prompts");
22
+ const MESSAGE_PATTERN = /^\[(\d+)\](.+)\.(md|json)$/i;
23
+ function promptpileToml() {
24
+ return `[[llm_api]]
25
+ name = "deepseek"
26
+ model = "deepseek-chat"
27
+ base_url = "https://api.deepseek.com/v1"
28
+ api_key_env = "DEEPSEEK_API_KEY"
29
+
30
+ [promptpile]
31
+ llm_api = "deepseek"
32
+ dir = "./messages"
33
+ tools_file = "./readonly.tools.toml"
34
+ quiet = true
35
+ `;
36
+ }
37
+ function createDailySession() {
38
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dayloom-daily-'));
39
+ const messagesDir = path_1.default.join(root, 'messages');
40
+ const toolsFile = path_1.default.join(root, 'readonly.tools.toml');
41
+ const promptpileConfig = path_1.default.join(root, 'promptpile.toml');
42
+ const draftFile = path_1.default.join(root, 'draft.json');
43
+ const playerContextRoot = path_1.default.join(root, 'player-context');
44
+ fs_1.default.mkdirSync(messagesDir, { recursive: true });
45
+ fs_1.default.writeFileSync(promptpileConfig, promptpileToml(), 'utf8');
46
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[0]system.md'), (0, prompts_1.loadDailyPrompt)('daily-dialogue'), 'utf8');
47
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[1]assistant.md'), constants_1.OPENING_ASSISTANT, 'utf8');
48
+ writeDraft({ root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot }, emptyDraft());
49
+ return { root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot };
50
+ }
51
+ function createFinalizeSession(transcript, draft, day) {
52
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dayloom-daily-finalize-'));
53
+ const messagesDir = path_1.default.join(root, 'messages');
54
+ const toolsFile = path_1.default.join(root, 'readonly.tools.toml');
55
+ const promptpileConfig = path_1.default.join(root, 'promptpile.toml');
56
+ const draftFile = path_1.default.join(root, 'draft.json');
57
+ const playerContextRoot = path_1.default.join(root, 'player-context');
58
+ fs_1.default.mkdirSync(messagesDir, { recursive: true });
59
+ fs_1.default.writeFileSync(promptpileConfig, promptpileToml(), 'utf8');
60
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[0]system.md'), (0, prompts_1.loadDailyPrompt)('daily-finalize-plan'), 'utf8');
61
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[1]user.md'), `# Current day\n\n${day}\n\n# Transcript\n\n${transcript}\n\n# Draft\n\n${JSON.stringify(draft, null, 2)}\n`, 'utf8');
62
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[2]user.md'), '请生成最终 daily-plan。', 'utf8');
63
+ writeDraft({ root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot }, draft);
64
+ return { root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot };
65
+ }
66
+ function createIntentSession(input) {
67
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dayloom-daily-intent-'));
68
+ const messagesDir = path_1.default.join(root, 'messages');
69
+ const toolsFile = path_1.default.join(root, 'readonly.tools.toml');
70
+ const promptpileConfig = path_1.default.join(root, 'promptpile.toml');
71
+ const draftFile = path_1.default.join(root, 'draft.json');
72
+ const playerContextRoot = path_1.default.join(root, 'unused-context');
73
+ fs_1.default.mkdirSync(messagesDir, { recursive: true });
74
+ fs_1.default.writeFileSync(promptpileConfig, promptpileToml(), 'utf8');
75
+ fs_1.default.writeFileSync(toolsFile, '', 'utf8');
76
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[0]system.md'), (0, prompts_1.loadDailyPrompt)('daily-intent-router'), 'utf8');
77
+ fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[1]user.md'), JSON.stringify({
78
+ latest_user_input: input.input,
79
+ current_draft: input.draft,
80
+ latest_assistant_reply: input.latestAssistantReply,
81
+ }, null, 2), 'utf8');
82
+ writeDraft({ root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot }, input.draft);
83
+ return { root, messagesDir, toolsFile, promptpileConfig, draftFile, playerContextRoot };
84
+ }
85
+ function emptyDraft() { return { user_intent: '', known_context: [], constraints: [], open_questions: [] }; }
86
+ function readDraft(session) { return JSON.parse(fs_1.default.readFileSync(session.draftFile, 'utf8')); }
87
+ function writeDraft(session, draft) { fs_1.default.writeFileSync(session.draftFile, `${JSON.stringify(draft, null, 2)}\n`, 'utf8'); }
88
+ function cleanupSession(session) { if (fs_1.default.existsSync(session.root))
89
+ fs_1.default.rmSync(session.root, { recursive: true, force: true }); }
90
+ function appendUserMessage(messagesDir, content) {
91
+ const indices = scanMessageIndices(messagesDir);
92
+ const next = indices.length ? Math.max(...indices) + 1 : 0;
93
+ const filePath = path_1.default.join(messagesDir, `[${next}]user.md`);
94
+ fs_1.default.writeFileSync(filePath, content, 'utf8');
95
+ return filePath;
96
+ }
97
+ function getLatestAssistantText(messagesDir) {
98
+ const files = fs_1.default.readdirSync(messagesDir).filter(name => /^\[\d+\]assistant\.md$/i.test(name)).sort(byMessageIndex);
99
+ if (!files.length)
100
+ throw new Error('No assistant message found in daily session');
101
+ return fs_1.default.readFileSync(path_1.default.join(messagesDir, files[files.length - 1]), 'utf8');
102
+ }
103
+ function getLatestCallsFile(messagesDir) {
104
+ const files = fs_1.default.readdirSync(messagesDir).filter(name => /^\[\d+\]assistant\.calls\.jsonl$/i.test(name)).sort(byMessageIndex);
105
+ if (!files.length)
106
+ return undefined;
107
+ const latest = path_1.default.join(messagesDir, files[files.length - 1]);
108
+ return fs_1.default.existsSync(latest.replace(/\.calls\.jsonl$/i, '.result.jsonl')) ? undefined : latest;
109
+ }
110
+ function buildTranscript(messagesDir) {
111
+ return fs_1.default.readdirSync(messagesDir)
112
+ .map(name => { const m = name.match(MESSAGE_PATTERN); return m ? { idx: Number(m[1]), role: m[2], content: fs_1.default.readFileSync(path_1.default.join(messagesDir, name), 'utf8') } : null; })
113
+ .filter((x) => x !== null)
114
+ .sort((a, b) => a.idx - b.idx || a.role.localeCompare(b.role))
115
+ .map(x => `## [${x.idx}] ${x.role}\n\n${x.content}`)
116
+ .join('\n\n');
117
+ }
118
+ function scanMessageIndices(messagesDir) { return fs_1.default.readdirSync(messagesDir).map(name => name.match(/^\[(\d+)\]/)?.[1]).filter((x) => Boolean(x)).map(Number); }
119
+ function byMessageIndex(a, b) { return Number(a.match(/^\[(\d+)\]/)[1]) - Number(b.match(/^\[(\d+)\]/)[1]); }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateDailyPlan = validateDailyPlan;
4
+ const DAY_ID = /^day_\d{4}$/;
5
+ const BEAT_ID = /^beat_\d{2}$/;
6
+ const FORBIDDEN_KEYS = new Set(['outcome', 'result', 'results', 'reward', 'rewards', 'success', 'failure']);
7
+ function validateDailyPlan(plan, expectedDay) {
8
+ if (!plan || typeof plan !== 'object')
9
+ throw new Error('Daily plan must be an object');
10
+ if (typeof plan.day !== 'string' || !DAY_ID.test(plan.day))
11
+ throw new Error('Daily plan day must be day_NNNN');
12
+ if (expectedDay && plan.day !== expectedDay)
13
+ throw new Error(`Daily plan day mismatch: expected ${expectedDay}, got ${plan.day}`);
14
+ assertNonEmpty(plan.user_intent, 'Daily plan user_intent');
15
+ assertStringArray(plan.known_context, 'Daily plan known_context');
16
+ assertStringArray(plan.constraints, 'Daily plan constraints');
17
+ assertStringArray(plan.open_questions, 'Daily plan open_questions');
18
+ if (!Number.isInteger(plan.max_events) || plan.max_events < 1 || plan.max_events > 5)
19
+ throw new Error('Daily plan max_events must be between 1 and 5');
20
+ if (!Array.isArray(plan.planned_beats) || plan.planned_beats.length < 1 || plan.planned_beats.length > 5)
21
+ throw new Error('Daily plan planned_beats must contain 1 to 5 beats');
22
+ for (const [index, beat] of plan.planned_beats.entries()) {
23
+ if (!beat || typeof beat !== 'object')
24
+ throw new Error(`Daily beat ${index} must be an object`);
25
+ for (const key of Object.keys(beat))
26
+ if (FORBIDDEN_KEYS.has(key))
27
+ throw new Error(`Daily beat ${index} contains forbidden result field: ${key}`);
28
+ if (typeof beat.id !== 'string' || !BEAT_ID.test(beat.id))
29
+ throw new Error(`Daily beat ${index} id must be beat_NN`);
30
+ assertNonEmpty(beat.intent, `Daily beat ${index} intent`);
31
+ if (beat.priority !== 'required' && beat.priority !== 'optional')
32
+ throw new Error(`Daily beat ${index} priority is invalid`);
33
+ if (beat.status !== 'tentative')
34
+ throw new Error(`Daily beat ${index} status must be tentative`);
35
+ if (beat.depends_on !== undefined)
36
+ assertStringArray(beat.depends_on, `Daily beat ${index} depends_on`);
37
+ }
38
+ }
39
+ function assertNonEmpty(value, label) {
40
+ if (typeof value !== 'string' || !value.trim())
41
+ throw new Error(`${label} must be a non-empty string`);
42
+ }
43
+ function assertStringArray(value, label) {
44
+ if (!Array.isArray(value) || value.some(item => typeof item !== 'string'))
45
+ throw new Error(`${label} must be a string array`);
46
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectLocale = detectLocale;
4
+ exports.normalizeLocale = normalizeLocale;
5
+ function detectLocale(argv = process.argv, env = process.env) {
6
+ return normalizeLocale(readArgLocale(argv) ?? env.DAYLOOM_LANG ?? env.LC_ALL ?? env.LC_MESSAGES ?? env.LANG);
7
+ }
8
+ function normalizeLocale(value) {
9
+ const normalized = (value ?? '').trim().toLowerCase().replace('_', '-');
10
+ if (normalized === 'zh' || normalized.startsWith('zh-') || normalized.includes('chinese'))
11
+ return 'zh';
12
+ return 'en';
13
+ }
14
+ function readArgLocale(argv) {
15
+ for (let index = 0; index < argv.length; index += 1) {
16
+ const arg = argv[index];
17
+ if (arg === '--lang')
18
+ return argv[index + 1];
19
+ if (arg.startsWith('--lang='))
20
+ return arg.slice('--lang='.length);
21
+ }
22
+ return undefined;
23
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeLocale = exports.detectLocale = void 0;
4
+ exports.createTranslator = createTranslator;
5
+ exports.addLangOption = addLangOption;
6
+ const detect_1 = require("./detect");
7
+ const messages_1 = require("./messages");
8
+ function createTranslator(locale = (0, detect_1.detectLocale)()) {
9
+ return (key, vars) => interpolate(messages_1.messages[locale][key] ?? messages_1.messages.en[key] ?? key, vars);
10
+ }
11
+ function addLangOption(command, t) {
12
+ return command.option('--lang <locale>', t('cli.lang'));
13
+ }
14
+ var detect_2 = require("./detect");
15
+ Object.defineProperty(exports, "detectLocale", { enumerable: true, get: function () { return detect_2.detectLocale; } });
16
+ Object.defineProperty(exports, "normalizeLocale", { enumerable: true, get: function () { return detect_2.normalizeLocale; } });
17
+ function interpolate(template, vars = {}) {
18
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (match, key) => {
19
+ const value = vars[key];
20
+ return value === undefined || value === null ? match : String(value);
21
+ });
22
+ }