pi-deck 0.1.0 → 0.1.1
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 +6 -3
- package/bin/pi-deck.js +286 -50
- package/dist/server.js +74 -72
- package/dist/server.js.map +3 -3
- package/package.json +2 -1
- package/packages/client/dist/assets/MarkdownContent-D7i8glJy.js +2 -0
- package/packages/client/dist/assets/{index-BIGMLGdI.js → index-C2Zq6AKt.js} +139 -129
- package/packages/client/dist/assets/index-vhbgYHbc.css +1 -0
- package/packages/client/dist/index.html +2 -2
- package/packages/client/dist/assets/MarkdownContent-BP8uvTu3.js +0 -2
- package/packages/client/dist/assets/index-1WD5ZoeL.css +0 -1
package/dist/server.js
CHANGED
|
@@ -23,9 +23,9 @@ __export(plan_service_exports, {
|
|
|
23
23
|
updateTaskInContent: () => updateTaskInContent,
|
|
24
24
|
writePlan: () => writePlan
|
|
25
25
|
});
|
|
26
|
-
import { existsSync as
|
|
27
|
-
import { join as
|
|
28
|
-
import { homedir as
|
|
26
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, readdirSync as readdirSync2 } from "fs";
|
|
27
|
+
import { join as join3, basename as basename2, resolve as resolve2 } from "path";
|
|
28
|
+
import { homedir as homedir2 } from "os";
|
|
29
29
|
function parseFrontmatter(content) {
|
|
30
30
|
const frontmatter = {};
|
|
31
31
|
if (!content.startsWith("---")) {
|
|
@@ -88,7 +88,7 @@ function parseTasks(content) {
|
|
|
88
88
|
function parsePlan(filePath, content) {
|
|
89
89
|
const { frontmatter } = parseFrontmatter(content);
|
|
90
90
|
const tasks = parseTasks(content);
|
|
91
|
-
const fileName =
|
|
91
|
+
const fileName = basename2(filePath, ".md");
|
|
92
92
|
let title = frontmatter.title;
|
|
93
93
|
if (!title) {
|
|
94
94
|
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
@@ -161,11 +161,11 @@ ${fmBlock}
|
|
|
161
161
|
---${content.slice(endIndex + 4)}`;
|
|
162
162
|
}
|
|
163
163
|
function getPlanDirectories(workspacePath) {
|
|
164
|
-
const workspaceName =
|
|
164
|
+
const workspaceName = basename2(workspacePath);
|
|
165
165
|
const dirs = [];
|
|
166
|
-
const globalDir =
|
|
166
|
+
const globalDir = join3(homedir2(), "plans", workspaceName);
|
|
167
167
|
dirs.push(globalDir);
|
|
168
|
-
const localDir =
|
|
168
|
+
const localDir = join3(workspacePath, ".pi", "plans");
|
|
169
169
|
dirs.push(localDir);
|
|
170
170
|
return dirs;
|
|
171
171
|
}
|
|
@@ -173,12 +173,12 @@ function discoverPlans(workspacePath) {
|
|
|
173
173
|
const dirs = getPlanDirectories(workspacePath);
|
|
174
174
|
const plans = [];
|
|
175
175
|
for (const dir of dirs) {
|
|
176
|
-
if (!
|
|
176
|
+
if (!existsSync3(dir))
|
|
177
177
|
continue;
|
|
178
178
|
try {
|
|
179
179
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
|
|
180
180
|
for (const file of files) {
|
|
181
|
-
const filePath = resolve2(
|
|
181
|
+
const filePath = resolve2(join3(dir, file));
|
|
182
182
|
try {
|
|
183
183
|
const content = readFileSync2(filePath, "utf-8");
|
|
184
184
|
plans.push(parsePlan(filePath, content));
|
|
@@ -216,7 +216,7 @@ When all tasks are complete, let the user know the plan is finished.
|
|
|
216
216
|
</active_plan>`;
|
|
217
217
|
}
|
|
218
218
|
function getActivePlanState(planPath) {
|
|
219
|
-
if (!
|
|
219
|
+
if (!existsSync3(planPath))
|
|
220
220
|
return null;
|
|
221
221
|
try {
|
|
222
222
|
const content = readFileSync2(planPath, "utf-8");
|
|
@@ -267,9 +267,9 @@ __export(job_service_exports, {
|
|
|
267
267
|
updateTaskInContent: () => updateTaskInContent2,
|
|
268
268
|
writeJob: () => writeJob
|
|
269
269
|
});
|
|
270
|
-
import { existsSync as
|
|
271
|
-
import { join as
|
|
272
|
-
import { homedir as
|
|
270
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, readdirSync as readdirSync3, mkdirSync, renameSync } from "fs";
|
|
271
|
+
import { join as join4, basename as basename3, resolve as resolve3, dirname as dirname2 } from "path";
|
|
272
|
+
import { homedir as homedir3 } from "os";
|
|
273
273
|
import YAML from "yaml";
|
|
274
274
|
function statusToPhase(status) {
|
|
275
275
|
switch (status) {
|
|
@@ -366,7 +366,7 @@ function parseJobFrontmatter(content) {
|
|
|
366
366
|
function parseJob(filePath, content) {
|
|
367
367
|
const { frontmatter } = parseJobFrontmatter(content);
|
|
368
368
|
const tasks = parseTasks(content);
|
|
369
|
-
const fileName =
|
|
369
|
+
const fileName = basename3(filePath, ".md");
|
|
370
370
|
let title = frontmatter.title;
|
|
371
371
|
if (!title) {
|
|
372
372
|
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
@@ -410,8 +410,10 @@ function updateJobFrontmatter(content, updates) {
|
|
|
410
410
|
body = content.slice(block.bodyStart);
|
|
411
411
|
}
|
|
412
412
|
for (const [key, value] of Object.entries(updates)) {
|
|
413
|
-
if (value === void 0)
|
|
413
|
+
if (value === void 0) {
|
|
414
|
+
delete existing[key];
|
|
414
415
|
continue;
|
|
416
|
+
}
|
|
415
417
|
existing[key] = value;
|
|
416
418
|
}
|
|
417
419
|
const yamlStr = YAML.stringify(existing).trimEnd();
|
|
@@ -432,10 +434,10 @@ function updateTaskInContent2(content, lineNumber, done) {
|
|
|
432
434
|
return lines.join("\n");
|
|
433
435
|
}
|
|
434
436
|
function getJobDirectories(workspacePath) {
|
|
435
|
-
const workspaceName =
|
|
437
|
+
const workspaceName = basename3(workspacePath);
|
|
436
438
|
const dirs = [];
|
|
437
|
-
dirs.push(
|
|
438
|
-
dirs.push(
|
|
439
|
+
dirs.push(join4(homedir3(), ".pi", "agent", "jobs", workspaceName));
|
|
440
|
+
dirs.push(join4(workspacePath, ".pi", "jobs"));
|
|
439
441
|
return dirs;
|
|
440
442
|
}
|
|
441
443
|
function discoverJobs(workspacePath) {
|
|
@@ -443,12 +445,12 @@ function discoverJobs(workspacePath) {
|
|
|
443
445
|
const jobs = [];
|
|
444
446
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
445
447
|
for (const dir of dirs) {
|
|
446
|
-
if (!
|
|
448
|
+
if (!existsSync4(dir))
|
|
447
449
|
continue;
|
|
448
450
|
try {
|
|
449
451
|
const files = readdirSync3(dir).filter((f) => f.endsWith(".md"));
|
|
450
452
|
for (const file of files) {
|
|
451
|
-
const filePath = resolve3(
|
|
453
|
+
const filePath = resolve3(join4(dir, file));
|
|
452
454
|
if (seenPaths.has(filePath))
|
|
453
455
|
continue;
|
|
454
456
|
seenPaths.add(filePath);
|
|
@@ -489,18 +491,18 @@ function writeJob(jobPath, content) {
|
|
|
489
491
|
return parseJob(jobPath, content);
|
|
490
492
|
}
|
|
491
493
|
function createJob(workspacePath, title, description, tags) {
|
|
492
|
-
const workspaceName =
|
|
493
|
-
const jobsDir =
|
|
494
|
-
if (!
|
|
495
|
-
|
|
494
|
+
const workspaceName = basename3(workspacePath);
|
|
495
|
+
const jobsDir = join4(homedir3(), ".pi", "agent", "jobs", workspaceName);
|
|
496
|
+
if (!existsSync4(jobsDir)) {
|
|
497
|
+
mkdirSync(jobsDir, { recursive: true });
|
|
496
498
|
}
|
|
497
499
|
const now = /* @__PURE__ */ new Date();
|
|
498
500
|
const dateStr = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
499
501
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
500
|
-
let filePath =
|
|
502
|
+
let filePath = join4(jobsDir, `${dateStr}-${slug}.md`);
|
|
501
503
|
let counter = 1;
|
|
502
|
-
while (
|
|
503
|
-
filePath =
|
|
504
|
+
while (existsSync4(filePath)) {
|
|
505
|
+
filePath = join4(jobsDir, `${dateStr}-${slug}-${counter}.md`);
|
|
504
506
|
counter++;
|
|
505
507
|
}
|
|
506
508
|
const isoNow = now.toISOString();
|
|
@@ -543,6 +545,7 @@ function promoteJob(jobPath, toPhase) {
|
|
|
543
545
|
};
|
|
544
546
|
if (targetPhase === "complete") {
|
|
545
547
|
updates.completedAt = now;
|
|
548
|
+
updates.finalized = void 0;
|
|
546
549
|
}
|
|
547
550
|
const updatedContent = updateJobFrontmatter(content, updates);
|
|
548
551
|
const updatedJob = writeJob(jobPath, updatedContent);
|
|
@@ -572,24 +575,24 @@ function setJobSessionId(jobPath, field, sessionId) {
|
|
|
572
575
|
writeFileSync2(jobPath, updatedContent, "utf-8");
|
|
573
576
|
}
|
|
574
577
|
function getArchivedDir(jobDir) {
|
|
575
|
-
return
|
|
578
|
+
return join4(jobDir, "archived");
|
|
576
579
|
}
|
|
577
580
|
function archiveJob(jobPath) {
|
|
578
|
-
const dir =
|
|
579
|
-
const file =
|
|
581
|
+
const dir = dirname2(jobPath);
|
|
582
|
+
const file = basename3(jobPath);
|
|
580
583
|
const archivedDir = getArchivedDir(dir);
|
|
581
|
-
if (!
|
|
582
|
-
|
|
584
|
+
if (!existsSync4(archivedDir)) {
|
|
585
|
+
mkdirSync(archivedDir, { recursive: true });
|
|
583
586
|
}
|
|
584
|
-
const newPath =
|
|
587
|
+
const newPath = join4(archivedDir, file);
|
|
585
588
|
renameSync(jobPath, newPath);
|
|
586
589
|
return newPath;
|
|
587
590
|
}
|
|
588
591
|
function unarchiveJob(jobPath) {
|
|
589
|
-
const archivedDir =
|
|
590
|
-
const parentDir =
|
|
591
|
-
const file =
|
|
592
|
-
const newPath =
|
|
592
|
+
const archivedDir = dirname2(jobPath);
|
|
593
|
+
const parentDir = dirname2(archivedDir);
|
|
594
|
+
const file = basename3(jobPath);
|
|
595
|
+
const newPath = join4(parentDir, file);
|
|
593
596
|
renameSync(jobPath, newPath);
|
|
594
597
|
return newPath;
|
|
595
598
|
}
|
|
@@ -598,12 +601,12 @@ function discoverArchivedJobs(workspacePath) {
|
|
|
598
601
|
const jobs = [];
|
|
599
602
|
for (const dir of dirs) {
|
|
600
603
|
const archivedDir = getArchivedDir(dir);
|
|
601
|
-
if (!
|
|
604
|
+
if (!existsSync4(archivedDir))
|
|
602
605
|
continue;
|
|
603
606
|
try {
|
|
604
607
|
const files = readdirSync3(archivedDir).filter((f) => f.endsWith(".md"));
|
|
605
608
|
for (const file of files) {
|
|
606
|
-
const filePath = resolve3(
|
|
609
|
+
const filePath = resolve3(join4(archivedDir, file));
|
|
607
610
|
try {
|
|
608
611
|
const content = readFileSync3(filePath, "utf-8");
|
|
609
612
|
jobs.push(parseJob(filePath, content));
|
|
@@ -942,15 +945,15 @@ var DirectoryBrowser = class {
|
|
|
942
945
|
|
|
943
946
|
// packages/server/dist/workspace-manager.js
|
|
944
947
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
945
|
-
import { basename as
|
|
948
|
+
import { basename as basename4 } from "path";
|
|
946
949
|
|
|
947
950
|
// packages/server/dist/session-orchestrator.js
|
|
948
951
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
949
952
|
|
|
950
953
|
// packages/server/dist/pi-session.js
|
|
951
954
|
import { EventEmitter } from "events";
|
|
952
|
-
import { existsSync as
|
|
953
|
-
import { createAgentSession, AuthStorage, ModelRegistry, SessionManager, VERSION } from "@mariozechner/pi-coding-agent";
|
|
955
|
+
import { existsSync as existsSync5, unlinkSync } from "fs";
|
|
956
|
+
import { createAgentSession, AuthStorage, DefaultResourceLoader, ModelRegistry, SessionManager, VERSION } from "@mariozechner/pi-coding-agent";
|
|
954
957
|
|
|
955
958
|
// packages/server/dist/git-info.js
|
|
956
959
|
import { execSync } from "child_process";
|
|
@@ -1107,6 +1110,9 @@ new file mode 100644
|
|
|
1107
1110
|
}
|
|
1108
1111
|
}
|
|
1109
1112
|
|
|
1113
|
+
// packages/server/dist/pi-session.js
|
|
1114
|
+
init_job_service();
|
|
1115
|
+
|
|
1110
1116
|
// packages/server/dist/web-tui-components.js
|
|
1111
1117
|
var nodeIdCounter = 0;
|
|
1112
1118
|
function generateNodeId() {
|
|
@@ -1644,11 +1650,24 @@ var PiSession = class extends EventEmitter {
|
|
|
1644
1650
|
this.modelRegistry = new ModelRegistry(this.authStorage);
|
|
1645
1651
|
}
|
|
1646
1652
|
async initialize() {
|
|
1653
|
+
const cwd = this.cwd;
|
|
1654
|
+
const loader = new DefaultResourceLoader({
|
|
1655
|
+
cwd,
|
|
1656
|
+
appendSystemPromptOverride: (base) => {
|
|
1657
|
+
const jobContext = buildJobSystemContext(cwd);
|
|
1658
|
+
if (jobContext) {
|
|
1659
|
+
return [...base, jobContext];
|
|
1660
|
+
}
|
|
1661
|
+
return base;
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
await loader.reload();
|
|
1647
1665
|
const { session } = await createAgentSession({
|
|
1648
1666
|
cwd: this.cwd,
|
|
1649
1667
|
authStorage: this.authStorage,
|
|
1650
1668
|
modelRegistry: this.modelRegistry,
|
|
1651
|
-
sessionManager: SessionManager.create(this.cwd)
|
|
1669
|
+
sessionManager: SessionManager.create(this.cwd),
|
|
1670
|
+
resourceLoader: loader
|
|
1652
1671
|
});
|
|
1653
1672
|
this.session = session;
|
|
1654
1673
|
this.unsubscribe = session.subscribe((event) => this.handleEvent(event));
|
|
@@ -1706,7 +1725,7 @@ var PiSession = class extends EventEmitter {
|
|
|
1706
1725
|
return;
|
|
1707
1726
|
}
|
|
1708
1727
|
try {
|
|
1709
|
-
if (
|
|
1728
|
+
if (existsSync5(sessionFile)) {
|
|
1710
1729
|
unlinkSync(sessionFile);
|
|
1711
1730
|
}
|
|
1712
1731
|
} catch {
|
|
@@ -3022,7 +3041,7 @@ var WorkspaceManager = class extends EventEmitter3 {
|
|
|
3022
3041
|
const workspace = {
|
|
3023
3042
|
id,
|
|
3024
3043
|
path: normalizedPath,
|
|
3025
|
-
name:
|
|
3044
|
+
name: basename4(normalizedPath) || normalizedPath,
|
|
3026
3045
|
orchestrator,
|
|
3027
3046
|
unsubscribe,
|
|
3028
3047
|
clientCount: 1,
|
|
@@ -3245,9 +3264,9 @@ function getWorkspaceManager(allowedDirectories) {
|
|
|
3245
3264
|
|
|
3246
3265
|
// packages/server/dist/ui-state.js
|
|
3247
3266
|
import Database from "better-sqlite3";
|
|
3248
|
-
import { existsSync as
|
|
3249
|
-
import { homedir as
|
|
3250
|
-
import { dirname as
|
|
3267
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
|
|
3268
|
+
import { homedir as homedir4 } from "os";
|
|
3269
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
3251
3270
|
var DEFAULT_STATE = {
|
|
3252
3271
|
openWorkspaces: [],
|
|
3253
3272
|
activeWorkspacePath: null,
|
|
@@ -3265,10 +3284,10 @@ var DEFAULT_STATE = {
|
|
|
3265
3284
|
var UIStateStore = class {
|
|
3266
3285
|
db;
|
|
3267
3286
|
constructor(dbPath) {
|
|
3268
|
-
const path = dbPath ||
|
|
3269
|
-
const dir =
|
|
3270
|
-
if (!
|
|
3271
|
-
|
|
3287
|
+
const path = dbPath || join5(homedir4(), ".config", "pi-deck", "ui-state.db");
|
|
3288
|
+
const dir = dirname3(path);
|
|
3289
|
+
if (!existsSync6(dir)) {
|
|
3290
|
+
mkdirSync2(dir, { recursive: true });
|
|
3272
3291
|
}
|
|
3273
3292
|
this.db = new Database(path);
|
|
3274
3293
|
this.init();
|
|
@@ -5207,7 +5226,6 @@ workspaceManager2.on("bufferedEvent", (event) => {
|
|
|
5207
5226
|
console.log(`[WorkspaceManager] Buffering event for disconnected workspace: ${event.type}`);
|
|
5208
5227
|
}
|
|
5209
5228
|
});
|
|
5210
|
-
var finalizedSessions = /* @__PURE__ */ new Set();
|
|
5211
5229
|
workspaceManager2.on("event", (event) => {
|
|
5212
5230
|
if (event.type !== "agentEnd" || !("workspaceId" in event))
|
|
5213
5231
|
return;
|
|
@@ -5284,17 +5302,14 @@ Please read the job file and execute the review steps.`;
|
|
|
5284
5302
|
}
|
|
5285
5303
|
} else if (matchingJob.phase === "review") {
|
|
5286
5304
|
const reviewSlotId = matchingJob.frontmatter.reviewSessionId;
|
|
5287
|
-
|
|
5288
|
-
if (!alreadyFinalized && reviewSlotId) {
|
|
5305
|
+
if (!matchingJob.frontmatter.finalized && reviewSlotId) {
|
|
5289
5306
|
console.log(`[Jobs] Sending finalize nudge for job "${matchingJob.title}"`);
|
|
5290
|
-
|
|
5307
|
+
updateJobFrontmatter(matchingJob.path, { finalized: true });
|
|
5291
5308
|
const orchestrator = workspaceManager2.getOrchestrator(workspaceId);
|
|
5292
5309
|
const finalizePrompt = buildFinalizePrompt(matchingJob.path);
|
|
5293
5310
|
await orchestrator.prompt(reviewSlotId, finalizePrompt);
|
|
5294
5311
|
} else {
|
|
5295
5312
|
console.log(`[Jobs] Auto-promoting job "${matchingJob.title}" from review \u2192 complete`);
|
|
5296
|
-
if (reviewSlotId)
|
|
5297
|
-
finalizedSessions.delete(reviewSlotId);
|
|
5298
5313
|
const { job } = promoteJob(matchingJob.path);
|
|
5299
5314
|
broadcastToWorkspace(workspaceId, {
|
|
5300
5315
|
type: "jobPromoted",
|
|
@@ -5580,20 +5595,7 @@ async function handleMessage(ws, message) {
|
|
|
5580
5595
|
case "prompt": {
|
|
5581
5596
|
const orchestrator = workspaceManager2.getOrchestrator(message.workspaceId);
|
|
5582
5597
|
const slotId = getSlotId(message);
|
|
5583
|
-
|
|
5584
|
-
let promptMessage = message.message;
|
|
5585
|
-
if (workspace) {
|
|
5586
|
-
const messages = orchestrator.getMessages(slotId);
|
|
5587
|
-
if (messages.length === 0) {
|
|
5588
|
-
const jobContext = buildJobSystemContext(workspace.path);
|
|
5589
|
-
if (jobContext) {
|
|
5590
|
-
promptMessage = `${jobContext}
|
|
5591
|
-
|
|
5592
|
-
${promptMessage}`;
|
|
5593
|
-
}
|
|
5594
|
-
}
|
|
5595
|
-
}
|
|
5596
|
-
await orchestrator.prompt(slotId, promptMessage, message.images);
|
|
5598
|
+
await orchestrator.prompt(slotId, message.message, message.images);
|
|
5597
5599
|
break;
|
|
5598
5600
|
}
|
|
5599
5601
|
case "steer": {
|