zigrix 0.1.0-alpha.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 (58) hide show
  1. package/LICENSE +184 -0
  2. package/README.md +128 -0
  3. package/dist/agents/registry.d.ts +28 -0
  4. package/dist/agents/registry.js +98 -0
  5. package/dist/config/defaults.d.ts +66 -0
  6. package/dist/config/defaults.js +58 -0
  7. package/dist/config/load.d.ts +13 -0
  8. package/dist/config/load.js +96 -0
  9. package/dist/config/mutate.d.ts +10 -0
  10. package/dist/config/mutate.js +61 -0
  11. package/dist/config/schema.d.ts +132 -0
  12. package/dist/config/schema.js +123 -0
  13. package/dist/configure.d.ts +24 -0
  14. package/dist/configure.js +164 -0
  15. package/dist/doctor.d.ts +4 -0
  16. package/dist/doctor.js +99 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +791 -0
  19. package/dist/onboard.d.ts +99 -0
  20. package/dist/onboard.js +490 -0
  21. package/dist/orchestration/dispatch.d.ts +9 -0
  22. package/dist/orchestration/dispatch.js +146 -0
  23. package/dist/orchestration/evidence.d.ts +19 -0
  24. package/dist/orchestration/evidence.js +97 -0
  25. package/dist/orchestration/finalize.d.ts +7 -0
  26. package/dist/orchestration/finalize.js +136 -0
  27. package/dist/orchestration/pipeline.d.ts +11 -0
  28. package/dist/orchestration/pipeline.js +26 -0
  29. package/dist/orchestration/report.d.ts +5 -0
  30. package/dist/orchestration/report.js +92 -0
  31. package/dist/orchestration/worker.d.ts +34 -0
  32. package/dist/orchestration/worker.js +132 -0
  33. package/dist/rules/templates.d.ts +24 -0
  34. package/dist/rules/templates.js +73 -0
  35. package/dist/runner/run.d.ts +10 -0
  36. package/dist/runner/run.js +91 -0
  37. package/dist/runner/schema.d.ts +33 -0
  38. package/dist/runner/schema.js +10 -0
  39. package/dist/runner/store.d.ts +5 -0
  40. package/dist/runner/store.js +19 -0
  41. package/dist/state/events.d.ts +3 -0
  42. package/dist/state/events.js +53 -0
  43. package/dist/state/paths.d.ts +15 -0
  44. package/dist/state/paths.js +23 -0
  45. package/dist/state/tasks.d.ts +61 -0
  46. package/dist/state/tasks.js +247 -0
  47. package/dist/state/verify.d.ts +2 -0
  48. package/dist/state/verify.js +65 -0
  49. package/examples/hello-workflow.json +13 -0
  50. package/package.json +44 -0
  51. package/skills/zigrix-doctor/SKILL.md +20 -0
  52. package/skills/zigrix-evidence/SKILL.md +21 -0
  53. package/skills/zigrix-init/SKILL.md +23 -0
  54. package/skills/zigrix-report/SKILL.md +20 -0
  55. package/skills/zigrix-shared/SKILL.md +31 -0
  56. package/skills/zigrix-task-create/SKILL.md +34 -0
  57. package/skills/zigrix-task-status/SKILL.md +27 -0
  58. package/skills/zigrix-worker/SKILL.md +22 -0
