guardian-framework 0.1.153 → 0.1.154
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/dist/cli.js +1 -1
- package/dist/exports.js +1 -1
- package/package.json +1 -1
- package/templates/pi/preflight_report.json +1 -1
- package/templates/pi/scripts/epic-fanout.sh +105 -38
package/dist/cli.js
CHANGED
|
@@ -3206,7 +3206,7 @@ __export(exports_package, {
|
|
|
3206
3206
|
bin: () => bin,
|
|
3207
3207
|
author: () => author
|
|
3208
3208
|
});
|
|
3209
|
-
var name = "guardian-framework", version = "0.1.
|
|
3209
|
+
var name = "guardian-framework", version = "0.1.154", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
|
|
3210
3210
|
var init_package = __esm(() => {
|
|
3211
3211
|
exports = {
|
|
3212
3212
|
".": {
|
package/dist/exports.js
CHANGED
|
@@ -1991,7 +1991,7 @@ __export(exports_package, {
|
|
|
1991
1991
|
bin: () => bin,
|
|
1992
1992
|
author: () => author
|
|
1993
1993
|
});
|
|
1994
|
-
var name = "guardian-framework", version = "0.1.
|
|
1994
|
+
var name = "guardian-framework", version = "0.1.154", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
|
|
1995
1995
|
var init_package = __esm(() => {
|
|
1996
1996
|
exports = {
|
|
1997
1997
|
".": {
|
package/package.json
CHANGED
|
@@ -170,13 +170,15 @@ echo ""
|
|
|
170
170
|
# ── Dependency gate ─────────────────────────────────────────────────────────
|
|
171
171
|
# A module may only run in parallel once the modules it depends on are
|
|
172
172
|
# implemented. Deps inside this same batch cannot be satisfied yet either.
|
|
173
|
-
DEP_CHECK="$(python3 - "$ROOT" ${MODULES[@]+"${MODULES[@]}"} <<'PY'
|
|
173
|
+
DEP_CHECK="$(python3 - "$ROOT" "$COMMON_ABS/guardian/epics.json" ${MODULES[@]+"${MODULES[@]}"} <<'PY'
|
|
174
174
|
import os, re, sys
|
|
175
175
|
|
|
176
176
|
root = sys.argv[1]
|
|
177
|
-
|
|
177
|
+
registry_path = sys.argv[2]
|
|
178
|
+
batch = sys.argv[3:]
|
|
178
179
|
mods_dir = os.path.join(root, ".pi/architecture/modules")
|
|
179
180
|
|
|
181
|
+
|
|
180
182
|
def doc_path(slug):
|
|
181
183
|
p = os.path.join(mods_dir, f"{slug}.md")
|
|
182
184
|
return p if os.path.exists(p) else None
|
|
@@ -199,63 +201,128 @@ def status_of(slug):
|
|
|
199
201
|
return "planned"
|
|
200
202
|
|
|
201
203
|
def deps_of(slug):
|
|
204
|
+
"""Modules this one depends on.
|
|
205
|
+
|
|
206
|
+
Module docs use several shapes, all of which appear in real projects:
|
|
207
|
+
**Depends On:** none.
|
|
208
|
+
**Depends On:** Alpha, Beta
|
|
209
|
+
### Depends On
|
|
210
|
+
| Module | What it provides |
|
|
211
|
+
| **Mandate** | ... |
|
|
212
|
+
|
|
213
|
+
Critically, a doc may also carry a "Used By" table listing its CONSUMERS.
|
|
214
|
+
Those must never be read as dependencies (that would invert the graph and
|
|
215
|
+
block a module on the work that depends on it).
|
|
216
|
+
"""
|
|
202
217
|
p = doc_path(slug)
|
|
203
218
|
if not p:
|
|
204
219
|
return []
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if
|
|
208
|
-
|
|
209
|
-
|
|
220
|
+
lines = open(p, encoding="utf-8", errors="ignore").read().splitlines()
|
|
221
|
+
|
|
222
|
+
# Scope: the "## Dependencies" section if present, else the whole doc.
|
|
223
|
+
scope, sec = list(lines), None
|
|
224
|
+
for i, ln in enumerate(lines):
|
|
225
|
+
if re.match(r"^##\s+Dependencies\b", ln, re.I):
|
|
226
|
+
sec = i
|
|
227
|
+
break
|
|
228
|
+
if sec is not None:
|
|
229
|
+
scope = []
|
|
230
|
+
for ln in lines[sec + 1:]:
|
|
231
|
+
if re.match(r"^##\s+", ln):
|
|
232
|
+
break
|
|
233
|
+
scope.append(ln)
|
|
234
|
+
|
|
235
|
+
# Inside that scope, take only the "Depends On" sub-block.
|
|
236
|
+
block, in_deps = [], False
|
|
237
|
+
for ln in scope:
|
|
238
|
+
label = ln.strip()
|
|
239
|
+
heading = re.match(r"^#{2,4}\s*Depends On\b(.*)$", label, re.I)
|
|
240
|
+
bold = re.match(r"^\*\*Depends On:?\*\*(.*)$", label, re.I)
|
|
241
|
+
if heading or bold:
|
|
242
|
+
in_deps = True
|
|
243
|
+
rest = (heading.group(1) if heading else bold.group(1)).strip()
|
|
244
|
+
if rest:
|
|
245
|
+
block.append(rest)
|
|
246
|
+
continue
|
|
247
|
+
if in_deps and re.match(r"^#{2,4}\s", label):
|
|
248
|
+
in_deps = False # next sibling section, e.g. "### Used By"
|
|
249
|
+
continue
|
|
250
|
+
if in_deps:
|
|
251
|
+
block.append(label)
|
|
252
|
+
|
|
253
|
+
if not block:
|
|
210
254
|
return []
|
|
211
|
-
|
|
212
|
-
|
|
255
|
+
|
|
256
|
+
# An explicit "none" anywhere in the Depends On block means: no dependencies.
|
|
257
|
+
joined = " ".join(block)
|
|
258
|
+
if re.search(r"\bnone\b", joined, re.I):
|
|
213
259
|
return []
|
|
260
|
+
|
|
214
261
|
found = []
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if first and not first.startswith("|") and not first.startswith("-"):
|
|
218
|
-
for part in re.split(r"[,;]", first):
|
|
219
|
-
nm = part.strip().strip(chr(96) + "* ").rstrip(".")
|
|
220
|
-
if nm and not nm.lower().startswith("none"):
|
|
221
|
-
found.append(nm)
|
|
222
|
-
for line in block.splitlines():
|
|
223
|
-
line = line.strip()
|
|
224
|
-
if not line.startswith("|"):
|
|
262
|
+
for ln in block:
|
|
263
|
+
if not ln:
|
|
225
264
|
continue
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if line.startswith("- "):
|
|
237
|
-
name = line[2:].split("—")[0].split(":")[0].strip().strip(chr(96) + "* ")
|
|
265
|
+
if ln.startswith("|"):
|
|
266
|
+
cells = [c.strip() for c in ln.strip("|").split("|")]
|
|
267
|
+
if not cells:
|
|
268
|
+
continue
|
|
269
|
+
name = cells[0].replace(chr(96), "").replace("*", "").strip()
|
|
270
|
+
if not name or name.lower() in ("module", "modules") or set(name) <= set("-: "):
|
|
271
|
+
continue
|
|
272
|
+
found.append(name)
|
|
273
|
+
elif ln.startswith("- "):
|
|
274
|
+
name = ln[2:].split("\u2014")[0].split(":")[0].strip().strip(chr(96) + "* ")
|
|
238
275
|
if name and name.lower() != "none":
|
|
239
276
|
found.append(name)
|
|
277
|
+
else:
|
|
278
|
+
# inline list: "Alpha, Beta"
|
|
279
|
+
for part in re.split(r"[,;]", ln):
|
|
280
|
+
nm = part.strip().strip(chr(96) + "* ").rstrip(".")
|
|
281
|
+
if nm and not nm.lower().startswith("none") and len(nm) < 60:
|
|
282
|
+
found.append(nm)
|
|
240
283
|
return found
|
|
241
284
|
|
|
285
|
+
|
|
242
286
|
def slugify(name):
|
|
243
287
|
return re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")
|
|
244
288
|
|
|
245
|
-
|
|
289
|
+
# Registry state: which modules have frozen contracts. Freeze is the gate for
|
|
290
|
+
# parallel work ("merge the contract-freeze issue first"), implementation the
|
|
291
|
+
# stricter also-accepted case. Loaded here because it needs slugify().
|
|
292
|
+
frozen = set()
|
|
293
|
+
try:
|
|
294
|
+
import json
|
|
295
|
+
_reg = json.load(open(registry_path, encoding="utf-8"))
|
|
296
|
+
for _mod, _entry in (_reg.get("epics") or {}).items():
|
|
297
|
+
if isinstance(_entry, dict) and _entry.get("contractFrozen"):
|
|
298
|
+
frozen.add(slugify(_mod))
|
|
299
|
+
except Exception:
|
|
300
|
+
frozen = set()
|
|
301
|
+
|
|
246
302
|
problems = []
|
|
247
|
-
for slug in batch:
|
|
303
|
+
for idx, slug in enumerate(batch):
|
|
248
304
|
for dep_name in deps_of(slug):
|
|
249
305
|
dep = slugify(dep_name)
|
|
250
306
|
st = status_of(dep)
|
|
251
|
-
if st
|
|
307
|
+
if st == "implemented":
|
|
308
|
+
continue
|
|
309
|
+
if dep in frozen:
|
|
252
310
|
continue
|
|
253
|
-
if dep in
|
|
254
|
-
|
|
311
|
+
if dep in batch and batch.index(dep) < idx:
|
|
312
|
+
continue # frozen earlier in this very run
|
|
313
|
+
if dep in batch:
|
|
314
|
+
problems.append(
|
|
315
|
+
f"{slug}: depends on '{dep_name}', which comes later in this batch — "
|
|
316
|
+
f"reorder so it starts first")
|
|
255
317
|
elif st == "unknown":
|
|
256
|
-
problems.append(
|
|
318
|
+
problems.append(
|
|
319
|
+
f"{slug}: depends on '{dep_name}' with no module doc under "
|
|
320
|
+
f".pi/architecture/modules/")
|
|
257
321
|
else:
|
|
258
|
-
problems.append(
|
|
322
|
+
problems.append(
|
|
323
|
+
f"{slug}: depends on '{dep_name}' ({st}) and its contracts are not "
|
|
324
|
+
f"frozen — merge its contract-freeze issue, then: "
|
|
325
|
+
f"bash .pi/scripts/epic-registry.sh freeze \"{dep_name}\" --frozen")
|
|
259
326
|
|
|
260
327
|
if problems:
|
|
261
328
|
print("\n".join(problems))
|