@plannotator/opencode 0.4.8 → 0.4.9

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 (2) hide show
  1. package/dist/index.js +72 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { tool } from "@opencode-ai/plugin";
4
4
 
5
5
  // ../../packages/server/index.ts
6
- import { mkdirSync as mkdirSync2 } from "fs";
6
+ import { mkdirSync as mkdirSync3 } from "fs";
7
7
 
8
8
  // ../../packages/server/remote.ts
9
9
  var DEFAULT_REMOTE_PORT = 19432;
@@ -264,6 +264,55 @@ ${hashtags}`;
264
264
  }
265
265
  }
266
266
 
267
+ // ../../packages/server/storage.ts
268
+ import { homedir } from "os";
269
+ import { join as join2 } from "path";
270
+ import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
271
+ function getPlanDir() {
272
+ const home = homedir();
273
+ const planDir = join2(home, ".plannotator", "plans");
274
+ mkdirSync2(planDir, { recursive: true });
275
+ return planDir;
276
+ }
277
+ function extractFirstHeading(markdown) {
278
+ const match = markdown.match(/^#\s+(.+)$/m);
279
+ if (!match)
280
+ return null;
281
+ return match[1].trim();
282
+ }
283
+ function generateSlug(plan) {
284
+ const date = new Date().toISOString().split("T")[0];
285
+ const heading = extractFirstHeading(plan);
286
+ const slug = heading ? sanitizeTag(heading) : null;
287
+ return slug ? `${date}-${slug}` : `${date}-plan`;
288
+ }
289
+ function savePlan(slug, content) {
290
+ const planDir = getPlanDir();
291
+ const filePath = join2(planDir, `${slug}.md`);
292
+ writeFileSync(filePath, content, "utf-8");
293
+ return filePath;
294
+ }
295
+ function saveAnnotations(slug, diffContent) {
296
+ const planDir = getPlanDir();
297
+ const filePath = join2(planDir, `${slug}.diff.md`);
298
+ writeFileSync(filePath, diffContent, "utf-8");
299
+ return filePath;
300
+ }
301
+ function saveFinalSnapshot(slug, status, plan, diff) {
302
+ const planDir = getPlanDir();
303
+ const filePath = join2(planDir, `${slug}-${status}.md`);
304
+ let content = plan;
305
+ if (diff && diff !== "No changes detected.") {
306
+ content += `
307
+
308
+ ---
309
+
310
+ ` + diff;
311
+ }
312
+ writeFileSync(filePath, content, "utf-8");
313
+ return filePath;
314
+ }
315
+
267
316
  // ../../packages/server/index.ts
268
317
  var MAX_RETRIES = 5;
269
318
  var RETRY_DELAY_MS = 500;
@@ -271,6 +320,8 @@ async function startPlannotatorServer(options) {
271
320
  const { plan, origin, htmlContent, onReady } = options;
272
321
  const isRemote = isRemoteSession();
273
322
  const configuredPort = getServerPort();
323
+ const slug = generateSlug(plan);
324
+ const planPath = savePlan(slug, plan);
274
325
  let resolveDecision;
275
326
  const decisionPromise = new Promise((resolve) => {
276
327
  resolveDecision = resolve;
@@ -309,7 +360,7 @@ async function startPlannotatorServer(options) {
309
360
  }
310
361
  const ext = file.name.split(".").pop() || "png";
311
362
  const tempDir = "/tmp/plannotator";
312
- mkdirSync2(tempDir, { recursive: true });
363
+ mkdirSync3(tempDir, { recursive: true });
313
364
  const tempPath = `${tempDir}/${crypto.randomUUID()}.${ext}`;
314
365
  await Bun.write(tempPath, file);
315
366
  return Response.json({ path: tempPath });
@@ -348,23 +399,24 @@ async function startPlannotatorServer(options) {
348
399
  } catch (err) {
349
400
  console.error(`[Integration] Error:`, err);
350
401
  }
351
- resolveDecision({ approved: true, feedback });
352
- return Response.json({ ok: true });
402
+ const diff = feedback || "";
403
+ if (diff) {
404
+ saveAnnotations(slug, diff);
405
+ }
406
+ const savedPath = saveFinalSnapshot(slug, "approved", plan, diff);
407
+ resolveDecision({ approved: true, feedback, savedPath });
408
+ return Response.json({ ok: true, savedPath });
353
409
  }
354
410
  if (url.pathname === "/api/deny" && req.method === "POST") {
411
+ let feedback = "Plan rejected by user";
355
412
  try {
356
413
  const body = await req.json();
357
- resolveDecision({
358
- approved: false,
359
- feedback: body.feedback || "Plan rejected by user"
360
- });
361
- } catch {
362
- resolveDecision({
363
- approved: false,
364
- feedback: "Plan rejected by user"
365
- });
366
- }
367
- return Response.json({ ok: true });
414
+ feedback = body.feedback || feedback;
415
+ } catch {}
416
+ saveAnnotations(slug, feedback);
417
+ const savedPath = saveFinalSnapshot(slug, "denied", plan, feedback);
418
+ resolveDecision({ approved: false, feedback, savedPath });
419
+ return Response.json({ ok: true, savedPath });
368
420
  }
369
421
  return new Response(htmlContent, {
370
422
  headers: { "Content-Type": "text/html" }
@@ -927,6 +979,7 @@ Do NOT proceed with implementation until your plan is approved.
927
979
  return `Plan approved with notes!
928
980
 
929
981
  Plan Summary: ${args.summary}
982
+ ${result.savedPath ? `Saved to: ${result.savedPath}` : ""}
930
983
 
931
984
  ## Implementation Notes
932
985
 
@@ -938,9 +991,12 @@ Proceed with implementation, incorporating these notes where applicable.`;
938
991
  }
939
992
  return `Plan approved!
940
993
 
941
- Plan Summary: ${args.summary}`;
994
+ Plan Summary: ${args.summary}
995
+ ${result.savedPath ? `Saved to: ${result.savedPath}` : ""}`;
942
996
  } else {
943
997
  return `Plan needs revision.
998
+ ${result.savedPath ? `
999
+ Saved to: ${result.savedPath}` : ""}
944
1000
 
945
1001
  The user has requested changes to your plan. Please review their feedback below and revise your plan accordingly.
946
1002
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plannotator/opencode",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Plannotator plugin for OpenCode - interactive plan review with visual annotation",
5
5
  "author": "backnotprop",
6
6
  "license": "BSL-1.1",