@arvorco/relentless 0.1.21 → 0.1.23

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": "@arvorco/relentless",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Universal AI agent orchestrator - works with Claude Code, Amp, OpenCode, Codex, Droid, and Gemini",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -141,6 +141,7 @@ export function parseConstitution(content: string): Constitution {
141
141
  const sections = new Set<string>();
142
142
 
143
143
  let currentSection = "";
144
+ let currentLevel: PrincipleLevel | null = null;
144
145
  const lines = content.split("\n");
145
146
 
146
147
  for (const line of lines) {
@@ -148,12 +149,37 @@ export function parseConstitution(content: string): Constitution {
148
149
  if (line.startsWith("## ")) {
149
150
  currentSection = line.replace("## ", "").trim();
150
151
  sections.add(currentSection);
152
+ currentLevel = null;
151
153
  } else if (line.startsWith("### ")) {
152
154
  currentSection = line.replace("### ", "").trim();
153
155
  sections.add(currentSection);
156
+ currentLevel = null;
154
157
  }
155
158
 
156
- // Extract MUST principles
159
+ // Detect MUST/SHOULD headers (format: **MUST:** or **SHOULD:**)
160
+ if (line.match(/^\*\*MUST:?\*\*:?\s*$/i)) {
161
+ currentLevel = "MUST";
162
+ continue;
163
+ }
164
+ if (line.match(/^\*\*SHOULD:?\*\*:?\s*$/i)) {
165
+ currentLevel = "SHOULD";
166
+ continue;
167
+ }
168
+
169
+ // Extract bullet points under current level
170
+ if (currentLevel && line.match(/^-\s+.+/)) {
171
+ const text = line.replace(/^-\s+/, "").trim();
172
+ if (text) {
173
+ principles.push({
174
+ level: currentLevel,
175
+ text,
176
+ section: currentSection,
177
+ });
178
+ }
179
+ continue;
180
+ }
181
+
182
+ // Extract inline MUST/SHOULD (format: **MUST** text or **SHOULD** text)
157
183
  const mustMatch = line.match(/\*\*MUST\*\*\s+(.+)/);
158
184
  if (mustMatch) {
159
185
  principles.push({
@@ -163,7 +189,6 @@ export function parseConstitution(content: string): Constitution {
163
189
  });
164
190
  }
165
191
 
166
- // Extract SHOULD principles
167
192
  const shouldMatch = line.match(/\*\*SHOULD\*\*\s+(.+)/);
168
193
  if (shouldMatch) {
169
194
  principles.push({
@@ -172,6 +197,11 @@ export function parseConstitution(content: string): Constitution {
172
197
  section: currentSection,
173
198
  });
174
199
  }
200
+
201
+ // Reset level on empty line or **Rationale** or other header
202
+ if (line.trim() === "" || line.match(/^\*\*[^MS]/)) {
203
+ currentLevel = null;
204
+ }
175
205
  }
176
206
 
177
207
  return {
@@ -70,8 +70,8 @@ async function buildPrompt(
70
70
 
71
71
  let prompt = await Bun.file(promptPath).text();
72
72
 
73
- // Load and append constitution if available
74
- const constitution = await loadConstitution(workingDirectory);
73
+ // Load and append constitution if available (pass undefined to auto-find)
74
+ const constitution = await loadConstitution();
75
75
  if (constitution) {
76
76
  // Validate constitution
77
77
  const validation = validateConstitution(constitution);
@@ -90,7 +90,7 @@ async function buildPrompt(
90
90
 
91
91
  // Load and append progress patterns if available
92
92
  const progress = await loadProgress(progressPath);
93
- if (progress && progress.metadata.patterns.length > 0) {
93
+ if (progress?.metadata?.patterns && progress.metadata.patterns.length > 0) {
94
94
  prompt += `\n\n## Learned Patterns from Previous Iterations\n\n`;
95
95
  prompt += `The following patterns were discovered in previous iterations:\n\n`;
96
96
  for (const pattern of progress.metadata.patterns) {