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.
- package/README.md +1146 -0
- package/dist/cli/daily.js +41 -0
- package/dist/cli/index.js +33 -0
- package/dist/cli/init.js +40 -0
- package/dist/cli/next.js +60 -0
- package/dist/cli/play.js +39 -0
- package/dist/cli/revise.js +41 -0
- package/dist/cli/settle.js +45 -0
- package/dist/daily/apply-plan.js +25 -0
- package/dist/daily/constants.js +16 -0
- package/dist/daily/dialogue-loop.js +147 -0
- package/dist/daily/finalize.js +23 -0
- package/dist/daily/guard.js +54 -0
- package/dist/daily/index.js +27 -0
- package/dist/daily/intent-router.js +65 -0
- package/dist/daily/mcp-gateway.js +5 -0
- package/dist/daily/mcp-tools.js +8 -0
- package/dist/daily/parse-assistant.js +38 -0
- package/dist/daily/parse-payload.js +10 -0
- package/dist/daily/player-context.js +85 -0
- package/dist/daily/project-plan.js +15 -0
- package/dist/daily/promptpile-loop.js +41 -0
- package/dist/daily/prompts.js +11 -0
- package/dist/daily/read-user-input.js +6 -0
- package/dist/daily/session.js +119 -0
- package/dist/daily/types.js +2 -0
- package/dist/daily/validate-plan.js +46 -0
- package/dist/i18n/detect.js +23 -0
- package/dist/i18n/index.js +22 -0
- package/dist/i18n/messages.js +149 -0
- package/dist/index.js +27 -0
- package/dist/init/apply-payload.js +18 -0
- package/dist/init/archive-transcript.js +28 -0
- package/dist/init/checklist.js +74 -0
- package/dist/init/cleanup.js +12 -0
- package/dist/init/constants.js +21 -0
- package/dist/init/errors.js +11 -0
- package/dist/init/finalize.js +35 -0
- package/dist/init/guard.js +31 -0
- package/dist/init/index.js +59 -0
- package/dist/init/interview-loop.js +103 -0
- package/dist/init/parse-assistant.js +50 -0
- package/dist/init/project-payload.js +78 -0
- package/dist/init/promptpile-run.js +80 -0
- package/dist/init/prompts.js +16 -0
- package/dist/init/read-user-input.js +44 -0
- package/dist/init/scaffold.js +66 -0
- package/dist/init/session.js +98 -0
- package/dist/init/types.js +2 -0
- package/dist/next/index.js +79 -0
- package/dist/next/inspect.js +90 -0
- package/dist/play/ai.js +11 -0
- package/dist/play/event-loop.js +244 -0
- package/dist/play/guard.js +14 -0
- package/dist/play/index.js +21 -0
- package/dist/play/parse-assistant.js +39 -0
- package/dist/play/player-context.js +20 -0
- package/dist/play/prompts.js +9 -0
- package/dist/play/session.js +14 -0
- package/dist/play/state.js +117 -0
- package/dist/play/types.js +2 -0
- package/dist/play/validate.js +156 -0
- package/dist/revise/apply-payload.js +58 -0
- package/dist/revise/bin-resolve.js +38 -0
- package/dist/revise/constants.js +17 -0
- package/dist/revise/dialogue-loop.js +116 -0
- package/dist/revise/diff.js +24 -0
- package/dist/revise/file-hash.js +27 -0
- package/dist/revise/finalize.js +23 -0
- package/dist/revise/guard.js +17 -0
- package/dist/revise/index.js +24 -0
- package/dist/revise/mcp-gateway.js +74 -0
- package/dist/revise/mcp-tools.js +91 -0
- package/dist/revise/parse-assistant.js +41 -0
- package/dist/revise/parse-payload.js +22 -0
- package/dist/revise/process-run.js +77 -0
- package/dist/revise/project-payload.js +62 -0
- package/dist/revise/promptpile-loop.js +41 -0
- package/dist/revise/prompts.js +16 -0
- package/dist/revise/read-user-input.js +35 -0
- package/dist/revise/session.js +119 -0
- package/dist/revise/types.js +2 -0
- package/dist/revise/validate-payload.js +47 -0
- package/dist/settle/ai.js +23 -0
- package/dist/settle/apply.js +58 -0
- package/dist/settle/context.js +69 -0
- package/dist/settle/derive.js +56 -0
- package/dist/settle/guard.js +71 -0
- package/dist/settle/index.js +105 -0
- package/dist/settle/parse-assistant.js +14 -0
- package/dist/settle/parse-payload.js +19 -0
- package/dist/settle/project.js +58 -0
- package/dist/settle/session.js +45 -0
- package/dist/settle/types.js +2 -0
- package/dist/settle/validate.js +100 -0
- package/dist/shared/filtered-stream-output.js +41 -0
- package/dist/shared/promptpile-stream.js +59 -0
- package/dist/shared/run-promptpile-with-stream.js +34 -0
- package/dist/utils/loading.js +54 -0
- package/package.json +39 -0
- package/prompts/README.md +39 -0
- package/prompts/choice.system.md +0 -0
- package/prompts/daily-dialogue.system.md +37 -0
- package/prompts/daily-finalize-plan.system.md +34 -0
- package/prompts/daily-intent-router.system.md +34 -0
- package/prompts/day-planner.system.md +0 -0
- package/prompts/day-summarizer.system.md +0 -0
- package/prompts/dialogue.system.md +0 -0
- package/prompts/diary-writer.system.md +0 -0
- package/prompts/event-runner.system.md +0 -0
- package/prompts/init-finalize.system.md +59 -0
- package/prompts/init-interviewer.system.md +37 -0
- package/prompts/memory-updater.system.md +0 -0
- package/prompts/next-day-seeder.system.md +0 -0
- package/prompts/play-event-dialogue.system.md +20 -0
- package/prompts/play-event-generator.system.md +19 -0
- package/prompts/play-event-resolver.system.md +26 -0
- package/prompts/play-replanner.system.md +21 -0
- package/prompts/revise-dialogue.system.md +22 -0
- package/prompts/revise-finalize.system.md +40 -0
- package/prompts/settle.system.md +28 -0
- package/prompts/spec.md +320 -0
- package/prompts/state-resolver.system.md +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
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.resolveWorldRoot = resolveWorldRoot;
|
|
7
|
+
exports.assertSettlementCanStart = assertSettlementCanStart;
|
|
8
|
+
exports.assertNextDayAvailable = assertNextDayAvailable;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
function resolveWorldRoot(dir) {
|
|
12
|
+
return path_1.default.resolve(dir);
|
|
13
|
+
}
|
|
14
|
+
function assertSettlementCanStart(worldRoot) {
|
|
15
|
+
if (!fs_1.default.existsSync(path_1.default.join(worldRoot, 'manifest.yaml')))
|
|
16
|
+
throw new Error(`World save is not initialized: ${worldRoot}`);
|
|
17
|
+
const currentPath = path_1.default.join(worldRoot, 'current.yaml');
|
|
18
|
+
if (!fs_1.default.existsSync(currentPath))
|
|
19
|
+
throw new Error('World save missing current.yaml');
|
|
20
|
+
const current = fs_1.default.readFileSync(currentPath, 'utf8');
|
|
21
|
+
const day = readYamlScalar(current, 'day', 'current.yaml');
|
|
22
|
+
const phase = readYamlScalar(current, 'phase', 'current.yaml');
|
|
23
|
+
if (phase !== 'settling')
|
|
24
|
+
throw new Error(`Settlement requires current phase settling, got: ${phase}`);
|
|
25
|
+
const dayRoot = path_1.default.join(worldRoot, 'days', day);
|
|
26
|
+
const metaPath = path_1.default.join(dayRoot, 'meta.yaml');
|
|
27
|
+
if (!fs_1.default.existsSync(metaPath))
|
|
28
|
+
throw new Error(`Missing day metadata: days/${day}/meta.yaml`);
|
|
29
|
+
const metaPhase = readYamlScalar(fs_1.default.readFileSync(metaPath, 'utf8'), 'phase', `days/${day}/meta.yaml`);
|
|
30
|
+
if (metaPhase !== 'settling')
|
|
31
|
+
throw new Error(`Settlement requires day phase settling, got: ${metaPhase}`);
|
|
32
|
+
const plan = readJson(path_1.default.join(dayRoot, 'plan.current.json'), 'current plan');
|
|
33
|
+
const playState = readJson(path_1.default.join(dayRoot, 'play.state.json'), 'play state');
|
|
34
|
+
if (plan.day !== day)
|
|
35
|
+
throw new Error(`Current plan day mismatch: expected ${day}, got ${plan.day}`);
|
|
36
|
+
if (playState.day !== day)
|
|
37
|
+
throw new Error(`Play state day mismatch: expected ${day}, got ${playState.day}`);
|
|
38
|
+
if (playState.phase !== 'settling' || playState.step !== 'complete')
|
|
39
|
+
throw new Error('Settlement requires completed play state in settling phase');
|
|
40
|
+
if (playState.active_event !== null || playState.active_beat !== null)
|
|
41
|
+
throw new Error('Settlement cannot start while an event or beat is active');
|
|
42
|
+
const unfinished = plan.beats.filter(beat => beat.status !== 'completed' && beat.status !== 'cancelled');
|
|
43
|
+
if (unfinished.length > 0)
|
|
44
|
+
throw new Error(`Settlement requires all beats closed: ${unfinished.map(beat => beat.id).join(', ')}`);
|
|
45
|
+
for (const eventId of playState.completed_events) {
|
|
46
|
+
if (!fs_1.default.existsSync(path_1.default.join(dayRoot, 'events', eventId, 'result.json')))
|
|
47
|
+
throw new Error(`Completed event is missing result.json: ${eventId}`);
|
|
48
|
+
}
|
|
49
|
+
return { day, dayRoot, plan, playState };
|
|
50
|
+
}
|
|
51
|
+
function assertNextDayAvailable(worldRoot, nextDay) {
|
|
52
|
+
const nextRoot = path_1.default.join(worldRoot, 'days', nextDay);
|
|
53
|
+
if (fs_1.default.existsSync(nextRoot) && fs_1.default.readdirSync(nextRoot).length > 0)
|
|
54
|
+
throw new Error(`Next day directory already exists and is not empty: days/${nextDay}`);
|
|
55
|
+
}
|
|
56
|
+
function readYamlScalar(text, key, label) {
|
|
57
|
+
const match = text.match(new RegExp(`^${key}:\\s*(\\S+)\\s*$`, 'm'));
|
|
58
|
+
if (!match)
|
|
59
|
+
throw new Error(`${label} missing ${key}`);
|
|
60
|
+
return match[1];
|
|
61
|
+
}
|
|
62
|
+
function readJson(filePath, label) {
|
|
63
|
+
if (!fs_1.default.existsSync(filePath))
|
|
64
|
+
throw new Error(`Missing ${label}: ${filePath}`);
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error(`Invalid JSON in ${label}: ${filePath}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.settleFromProposal = settleFromProposal;
|
|
21
|
+
exports.settleWithAi = settleWithAi;
|
|
22
|
+
const fs_1 = __importDefault(require("fs"));
|
|
23
|
+
const os_1 = __importDefault(require("os"));
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const mcp_gateway_1 = require("../daily/mcp-gateway");
|
|
26
|
+
const mcp_tools_1 = require("../daily/mcp-tools");
|
|
27
|
+
const ai_1 = require("./ai");
|
|
28
|
+
const apply_1 = require("./apply");
|
|
29
|
+
const context_1 = require("./context");
|
|
30
|
+
const derive_1 = require("./derive");
|
|
31
|
+
const guard_1 = require("./guard");
|
|
32
|
+
const parse_assistant_1 = require("./parse-assistant");
|
|
33
|
+
const parse_payload_1 = require("./parse-payload");
|
|
34
|
+
const project_1 = require("./project");
|
|
35
|
+
const validate_1 = require("./validate");
|
|
36
|
+
const loading_1 = require("../utils/loading");
|
|
37
|
+
function settleFromProposal(dir, proposalPath, options = {}) {
|
|
38
|
+
const worldRoot = (0, guard_1.resolveWorldRoot)(dir);
|
|
39
|
+
const { day } = (0, guard_1.assertSettlementCanStart)(worldRoot);
|
|
40
|
+
const nextDay = (0, validate_1.nextDayId)(day);
|
|
41
|
+
(0, guard_1.assertNextDayAvailable)(worldRoot, nextDay);
|
|
42
|
+
const proposal = (0, parse_payload_1.readSettlementProposal)(proposalPath);
|
|
43
|
+
(0, validate_1.validateSettlementProposal)(proposal, day, worldRoot);
|
|
44
|
+
const changes = (0, project_1.projectSettlement)(worldRoot, proposal, nextDay, new Date().toISOString());
|
|
45
|
+
const description = (0, project_1.describeSettlementChanges)(worldRoot, changes);
|
|
46
|
+
if (options.dryRun)
|
|
47
|
+
return { worldRoot, day, nextDay, description, applied: false };
|
|
48
|
+
if (!options.yes)
|
|
49
|
+
throw new Error('Applying a settlement requires --yes. Use --dry-run to inspect changes.');
|
|
50
|
+
(0, apply_1.applySettlement)(worldRoot, proposal, changes, nextDay);
|
|
51
|
+
return { worldRoot, day, nextDay, description, applied: true };
|
|
52
|
+
}
|
|
53
|
+
async function settleWithAi(dir, options = {}) {
|
|
54
|
+
if (!process.env.DEEPSEEK_API_KEY?.trim())
|
|
55
|
+
throw new Error('DEEPSEEK_API_KEY is not set. AI settlement requires an API key.');
|
|
56
|
+
const worldRoot = (0, guard_1.resolveWorldRoot)(dir);
|
|
57
|
+
const { day } = (0, guard_1.assertSettlementCanStart)(worldRoot);
|
|
58
|
+
const nextDay = (0, validate_1.nextDayId)(day);
|
|
59
|
+
(0, guard_1.assertNextDayAvailable)(worldRoot, nextDay);
|
|
60
|
+
const serviceRoot = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dayloom-settle-service-'));
|
|
61
|
+
const contextRoot = path_1.default.join(serviceRoot, 'player-context');
|
|
62
|
+
const toolsFile = path_1.default.join(serviceRoot, 'readonly.tools.toml');
|
|
63
|
+
let gateway;
|
|
64
|
+
try {
|
|
65
|
+
await (0, loading_1.withLoading)('正在准备结算上下文...', async (loading) => {
|
|
66
|
+
(0, context_1.buildSettlementPlayerContext)(worldRoot, day, contextRoot);
|
|
67
|
+
loading.update('正在启动只读服务...');
|
|
68
|
+
gateway = await (0, mcp_gateway_1.connectOrStartGateway)(serviceRoot, contextRoot, options.mcpBaseUrl, options.mcpToken);
|
|
69
|
+
loading.update('正在准备只读工具...');
|
|
70
|
+
await (0, mcp_tools_1.exportReadonlyTools)(gateway.baseUrl, gateway.token, toolsFile);
|
|
71
|
+
await (0, mcp_tools_1.assertAllowedPlayerContextRoot)(gateway.baseUrl, gateway.token, contextRoot, serviceRoot);
|
|
72
|
+
});
|
|
73
|
+
const reply = await (0, loading_1.withLoading)('正在生成结算提案...', () => (0, ai_1.callSettlementAi)((0, context_1.buildSettlementPromptInput)(worldRoot, day), toolsFile, gateway.baseUrl, gateway.token, options.maxToolRounds ?? 8, options.keepSession));
|
|
74
|
+
const narrative = (0, parse_assistant_1.parseSettlementNarrative)(reply);
|
|
75
|
+
(0, validate_1.validateSettlementNarrative)(narrative);
|
|
76
|
+
const proposal = (0, derive_1.buildProgramSettlementProposal)(worldRoot, day, narrative);
|
|
77
|
+
(0, validate_1.validateSettlementProposal)(proposal, day, worldRoot);
|
|
78
|
+
const changes = (0, project_1.projectSettlement)(worldRoot, proposal, nextDay, new Date().toISOString());
|
|
79
|
+
const description = (0, project_1.describeSettlementChanges)(worldRoot, changes);
|
|
80
|
+
if (options.dryRun)
|
|
81
|
+
return { worldRoot, day, nextDay, description, applied: false };
|
|
82
|
+
if (!options.yes) {
|
|
83
|
+
const proposalPath = path_1.default.join(worldRoot, 'days', day, 'ending', 'settlement.proposal.json');
|
|
84
|
+
writeJsonAtomic(proposalPath, proposal);
|
|
85
|
+
return { worldRoot, day, nextDay, description, applied: false, proposalPath };
|
|
86
|
+
}
|
|
87
|
+
(0, apply_1.applySettlement)(worldRoot, proposal, changes, nextDay);
|
|
88
|
+
return { worldRoot, day, nextDay, description, applied: true };
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
if (gateway)
|
|
92
|
+
await gateway.stop();
|
|
93
|
+
if (options.keepSession)
|
|
94
|
+
process.stderr.write(`Settlement service session preserved at: ${serviceRoot}\n`);
|
|
95
|
+
else
|
|
96
|
+
fs_1.default.rmSync(serviceRoot, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function writeJsonAtomic(filePath, value) {
|
|
100
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
101
|
+
const temporary = `${filePath}.tmp`;
|
|
102
|
+
fs_1.default.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
103
|
+
fs_1.default.renameSync(temporary, filePath);
|
|
104
|
+
}
|
|
105
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSettlementNarrative = parseSettlementNarrative;
|
|
4
|
+
function parseSettlementNarrative(text) {
|
|
5
|
+
const match = text.match(/```(?:json\s+)?settlement-narrative\s*\n([\s\S]*?)```/i);
|
|
6
|
+
if (!match)
|
|
7
|
+
throw new Error('Assistant response missing settlement-narrative JSON block');
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(match[1].trim());
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
throw new Error(`Failed to parse settlement-narrative JSON: ${error instanceof Error ? error.message : error}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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.readSettlementProposal = readSettlementProposal;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function readSettlementProposal(proposalPath) {
|
|
10
|
+
const resolved = path_1.default.resolve(proposalPath);
|
|
11
|
+
if (!fs_1.default.existsSync(resolved))
|
|
12
|
+
throw new Error(`Settlement proposal not found: ${resolved}`);
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(fs_1.default.readFileSync(resolved, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
throw new Error(`Settlement proposal is not valid JSON: ${resolved}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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.projectSettlement = projectSettlement;
|
|
7
|
+
exports.describeSettlementChanges = describeSettlementChanges;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
function projectSettlement(worldRoot, proposal, nextDay, committedAt) {
|
|
11
|
+
const dayDir = `days/${proposal.day}`;
|
|
12
|
+
const changes = [
|
|
13
|
+
{ relativePath: `${dayDir}/summary.md`, content: ensureNewline(proposal.summary) },
|
|
14
|
+
{ relativePath: `${dayDir}/ending/objective_summary.md`, content: ensureNewline(proposal.summary) },
|
|
15
|
+
{ relativePath: `${dayDir}/ending/diary.md`, content: ensureNewline(proposal.diary) },
|
|
16
|
+
{ relativePath: `${dayDir}/ending/state_patch.json`, content: json(proposal.state_patch) },
|
|
17
|
+
{ relativePath: `${dayDir}/ending/next_day_seed.json`, content: json(proposal.next_day_seed) },
|
|
18
|
+
{ relativePath: `${dayDir}/ending/settlement.json`, content: json(proposal) },
|
|
19
|
+
];
|
|
20
|
+
for (const patch of proposal.state_patch) {
|
|
21
|
+
const existing = fs_1.default.readFileSync(path_1.default.join(worldRoot, patch.path), 'utf8');
|
|
22
|
+
changes.push({
|
|
23
|
+
relativePath: patch.path,
|
|
24
|
+
content: patch.op === 'replace' ? ensureNewline(patch.content) : appendContent(existing, patch.content),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const logPath = path_1.default.join(worldRoot, 'logs', 'state_changes.jsonl');
|
|
28
|
+
const existingLog = fs_1.default.existsSync(logPath) ? fs_1.default.readFileSync(logPath, 'utf8') : '';
|
|
29
|
+
changes.push({
|
|
30
|
+
relativePath: 'logs/state_changes.jsonl',
|
|
31
|
+
content: `${existingLog}${JSON.stringify({ type: 'day_settled', day: proposal.day, next_day: nextDay, summary: proposal.summary })}\n`,
|
|
32
|
+
});
|
|
33
|
+
changes.push({
|
|
34
|
+
relativePath: `${dayDir}/meta.yaml`,
|
|
35
|
+
content: updateDayMeta(fs_1.default.readFileSync(path_1.default.join(worldRoot, dayDir, 'meta.yaml'), 'utf8'), committedAt),
|
|
36
|
+
});
|
|
37
|
+
changes.push({
|
|
38
|
+
relativePath: `${dayDir}/ending/settle.state.json`,
|
|
39
|
+
content: json({ version: 1, day: proposal.day, status: 'committed', next_day: nextDay, committed_at: committedAt }),
|
|
40
|
+
});
|
|
41
|
+
changes.push({ relativePath: 'current.yaml', content: [`day: ${nextDay}`, 'phase: idle', `last_committed_day: ${proposal.day}`, ''].join('\n') });
|
|
42
|
+
return changes;
|
|
43
|
+
}
|
|
44
|
+
function describeSettlementChanges(worldRoot, changes) {
|
|
45
|
+
return changes.map(change => `${fs_1.default.existsSync(path_1.default.join(worldRoot, change.relativePath)) ? 'update' : 'create'} ${change.relativePath}`).join('\n');
|
|
46
|
+
}
|
|
47
|
+
function appendContent(existing, addition) {
|
|
48
|
+
const base = existing.replace(/\s+$/, '');
|
|
49
|
+
const next = addition.trim();
|
|
50
|
+
return base ? `${base}\n\n${next}\n` : `${next}\n`;
|
|
51
|
+
}
|
|
52
|
+
function updateDayMeta(text, committedAt) {
|
|
53
|
+
let next = /^phase:/m.test(text) ? text.replace(/^phase:.*$/m, 'phase: settled') : `${text.replace(/\s*$/, '')}\nphase: settled\n`;
|
|
54
|
+
next = /^settled_at:/m.test(next) ? next.replace(/^settled_at:.*$/m, `settled_at: ${committedAt}`) : `${next.replace(/\s*$/, '')}\nsettled_at: ${committedAt}\n`;
|
|
55
|
+
return next;
|
|
56
|
+
}
|
|
57
|
+
function ensureNewline(value) { return `${value.trim()}\n`; }
|
|
58
|
+
function json(value) { return `${JSON.stringify(value, null, 2)}\n`; }
|
|
@@ -0,0 +1,45 @@
|
|
|
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.createSettlementSession = createSettlementSession;
|
|
7
|
+
exports.cleanupSettlementSession = cleanupSettlementSession;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
function promptpileToml() {
|
|
12
|
+
return `[[llm_api]]
|
|
13
|
+
name = "deepseek"
|
|
14
|
+
model = "deepseek-chat"
|
|
15
|
+
base_url = "https://api.deepseek.com/v1"
|
|
16
|
+
api_key_env = "DEEPSEEK_API_KEY"
|
|
17
|
+
|
|
18
|
+
[promptpile]
|
|
19
|
+
llm_api = "deepseek"
|
|
20
|
+
dir = "./messages"
|
|
21
|
+
tools_file = "./readonly.tools.toml"
|
|
22
|
+
quiet = true
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
function createSettlementSession(systemPrompt, userContent, toolsSource) {
|
|
26
|
+
const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dayloom-settle-'));
|
|
27
|
+
const messagesDir = path_1.default.join(root, 'messages');
|
|
28
|
+
const session = {
|
|
29
|
+
root,
|
|
30
|
+
messagesDir,
|
|
31
|
+
toolsFile: path_1.default.join(root, 'readonly.tools.toml'),
|
|
32
|
+
promptpileConfig: path_1.default.join(root, 'promptpile.toml'),
|
|
33
|
+
draftFile: path_1.default.join(root, 'unused.json'),
|
|
34
|
+
playerContextRoot: path_1.default.join(root, 'unused-context'),
|
|
35
|
+
};
|
|
36
|
+
fs_1.default.mkdirSync(messagesDir, { recursive: true });
|
|
37
|
+
fs_1.default.writeFileSync(session.promptpileConfig, promptpileToml(), 'utf8');
|
|
38
|
+
fs_1.default.copyFileSync(toolsSource, session.toolsFile);
|
|
39
|
+
fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[0]system.md'), systemPrompt, 'utf8');
|
|
40
|
+
fs_1.default.writeFileSync(path_1.default.join(messagesDir, '[1]user.md'), userContent, 'utf8');
|
|
41
|
+
return session;
|
|
42
|
+
}
|
|
43
|
+
function cleanupSettlementSession(session) {
|
|
44
|
+
fs_1.default.rmSync(session.root, { recursive: true, force: true });
|
|
45
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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.validateSettlementProposal = validateSettlementProposal;
|
|
7
|
+
exports.nextDayId = nextDayId;
|
|
8
|
+
exports.validateSettlementNarrative = validateSettlementNarrative;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const DAY_ID = /^day_(\d{4})$/;
|
|
12
|
+
const REPLACE_PATHS = new Set([
|
|
13
|
+
'state/world.yaml', 'state/calendar.yaml', 'state/progress.yaml', 'state/variables.yaml',
|
|
14
|
+
'memory/facts.yaml', 'memory/important_events.yaml', 'memory/unresolved_threads.yaml',
|
|
15
|
+
]);
|
|
16
|
+
const APPEND_PATHS = [
|
|
17
|
+
/^memory\/(?:short_term|long_term)\.md$/,
|
|
18
|
+
/^characters\/[a-z][a-z0-9_]*\/(?:memory|timeline|relationships)\.md$/,
|
|
19
|
+
/^scenes\/[a-z][a-z0-9_]*\/(?:memory|timeline)\.md$/,
|
|
20
|
+
/^arcs\/[a-z][a-z0-9_]*\/timeline\.md$/,
|
|
21
|
+
];
|
|
22
|
+
function validateSettlementProposal(proposal, expectedDay, worldRoot) {
|
|
23
|
+
if (!proposal || typeof proposal !== 'object' || Array.isArray(proposal))
|
|
24
|
+
throw new Error('Settlement proposal must be an object');
|
|
25
|
+
if (proposal.version !== 1)
|
|
26
|
+
throw new Error('Settlement proposal version must be 1');
|
|
27
|
+
if (typeof proposal.day !== 'string' || !DAY_ID.test(proposal.day))
|
|
28
|
+
throw new Error('Settlement proposal day must be day_NNNN');
|
|
29
|
+
if (proposal.day !== expectedDay)
|
|
30
|
+
throw new Error(`Settlement proposal day mismatch: expected ${expectedDay}, got ${proposal.day}`);
|
|
31
|
+
assertNonEmpty(proposal.summary, 'Settlement proposal summary');
|
|
32
|
+
assertNonEmpty(proposal.diary, 'Settlement proposal diary');
|
|
33
|
+
if (!Array.isArray(proposal.state_patch))
|
|
34
|
+
throw new Error('Settlement proposal state_patch must be an array');
|
|
35
|
+
const patchedPaths = new Set();
|
|
36
|
+
proposal.state_patch.forEach((patch, index) => {
|
|
37
|
+
validatePatch(patch, index, worldRoot);
|
|
38
|
+
if (patchedPaths.has(patch.path))
|
|
39
|
+
throw new Error(`Settlement patch path is duplicated: ${patch.path}`);
|
|
40
|
+
patchedPaths.add(patch.path);
|
|
41
|
+
});
|
|
42
|
+
const seed = proposal.next_day_seed;
|
|
43
|
+
if (!seed || typeof seed !== 'object' || Array.isArray(seed))
|
|
44
|
+
throw new Error('Settlement proposal next_day_seed must be an object');
|
|
45
|
+
assertNonEmpty(seed.summary, 'Settlement proposal next_day_seed.summary');
|
|
46
|
+
assertStringArray(seed.suggested_intents, 'Settlement proposal next_day_seed.suggested_intents');
|
|
47
|
+
assertStringArray(seed.unresolved_threads, 'Settlement proposal next_day_seed.unresolved_threads');
|
|
48
|
+
}
|
|
49
|
+
function nextDayId(day) {
|
|
50
|
+
const match = day.match(DAY_ID);
|
|
51
|
+
if (!match)
|
|
52
|
+
throw new Error(`Invalid day id: ${day}`);
|
|
53
|
+
const next = Number(match[1]) + 1;
|
|
54
|
+
if (next > 9999)
|
|
55
|
+
throw new Error(`Cannot advance beyond ${day}`);
|
|
56
|
+
return `day_${String(next).padStart(4, '0')}`;
|
|
57
|
+
}
|
|
58
|
+
function validatePatch(patch, index, worldRoot) {
|
|
59
|
+
if (!patch || typeof patch !== 'object' || Array.isArray(patch))
|
|
60
|
+
throw new Error(`Settlement patch ${index} must be an object`);
|
|
61
|
+
if (patch.op !== 'replace' && patch.op !== 'append')
|
|
62
|
+
throw new Error(`Settlement patch ${index} has unsupported op`);
|
|
63
|
+
if (typeof patch.path !== 'string' || !patch.path)
|
|
64
|
+
throw new Error(`Settlement patch ${index} path must be non-empty`);
|
|
65
|
+
if (path_1.default.isAbsolute(patch.path) || patch.path.includes('\\') || patch.path.split('/').includes('..'))
|
|
66
|
+
throw new Error(`Settlement patch ${index} path is unsafe: ${patch.path}`);
|
|
67
|
+
assertNonEmpty(patch.content, `Settlement patch ${index} content`);
|
|
68
|
+
if (patch.op === 'replace') {
|
|
69
|
+
if (!REPLACE_PATHS.has(patch.path))
|
|
70
|
+
throw new Error(`Settlement patch ${index} replace path is not allowed: ${patch.path}`);
|
|
71
|
+
if (!fs_1.default.existsSync(path_1.default.join(worldRoot, patch.path)))
|
|
72
|
+
throw new Error(`Settlement patch ${index} cannot replace missing file: ${patch.path}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!APPEND_PATHS.some(pattern => pattern.test(patch.path)))
|
|
76
|
+
throw new Error(`Settlement patch ${index} append path is not allowed: ${patch.path}`);
|
|
77
|
+
if (!fs_1.default.existsSync(path_1.default.join(worldRoot, patch.path)))
|
|
78
|
+
throw new Error(`Settlement patch ${index} cannot append to missing file: ${patch.path}`);
|
|
79
|
+
}
|
|
80
|
+
function assertNonEmpty(value, label) {
|
|
81
|
+
if (typeof value !== 'string' || !value.trim())
|
|
82
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
83
|
+
}
|
|
84
|
+
function assertStringArray(value, label) {
|
|
85
|
+
if (!Array.isArray(value) || value.some(item => typeof item !== 'string' || !item.trim()))
|
|
86
|
+
throw new Error(`${label} must be an array of non-empty strings`);
|
|
87
|
+
}
|
|
88
|
+
function validateSettlementNarrative(narrative) {
|
|
89
|
+
if (!narrative || typeof narrative !== 'object' || Array.isArray(narrative))
|
|
90
|
+
throw new Error('Settlement narrative must be an object');
|
|
91
|
+
assertNonEmpty(narrative.summary, 'Settlement narrative summary');
|
|
92
|
+
assertNonEmpty(narrative.diary, 'Settlement narrative diary');
|
|
93
|
+
const seed = narrative.next_day_seed;
|
|
94
|
+
if (!seed || typeof seed !== 'object' || Array.isArray(seed))
|
|
95
|
+
throw new Error('Settlement narrative next_day_seed must be an object');
|
|
96
|
+
assertNonEmpty(seed.summary, 'Settlement narrative next_day_seed.summary');
|
|
97
|
+
assertStringArray(seed.suggested_intents, 'Settlement narrative next_day_seed.suggested_intents');
|
|
98
|
+
if (seed.suggested_intents.length < 1 || seed.suggested_intents.length > 5)
|
|
99
|
+
throw new Error('Settlement narrative suggested_intents must contain 1 to 5 items');
|
|
100
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createFilteredStreamOutput = createFilteredStreamOutput;
|
|
4
|
+
function createFilteredStreamOutput(options) {
|
|
5
|
+
const write = options.write ?? (text => process.stdout.write(text));
|
|
6
|
+
const hidden = new Set(options.hiddenBlocks.map(label => label.toLowerCase()));
|
|
7
|
+
let buffer = '';
|
|
8
|
+
let suppressing = false;
|
|
9
|
+
const handleLine = (line, newline) => {
|
|
10
|
+
const trimmed = line.trim();
|
|
11
|
+
if (suppressing) {
|
|
12
|
+
if (trimmed.startsWith('```'))
|
|
13
|
+
suppressing = false;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const match = trimmed.match(/^```(?:json\s+)?([a-z0-9_-]+)/i);
|
|
17
|
+
if (match && hidden.has(match[1].toLowerCase())) {
|
|
18
|
+
suppressing = true;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
write(line);
|
|
22
|
+
if (newline)
|
|
23
|
+
write('\n');
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
push(chunk) {
|
|
27
|
+
buffer += chunk;
|
|
28
|
+
const lines = buffer.split('\n');
|
|
29
|
+
buffer = lines.pop() ?? '';
|
|
30
|
+
for (const line of lines)
|
|
31
|
+
handleLine(line, true);
|
|
32
|
+
},
|
|
33
|
+
flush() {
|
|
34
|
+
if (buffer !== '') {
|
|
35
|
+
const line = buffer;
|
|
36
|
+
buffer = '';
|
|
37
|
+
handleLine(line, false);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPromptpileStreamConsumer = createPromptpileStreamConsumer;
|
|
4
|
+
function createPromptpileStreamConsumer(options) {
|
|
5
|
+
let buffer = '';
|
|
6
|
+
const handleLine = (rawLine) => {
|
|
7
|
+
const line = rawLine.trim();
|
|
8
|
+
if (!line) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
let event;
|
|
12
|
+
try {
|
|
13
|
+
event = JSON.parse(line);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
17
|
+
throw new Error('Invalid promptpile stream JSON: ' + detail + ': ' + line);
|
|
18
|
+
}
|
|
19
|
+
if (!event || typeof event !== 'object') {
|
|
20
|
+
throw new Error('Invalid promptpile stream event: ' + line);
|
|
21
|
+
}
|
|
22
|
+
const payload = event;
|
|
23
|
+
const type = payload.type;
|
|
24
|
+
if (type === 'assistant_delta') {
|
|
25
|
+
if (typeof payload.content !== 'string') {
|
|
26
|
+
throw new Error('Invalid promptpile assistant_delta event: ' + line);
|
|
27
|
+
}
|
|
28
|
+
options.onDelta(payload.content);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (type === 'assistant_done') {
|
|
32
|
+
options.onDone?.();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (type === 'error') {
|
|
36
|
+
const message = typeof payload.message === 'string' ? payload.message : line;
|
|
37
|
+
options.onError?.(message);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw new Error('Unknown promptpile stream event type: ' + String(type));
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
push(chunk) {
|
|
44
|
+
buffer += chunk;
|
|
45
|
+
const lines = buffer.split('\n');
|
|
46
|
+
buffer = lines.pop() ?? '';
|
|
47
|
+
for (const line of lines) {
|
|
48
|
+
handleLine(line);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
flush() {
|
|
52
|
+
if (buffer.trim() !== '') {
|
|
53
|
+
const line = buffer;
|
|
54
|
+
buffer = '';
|
|
55
|
+
handleLine(line);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runPromptpileWithStream = runPromptpileWithStream;
|
|
4
|
+
const process_run_1 = require("../revise/process-run");
|
|
5
|
+
const promptpile_stream_1 = require("./promptpile-stream");
|
|
6
|
+
async function runPromptpileWithStream(options) {
|
|
7
|
+
const consumer = (0, promptpile_stream_1.createPromptpileStreamConsumer)({
|
|
8
|
+
onDelta: options.onDelta,
|
|
9
|
+
onError: message => {
|
|
10
|
+
throw new Error('promptpile stream error: ' + message);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const result = await (0, process_run_1.runProcess)(options.command, [
|
|
14
|
+
...options.args,
|
|
15
|
+
'--output-pile-fd',
|
|
16
|
+
'3',
|
|
17
|
+
'--output-pile-format',
|
|
18
|
+
'json'
|
|
19
|
+
], {
|
|
20
|
+
cwd: options.cwd,
|
|
21
|
+
quiet: options.quiet,
|
|
22
|
+
outputPile: {
|
|
23
|
+
fd: 3,
|
|
24
|
+
onData: chunk => consumer.push(chunk)
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
consumer.flush();
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
return { ...result, error: e instanceof Error ? e : new Error(String(e)) };
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startLoading = startLoading;
|
|
4
|
+
exports.withLoading = withLoading;
|
|
5
|
+
const FRAMES = ['|', '/', '-', '\\'];
|
|
6
|
+
function startLoading(label, options = {}) {
|
|
7
|
+
const stream = options.stream ?? process.stdout;
|
|
8
|
+
if (!stream.isTTY)
|
|
9
|
+
return { update: () => undefined, stop: () => undefined };
|
|
10
|
+
const delayMs = options.delayMs ?? 300;
|
|
11
|
+
const intervalMs = options.intervalMs ?? 100;
|
|
12
|
+
let currentLabel = label;
|
|
13
|
+
let frameIndex = 0;
|
|
14
|
+
let visible = false;
|
|
15
|
+
let stopped = false;
|
|
16
|
+
let interval;
|
|
17
|
+
const render = () => {
|
|
18
|
+
if (stopped)
|
|
19
|
+
return;
|
|
20
|
+
visible = true;
|
|
21
|
+
const text = `${currentLabel} ${FRAMES[frameIndex++ % FRAMES.length]}`;
|
|
22
|
+
stream.write(`\r\u001b[2K${text}`);
|
|
23
|
+
};
|
|
24
|
+
const delay = setTimeout(() => {
|
|
25
|
+
render();
|
|
26
|
+
interval = setInterval(render, intervalMs);
|
|
27
|
+
}, delayMs);
|
|
28
|
+
return {
|
|
29
|
+
update(nextLabel) {
|
|
30
|
+
currentLabel = nextLabel;
|
|
31
|
+
if (visible)
|
|
32
|
+
render();
|
|
33
|
+
},
|
|
34
|
+
stop() {
|
|
35
|
+
if (stopped)
|
|
36
|
+
return;
|
|
37
|
+
stopped = true;
|
|
38
|
+
clearTimeout(delay);
|
|
39
|
+
if (interval)
|
|
40
|
+
clearInterval(interval);
|
|
41
|
+
if (visible)
|
|
42
|
+
stream.write('\r\u001b[2K');
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function withLoading(label, task, options = {}) {
|
|
47
|
+
const loading = startLoading(label, options);
|
|
48
|
+
try {
|
|
49
|
+
return await task(loading);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
loading.stop();
|
|
53
|
+
}
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dayloom",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "File-based AI life simulation and diary engine.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dayloom": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"prepare": "npm run build",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "ts-node src/index.ts",
|
|
14
|
+
"test": "npm run build && node --test test/init/*.test.js test/revise/*.test.js test/daily/*.test.js test/play/*.test.js test/settle/*.test.js test/next/*.test.js test/i18n/*.test.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"dayloom",
|
|
18
|
+
"command-line"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"type": "commonjs",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"prompts",
|
|
26
|
+
"README.md",
|
|
27
|
+
"package.json"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^14.0.3",
|
|
31
|
+
"promptpile": "^0.1.0-beta.0",
|
|
32
|
+
"promptpile-mcp": "^0.1.0-beta.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.5.2",
|
|
36
|
+
"ts-node": "^10.9.2",
|
|
37
|
+
"typescript": "~5.9.3"
|
|
38
|
+
}
|
|
39
|
+
}
|