@llm-dev-ops/agentics-cli 1.7.2 → 1.8.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.
@@ -234,13 +234,15 @@ export async function executeAutoChain(traceId, options = {}) {
234
234
  let scenarioBranch;
235
235
  let originalBranch;
236
236
  let scenarioQuery = '';
237
- // Read scenario query from Phase 1 manifest (needed for branch naming)
237
+ // Read scenario query and simulation ID from Phase 1 manifest
238
+ let simulationId = '';
238
239
  try {
239
240
  const manifestPath = path.join(runDir, 'manifest.json');
240
241
  if (fs.existsSync(manifestPath)) {
241
242
  const raw = fs.readFileSync(manifestPath, 'utf-8');
242
243
  const manifest = JSON.parse(raw);
243
244
  scenarioQuery = manifest.query ?? '';
245
+ simulationId = manifest.simulation_id ?? manifest.execution_id ?? '';
244
246
  }
245
247
  }
246
248
  catch {
@@ -869,23 +871,34 @@ The prompts must be production-grade — they will be given directly to a coding
869
871
  derivedPhases.push({ title: heading, slug, content: section, folder, adrIds: matchedAdrIds });
870
872
  }
871
873
  }
872
- // If SPARC didn't produce enough sections, fall back to ADR-derived phases
873
- if (derivedPhases.length < 3) {
874
- // Group ADRs into logical clusters
874
+ // ADR-PIPELINE-031: Enrich with ADR-derived phases when SPARC sections alone are insufficient.
875
+ // Each ADR that isn't already covered by a SPARC-derived phase becomes its own build step.
876
+ if (derivedPhases.length < 8 && adrs.length > 0) {
877
+ const existingSlugs = new Set(derivedPhases.map(p => p.slug));
878
+ const existingTitleWords = new Set(derivedPhases.flatMap(p => p.title.toLowerCase().split(/\W+/).filter(w => w.length > 3)));
875
879
  for (const adr of adrs) {
876
880
  const slug = adr.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 50);
881
+ // Skip if a phase with similar slug or overlapping title already exists
882
+ if (existingSlugs.has(slug))
883
+ continue;
884
+ const adrKeywords = adr.title.toLowerCase().split(/\W+/).filter(w => w.length > 3);
885
+ const overlap = adrKeywords.filter(w => existingTitleWords.has(w)).length;
886
+ if (overlap >= 2)
887
+ continue; // sufficiently covered by an existing phase
877
888
  const adrLower = `${adr.title} ${adr.context} ${adr.decision}`.toLowerCase();
878
889
  let folder = 'backend';
879
890
  if (/frontend|ui|dashboard/.test(adrLower))
880
891
  folder = 'frontend';
881
- else if (/erp|netsuite|sap|dynamics/.test(adrLower))
892
+ else if (/erp|netsuite|sap|dynamics|coupa|workday|maximo|oracle/.test(adrLower))
882
893
  folder = 'erp';
883
- else if (/integration|connector/.test(adrLower))
894
+ else if (/integration|connector|webhook/.test(adrLower))
884
895
  folder = 'integrations';
885
896
  else if (/deploy|infra|docker/.test(adrLower))
886
897
  folder = 'src';
887
898
  else if (/test|quality/.test(adrLower))
888
899
  folder = 'tests';
900
+ else if (/audit|governance|approval/.test(adrLower))
901
+ folder = 'backend';
889
902
  derivedPhases.push({
890
903
  title: adr.title,
891
904
  slug,
@@ -893,6 +906,9 @@ The prompts must be production-grade — they will be given directly to a coding
893
906
  folder,
894
907
  adrIds: [adr.id],
895
908
  });
909
+ existingSlugs.add(slug);
910
+ for (const w of adrKeywords)
911
+ existingTitleWords.add(w);
896
912
  }
897
913
  }
898
914
  // Always add foundation (first) and testing/deployment (last) if not present
@@ -934,6 +950,186 @@ The prompts must be production-grade — they will be given directly to a coding
934
950
  adrIds: [],
935
951
  });
936
952
  }
