clawspec 1.0.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.
Files changed (71) hide show
  1. package/README.md +908 -0
  2. package/README.zh-CN.md +914 -0
  3. package/index.ts +3 -0
  4. package/openclaw.plugin.json +129 -0
  5. package/package.json +52 -0
  6. package/skills/openspec-apply-change.md +146 -0
  7. package/skills/openspec-explore.md +75 -0
  8. package/skills/openspec-propose.md +102 -0
  9. package/src/acp/client.ts +693 -0
  10. package/src/config.ts +220 -0
  11. package/src/control/keywords.ts +72 -0
  12. package/src/dependencies/acpx.ts +221 -0
  13. package/src/dependencies/openspec.ts +148 -0
  14. package/src/execution/session.ts +56 -0
  15. package/src/execution/state.ts +125 -0
  16. package/src/index.ts +179 -0
  17. package/src/memory/store.ts +118 -0
  18. package/src/openspec/cli.ts +279 -0
  19. package/src/openspec/tasks.ts +40 -0
  20. package/src/orchestrator/helpers.ts +312 -0
  21. package/src/orchestrator/service.ts +2971 -0
  22. package/src/planning/journal.ts +118 -0
  23. package/src/rollback/store.ts +173 -0
  24. package/src/state/locks.ts +133 -0
  25. package/src/state/store.ts +527 -0
  26. package/src/types.ts +301 -0
  27. package/src/utils/args.ts +88 -0
  28. package/src/utils/channel-key.ts +66 -0
  29. package/src/utils/env-path.ts +31 -0
  30. package/src/utils/fs.ts +218 -0
  31. package/src/utils/markdown.ts +136 -0
  32. package/src/utils/messages.ts +5 -0
  33. package/src/utils/paths.ts +127 -0
  34. package/src/utils/shell-command.ts +227 -0
  35. package/src/utils/slug.ts +50 -0
  36. package/src/watchers/manager.ts +3042 -0
  37. package/src/watchers/notifier.ts +69 -0
  38. package/src/worker/prompts.ts +484 -0
  39. package/src/worker/skills.ts +52 -0
  40. package/src/workspace/store.ts +140 -0
  41. package/test/acp-client.test.ts +234 -0
  42. package/test/acpx-dependency.test.ts +112 -0
  43. package/test/assistant-journal.test.ts +136 -0
  44. package/test/command-surface.test.ts +23 -0
  45. package/test/config.test.ts +77 -0
  46. package/test/detach-attach.test.ts +98 -0
  47. package/test/file-lock.test.ts +78 -0
  48. package/test/fs-utils.test.ts +22 -0
  49. package/test/helpers/harness.ts +241 -0
  50. package/test/helpers.test.ts +108 -0
  51. package/test/keywords.test.ts +80 -0
  52. package/test/notifier.test.ts +29 -0
  53. package/test/openspec-dependency.test.ts +67 -0
  54. package/test/pause-cancel.test.ts +55 -0
  55. package/test/planning-journal.test.ts +69 -0
  56. package/test/plugin-registration.test.ts +35 -0
  57. package/test/project-memory.test.ts +42 -0
  58. package/test/proposal.test.ts +24 -0
  59. package/test/queue-planning.test.ts +247 -0
  60. package/test/queue-work.test.ts +110 -0
  61. package/test/recovery.test.ts +576 -0
  62. package/test/service-archive.test.ts +82 -0
  63. package/test/shell-command.test.ts +48 -0
  64. package/test/state-store.test.ts +74 -0
  65. package/test/tasks-and-checkpoint.test.ts +60 -0
  66. package/test/use-project.test.ts +19 -0
  67. package/test/watcher-planning.test.ts +504 -0
  68. package/test/watcher-work.test.ts +1741 -0
  69. package/test/worker-command.test.ts +66 -0
  70. package/test/worker-skills.test.ts +12 -0
  71. package/tsconfig.json +25 -0
