opencode-writer-swarm 1.0.0 → 1.2.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.
@@ -0,0 +1,2 @@
1
+ export * from './schema';
2
+ export * from './manager';
@@ -0,0 +1,63 @@
1
+ import { type PlanDocument, type PlanPhase, type TaskStatus } from './schema';
2
+ /**
3
+ * Error thrown by PlanManager operations
4
+ */
5
+ export declare class PlanManagerError extends Error {
6
+ code: string;
7
+ cause?: unknown | undefined;
8
+ constructor(message: string, code: string, cause?: unknown | undefined);
9
+ }
10
+ /**
11
+ * Interface for plan management operations
12
+ */
13
+ export interface PlanManager {
14
+ /**
15
+ * Load and parse a plan from file (plan.md or plan.json)
16
+ * @param filePath - Path to plan file (optional, uses default discovery)
17
+ * @returns Parsed plan document
18
+ * @throws PlanManagerError if loading or parsing fails
19
+ */
20
+ loadPlan(filePath?: string): Promise<PlanDocument>;
21
+ /**
22
+ * Get the current active phase
23
+ * @returns Current phase or null if no active phase
24
+ */
25
+ getCurrentPhase(): PlanPhase | null;
26
+ /**
27
+ * Update the status of a specific task
28
+ * @param taskId - Task identifier
29
+ * @param status - New status value
30
+ * @returns true if update succeeded
31
+ * @throws PlanManagerError if task not found
32
+ */
33
+ updateTaskStatus(taskId: string, status: TaskStatus): Promise<boolean>;
34
+ /**
35
+ * Get the resolved path to the plan file
36
+ * @returns Absolute path to plan file
37
+ */
38
+ getPlanPath(): string;
39
+ /**
40
+ * Get the currently loaded plan document
41
+ * @returns Current plan or null if not loaded
42
+ */
43
+ getPlan(): PlanDocument | null;
44
+ }
45
+ /**
46
+ * Options for creating a PlanManager instance
47
+ */
48
+ export interface PlanManagerOptions {
49
+ /** Base directory for plan discovery */
50
+ baseDir: string;
51
+ /** Default plan file name (default: 'plan.json') */
52
+ defaultPlanName?: string;
53
+ /** Whether to auto-discover plan.md if plan.json not found */
54
+ autoDiscoverMarkdown?: boolean;
55
+ }
56
+ /**
57
+ * Create a new PlanManager instance
58
+ */
59
+ export declare function createPlanManager(options: PlanManagerOptions): PlanManager;
60
+ /**
61
+ * Load a plan document from file directly (convenience function)
62
+ */
63
+ export declare function loadPlanDocument(filePath: string): Promise<PlanDocument>;
@@ -0,0 +1,160 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Task status values representing the lifecycle of a task
4
+ */
5
+ export declare const TaskStatusSchema: z.ZodEnum<{
6
+ pending: "pending";
7
+ in_progress: "in_progress";
8
+ completed: "completed";
9
+ blocked: "blocked";
10
+ cancelled: "cancelled";
11
+ }>;
12
+ export type TaskStatus = z.infer<typeof TaskStatusSchema>;
13
+ /**
14
+ * Individual task within a phase
15
+ */
16
+ export declare const PlanTaskSchema: z.ZodObject<{
17
+ id: z.ZodString;
18
+ title: z.ZodString;
19
+ description: z.ZodOptional<z.ZodString>;
20
+ status: z.ZodDefault<z.ZodEnum<{
21
+ pending: "pending";
22
+ in_progress: "in_progress";
23
+ completed: "completed";
24
+ blocked: "blocked";
25
+ cancelled: "cancelled";
26
+ }>>;
27
+ assignee: z.ZodOptional<z.ZodString>;
28
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
29
+ acceptance_criteria: z.ZodDefault<z.ZodArray<z.ZodString>>;
30
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
31
+ }, z.core.$strip>;
32
+ export type PlanTask = z.infer<typeof PlanTaskSchema>;
33
+ /**
34
+ * Phase status values
35
+ */
36
+ export declare const PhaseStatusSchema: z.ZodEnum<{
37
+ pending: "pending";
38
+ in_progress: "in_progress";
39
+ completed: "completed";
40
+ blocked: "blocked";
41
+ }>;
42
+ export type PhaseStatus = z.infer<typeof PhaseStatusSchema>;
43
+ /**
44
+ * A phase containing multiple tasks
45
+ */
46
+ export declare const PlanPhaseSchema: z.ZodObject<{
47
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
48
+ name: z.ZodString;
49
+ status: z.ZodDefault<z.ZodEnum<{
50
+ pending: "pending";
51
+ in_progress: "in_progress";
52
+ completed: "completed";
53
+ blocked: "blocked";
54
+ }>>;
55
+ tasks: z.ZodDefault<z.ZodArray<z.ZodObject<{
56
+ id: z.ZodString;
57
+ title: z.ZodString;
58
+ description: z.ZodOptional<z.ZodString>;
59
+ status: z.ZodDefault<z.ZodEnum<{
60
+ pending: "pending";
61
+ in_progress: "in_progress";
62
+ completed: "completed";
63
+ blocked: "blocked";
64
+ cancelled: "cancelled";
65
+ }>>;
66
+ assignee: z.ZodOptional<z.ZodString>;
67
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
68
+ acceptance_criteria: z.ZodDefault<z.ZodArray<z.ZodString>>;
69
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
70
+ }, z.core.$strip>>>;
71
+ started_at: z.ZodOptional<z.ZodString>;
72
+ completed_at: z.ZodOptional<z.ZodString>;
73
+ }, z.core.$strip>;
74
+ export type PlanPhase = z.infer<typeof PlanPhaseSchema>;
75
+ /**
76
+ * Plan metadata for tracking and versioning
77
+ */
78
+ export declare const PlanMetadataSchema: z.ZodObject<{
79
+ created_at: z.ZodOptional<z.ZodString>;
80
+ updated_at: z.ZodOptional<z.ZodString>;
81
+ version: z.ZodDefault<z.ZodString>;
82
+ author: z.ZodOptional<z.ZodString>;
83
+ swarm: z.ZodOptional<z.ZodString>;
84
+ migration_status: z.ZodOptional<z.ZodEnum<{
85
+ pending: "pending";
86
+ migrated: "migrated";
87
+ failed: "failed";
88
+ }>>;
89
+ }, z.core.$strip>;
90
+ export type PlanMetadata = z.infer<typeof PlanMetadataSchema>;
91
+ /**
92
+ * Main plan document schema supporting both JSON and Markdown-derived structures
93
+ */
94
+ export declare const PlanDocumentSchema: z.ZodObject<{
95
+ schema_version: z.ZodDefault<z.ZodString>;
96
+ title: z.ZodString;
97
+ swarm: z.ZodOptional<z.ZodString>;
98
+ current_phase: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
99
+ phases: z.ZodDefault<z.ZodArray<z.ZodObject<{
100
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
101
+ name: z.ZodString;
102
+ status: z.ZodDefault<z.ZodEnum<{
103
+ pending: "pending";
104
+ in_progress: "in_progress";
105
+ completed: "completed";
106
+ blocked: "blocked";
107
+ }>>;
108
+ tasks: z.ZodDefault<z.ZodArray<z.ZodObject<{
109
+ id: z.ZodString;
110
+ title: z.ZodString;
111
+ description: z.ZodOptional<z.ZodString>;
112
+ status: z.ZodDefault<z.ZodEnum<{
113
+ pending: "pending";
114
+ in_progress: "in_progress";
115
+ completed: "completed";
116
+ blocked: "blocked";
117
+ cancelled: "cancelled";
118
+ }>>;
119
+ assignee: z.ZodOptional<z.ZodString>;
120
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
121
+ acceptance_criteria: z.ZodDefault<z.ZodArray<z.ZodString>>;
122
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
123
+ }, z.core.$strip>>>;
124
+ started_at: z.ZodOptional<z.ZodString>;
125
+ completed_at: z.ZodOptional<z.ZodString>;
126
+ }, z.core.$strip>>>;
127
+ metadata: z.ZodOptional<z.ZodObject<{
128
+ created_at: z.ZodOptional<z.ZodString>;
129
+ updated_at: z.ZodOptional<z.ZodString>;
130
+ version: z.ZodDefault<z.ZodString>;
131
+ author: z.ZodOptional<z.ZodString>;
132
+ swarm: z.ZodOptional<z.ZodString>;
133
+ migration_status: z.ZodOptional<z.ZodEnum<{
134
+ pending: "pending";
135
+ migrated: "migrated";
136
+ failed: "failed";
137
+ }>>;
138
+ }, z.core.$strip>>;
139
+ }, z.core.$strip>;
140
+ export type PlanDocument = z.infer<typeof PlanDocumentSchema>;
141
+ /**
142
+ * Validation result for plan documents
143
+ */
144
+ export interface PlanValidationResult {
145
+ valid: boolean;
146
+ errors: z.ZodError | null;
147
+ data?: PlanDocument;
148
+ }
149
+ /**
150
+ * Validate a plan document against the schema
151
+ */
152
+ export declare function validatePlanDocument(data: unknown): PlanValidationResult;
153
+ /**
154
+ * Default empty plan document
155
+ */
156
+ export declare function createEmptyPlan(title?: string): PlanDocument;
157
+ /**
158
+ * Get default values for plan metadata
159
+ */
160
+ export declare function getPlanMetadataDefaults(): PlanMetadata;
package/dist/state.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- /**
2
- * Shared state module for OpenCode Writer Swarm plugin.
3
- */
1
+ import type { PluginConfig } from './config/schema';
2
+ /** Shared state for plugin sessions and cache tracking. */
4
3
  export interface DelegationEntry {
5
4
  from: string;
6
5
  to: string;
@@ -11,6 +10,16 @@ export interface CacheStats {
11
10
  cacheMisses: number;
12
11
  cacheSizeBytes: number;
13
12
  }
13
+ /** Guardrail tracking state per session */
14
+ export interface GuardrailSession {
15
+ toolCalls: number;
16
+ firstToolAt: number | null;
17
+ repetitionCount: number;
18
+ consecutiveErrors: number;
19
+ lastTool: string | null;
20
+ }
21
+ /** Maximum number of sessions to track before pruning */
22
+ export declare const MAX_SESSIONS = 1000;
14
23
  export declare const swarmState: {
15
24
  /** Active agent per session — keyed by sessionID */
16
25
  activeAgent: Map<string, string>;
@@ -20,5 +29,37 @@ export declare const swarmState: {
20
29
  pendingEvents: number;
21
30
  /** Cache statistics for markdown AST parsing */
22
31
  cacheStats: CacheStats;
32
+ /** Last successfully loaded config document */
33
+ lastValidConfig: PluginConfig | null;
34
+ /** Guardrail tracking per session — keyed by sessionID */
35
+ guardrails: Map<string, GuardrailSession>;
23
36
  };
37
+ /**
38
+ * Prune the oldest sessions from both Maps.
39
+ * Map iteration order is insertion order, so the first entries are oldest.
40
+ * @param count - Number of sessions to prune
41
+ */
42
+ export declare function pruneOldestSessions(count: number): void;
43
+ /**
44
+ * Enforce the session limit by pruning if Maps exceed MAX_SESSIONS.
45
+ * Prunes 10% of sessions when the limit is hit.
46
+ */
47
+ export declare function enforceSessionLimit(): void;
48
+ /** Clear all session tracking, events, and cache stats. Used between tests and for plugin reinitialization. */
24
49
  export declare function resetSwarmState(): void;
50
+ /**
51
+ * Finalize and clear all swarm state.
52
+ * Alias for resetSwarmState, signaling end-of-lifecycle cleanup.
53
+ */
54
+ export declare function disposeSwarmState(): void;
55
+ /**
56
+ * Get or initialize guardrail session state for a given sessionID.
57
+ * @param sessionID - The session identifier
58
+ * @returns The guardrail session state (initializes if missing)
59
+ */
60
+ export declare function getGuardrailSession(sessionID: string): GuardrailSession;
61
+ /**
62
+ * Reset guardrail state for a specific session.
63
+ * @param sessionID - The session identifier to clear
64
+ */
65
+ export declare function resetGuardrailState(sessionID: string): void;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'node:fs/promises';
2
2
  import { type ToolDefinition } from '@opencode-ai/plugin/tool';
3
3
  import { MAX_FILE_SIZE, MAX_DIRECTORY_DEPTH } from '../config/constants';
4
+ import { type PluginConfig } from '../config/schema';
4
5
  /**
5
6
  * Sleep for a given number of milliseconds
6
7
  */
@@ -21,15 +22,15 @@ export declare function writeFileWithRetry(filePath: string, content: string, op
21
22
  encoding: BufferEncoding;
22
23
  }, writeFn?: typeof fs.writeFile, retryEnabled?: boolean, maxRetries?: number): Promise<void>;
23
24
  /**
24
- * Read a file from the .writer/ directory.
25
+ * Create a tool to read a file from the .writer/ directory.
25
26
  */
26
- export declare const read_writer_file: ToolDefinition;
27
+ export declare function createReadWriterFile(directory: string): ToolDefinition;
27
28
  /**
28
- * Write content to a file in the .writer/ directory. Overwrites if exists.
29
+ * Create a tool to write content to a file in the .writer/ directory. Overwrites if exists.
29
30
  */
30
- export declare const write_writer_file: ToolDefinition;
31
+ export declare function createWriteWriterFile(directory: string, config?: PluginConfig): ToolDefinition;
31
32
  /**
32
- * List all files in the .writer/ directory recursively.
33
+ * Create a tool to list all files in the .writer/ directory recursively.
33
34
  */
34
- export declare const list_writer_files: ToolDefinition;
35
+ export declare function createListWriterFiles(directory: string): ToolDefinition;
35
36
  export { MAX_FILE_SIZE, MAX_DIRECTORY_DEPTH };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "opencode-writer-swarm",
3
- "version": "1.0.0",
2
+ "name": "opencode-writer-swarm",
3
+ "version": "1.2.1",
4
4
  "description": "Editorial swarm plugin for OpenCode - professional writing workflow with editor-in-chief, writers, and reviewers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,14 +39,15 @@
39
39
  "dependencies": {
40
40
  "@opencode-ai/plugin": "^1.1.53",
41
41
  "@opencode-ai/sdk": "^1.1.53",
42
+ "mdast-util-from-markdown": "^2.0.2",
43
+ "mdast-util-gfm": "^3.1.0",
42
44
  "micromark-extension-gfm": "^3.0.0",
43
- "zod": "^4.1.8",
44
- "mdast-util-from-markdown": "^1.0.0",
45
- "mdast-util-gfm": "^1.0.0",
46
- "unist-util-visit": "^4.1.0"
45
+ "unist-util-visit": "^5.1.0",
46
+ "zod": "^4.1.8"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@biomejs/biome": "2.3.14",
50
+ "@types/mdast": "^4.0.4",
50
51
  "bun-types": "latest",
51
52
  "typescript": "^5.7.3"
52
53
  }