953
+ // ADR-PIPELINE-031: Guarantee ≥10 prompts by adding standard cross-cutting phases
954
+ // when domain-specific + ADR-derived phases don't reach the minimum.
955
+ const crossCutting = [
956
+ { title: 'Observability & Structured Logging', slug: 'observability', folder: 'backend',
957
+ content: `ADR-PIPELINE-034: Implement complete observability infrastructure.
958
+
959
+ ## 1. Structured Logger (src/logger.ts)
960
+
961
+ Create a logger factory that outputs JSON to stderr:
962
+
963
+ \`\`\`typescript
964
+ export interface Logger {
965
+ info(event: string, data?: Record<string, unknown>): void;
966
+ warn(event: string, data?: Record<string, unknown>): void;
967
+ error(event: string, error: Error, data?: Record<string, unknown>): void;
968
+ }
969
+
970
+ export function createLogger(service: string): Logger {
971
+ // Each log entry: { timestamp, level, service, event, correlationId?, ...data }
972
+ // Output to stderr as single-line JSON
973
+ }
974
+
975
+ // Correlation ID context — thread through entire request lifecycle
976
+ export function withCorrelationId<T>(correlationId: string, fn: () => T): T;
977
+ export function getCorrelationId(): string | undefined;
978
+ \`\`\`
979
+
980
+ ## 2. Correlation ID Threading
981
+
982
+ Every analysis run generates a correlationId (UUID). This ID flows through:
983
+ - analysis.started → analysis.excess_detected → analysis.completed
984
+ - decision.created → erp.sync.attempted → erp.sync.succeeded/failed
985
+
986
+ Pass correlationId as a parameter through service functions or use AsyncLocalStorage.
987
+
988
+ ## 3. Instrumentation Points (minimum)
989
+
990
+ | Event | When | Data |
991
+ |-------|------|------|
992
+ | analysis.started | Analysis begins | { correlationId, supplierCount, recordCount } |
993
+ | analysis.completed | Analysis finishes | { correlationId, durationMs, flagCount, opportunityCount } |
994
+ | decision.created | Decision recorded | { correlationId, decisionId, opportunityId, status } |
995
+ | erp.sync.attempted | ERP write starts | { correlationId, transactionId, supplierId, action } |
996
+ | erp.sync.succeeded | ERP write succeeds | { correlationId, transactionId, responseTime } |
997
+ | erp.sync.failed | ERP write fails | { correlationId, transactionId, error, retryCount } |
998
+
999
+ ## 4. ERP Error Handling
1000
+
1001
+ The ERP connector must handle:
1002
+ - Network timeout: configurable (default 30s), log erp.sync.failed with timeout error
1003
+ - Rate limiting (429): exponential backoff (1s, 2s, 4s, max 3 retries), log each retry
1004
+ - Schema validation: log and quarantine invalid records, don't crash the pipeline
1005
+ - Idempotency: generate idempotency key per transaction to prevent duplicate writes on retry
1006
+
1007
+ ## 5. Health Check
1008
+
1009
+ If the project includes an API layer, add GET /health returning:
1010
+ \`\`\`json
1011
+ { "status": "ok", "service": "packaging-waste-optimizer", "version": "0.1.0", "uptime": 12345, "lastAnalysisRun": "2026-04-09T..." }
1012
+ \`\`\`
1013
+
1014
+ ## 6. Tests
1015
+
1016
+ - Test that logger outputs valid JSON to stderr
1017
+ - Test that correlationId flows through analysis → decision → ERP sync
1018
+ - Test that ERP error handling retries on 429 and logs failures` },
1019
+ { title: 'Configuration & Environment Management', slug: 'configuration', folder: 'src',
1020
+ content: `ADR-PIPELINE-034: Configuration module for environment-based settings.
1021
+
1022
+ Create src/config.ts with a typed configuration object:
1023
+
1024
+ \`\`\`typescript
1025
+ export interface AppConfig {
1026
+ env: 'development' | 'staging' | 'production';
1027
+ logLevel: 'debug' | 'info' | 'warn' | 'error';
1028
+ erp: {
1029
+ baseUrl: string;
1030
+ apiVersion: string;
1031
+ clientId: string;
1032
+ timeoutMs: number; // default 30000
1033
+ maxRetries: number; // default 3
1034
+ };
1035
+ analysis: {
1036
+ // Domain-specific thresholds — externalized, not hardcoded
1037
+ [key: string]: number | string | boolean;
1038
+ };
1039
+ }
1040
+ \`\`\`
1041
+
1042
+ Requirements:
1043
+ - Read all values from environment variables (never hardcode secrets)
1044
+ - Validate at startup — fail fast with clear error messages for missing required vars
1045
+ - Provide sensible defaults for optional values (timeoutMs, maxRetries, logLevel)
1046
+ - Export a singleton config object used by all services
1047
+ - Include tests that verify validation catches missing required vars` },
1048
+ { title: 'API Layer & Request Handling', slug: 'api-layer', folder: 'backend',
1049
+ content: 'Build REST API endpoints exposing core domain operations. Input validation at API boundary (Zod or equivalent). Authentication and authorization middleware. Structured error responses with correlation IDs. Rate limiting.' },
1050
+ { title: 'Persistence & Data Access Layer', slug: 'persistence', folder: 'backend',
1051
+ content: 'Implement repository interfaces per aggregate (ports pattern). Database adapter implementations. Audit trail persistence (append-only, tamper-evident). Transaction management for multi-aggregate operations.' },
1052
+ { title: 'Demo Script & CLI Entry Point', slug: 'demo', folder: 'src',
1053
+ content: `ADR-PIPELINE-037: User-facing entry points for the prototype.
1054
+
1055
+ ## 1. Demo Script (src/demo.ts) — REQUIRED
1056
+
1057
+ Create a runnable demo (\`npx tsx src/demo.ts\`) that:
1058
+ 1. Loads all seed data
1059
+ 2. Runs the complete analysis pipeline end-to-end
1060
+ 3. Prints formatted results to stdout using tables (not raw JSON):
1061
+ - Summary table: key metrics, top findings
1062
+ - Per-entity breakdown (e.g., per-supplier, per-zone, per-employee)
1063
+ - Scenario comparison table with tradeoff columns
1064
+ 4. Demonstrates the decision/approval workflow:
1065
+ - Create a draft decision for the top opportunity
1066
+ - Approve it with a test approver
1067
+ 5. Shows the ERP sync payload:
1068
+ - Print the structured payload that would be sent to the ERP
1069
+ - Mark as "dry run" — do not actually sync
1070
+
1071
+ The demo must run without any external dependencies (no database, no API keys, no network).
1072
+
1073
+ ## 2. CLI Interface (src/cli.ts) — OPTIONAL
1074
+
1075
+ If time permits, create a minimal CLI:
1076
+ \`\`\`
1077
+ npx tsx src/cli.ts --analyze # Run analysis, print results
1078
+ npx tsx src/cli.ts --scenarios # Show scenario comparison
1079
+ npx tsx src/cli.ts --decide <id> # Create decision for opportunity
1080
+ npx tsx src/cli.ts --sync <id> # Dry-run ERP sync for decision
1081
+ npx tsx src/cli.ts --help # Usage examples
1082
+ \`\`\`
1083
+
1084
+ ## 3. Architecture Divergence ADR — REQUIRED
1085
+
1086
+ Create \`docs/ADR-001-monolithic-prototype.md\` in the generated project:
1087
+
1088
+ \`\`\`markdown
1089
+ # ADR-001: Monolithic Library for Prototype Phase
1090
+
1091
+ ## Status
1092
+ Accepted
1093
+
1094
+ ## Context
1095
+ The SPARC architecture specification describes multiple microservices with event-driven
1096
+ communication. For the prototype evaluation period (3-7 days), deploying and operating
1097
+ microservices adds unnecessary complexity without delivering proportional value.
1098
+
1099
+ ## Decision
1100
+ Build as a single TypeScript library with clean module boundaries:
1101
+ - analysis/ — Pure computation, no side effects
1102
+ - decisions/ — State management with audit trail
1103
+ - erp/ — External system integration (adapter pattern)
1104
+ - data/ — Seed data and data access
1105
+
1106
+ Each module exports a barrel (index.ts) and communicates via typed interfaces,
1107
+ not shared mutable state. This structure enables decomposition into independent
1108
+ services when the pilot validates the approach.
1109
+
1110
+ ## Consequences
1111
+ - Prototype can be built, tested, and demonstrated in days, not weeks
1112
+ - Module boundaries enforce separation of concerns without deployment overhead
1113
+ - Migration to microservices requires extracting modules into packages — not rewriting
1114
+ \`\`\`
1115
+
1116
+ ## Tests
1117
+ - Test that demo.ts runs without errors (import and execute main function)
1118
+ - Test that it produces non-empty stdout output` },
1119
+ ];
1120
+ const existingSlugSet = new Set(derivedPhases.map(p => p.slug));
1121
+ for (const cc of crossCutting) {
1122
+ if (derivedPhases.length >= 12)
1123
+ break;
1124
+ if (existingSlugSet.has(cc.slug))
1125
+ continue;
1126
+ // Don't add if a phase already covers this topic
1127
+ if (derivedPhases.some(p => p.title.toLowerCase().includes(cc.slug.split('-')[0])))
1128
+ continue;
1129
+ derivedPhases.push({ ...cc, adrIds: [] });
1130
+ existingSlugSet.add(cc.slug);
1131
+ }
1132
+ console.error(` [PROMPTS] ${derivedPhases.length} phases derived (SPARC + ADRs + cross-cutting, minimum 10 per ADR-PIPELINE-031)`);
937
1133
  // ── Helper: extract DDD context names and summaries relevant to a phase ──