@@ -0,0 +1,66 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { createServiceHarness, seedPlanningProject } from "./helpers/harness.ts";
4
+
5
+ test("worker command sets agent", async () => {
6
+ const harness = await createServiceHarness("clawspec-worker-command-");
7
+ const { service, stateStore } = harness;
8
+ const channelKey = "discord:worker-command:default:main";
9
+
10
+ await service.startProject(channelKey);
11
+ const before = await service.workerProject(channelKey, "");
12
+ const setResult = await service.workerProject(channelKey, "piper");
13
+ const project = await stateStore.getActiveProject(channelKey);
14
+
15
+ assert.match(before.text ?? "", /Current worker agent: `codex`/);
16
+ assert.match(setResult.text ?? "", /Worker Agent Updated/);
17
+ assert.equal(project?.workerAgentId, "piper");
18
+ });
19
+
20
+ test("worker status shows live state", async () => {
21
+ const harness = await createServiceHarness("clawspec-worker-status-");
22
+ const { service, stateStore, workspacePath, repoPath, changeDir } = harness;
23
+ const channelKey = "discord:worker-status:default:main";
24
+
25
+ await seedPlanningProject(stateStore, channelKey, {
26
+ workspacePath,
27
+ repoPath,
28
+ projectName: "demo-app",
29
+ changeName: "watch-status",
30
+ changeDir,
31
+ phase: "implementing",
32
+ status: "running",
33
+ planningDirty: false,
34
+ execution: { action: "work", state: "running", mode: "apply" },
35
+ });
36
+
37
+ await stateStore.updateProject(channelKey, (current) => ({
38
+ ...current,
39
+ workerAgentId: "codex",
40
+ latestSummary: "Worker is currently applying task 1.2.",
41
+ taskCounts: { total: 4, complete: 1, remaining: 3 },
42
+ execution: current.execution
43
+ ? {
44
+ ...current.execution,
45
+ workerAgentId: "codex",
46
+ workerSlot: "primary",
47
+ startupPhase: "connected",
48
+ currentTaskId: "1.2",
49
+ currentArtifact: undefined,
50
+ sessionKey: "watcher:demo",
51
+ connectedAt: new Date(Date.now() - 6_000).toISOString(),
52
+ lastHeartbeatAt: "2026-03-22T10:00:00.000Z",
53
+ }
54
+ : current.execution,
55
+ }));
56
+
57
+ const result = await service.workerProject(channelKey, "status");
58
+ assert.match(result.text ?? "", /Worker Status/);
59
+ assert.match(result.text ?? "", /Change: `watch-status`/);
60
+ assert.match(result.text ?? "", /Execution state: `running`/);
61
+ assert.match(result.text ?? "", /Startup phase: `connected`/);
62
+ assert.match(result.text ?? "", /Startup wait: `\d+s`/);
63
+ assert.match(result.text ?? "", /Current task: `1.2`/);
64
+ assert.match(result.text ?? "", /Progress: 1\/4 complete, 3 remaining/);
65
+ assert.match(result.text ?? "", /Next: Wait for worker updates or use `\/clawspec pause`\./);
66
+ });
@@ -0,0 +1,12 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { loadClawSpecSkillBundle } from "../src/worker/skills.ts";
4
+
5
+ test("loadClawSpecSkillBundle reads bundled runtime skills", async () => {
6
+ const bundle = await loadClawSpecSkillBundle(["apply", "explore", "propose"]);
7
+
8
+ assert.match(bundle, /Imported Skill: openspec-apply-change/);
9
+ assert.match(bundle, /Imported Skill: openspec-explore/);
10
+ assert.match(bundle, /Imported Skill: openspec-propose/);
11
+ assert.doesNotMatch(bundle, /\.codex[\\/]/);
12
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": [
7
+ "ES2022"
8
+ ],
9
+ "strict": true,
10
+ "noEmit": true,
11
+ "skipLibCheck": true,
12
+ "allowImportingTsExtensions": true,
13
+ "resolveJsonModule": true,
14
+ "esModuleInterop": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "types": [
17
+ "node"
18
+ ]
19
+ },
20
+ "include": [
21
+ "index.ts",
22
+ "src/**/*.ts",
23
+ "test/**/*.ts"
24
+ ]
25
+ }