agentxchain 0.8.6 → 0.8.8

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.
@@ -1,6 +1,23 @@
1
1
  import { existsSync, readFileSync, readdirSync } from 'fs';
2
2
  import { join } from 'path';
3
3
 
4
+ const DEFAULT_REQUIRED_FILES = [
5
+ '.planning/PROJECT.md',
6
+ '.planning/REQUIREMENTS.md',
7
+ '.planning/ROADMAP.md',
8
+ '.planning/PM_SIGNOFF.md',
9
+ '.planning/qa/TEST-COVERAGE.md',
10
+ '.planning/qa/BUGS.md',
11
+ '.planning/qa/UX-AUDIT.md',
12
+ '.planning/qa/ACCEPTANCE-MATRIX.md',
13
+ '.planning/qa/REGRESSION-LOG.md',
14
+ ];
15
+
16
+ const PROTOCOL_FILES = [
17
+ 'lock.json',
18
+ 'state.json'
19
+ ];
20
+
4
21
  export function validateProject(root, config, opts = {}) {
5
22
  const mode = opts.mode || 'full';
6
23
  const expectedAgent = opts.expectedAgent || null;
@@ -9,23 +26,17 @@ export function validateProject(root, config, opts = {}) {
9
26
  const errors = [];
10
27
  const warnings = [];
11
28
 
12
- const mustExist = [
13
- '.planning/PROJECT.md',
14
- '.planning/REQUIREMENTS.md',
15
- '.planning/ROADMAP.md',
16
- '.planning/PM_SIGNOFF.md',
17
- '.planning/qa/TEST-COVERAGE.md',
18
- '.planning/qa/BUGS.md',
19
- '.planning/qa/UX-AUDIT.md',
20
- '.planning/qa/ACCEPTANCE-MATRIX.md',
21
- '.planning/qa/REGRESSION-LOG.md',
29
+ const customRequired = config.rules?.required_files;
30
+ const planningFiles = Array.isArray(customRequired) ? customRequired : DEFAULT_REQUIRED_FILES;
31
+
32
+ const dynamicFiles = [
22
33
  talkFile,
23
- 'state.md',
24
- 'history.jsonl',
25
- 'lock.json',
26
- 'state.json'
34
+ config.state_file || 'state.md',
35
+ config.history_file || 'history.jsonl',
27
36
  ];
28
37
 
38
+ const mustExist = [...planningFiles, ...dynamicFiles, ...PROTOCOL_FILES];
39
+
29
40
  for (const rel of mustExist) {
30
41
  if (!existsSync(join(root, rel))) {
31
42
  errors.push(`Missing required file: ${rel}`);
@@ -98,9 +109,9 @@ function validatePhaseArtifacts(root) {
98
109
 
99
110
  function validateHistory(root, config, opts) {
100
111
  const result = { errors: [], warnings: [] };
101
- const historyPath = join(root, 'history.jsonl');
112
+ const historyPath = join(root, config.history_file || 'history.jsonl');
102
113
  if (!existsSync(historyPath)) {
103
- result.errors.push('history.jsonl is missing.');
114
+ result.errors.push(`${config.history_file || 'history.jsonl'} is missing.`);
104
115
  return result;
105
116
  }
106
117
 
@@ -111,9 +122,9 @@ function validateHistory(root, config, opts) {
111
122
 
112
123
  if (lines.length === 0) {
113
124
  if (opts.requireEntry) {
114
- result.errors.push('history.jsonl has no entries.');
125
+ result.errors.push(`${config.history_file || 'history.jsonl'} has no entries.`);
115
126
  } else {
116
- result.warnings.push('history.jsonl has no entries yet.');
127
+ result.warnings.push(`${config.history_file || 'history.jsonl'} has no entries yet.`);
117
128
  }
118
129
  return result;
119
130
  }
@@ -123,7 +134,7 @@ function validateHistory(root, config, opts) {
123
134
  try {
124
135
  last = JSON.parse(lastRaw);
125
136
  } catch {
126
- result.errors.push('Last history.jsonl entry is not valid JSON.');
137
+ result.errors.push(`Last ${config.history_file || 'history.jsonl'} entry is not valid JSON.`);
127
138
  return result;
128
139
  }
129
140
 
@@ -0,0 +1,72 @@
1
+ import { spawnSync } from 'child_process';
2
+
3
+ export function parseCommandArgs(input) {
4
+ if (Array.isArray(input)) {
5
+ return input.filter(part => typeof part === 'string' && part.length > 0);
6
+ }
7
+
8
+ if (typeof input !== 'string' || !input.trim()) {
9
+ return [];
10
+ }
11
+
12
+ const out = [];
13
+ let current = '';
14
+ let quote = null;
15
+ let escape = false;
16
+
17
+ for (const char of input.trim()) {
18
+ if (escape) {
19
+ current += char;
20
+ escape = false;
21
+ continue;
22
+ }
23
+ if (char === '\\') {
24
+ escape = true;
25
+ continue;
26
+ }
27
+ if (quote) {
28
+ if (char === quote) {
29
+ quote = null;
30
+ } else {
31
+ current += char;
32
+ }
33
+ continue;
34
+ }
35
+ if (char === '"' || char === "'") {
36
+ quote = char;
37
+ continue;
38
+ }
39
+ if (/\s/.test(char)) {
40
+ if (current) {
41
+ out.push(current);
42
+ current = '';
43
+ }
44
+ continue;
45
+ }
46
+ current += char;
47
+ }
48
+
49
+ if (current) {
50
+ out.push(current);
51
+ }
52
+
53
+ return out;
54
+ }
55
+
56
+ export function runConfiguredVerify(config, root) {
57
+ const args = parseCommandArgs(config?.rules?.verify_command);
58
+ if (args.length === 0) {
59
+ return { ok: true, skipped: true, command: null };
60
+ }
61
+
62
+ const result = spawnSync(args[0], args.slice(1), {
63
+ cwd: root,
64
+ stdio: 'inherit'
65
+ });
66
+
67
+ return {
68
+ ok: result.status === 0,
69
+ skipped: false,
70
+ command: args.join(' ')
71
+ };
72
+ }