clawspec 1.0.13 → 1.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawspec",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "type": "module",
5
5
  "description": "OpenClaw plugin that orchestrates OpenSpec project workflows with visible main-agent execution.",
6
6
  "keywords": [
@@ -6,6 +6,7 @@ import type {
6
6
  PluginCommandResult,
7
7
  PluginLogger,
8
8
  } from "openclaw/plugin-sdk";
9
+ import { debugLog } from "../utils/debug-log.ts";
9
10
  import { ProjectMemoryStore } from "../memory/store.ts";
10
11
  import { OpenSpecClient, OpenSpecCommandError } from "../openspec/cli.ts";
11
12
  import { parseTasksFile } from "../openspec/tasks.ts";
@@ -249,7 +250,9 @@ export class ClawSpecService {
249
250
  event: PromptBuildEvent,
250
251
  ctx: PromptBuildContext,
251
252
  ): Promise<{ prependContext?: string; prependSystemContext?: string } | void> {
253
+ debugLog(`[handleBeforePromptBuild] prompt="${event.prompt}", trigger=${ctx.trigger}`);
252
254
  if (!shouldHandleUserVisiblePrompt(ctx.trigger)) {
255
+ debugLog(`[handleBeforePromptBuild] Skipped: non-user trigger`);
253
256
  this.logger.debug?.(
254
257
  `[clawspec] skipping prompt injection for non-user trigger "${ctx.trigger ?? "unknown"}".`,
255
258
  );
@@ -257,6 +260,7 @@ export class ClawSpecService {
257
260
  }
258
261
 
259
262
  const keyword = extractEmbeddedClawSpecKeyword(event.prompt);
263
+ debugLog(`[handleBeforePromptBuild] keyword=${keyword?.command}`);
260
264
  if (keyword) {
261
265
  this.logger.debug?.(
262
266
  `[clawspec] detected control keyword "${keyword.command}" for prompt build (session=${ctx.sessionKey ?? "unknown"}).`,
@@ -316,16 +320,21 @@ export class ClawSpecService {
316
320
 
317
321
  switch (keyword.kind) {
318
322
  case "plan": {
323
+ debugLog(`[cs-plan] Triggered for project: ${match?.project.changeName}`);
319
324
  if (!match?.project.repoPath || !match.project.changeName) {
325
+ debugLog(`[cs-plan] Missing repoPath or changeName`);
320
326
  return this.buildPluginReplyInjection(
321
327
  event.prompt,
322
328
  "Select a project and create a change first with `/clawspec use <project-name>` and `/clawspec proposal <change-name> [description]`.",
323
329
  );
324
330
  }
331
+ debugLog(`[cs-plan] Calling startVisiblePlanningSync`);
325
332
  const planningSync = await this.startVisiblePlanningSync(match.channelKey, match.project, ctx, event.prompt, "apply");
326
333
  if ("prependContext" in planningSync || "prependSystemContext" in planningSync) {
334
+ debugLog(`[cs-plan] Returning prompt injection`);
327
335
  return planningSync;
328
336
  }
337
+ debugLog(`[cs-plan] Returning plugin reply`);
329
338
  return this.buildPluginReplyInjection(event.prompt, planningSync.text ?? "");
330
339
  }
331
340
  case "work":
@@ -758,14 +767,19 @@ export class ClawSpecService {
758
767
  userPrompt: string,
759
768
  mode: ExecutionMode,
760
769
  ): Promise<{ prependContext?: string; prependSystemContext?: string } | PluginCommandResult> {
770
+ debugLog(`[startVisiblePlanningSync] Called for ${project.changeName}`);
771
+ this.logger.info(`[clawspec] startVisiblePlanningSync called for ${project.changeName}`);
761
772
  void project;
762
773
  void mode;
763
774
 
764
775
  const prepared = await this.preparePlanningSync(channelKey);
765
776
  if ("result" in prepared) {
777
+ debugLog(`[startVisiblePlanningSync] preparePlanningSync failed`);
778
+ this.logger.warn(`[clawspec] preparePlanningSync returned error: ${prepared.result.text}`);
766
779
  return prepared.result;
767
780
  }
768
781
 
782
+ debugLog(`[startVisiblePlanningSync] Updating state to planning`);
769
783
  const startedAt = new Date().toISOString();
770
784
  const runningProject = await this.stateStore.updateProject(channelKey, (current) => ({
771
785
  ...current,
@@ -779,6 +793,8 @@ export class ClawSpecService {
779
793
  execution: undefined,
780
794
  lastExecutionAt: startedAt,
781
795
  }));
796
+ debugLog(`[startVisiblePlanningSync] State updated: status=${runningProject.status}, phase=${runningProject.phase}, sessionKey=${runningProject.boundSessionKey}`);
797
+ this.logger.info(`[clawspec] Project state updated: status=planning, phase=planning_sync, boundSessionKey=${runningProject.boundSessionKey}`);
782
798
 
783
799
  return await this.buildPlanningSyncInjection(runningProject, userPrompt, prepared.instructionResults);
784
800
  }
@@ -896,6 +912,7 @@ export class ClawSpecService {
896
912
  }
897
913
 
898
914
  async handleAgentEnd(event: AgentEndEvent, ctx: PromptBuildContext): Promise<void> {
915
+ debugLog(`[agent_end] Called, sessionKey=${ctx.sessionKey}`);
899
916
  const runningProject = await this.findRunningProjectBySessionKey(ctx.sessionKey);
900
917
  if (runningProject?.repoPath && runningProject.changeName) {
901
918
  const project = runningProject;
@@ -960,7 +977,9 @@ export class ClawSpecService {
960
977
 
961
978
  const planningProject = await this.findPlanningProjectBySessionKey(ctx.sessionKey)
962
979
  ?? await this.findPlanningProjectByContext(ctx);
980
+ debugLog(`[agent_end] Planning project: ${planningProject?.changeName}, status=${planningProject?.status}, phase=${planningProject?.phase}`);
963
981
  if (planningProject) {
982
+ debugLog(`[agent_end] Calling finalizePlanningTurn`);
964
983
  this.logger.info(`[clawspec] agent_end: found planning project ${planningProject.changeName}, calling finalizePlanningTurn`);
965
984
  await this.finalizePlanningTurn(planningProject, event);
966
985
  return;
@@ -2409,8 +2428,10 @@ export class ClawSpecService {
2409
2428
  }
2410
2429
 
2411
2430
  private async finalizePlanningTurn(project: ProjectState, event: AgentEndEvent): Promise<void> {
2431
+ debugLog(`[finalizePlanningTurn] Called for ${project.changeName}, success=${event.success}`);
2412
2432
  this.logger.info(`[clawspec] finalizePlanningTurn called for ${project.changeName}, success=${event.success}`);
2413
2433
  if (!project.repoPath || !project.changeName) {
2434
+ debugLog(`[finalizePlanningTurn] Skipped: missing repoPath or changeName`);
2414
2435
  this.logger.warn(`[clawspec] finalizePlanningTurn skipped: missing repoPath or changeName`);
2415
2436
  return;
2416
2437
  }
@@ -2470,7 +2491,9 @@ export class ClawSpecService {
2470
2491
  }
2471
2492
  }
2472
2493
 
2494
+ debugLog(`[finalizePlanningTurn] Writing snapshot`);
2473
2495
  const snapshot = await journalStore.writeSnapshot(repoStatePaths.planningJournalSnapshotFile, project.changeName, timestamp);
2496
+ debugLog(`[finalizePlanningTurn] Snapshot written: entryCount=${snapshot.entryCount}, lastEntryAt=${snapshot.lastEntryAt}`);
2474
2497
  this.logger.info(`[clawspec] Planning snapshot written for ${project.changeName}: entryCount=${snapshot.entryCount}, lastEntryAt=${snapshot.lastEntryAt}`);
2475
2498
  this.logger.info(`[clawspec] Updating project state: status=${status}, phase=${phase}, dirty=${journalDirty}`);
2476
2499
  await this.writeLatestSummary(repoStatePaths, latestSummary);
@@ -0,0 +1,14 @@
1
+ import { appendFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+
5
+ const LOG_FILE = path.join(homedir(), ".openclaw", "clawspec-debug.log");
6
+
7
+ export function debugLog(message: string): void {
8
+ try {
9
+ const timestamp = new Date().toISOString();
10
+ appendFileSync(LOG_FILE, `${timestamp} ${message}\n`);
11
+ } catch {
12
+ // ignore
13
+ }
14
+ }