938
1134
  function getDddSummaryForPhase(phaseTitle, phaseContent) {
939
1135
  if (!dddContent)
@@ -1024,6 +1220,14 @@ The prompts must be production-grade — they will be given directly to a coding
1024
1220
  `**Target folder:** \`${phase.folder}/\``,
1025
1221
  '',
1026
1222
  ];
1223
+ // ADR-PIPELINE-033: Simulation lineage in every prompt
1224
+ if (simulationId || traceId) {
1225
+ lines.push('## Simulation Lineage', '');
1226
+ if (simulationId)
1227
+ lines.push(`Originating simulation: \`${simulationId}\``);
1228
+ lines.push(`Trace ID: \`${traceId}\``);
1229
+ lines.push('');
1230
+ }
1027
1231
  // ── Narrative description — the core of each prompt ──
1028
1232
  lines.push('## Overview', '', narrative, '');
1029
1233
  // Previously completed phases (brief list)
@@ -1075,8 +1279,8 @@ The prompts must be production-grade — they will be given directly to a coding
1075
1279
  if (dddSummary) {
1076
1280
  lines.push('## Domain Model Reference', '', dddSummary, '');
1077
1281
  }
1078
- // Implementation instructions
1079
- lines.push('## Implementation Requirements', '', '- All code must be CUSTOM to this project — implement the specific business logic described above', '- Follow the technology decisions from the ADRs referenced in the overview', '- Write production-quality code with proper error handling', '- Include unit tests (London School TDD — mock at module boundaries)', '- Export public interfaces so later build phases can import them', `- Place all files in the \`${phase.folder}/\` directory`, '');
1282
+ // Implementation instructions — ADR-PIPELINE-033: include traceability requirements
1283
+ lines.push('## Implementation Requirements', '', '- All code must be CUSTOM to this project — implement the specific business logic described above', '- Follow the technology decisions from the ADRs referenced in the overview', '- Write production-quality code with proper error handling', '- Include unit tests (London School TDD — mock at module boundaries)', '- Export public interfaces so later build phases can import them', `- Place all files in the \`${phase.folder}/\` directory`, '', '## Traceability Requirements (ADR-PIPELINE-033)', '', '- All domain types that represent decisions, recommendations, or ERP actions must include optional `simulationId?: string` and `traceId?: string` fields', '- Audit trail entries must include these IDs when available', '- ERP transaction payloads must carry `simulationId` and `traceId` for end-to-end lineage', `${simulationId ? `- Use simulation ID \`${simulationId}\` as the default value when creating records in this build step` : '- Simulation ID will be injected at runtime from the pipeline context'}`, '');
1080
1284
  fs.writeFileSync(path.join(promptsDir, filename), lines.join('\n'), { mode: 0o600, encoding: 'utf-8' });
1081
1285
  completedPhases.push(`${order}. ${phase.title}`);
1082
1286
  }
@@ -1087,7 +1291,17 @@ The prompts must be production-grade — they will be given directly to a coding
1087
1291
  folder: phase.folder,
1088
1292
  adrs: phase.adrIds,
1089
1293
  }));
1090
- fs.writeFileSync(path.join(promptsDir, 'execution-plan.json'), JSON.stringify({ totalSteps, prompts: planItems }, null, 2), { mode: 0o600, encoding: 'utf-8' });
1294
+ // ADR-PIPELINE-033: Include simulation lineage in execution plan
1295
+ const plan = {
1296
+ totalSteps,
1297
+ prompts: planItems,
1298
+ lineage: {
1299
+ simulationId: simulationId || undefined,
1300
+ traceId: traceId || undefined,
1301
+ pipelineVersion: '1.7.3',
1302
+ },
1303
+ };
1304
+ fs.writeFileSync(path.join(promptsDir, 'execution-plan.json'), JSON.stringify(plan, null, 2), { mode: 0o600, encoding: 'utf-8' });
1091
1305
  console.error(` [PROMPTS] Wrote ${totalSteps} implementation prompts derived from SPARC architecture + ADRs`);
1092
1306
  }
1093
1307
  copyPlanningArtifacts(runDir, projectRoot);