@@ -0,0 +1,132 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { appendEvent } from '../state/events.js';
4
+ import { ensureBaseState } from '../state/paths.js';
5
+ import { loadTask, saveTask } from '../state/tasks.js';
6
+ export const DEFAULT_REQUIRED_AGENTS = ['pro-zig', 'qa-zig'];
7
+ export function resolveRequiredAgents(task) {
8
+ for (const key of ['requiredAgents', 'selectedAgents', 'baselineRequiredAgents']) {
9
+ const value = task[key];
10
+ if (Array.isArray(value) && value.length > 0) {
11
+ return value.map(String);
12
+ }
13
+ }
14
+ const workers = task.workerSessions;
15
+ if (workers && typeof workers === 'object' && Object.keys(workers).length > 0) {
16
+ return Object.keys(workers).sort();
17
+ }
18
+ return [...DEFAULT_REQUIRED_AGENTS];
19
+ }
20
+ function renderPrompt(params) {
21
+ const sections = [
22
+ `## Worker Assignment: ${params.task.taskId}`,
23
+ '',
24
+ '| Field | Value |',
25
+ '|---|---|',
26
+ `| taskId | ${params.task.taskId} |`,
27
+ `| title | ${params.task.title} |`,
28
+ `| scale | ${params.task.scale} |`,
29
+ `| role | ${params.agentId} |`,
30
+ ...(params.projectDir ? [`| projectDir | ${params.projectDir} |`] : []),
31
+ '',
32
+ '### Assignment',
33
+ params.description,
34
+ ];
35
+ if (params.constraints)
36
+ sections.push('', '### Constraints', params.constraints);
37
+ if (params.dod)
38
+ sections.push('', '### Definition of Done', params.dod);
39
+ if (params.unitId || params.workPackage) {
40
+ sections.push('', '### Execution Context', `- unitId: ${params.unitId ?? 'N/A'}`, `- workPackage: ${params.workPackage ?? 'N/A'}`);
41
+ }
42
+ sections.push('', '### Completion', '작업 완료 후 결과와 근거를 명확히 보고하라.');
43
+ return sections.join('\n');
44
+ }
45
+ export function prepareWorker(paths, params) {
46
+ ensureBaseState(paths);
47
+ const task = loadTask(paths, params.taskId);
48
+ if (!task)
49
+ return null;
50
+ const projectDir = params.projectDir ?? task.projectDir;
51
+ const prompt = renderPrompt({ task, ...params, projectDir });
52
+ const promptPath = path.join(paths.promptsDir, `${params.taskId}-${params.agentId}.md`);
53
+ fs.writeFileSync(promptPath, `${prompt}\n`, 'utf8');
54
+ task.workerSessions[params.agentId] = {
55
+ status: 'prepared',
56
+ unitId: params.unitId,
57
+ workPackage: params.workPackage,
58
+ promptPath,
59
+ };
60
+ const required = task.requiredAgents.length > 0 ? task.requiredAgents : resolveRequiredAgents(task);
61
+ if (!required.includes(params.agentId))
62
+ required.push(params.agentId);
63
+ task.requiredAgents = required;
64
+ saveTask(paths, task);
65
+ appendEvent(paths.eventsFile, {
66
+ event: 'worker_prepared',
67
+ taskId: params.taskId,
68
+ phase: 'execution',
69
+ actor: 'zigrix',
70
+ targetAgent: params.agentId,
71
+ status: 'IN_PROGRESS',
72
+ unitId: params.unitId,
73
+ workPackage: params.workPackage,
74
+ payload: { agentId: params.agentId, description: params.description, constraints: params.constraints ?? '', dod: params.dod ?? '', promptPath },
75
+ });
76
+ return { ok: true, taskId: params.taskId, agentId: params.agentId, promptPath, prompt, unitId: params.unitId, workPackage: params.workPackage };
77
+ }
78
+ export function registerWorker(paths, params) {
79
+ const task = loadTask(paths, params.taskId);
80
+ if (!task)
81
+ return null;
82
+ task.workerSessions[params.agentId] = {
83
+ ...(task.workerSessions[params.agentId] ?? {}),
84
+ status: 'dispatched',
85
+ sessionKey: params.sessionKey,
86
+ runId: params.runId ?? '',
87
+ sessionId: params.sessionId ?? null,
88
+ unitId: params.unitId,
89
+ workPackage: params.workPackage,
90
+ reason: params.reason ?? '',
91
+ };
92
+ const required = task.requiredAgents.length > 0 ? task.requiredAgents : resolveRequiredAgents(task);
93
+ if (!required.includes(params.agentId))
94
+ required.push(params.agentId);
95
+ task.requiredAgents = required;
96
+ saveTask(paths, task);
97
+ appendEvent(paths.eventsFile, {
98
+ event: 'worker_dispatched', taskId: params.taskId, phase: 'execution', actor: 'zigrix', targetAgent: params.agentId, status: 'IN_PROGRESS',
99
+ sessionKey: params.sessionKey, sessionId: params.sessionId ?? null, unitId: params.unitId, workPackage: params.workPackage,
100
+ payload: { agentId: params.agentId, runId: params.runId ?? '', reason: params.reason ?? '' },
101
+ });
102
+ return { ok: true, taskId: params.taskId, agentId: params.agentId, sessionKey: params.sessionKey, runId: params.runId ?? '', sessionId: params.sessionId ?? null, unitId: params.unitId, workPackage: params.workPackage, status: 'dispatched' };
103
+ }
104
+ export function completeWorker(paths, params) {
105
+ const task = loadTask(paths, params.taskId);
106
+ if (!task)
107
+ return null;
108
+ const prev = task.workerSessions[params.agentId] ?? {};
109
+ task.workerSessions[params.agentId] = {
110
+ ...prev,
111
+ status: params.result ?? 'done',
112
+ sessionKey: params.sessionKey,
113
+ runId: params.runId,
114
+ sessionId: params.sessionId ?? prev.sessionId ?? null,
115
+ unitId: params.unitId ?? prev.unitId,
116
+ workPackage: params.workPackage ?? prev.workPackage,
117
+ };
118
+ saveTask(paths, task);
119
+ appendEvent(paths.eventsFile, {
120
+ event: 'worker_done', taskId: params.taskId, phase: 'execution', actor: params.agentId, targetAgent: params.agentId,
121
+ status: (params.result ?? 'done') === 'blocked' ? 'BLOCKED' : 'IN_PROGRESS', sessionKey: params.sessionKey, sessionId: params.sessionId ?? null,
122
+ unitId: params.unitId ?? prev.unitId, workPackage: params.workPackage ?? prev.workPackage,
123
+ payload: { result: params.result ?? 'done', runId: params.runId },
124
+ });
125
+ const evidenceDir = path.join(paths.evidenceDir, params.taskId);
126
+ const presentAgents = fs.existsSync(evidenceDir)
127
+ ? fs.readdirSync(evidenceDir).filter((file) => file.endsWith('.json') && file !== '_merged.json').map((file) => path.basename(file, '.json')).sort()
128
+ : [];
129
+ const required = resolveRequiredAgents(task);
130
+ const missingAgents = required.filter((agentId) => !presentAgents.includes(agentId));
131
+ return { ok: true, taskId: params.taskId, agentId: params.agentId, result: params.result ?? 'done', requiredAgents: required, presentEvidenceAgents: presentAgents, missingEvidenceAgents: missingAgents, allEvidenceCollected: missingAgents.length === 0 };
132
+ }
@@ -0,0 +1,24 @@
1
+ import { type ZigrixConfig } from '../config/schema.js';
2
+ export declare const TEMPLATE_PLACEHOLDERS: {
3
+ readonly workerPrompt: readonly ["taskId", "title", "scale", "agentId", "description", "constraints", "requiredRoles", "workPackage", "unitId"];
4
+ readonly finalReport: readonly ["taskId", "title", "scale", "status", "summary", "missingAgents"];
5
+ };
6
+ export type TemplateKind = keyof typeof TEMPLATE_PLACEHOLDERS;
7
+ export declare function listRules(config: ZigrixConfig): Array<{
8
+ path: string;
9
+ kind: 'policy' | 'template';
10
+ }>;
11
+ export declare function extractPlaceholders(body: string): string[];
12
+ export declare function validateTemplate(kind: TemplateKind, body: string): {
13
+ ok: boolean;
14
+ placeholders: string[];
15
+ allowed: readonly string[];
16
+ unknown: string[];
17
+ missingRecommended: string[];
18
+ };
19
+ export declare function validateRules(config: ZigrixConfig): {
20
+ ok: boolean;
21
+ templates: Record<string, ReturnType<typeof validateTemplate>>;
22
+ invalidRoles: string[];
23
+ };
24
+ export declare function renderTemplate(kind: TemplateKind, body: string, context: Record<string, unknown>): string;
@@ -0,0 +1,73 @@
1
+ export const TEMPLATE_PLACEHOLDERS = {
2
+ workerPrompt: ['taskId', 'title', 'scale', 'agentId', 'description', 'constraints', 'requiredRoles', 'workPackage', 'unitId'],
3
+ finalReport: ['taskId', 'title', 'scale', 'status', 'summary', 'missingAgents'],
4
+ };
5
+ const PLACEHOLDER_RE = /{{\s*([a-zA-Z0-9_]+)\s*}}/g;
6
+ export function listRules(config) {
7
+ return [
8
+ { path: 'rules.scales', kind: 'policy' },
9
+ { path: 'rules.completion', kind: 'policy' },
10
+ { path: 'rules.stale', kind: 'policy' },
11
+ { path: 'templates.workerPrompt', kind: 'template' },
12
+ { path: 'templates.finalReport', kind: 'template' },
13
+ ];
14
+ }
15
+ export function extractPlaceholders(body) {
16
+ const found = new Set();
17
+ for (const match of body.matchAll(PLACEHOLDER_RE)) {
18
+ const key = match[1]?.trim();
19
+ if (key)
20
+ found.add(key);
21
+ }
22
+ return [...found];
23
+ }
24
+ export function validateTemplate(kind, body) {
25
+ const placeholders = extractPlaceholders(body);
26
+ const allowed = TEMPLATE_PLACEHOLDERS[kind];
27
+ const unknown = placeholders.filter((item) => !allowed.includes(item));
28
+ const missingRecommended = allowed.filter((item) => !placeholders.includes(item));
29
+ return {
30
+ ok: unknown.length === 0,
31
+ placeholders,
32
+ allowed,
33
+ unknown,
34
+ missingRecommended,
35
+ };
36
+ }
37
+ export function validateRules(config) {
38
+ const knownRoles = new Set(Object.values(config.agents.registry).map((agent) => agent.role));
39
+ knownRoles.add('orchestrator');
40
+ knownRoles.add('qa');
41
+ knownRoles.add('frontend');
42
+ knownRoles.add('backend');
43
+ knownRoles.add('security');
44
+ knownRoles.add('infra');
45
+ const invalidRoles = new Set();
46
+ for (const scale of Object.values(config.rules.scales)) {
47
+ for (const role of [...scale.requiredRoles, ...scale.optionalRoles]) {
48
+ if (!knownRoles.has(role))
49
+ invalidRoles.add(role);
50
+ }
51
+ }
52
+ const templates = {
53
+ workerPrompt: validateTemplate('workerPrompt', config.templates.workerPrompt.body),
54
+ finalReport: validateTemplate('finalReport', config.templates.finalReport.body),
55
+ };
56
+ return {
57
+ ok: invalidRoles.size === 0 && Object.values(templates).every((item) => item.ok),
58
+ templates,
59
+ invalidRoles: [...invalidRoles].sort(),
60
+ };
61
+ }
62
+ export function renderTemplate(kind, body, context) {
63
+ return body.replaceAll(PLACEHOLDER_RE, (_full, key) => {
64
+ const value = context[key];
65
+ if (Array.isArray(value))
66
+ return value.join(', ');
67
+ if (value === undefined || value === null)
68
+ return '';
69
+ if (typeof value === 'object')
70
+ return JSON.stringify(value);
71
+ return String(value);
72
+ });
73
+ }
@@ -0,0 +1,10 @@
1
+ import type { ZigrixConfig } from '../config/schema.js';
2
+ import { type WorkflowRunRecord } from './schema.js';
3
+ export declare function runWorkflow(params: {
4
+ config: ZigrixConfig;
5
+ workflowPath: string;
6
+ }): Promise<{
7
+ record: WorkflowRunRecord;
8
+ savedPath: string;
9
+ }>;
10
+ export declare function summarizeRun(record: WorkflowRunRecord): string;
@@ -0,0 +1,91 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { spawn } from 'node:child_process';
4
+ import { saveRunRecord } from './store.js';
5
+ import { workflowSchema } from './schema.js';
6
+ function nowIso() {
7
+ return new Date().toISOString();
8
+ }
9
+ function runStep(step, cwd) {
10
+ const startedAt = new Date();
11
+ return new Promise((resolve) => {
12
+ const child = spawn(step.run, {
13
+ cwd,
14
+ env: process.env,
15
+ shell: true,
16
+ });
17
+ let stdout = '';
18
+ let stderr = '';
19
+ let timedOut = false;
20
+ child.stdout.on('data', (chunk) => {
21
+ stdout += String(chunk);
22
+ });
23
+ child.stderr.on('data', (chunk) => {
24
+ stderr += String(chunk);
25
+ });
26
+ const timeout = step.timeoutMs
27
+ ? setTimeout(() => {
28
+ timedOut = true;
29
+ child.kill('SIGTERM');
30
+ }, step.timeoutMs)
31
+ : null;
32
+ child.on('close', (code) => {
33
+ if (timeout)
34
+ clearTimeout(timeout);
35
+ const finishedAt = new Date();
36
+ resolve({
37
+ id: step.id,
38
+ run: step.run,
39
+ cwd,
40
+ status: timedOut ? 'timeout' : code === 0 ? 'success' : 'failed',
41
+ exitCode: code,
42
+ startedAt: startedAt.toISOString(),
43
+ finishedAt: finishedAt.toISOString(),
44
+ durationMs: finishedAt.getTime() - startedAt.getTime(),
45
+ stdout,
46
+ stderr,
47
+ });
48
+ });
49
+ });
50
+ }
51
+ export async function runWorkflow(params) {
52
+ const workflowPath = path.resolve(params.workflowPath);
53
+ const raw = fs.readFileSync(workflowPath, 'utf8');
54
+ const parsed = workflowSchema.parse(JSON.parse(raw));
55
+ const workflowDir = path.dirname(workflowPath);
56
+ const startedAt = new Date();
57
+ const runId = `run-${startedAt.toISOString().replace(/[:.]/g, '-').replace('T', '_').slice(0, 19)}`;
58
+ const steps = [];
59
+ let overallStatus = 'success';
60
+ for (const step of parsed.steps) {
61
+ const cwd = step.cwd ? path.resolve(workflowDir, step.cwd) : workflowDir;
62
+ const result = await runStep(step, cwd);
63
+ steps.push(result);
64
+ if (result.status !== 'success') {
65
+ overallStatus = 'failed';
66
+ break;
67
+ }
68
+ }
69
+ const finishedAt = new Date();
70
+ const record = {
71
+ runId,
72
+ workflowName: parsed.name,
73
+ workflowPath,
74
+ status: overallStatus,
75
+ startedAt: startedAt.toISOString(),
76
+ finishedAt: finishedAt.toISOString(),
77
+ durationMs: finishedAt.getTime() - startedAt.getTime(),
78
+ steps,
79
+ };
80
+ const savedPath = saveRunRecord(params.config, record);
81
+ return { record, savedPath };
82
+ }
83
+ export function summarizeRun(record) {
84
+ return [
85
+ `runId: ${record.runId}`,
86
+ `workflow: ${record.workflowName}`,
87
+ `status: ${record.status}`,
88
+ `steps: ${record.steps.length}`,
89
+ `durationMs: ${record.durationMs}`,
90
+ ].join('\n');
91
+ }
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+ export declare const workflowSchema: z.ZodObject<{
3
+ name: z.ZodString;
4
+ steps: z.ZodArray<z.ZodObject<{
5
+ id: z.ZodString;
6
+ run: z.ZodString;
7
+ cwd: z.ZodOptional<z.ZodString>;
8
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
9
+ }, z.core.$strip>>;
10
+ }, z.core.$strip>;
11
+ export type Workflow = z.infer<typeof workflowSchema>;
12
+ export type StepRunRecord = {
13
+ id: string;
14
+ run: string;
15
+ cwd: string;
16
+ status: 'success' | 'failed' | 'timeout';
17
+ exitCode: number | null;
18
+ startedAt: string;
19
+ finishedAt: string;
20
+ durationMs: number;
21
+ stdout: string;
22
+ stderr: string;
23
+ };
24
+ export type WorkflowRunRecord = {
25
+ runId: string;
26
+ workflowName: string;
27
+ workflowPath: string;
28
+ status: 'success' | 'failed';
29
+ startedAt: string;
30
+ finishedAt: string;
31
+ durationMs: number;
32
+ steps: StepRunRecord[];
33
+ };
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ export const workflowSchema = z.object({
3
+ name: z.string().min(1),
4
+ steps: z.array(z.object({
5
+ id: z.string().min(1),
6
+ run: z.string().min(1),
7
+ cwd: z.string().optional(),
8
+ timeoutMs: z.number().int().positive().max(3_600_000).optional(),
9
+ })).min(1),
10
+ });
@@ -0,0 +1,5 @@
1
+ import type { ZigrixConfig } from '../config/schema.js';
2
+ import type { WorkflowRunRecord } from './schema.js';
3
+ export declare function ensureRunsDir(config: ZigrixConfig): string;
4
+ export declare function saveRunRecord(config: ZigrixConfig, record: WorkflowRunRecord): string;
5
+ export declare function loadRunRecord(config: ZigrixConfig, runIdOrPath: string): WorkflowRunRecord;
@@ -0,0 +1,19 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function ensureRunsDir(config) {
4
+ const runsDir = config.paths.runsDir;
5
+ fs.mkdirSync(runsDir, { recursive: true });
6
+ return runsDir;
7
+ }
8
+ export function saveRunRecord(config, record) {
9
+ const runsDir = ensureRunsDir(config);
10
+ const filePath = path.join(runsDir, `${record.runId}.json`);
11
+ fs.writeFileSync(filePath, `${JSON.stringify(record, null, config.runtime.jsonIndent)}\n`, 'utf8');
12
+ return filePath;
13
+ }
14
+ export function loadRunRecord(config, runIdOrPath) {
15
+ const candidatePath = path.isAbsolute(runIdOrPath)
16
+ ? runIdOrPath
17
+ : path.join(config.paths.runsDir, runIdOrPath.endsWith('.json') ? runIdOrPath : `${runIdOrPath}.json`);
18
+ return JSON.parse(fs.readFileSync(candidatePath, 'utf8'));
19
+ }
@@ -0,0 +1,3 @@
1
+ export declare function nowIso(): string;
2
+ export declare function appendEvent(eventsFile: string, event: Record<string, unknown>): Record<string, unknown>;
3
+ export declare function loadEvents(eventsFile: string): Array<Record<string, unknown>>;
@@ -0,0 +1,53 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function nowIso() {
4
+ return new Date().toISOString();
5
+ }
6
+ /**
7
+ * Normalize a legacy event to the standard envelope.
8
+ * - `timestamp` → `ts`
9
+ * - top-level `agentId`/`reason` → payload
10
+ */
11
+ function normalizeEvent(raw) {
12
+ const event = { ...raw };
13
+ // timestamp → ts
14
+ if ('timestamp' in event && !('ts' in event)) {
15
+ event.ts = event.timestamp;
16
+ delete event.timestamp;
17
+ }
18
+ // Ensure payload exists
19
+ if (!event.payload || typeof event.payload !== 'object') {
20
+ event.payload = {};
21
+ }
22
+ const payload = event.payload;
23
+ // Move top-level agentId/reason into payload if not already there
24
+ if ('agentId' in event && event.agentId !== undefined && !('agentId' in payload)) {
25
+ payload.agentId = event.agentId;
26
+ }
27
+ if ('reason' in event && event.reason !== undefined && !('reason' in payload)) {
28
+ payload.reason = event.reason;
29
+ }
30
+ return event;
31
+ }
32
+ export function appendEvent(eventsFile, event) {
33
+ const payload = { ...event, ts: event.ts ?? nowIso() };
34
+ fs.mkdirSync(path.dirname(eventsFile), { recursive: true });
35
+ fs.appendFileSync(eventsFile, `${JSON.stringify(payload)}\n`, 'utf8');
36
+ return payload;
37
+ }
38
+ export function loadEvents(eventsFile) {
39
+ if (!fs.existsSync(eventsFile))
40
+ return [];
41
+ return fs.readFileSync(eventsFile, 'utf8')
42
+ .split(/\r?\n/)
43
+ .filter(Boolean)
44
+ .flatMap((line) => {
45
+ try {
46
+ const parsed = JSON.parse(line);
47
+ return [normalizeEvent(parsed)];
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ });
53
+ }
@@ -0,0 +1,15 @@
1
+ import type { ZigrixConfig } from '../config/schema.js';
2
+ export type ZigrixPaths = {
3
+ baseDir: string;
4
+ tasksDir: string;
5
+ promptsDir: string;
6
+ evidenceDir: string;
7
+ eventsFile: string;
8
+ indexFile: string;
9
+ runsDir: string;
10
+ rulesDir: string;
11
+ };
12
+ export declare function resolvePaths(config: ZigrixConfig): ZigrixPaths;
13
+ export declare function ensureBaseState(paths: ZigrixPaths): void;
14
+ /** @deprecated Use ensureBaseState */
15
+ export declare const ensureProjectState: typeof ensureBaseState;
@@ -0,0 +1,23 @@
1
+ import fs from 'node:fs';
2
+ export function resolvePaths(config) {
3
+ return {
4
+ baseDir: config.paths.baseDir,
5
+ tasksDir: config.paths.tasksDir,
6
+ promptsDir: config.paths.promptsDir,
7
+ evidenceDir: config.paths.evidenceDir,
8
+ eventsFile: config.paths.eventsFile,
9
+ indexFile: config.paths.indexFile,
10
+ runsDir: config.paths.runsDir,
11
+ rulesDir: config.paths.rulesDir,
12
+ };
13
+ }
14
+ export function ensureBaseState(paths) {
15
+ fs.mkdirSync(paths.baseDir, { recursive: true });
16
+ fs.mkdirSync(paths.tasksDir, { recursive: true });
17
+ fs.mkdirSync(paths.promptsDir, { recursive: true });
18
+ fs.mkdirSync(paths.evidenceDir, { recursive: true });
19
+ fs.mkdirSync(paths.runsDir, { recursive: true });
20
+ fs.mkdirSync(paths.rulesDir, { recursive: true });
21
+ }
22
+ /** @deprecated Use ensureBaseState */
23
+ export const ensureProjectState = ensureBaseState;
@@ -0,0 +1,61 @@
1
+ import { type ZigrixPaths } from './paths.js';
2
+ export type WorkPackage = {
3
+ id: string;
4
+ key: string;
5
+ title: string;
6
+ parallel: boolean;
7
+ };
8
+ export type ExecutionUnit = {
9
+ id: string;
10
+ title: string;
11
+ kind: string;
12
+ owner: string;
13
+ workPackage: string;
14
+ dependsOn: string[];
15
+ parallel: boolean;
16
+ status: string;
17
+ dod: string;
18
+ };
19
+ export type ZigrixTask = {
20
+ taskId: string;
21
+ title: string;
22
+ description: string;
23
+ scale: string;
24
+ status: string;
25
+ createdAt: string;
26
+ updatedAt: string;
27
+ requiredAgents: string[];
28
+ workerSessions: Record<string, unknown>;
29
+ projectDir?: string;
30
+ requestedBy?: string;
31
+ selectedAgents?: string[];
32
+ workPackages?: WorkPackage[];
33
+ executionUnits?: ExecutionUnit[];
34
+ orchestratorSessionKey?: string;
35
+ orchestratorSessionId?: string;
36
+ };
37
+ export declare function nextTaskId(paths: ZigrixPaths, prefix?: string): string;
38
+ export declare function saveTask(paths: ZigrixPaths, task: ZigrixTask): ZigrixTask;
39
+ export declare function loadTask(paths: ZigrixPaths, taskId: string): ZigrixTask | null;
40
+ export declare function listTasks(paths: ZigrixPaths): ZigrixTask[];
41
+ export declare function listTaskEvents(paths: ZigrixPaths, taskId?: string): Array<Record<string, unknown>>;
42
+ export declare function createTask(paths: ZigrixPaths, params: {
43
+ title: string;
44
+ description: string;
45
+ scale?: string;
46
+ requiredAgents?: string[];
47
+ projectDir?: string;
48
+ requestedBy?: string;
49
+ prefix?: string;
50
+ }): ZigrixTask;
51
+ export declare function updateTaskStatus(paths: ZigrixPaths, taskId: string, status: string): ZigrixTask | null;
52
+ export declare function recordTaskProgress(paths: ZigrixPaths, params: {
53
+ taskId: string;
54
+ actor: string;
55
+ message: string;
56
+ unitId?: string;
57
+ workPackage?: string;
58
+ }): Record<string, unknown> | null;
59
+ export declare function findStaleTasks(paths: ZigrixPaths, hours?: number): ZigrixTask[];
60
+ export declare function applyStalePolicy(paths: ZigrixPaths, hours?: number, reason?: string): Record<string, unknown>;
61
+ export declare function rebuildIndex(paths: ZigrixPaths): Record<string, unknown>;