guardian-framework 0.1.157 → 0.1.158

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 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.157", 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;
3209
+ var name = "guardian-framework", version = "0.1.158", 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.157", 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;
1994
+ var name = "guardian-framework", version = "0.1.158", 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.157",
3
+ "version": "0.1.158",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -98,6 +98,61 @@ export interface TddGenerateOptions {
98
98
  * Generate failing test files for all components in an epic slice.
99
99
  * Returns list of generated file paths.
100
100
  */
101
+ /**
102
+ * Identifier builders shared by every language generator.
103
+ *
104
+ * Component and module ids are human labels ("aggregate-household",
105
+ * "payee review & digest", "--bankdigest-"), not identifiers. Interpolating
106
+ * them raw produced invalid code:
107
+ * Python def test_aggregate-household_is_defined(): -> SyntaxError
108
+ * Rust fn test_aggregate-household_is_defined() -> will not compile
109
+ * Go/Java/CamelCase(...) names that start with a digit or keep spaces
110
+ *
111
+ * Every generated identifier now goes through one of these.
112
+ */
113
+
114
+ /** Split a human label into alphanumeric words (never empty). */
115
+ function identWords(raw: string): string[] {
116
+ const words = (raw ?? "")
117
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
118
+ .split(/[^A-Za-z0-9]+/)
119
+ .filter((w) => w.length > 0);
120
+ return words.length > 0 ? words : ["component"];
121
+ }
122
+
123
+ /** `aggregate-household` -> `aggregate_household` (python, rust). */
124
+ export function snakeIdent(raw: string): string {
125
+ const joined = identWords(raw)
126
+ .map((w) => w.toLowerCase())
127
+ .join("_");
128
+ // Identifiers may not start with a digit.
129
+ return /^[0-9]/.test(joined) ? `n_${joined}` : joined;
130
+ }
131
+
132
+ /** `aggregate-household` -> `AggregateHousehold` (java, go, ts types). */
133
+ export function pascalIdent(raw: string): string {
134
+ const joined = identWords(raw)
135
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
136
+ .join("");
137
+ return /^[0-9]/.test(joined) ? `N${joined}` : joined;
138
+ }
139
+
140
+ /** `aggregate-household` -> `aggregateHousehold` (ts values). */
141
+ export function camelIdent(raw: string): string {
142
+ const p = pascalIdent(raw);
143
+ return p.charAt(0).toLowerCase() + p.slice(1);
144
+ }
145
+
146
+ /** Kept for callers/tests that ask for a Python identifier specifically. */
147
+ export function pyIdent(raw: string): string {
148
+ return snakeIdent(raw);
149
+ }
150
+
151
+ /** Components are not required to declare dependencies. */
152
+ function depsOf(component: { dependencies?: string[] }): string[] {
153
+ return component.dependencies ?? [];
154
+ }
155
+
101
156
  export function generateEpicTestFiles(options: TddGenerateOptions): string[] {
102
157
  const {
103
158
  components,
@@ -176,7 +231,7 @@ function getTestFileName(componentId: string, language: string): string {
176
231
  case "go":
177
232
  return `${componentId}_test.go`;
178
233
  case "java":
179
- return `${toPascalCase(componentId)}Test.java`;
234
+ return `${pascalIdent(componentId)}Test.java`;
180
235
  default:
181
236
  return `${componentId}.test.ts`;
182
237
  }
@@ -228,19 +283,19 @@ function generateTypeScript(
228
283
  `it("should be defined", () => {`,
229
284
  ` expect(false).toBe(true);`,
230
285
  ` // TODO: uncomment when ${component.name} is implemented`,
231
- ` // const instance = new ${component.name.replace(/[^a-zA-Z0-9]/g, "")}();`,
286
+ ` // const instance = new ${pascalIdent(component.name)}();`,
232
287
  ` // expect(instance).toBeDefined();`,
233
288
  `});`,
234
289
  ], 1));
235
290
 
236
291
  // Dependency interaction tests
237
- for (const dep of component.dependencies) {
292
+ for (const dep of depsOf(component)) {
238
293
  lines.push(...indent([
239
294
  `it("should interact with ${dep}", () => {`,
240
295
  ` expect(false).toBe(true);`,
241
296
  ` // TODO: implement dependency test for ${dep}`,
242
297
  ` // const mock = { /* mock ${dep} interface */ };`,
243
- ` // const result = new ${component.name.replace(/[^a-zA-Z0-9]/g, "")}(mock);`,
298
+ ` // const result = new ${pascalIdent(component.name)}(mock);`,
244
299
  ` // expect(result).toBeDefined();`,
245
300
  `});`,
246
301
  ], 1));
@@ -268,21 +323,21 @@ function generateRust(
268
323
  ` use super::*;`,
269
324
  ``,
270
325
  ` #[test]`,
271
- ` fn test_${componentId}_is_defined() {`,
326
+ ` fn test_${snakeIdent(componentId)}_is_defined() {`,
272
327
  ` // TODO: uncomment when ${component.name} is implemented`,
273
- ` // let _instance = ${toPascalCase(componentId)}::new();`,
328
+ ` // let _instance = ${pascalIdent(componentId)}::new();`,
274
329
  ` assert!(false, "Test not yet implemented");`,
275
330
  ` }`,
276
331
  ];
277
332
 
278
- for (const dep of component.dependencies) {
333
+ for (const dep of depsOf(component)) {
279
334
  lines.push(...[
280
335
  ``,
281
336
  ` #[test]`,
282
- ` fn test_${componentId}_interacts_with_${dep.replace(/[^a-z0-9]/gi, "_").toLowerCase()}() {`,
337
+ ` fn test_${snakeIdent(componentId)}_interacts_with_${snakeIdent(dep)}() {`,
283
338
  ` // TODO: implement dependency test for ${dep}`,
284
339
  ` // let mock = Mock${dep.replace(/[^a-zA-Z0-9]/g, "")}::new();`,
285
- ` // let result = ${toPascalCase(componentId)}::new(mock);`,
340
+ ` // let result = ${pascalIdent(componentId)}::new(mock);`,
286
341
  ` assert!(false, "Dependency test not yet implemented");`,
287
342
  ` }`,
288
343
  ]);
@@ -300,7 +355,7 @@ function generatePython(
300
355
  moduleId: string,
301
356
  componentId: string,
302
357
  ): string {
303
- const clsName = toPascalCase(componentId);
358
+ const clsName = pascalIdent(componentId);
304
359
  const lines: string[] = [
305
360
  `# Generated by Guardian TDD`,
306
361
  `# From: ${component.name} (${moduleId} module)`,
@@ -312,17 +367,17 @@ function generatePython(
312
367
  `class Test${clsName}:`,
313
368
  ` """Tests for ${component.name}."""`,
314
369
  ``,
315
- ` def test_${componentId}_is_defined(self):`,
370
+ ` def test_${snakeIdent(componentId)}_is_defined(self):`,
316
371
  ` """${component.name} should be instantiable."""`,
317
372
  ` assert False, "TODO: uncomment when ${component.name} is implemented"`,
318
373
  ` # instance = ${clsName}()`,
319
374
  ` # assert instance is not None`,
320
375
  ];
321
376
 
322
- for (const dep of component.dependencies) {
377
+ for (const dep of depsOf(component)) {
323
378
  lines.push(...[
324
379
  ``,
325
- ` def test_${componentId}_interacts_with_${dep.replace(/[^a-z0-9]/gi, "_").toLowerCase()}(self):`,
380
+ ` def test_${snakeIdent(componentId)}_interacts_with_${snakeIdent(dep)}(self):`,
326
381
  ` """${component.name} should interact with ${dep}."""`,
327
382
  ` assert False, "TODO: implement dependency test for ${dep}"`,
328
383
  ` # mock = MagicMock(spec=${dep.replace(/[^a-zA-Z0-9]/g, "")})`,
@@ -348,13 +403,13 @@ function generateGo(
348
403
  `// From: ${component.name} (${moduleId} module)`,
349
404
  `// These tests will FAIL until ${component.name} is implemented.`,
350
405
  ``,
351
- `package ${moduleId.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()}`,
406
+ `package ${snakeIdent(moduleId).replace(/_/g, "")}`,
352
407
  ``,
353
408
  `import "testing"`,
354
409
  ``,
355
- `func Test${toPascalCase(componentId)}_IsDefined(t *testing.T) {`,
410
+ `func Test${pascalIdent(componentId)}_IsDefined(t *testing.T) {`,
356
411
  ` // TODO: uncomment when ${component.name} is implemented`,
357
- ` // instance := New${toPascalCase(componentId)}()`,
412
+ ` // instance := New${pascalIdent(componentId)}()`,
358
413
  ` // if instance == nil {`,
359
414
  ` // t.Fail()`,
360
415
  ` // }`,
@@ -362,13 +417,13 @@ function generateGo(
362
417
  `}`,
363
418
  ];
364
419
 
365
- for (const dep of component.dependencies) {
420
+ for (const dep of depsOf(component)) {
366
421
  lines.push(...[
367
422
  ``,
368
- `func Test${toPascalCase(componentId)}_InteractsWith_${capitalize(dep.replace(/[^a-zA-Z0-9]/g, ""))}(t *testing.T) {`,
423
+ `func Test${pascalIdent(componentId)}_InteractsWith_${pascalIdent(dep)}(t *testing.T) {`,
369
424
  ` // TODO: implement dependency test for ${dep}`,
370
- ` // mock := new(Mock${capitalize(dep.replace(/[^a-zA-Z0-9]/g, ""))})`,
371
- ` // instance := New${toPascalCase(componentId)}(mock)`,
425
+ ` // mock := new(Mock${pascalIdent(dep)})`,
426
+ ` // instance := New${pascalIdent(componentId)}(mock)`,
372
427
  ` // result := instance.Execute()`,
373
428
  ` t.Fatal("Dependency test not yet implemented")`,
374
429
  `}`,
@@ -387,7 +442,7 @@ function generateJava(
387
442
  componentId: string,
388
443
  javaPackage?: string,
389
444
  ): string {
390
- const clsName = toPascalCase(componentId);
445
+ const clsName = pascalIdent(componentId);
391
446
  const lines: string[] = [
392
447
  `// Generated by Guardian TDD`,
393
448
  `// From: ${component.name} (${moduleId} module)`,
@@ -415,13 +470,13 @@ function generateJava(
415
470
  ` }`,
416
471
  );
417
472
 
418
- for (const dep of component.dependencies) {
473
+ for (const dep of depsOf(component)) {
419
474
  lines.push(
420
475
  ``,
421
476
  ` @Test`,
422
- ` void test${clsName}_InteractsWith_${capitalize(dep.replace(/[^a-zA-Z0-9]/g, ""))}() {`,
477
+ ` void test${clsName}_InteractsWith_${pascalIdent(dep)}() {`,
423
478
  ` // TODO: implement dependency test for ${dep}`,
424
- ` // ${capitalize(dep.replace(/[^a-zA-Z0-9]/g, ""))} mock = mock(${capitalize(dep.replace(/[^a-zA-Z0-9]/g, ""))}.class);`,
479
+ ` // ${pascalIdent(dep)} mock = mock(${pascalIdent(dep)}.class);`,
425
480
  ` // ${clsName} instance = new ${clsName}(mock);`,
426
481
  ` fail("Dependency test not yet implemented");`,
427
482
  ` }`,
@@ -434,14 +489,6 @@ function generateJava(
434
489
 
435
490
  // ── Utility ──
436
491
 
437
- function capitalize(s: string): string {
438
- return s.charAt(0).toUpperCase() + s.slice(1);
439
- }
440
-
441
- function toPascalCase(s: string): string {
442
- return s.split("-").map(capitalize).join("");
443
- }
444
-
445
492
  function indent(lines: string[], level: number): string[] {
446
493
  const pad = " ".repeat(level);
447
494
  return lines.map((l) => `${pad}${l}`);
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-11-13T17:52:57Z",
2
+ "timestamp": "2026-11-13T19:00:09Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -62,7 +62,10 @@ const args = ["--mode", "rpc"];
62
62
  if (opts.session) args.push("--session-id", opts.session);
63
63
  else args.push("--no-session");
64
64
 
65
- const child = spawn("pi", args, {
65
+ // Explicit binary wins: tests and CI set GUARDIAN_PI_BIN so resolution never
66
+ // depends on PATH (a project's node_modules/.bin can contain another `pi`).
67
+ const piBin = process.env.GUARDIAN_PI_BIN || "pi";
68
+ const child = spawn(piBin, args, {
66
69
  cwd: opts.cwd,
67
70
  stdio: ["pipe", "pipe", "pipe"],
68
71
  env: process.env,