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/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 existsSync5, readFileSync as readFileSync2, writeFileSync, readdirSync as readdirSync2 } from "fs";
27
- import { join as join4, basename as basename3, resolve as resolve2 } from "path";
28
- import { homedir as homedir3 } from "os";
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 = basename3(filePath, ".md");
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 = basename3(workspacePath);
164
+ const workspaceName = basename2(workspacePath);
165
165
  const dirs = [];
166
- const globalDir = join4(homedir3(), "plans", workspaceName);
166
+ const globalDir = join3(homedir2(), "plans", workspaceName);
167
167
  dirs.push(globalDir);
168
- const localDir = join4(workspacePath, ".pi", "plans");
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 (!existsSync5(dir))
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(join4(dir, file));
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 (!existsSync5(planPath))
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 existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync2, readdirSync as readdirSync3, mkdirSync as mkdirSync2, renameSync } from "fs";
271
- import { join as join5, basename as basename4, resolve as resolve3, dirname as dirname3 } from "path";
272
- import { homedir as homedir4 } from "os";
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 = basename4(filePath, ".md");
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 = basename4(workspacePath);
437
+ const workspaceName = basename3(workspacePath);
436
438
  const dirs = [];
437
- dirs.push(join5(homedir4(), ".pi", "agent", "jobs", workspaceName));
438
- dirs.push(join5(workspacePath, ".pi", "jobs"));
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 (!existsSync6(dir))
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(join5(dir, file));
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 = basename4(workspacePath);
493
- const jobsDir = join5(homedir4(), ".pi", "agent", "jobs", workspaceName);
494
- if (!existsSync6(jobsDir)) {
495
- mkdirSync2(jobsDir, { recursive: true });
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 = join5(jobsDir, `${dateStr}-${slug}.md`);
502
+ let filePath = join4(jobsDir, `${dateStr}-${slug}.md`);
501
503
  let counter = 1;
502
- while (existsSync6(filePath)) {
503
- filePath = join5(jobsDir, `${dateStr}-${slug}-${counter}.md`);
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 join5(jobDir, "archived");
578
+ return join4(jobDir, "archived");
576
579
  }
577
580
  function archiveJob(jobPath) {
578
- const dir = dirname3(jobPath);
579
- const file = basename4(jobPath);
581
+ const dir = dirname2(jobPath);
582
+ const file = basename3(jobPath);
580
583
  const archivedDir = getArchivedDir(dir);
581
- if (!existsSync6(archivedDir)) {
582
- mkdirSync2(archivedDir, { recursive: true });
584
+ if (!existsSync4(archivedDir)) {
585
+ mkdirSync(archivedDir, { recursive: true });
583
586
  }
584
- const newPath = join5(archivedDir, file);
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 = dirname3(jobPath);
590
- const parentDir = dirname3(archivedDir);
591
- const file = basename4(jobPath);
592
- const newPath = join5(parentDir, file);
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 (!existsSync6(archivedDir))
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(join5(archivedDir, file));
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 basename2 } from "path";
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 existsSync3, unlinkSync } from "fs";
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 (existsSync3(sessionFile)) {
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: basename2(normalizedPath) || normalizedPath,
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 existsSync4, mkdirSync } from "fs";
3249
- import { homedir as homedir2 } from "os";
3250
- import { dirname as dirname2, join as join3 } from "path";
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 || join3(homedir2(), ".config", "pi-deck", "ui-state.db");
3269
- const dir = dirname2(path);
3270
- if (!existsSync4(dir)) {
3271
- mkdirSync(dir, { recursive: true });
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
- const alreadyFinalized = reviewSlotId && finalizedSessions.has(reviewSlotId);
5288
- if (!alreadyFinalized && reviewSlotId) {
5305
+ if (!matchingJob.frontmatter.finalized && reviewSlotId) {
5289
5306
  console.log(`[Jobs] Sending finalize nudge for job "${matchingJob.title}"`);
5290
- finalizedSessions.add(reviewSlotId);
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
- const workspace = workspaceManager2.getWorkspace(message.workspaceId);
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": {