pumuki 6.3.49 → 6.3.51
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/README.md +19 -19
- package/core/facts/detectors/text/ios.test.ts +13 -0
- package/core/rules/presets/iosEnterpriseRuleSet.test.ts +46 -0
- package/core/rules/presets/iosEnterpriseRuleSet.ts +4 -2
- package/docs/README.md +42 -63
- package/docs/validation/README.md +25 -31
- package/integrations/git/gitAtomicity.ts +32 -7
- package/integrations/git/runPlatformGate.ts +6 -4
- package/integrations/git/runPlatformGateOutput.ts +2 -2
- package/integrations/git/stageRunners.ts +156 -8
- package/integrations/lifecycle/watch.ts +5 -4
- package/integrations/sdd/evidenceScaffold.ts +6 -2
- package/integrations/sdd/policy.ts +6 -5
- package/package.json +1 -1
- package/scripts/adapter-readiness-markdown-next-actions-lib.ts +1 -1
- package/scripts/build-phase8-ready-handoff-summary.sh +1 -1
- package/scripts/check-refactor-progress-single-active.sh +1 -1
- package/scripts/check-tracking-single-active.sh +19 -2
- package/scripts/close-phase5-escalation-submission.sh +1 -1
- package/scripts/phase5-blockers-markdown-next-actions-blocked-lib.ts +1 -1
- package/docs/API_REFERENCE.md +0 -338
- package/docs/ARCHITECTURE.md +0 -190
- package/docs/BRANCH_PROTECTION_GUIDE.md +0 -50
- package/docs/CODE_STANDARDS.md +0 -73
- package/docs/CONFIGURATION.md +0 -366
- package/docs/CONTRIBUTING.md +0 -92
- package/docs/DEPENDENCIES.md +0 -54
- package/docs/HOW_IT_WORKS.md +0 -160
- package/docs/INSTALLATION.md +0 -270
- package/docs/MCP_AGENT_CONTEXT_CONSUMPTION.md +0 -188
- package/docs/MCP_EVIDENCE_CONTEXT_SERVER.md +0 -244
- package/docs/MCP_SERVERS.md +0 -280
- package/docs/OPERATIONS.md +0 -74
- package/docs/README_MENU_WALKTHROUGH.md +0 -65
- package/docs/RELEASE_NOTES.md +0 -562
- package/docs/TESTING.md +0 -114
- package/docs/USAGE.md +0 -749
- package/docs/evidence-v2.1.md +0 -98
- package/docs/registro-maestro-de-seguimiento.md +0 -20
- package/docs/seguimiento-activo-pumuki-saas-supermercados.md +0 -2591
- package/docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md +0 -2507
- package/docs/validation/c022-phase-acceptance-contract.md +0 -172
- /package/docs/validation/{adapter-hook-runtime-validation.md → adapter-hook-runtime-runbook.md} +0 -0
- /package/docs/validation/{skills-rollout-consumer-repositories.md → consumer-repositories-skills-rollout-validation.md} +0 -0
- /package/docs/validation/{detection-audit-baseline.md → full-repo-detection-audit-baseline.md} +0 -0
|
@@ -22,8 +22,11 @@ import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
|
22
22
|
import { join } from 'node:path';
|
|
23
23
|
import { readEvidence, readEvidenceResult } from '../evidence/readEvidence';
|
|
24
24
|
import type { EvidenceReadResult } from '../evidence/readEvidence';
|
|
25
|
+
import type { SnapshotFinding } from '../evidence/schema';
|
|
25
26
|
import { ensureRuntimeArtifactsIgnored } from '../lifecycle/artifacts';
|
|
26
27
|
import { runPolicyReconcile } from '../lifecycle/policyReconcile';
|
|
28
|
+
import { isSeverityAtLeast } from '../../core/rules/Severity';
|
|
29
|
+
import type { SddDecision } from '../sdd';
|
|
27
30
|
|
|
28
31
|
const PRE_PUSH_UPSTREAM_REQUIRED_MESSAGE =
|
|
29
32
|
'pumuki pre-push blocked: branch has no upstream tracking reference. Configure upstream first (for example: git push --set-upstream origin <branch>) and retry.';
|
|
@@ -36,11 +39,14 @@ const PRE_PUSH_UPSTREAM_MISALIGNED_AHEAD_THRESHOLD = 5;
|
|
|
36
39
|
const PRE_COMMIT_EVIDENCE_MAX_AGE_SECONDS = 900;
|
|
37
40
|
const PRE_PUSH_EVIDENCE_MAX_AGE_SECONDS = 1800;
|
|
38
41
|
const DEFAULT_BLOCKED_REMEDIATION = 'Corrige la causa del bloqueo y vuelve a ejecutar el gate.';
|
|
42
|
+
const EVIDENCE_FILE_PATH = '.ai_evidence.json';
|
|
39
43
|
|
|
40
44
|
const BLOCKED_REMEDIATION_BY_CODE: Readonly<Record<string, string>> = {
|
|
41
45
|
EVIDENCE_MISSING: 'Regenera .ai_evidence.json ejecutando una auditoría.',
|
|
42
46
|
EVIDENCE_INVALID: 'Corrige/regenera .ai_evidence.json y vuelve a ejecutar el gate.',
|
|
43
47
|
EVIDENCE_CHAIN_INVALID: 'Regenera evidencia para restaurar la cadena criptográfica.',
|
|
48
|
+
EVIDENCE_STAGE_SYNC_FAILED:
|
|
49
|
+
'Sincroniza la evidencia trackeada y reintenta: git add -- .ai_evidence.json && git commit --amend --no-edit',
|
|
44
50
|
EVIDENCE_STALE: 'Refresca evidencia antes de continuar.',
|
|
45
51
|
EVIDENCE_REPO_ROOT_MISMATCH: 'Regenera evidencia desde este mismo repositorio.',
|
|
46
52
|
EVIDENCE_BRANCH_MISMATCH: 'Regenera evidencia en la rama actual y reintenta.',
|
|
@@ -102,6 +108,9 @@ type StageRunnerDependencies = {
|
|
|
102
108
|
isQuietMode: () => boolean;
|
|
103
109
|
ensureRuntimeArtifactsIgnored: (repoRoot: string) => void;
|
|
104
110
|
runPolicyReconcile: typeof runPolicyReconcile;
|
|
111
|
+
isPathTracked: (repoRoot: string, relativePath: string) => boolean;
|
|
112
|
+
stagePath: (repoRoot: string, relativePath: string) => void;
|
|
113
|
+
resolveHeadOid: (repoRoot: string) => string | null;
|
|
105
114
|
};
|
|
106
115
|
|
|
107
116
|
const defaultDependencies: StageRunnerDependencies = {
|
|
@@ -158,6 +167,24 @@ const defaultDependencies: StageRunnerDependencies = {
|
|
|
158
167
|
}
|
|
159
168
|
},
|
|
160
169
|
runPolicyReconcile,
|
|
170
|
+
isPathTracked: (repoRoot, relativePath) => {
|
|
171
|
+
try {
|
|
172
|
+
new GitService().runGit(['ls-files', '--error-unmatch', '--', relativePath], repoRoot);
|
|
173
|
+
return true;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
stagePath: (repoRoot, relativePath) => {
|
|
179
|
+
new GitService().runGit(['add', '--', relativePath], repoRoot);
|
|
180
|
+
},
|
|
181
|
+
resolveHeadOid: (repoRoot) => {
|
|
182
|
+
try {
|
|
183
|
+
return new GitService().runGit(['rev-parse', 'HEAD'], repoRoot).trim();
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
161
188
|
};
|
|
162
189
|
|
|
163
190
|
const getDependencies = (
|
|
@@ -177,6 +204,14 @@ const notifyAuditSummaryForStage = (
|
|
|
177
204
|
});
|
|
178
205
|
};
|
|
179
206
|
|
|
207
|
+
const resolvePrimaryBlockedStageFinding = (
|
|
208
|
+
findings: ReadonlyArray<SnapshotFinding>
|
|
209
|
+
): SnapshotFinding | undefined => (
|
|
210
|
+
findings.find((finding) => {
|
|
211
|
+
return isSeverityAtLeast(finding.severity, 'ERROR');
|
|
212
|
+
}) ?? findings[0]
|
|
213
|
+
);
|
|
214
|
+
|
|
180
215
|
const notifyGateBlockedForStage = (params: {
|
|
181
216
|
dependencies: StageRunnerDependencies;
|
|
182
217
|
stage: 'PRE_COMMIT' | 'PRE_PUSH' | 'CI';
|
|
@@ -190,10 +225,10 @@ const notifyGateBlockedForStage = (params: {
|
|
|
190
225
|
evidence?.snapshot.stage === params.stage
|
|
191
226
|
? evidence.snapshot.findings
|
|
192
227
|
: [];
|
|
193
|
-
const
|
|
228
|
+
const primaryStageFinding = resolvePrimaryBlockedStageFinding(stageFindings);
|
|
194
229
|
const firstViolation = evidence?.ai_gate.violations[0];
|
|
195
|
-
const causeCode =
|
|
196
|
-
const causeMessage =
|
|
230
|
+
const causeCode = primaryStageFinding?.code ?? firstViolation?.code ?? params.fallbackCauseCode;
|
|
231
|
+
const causeMessage = primaryStageFinding?.message ?? firstViolation?.message ?? params.fallbackCauseMessage;
|
|
197
232
|
const remediation =
|
|
198
233
|
BLOCKED_REMEDIATION_BY_CODE[causeCode]
|
|
199
234
|
?? params.fallbackRemediation
|
|
@@ -327,12 +362,14 @@ const runHookGateAttempt = async (params: {
|
|
|
327
362
|
dependencies: StageRunnerDependencies;
|
|
328
363
|
stage: HookStage;
|
|
329
364
|
scope: Parameters<typeof runPlatformGate>[0]['scope'];
|
|
365
|
+
sddDecisionOverride?: Pick<SddDecision, 'allowed' | 'code' | 'message'>;
|
|
330
366
|
}): Promise<{ exitCode: number; policyTrace: HookPolicyTrace }> => {
|
|
331
367
|
const resolved = params.dependencies.resolvePolicyForStage(params.stage);
|
|
332
368
|
const exitCode = await params.dependencies.runPlatformGate({
|
|
333
369
|
policy: resolved.policy,
|
|
334
370
|
policyTrace: resolved.trace,
|
|
335
371
|
scope: params.scope,
|
|
372
|
+
sddDecisionOverride: params.sddDecisionOverride,
|
|
336
373
|
});
|
|
337
374
|
return {
|
|
338
375
|
exitCode,
|
|
@@ -345,11 +382,13 @@ const runHookGateWithPolicyRetry = async (params: {
|
|
|
345
382
|
repoRoot: string;
|
|
346
383
|
stage: HookStage;
|
|
347
384
|
scope: Parameters<typeof runPlatformGate>[0]['scope'];
|
|
385
|
+
sddDecisionOverride?: Pick<SddDecision, 'allowed' | 'code' | 'message'>;
|
|
348
386
|
}): Promise<{ exitCode: number; policyTrace: HookPolicyTrace }> => {
|
|
349
387
|
const firstAttempt = await runHookGateAttempt({
|
|
350
388
|
dependencies: params.dependencies,
|
|
351
389
|
stage: params.stage,
|
|
352
390
|
scope: params.scope,
|
|
391
|
+
sddDecisionOverride: params.sddDecisionOverride,
|
|
353
392
|
});
|
|
354
393
|
if (firstAttempt.exitCode === 0) {
|
|
355
394
|
return firstAttempt;
|
|
@@ -375,9 +414,44 @@ const runHookGateWithPolicyRetry = async (params: {
|
|
|
375
414
|
dependencies: params.dependencies,
|
|
376
415
|
stage: params.stage,
|
|
377
416
|
scope: params.scope,
|
|
417
|
+
sddDecisionOverride: params.sddDecisionOverride,
|
|
378
418
|
});
|
|
379
419
|
};
|
|
380
420
|
|
|
421
|
+
const syncTrackedEvidenceAfterSuccessfulPreCommit = (params: {
|
|
422
|
+
dependencies: StageRunnerDependencies;
|
|
423
|
+
repoRoot: string;
|
|
424
|
+
}): boolean => {
|
|
425
|
+
const evidenceAbsolutePath = join(params.repoRoot, EVIDENCE_FILE_PATH);
|
|
426
|
+
if (!existsSync(evidenceAbsolutePath)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
if (!params.dependencies.isPathTracked(params.repoRoot, EVIDENCE_FILE_PATH)) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
params.dependencies.stagePath(params.repoRoot, EVIDENCE_FILE_PATH);
|
|
434
|
+
return false;
|
|
435
|
+
} catch (error) {
|
|
436
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
437
|
+
process.stderr.write(
|
|
438
|
+
`[pumuki][evidence-sync] unable to restage tracked ${EVIDENCE_FILE_PATH}: ${details}\n`
|
|
439
|
+
);
|
|
440
|
+
params.dependencies.notifyGateBlocked({
|
|
441
|
+
repoRoot: params.repoRoot,
|
|
442
|
+
stage: 'PRE_COMMIT',
|
|
443
|
+
totalViolations: 1,
|
|
444
|
+
causeCode: 'EVIDENCE_STAGE_SYNC_FAILED',
|
|
445
|
+
causeMessage:
|
|
446
|
+
`Unable to restage tracked ${EVIDENCE_FILE_PATH} after successful PRE_COMMIT gate.`,
|
|
447
|
+
remediation: BLOCKED_REMEDIATION_BY_CODE.EVIDENCE_STAGE_SYNC_FAILED
|
|
448
|
+
?? DEFAULT_BLOCKED_REMEDIATION,
|
|
449
|
+
});
|
|
450
|
+
notifyAuditSummaryForStage(params.dependencies, 'PRE_COMMIT');
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
381
455
|
const ZERO_HASH = /^0+$/;
|
|
382
456
|
|
|
383
457
|
const toEvidenceAgeSeconds = (
|
|
@@ -450,6 +524,61 @@ const shouldAllowBootstrapPrePush = (rawInput: string): boolean => {
|
|
|
450
524
|
return false;
|
|
451
525
|
};
|
|
452
526
|
|
|
527
|
+
const resolveExplicitPrePushRange = (
|
|
528
|
+
rawInput: string
|
|
529
|
+
): { fromRef: string; toRef: string } | undefined => {
|
|
530
|
+
const lines = rawInput
|
|
531
|
+
.split('\n')
|
|
532
|
+
.map((line) => line.trim())
|
|
533
|
+
.filter((line) => line.length > 0);
|
|
534
|
+
|
|
535
|
+
const eligibleRanges = lines
|
|
536
|
+
.map((line) => {
|
|
537
|
+
const [localRef, localOid, remoteRef, remoteOid] = line.split(/\s+/);
|
|
538
|
+
if (!localRef || !localOid || !remoteRef || !remoteOid) {
|
|
539
|
+
return undefined;
|
|
540
|
+
}
|
|
541
|
+
const localIsDeletion = ZERO_HASH.test(localOid);
|
|
542
|
+
const remoteIsNewBranch = ZERO_HASH.test(remoteOid);
|
|
543
|
+
if (localIsDeletion || remoteIsNewBranch) {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
return {
|
|
547
|
+
fromRef: remoteOid,
|
|
548
|
+
toRef: localOid,
|
|
549
|
+
};
|
|
550
|
+
})
|
|
551
|
+
.filter((value): value is { fromRef: string; toRef: string } => Boolean(value));
|
|
552
|
+
|
|
553
|
+
if (eligibleRanges.length !== 1) {
|
|
554
|
+
return undefined;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return eligibleRanges[0];
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
const resolveHistoricalPrePushSddOverride = (params: {
|
|
561
|
+
dependencies: StageRunnerDependencies;
|
|
562
|
+
repoRoot: string;
|
|
563
|
+
explicitPrePushRange?: { fromRef: string; toRef: string };
|
|
564
|
+
}): Pick<SddDecision, 'allowed' | 'code' | 'message'> | undefined => {
|
|
565
|
+
const explicitRange = params.explicitPrePushRange;
|
|
566
|
+
if (!explicitRange) {
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
const headOid = params.dependencies.resolveHeadOid(params.repoRoot);
|
|
570
|
+
if (!headOid || explicitRange.toRef === headOid) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
allowed: true,
|
|
575
|
+
code: 'ALLOWED',
|
|
576
|
+
message:
|
|
577
|
+
`SDD enforcement suspended for PRE_PUSH historical publish targeting ${explicitRange.toRef.slice(0, 12)} ` +
|
|
578
|
+
`instead of current HEAD ${headOid.slice(0, 12)}.`,
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
|
|
453
582
|
const PRE_PUSH_TOPIC_BRANCH_PREFIXES = [
|
|
454
583
|
'feature/',
|
|
455
584
|
'bugfix/',
|
|
@@ -568,6 +697,15 @@ export async function runPreCommitStage(
|
|
|
568
697
|
) {
|
|
569
698
|
return 1;
|
|
570
699
|
}
|
|
700
|
+
if (
|
|
701
|
+
result.exitCode === 0 &&
|
|
702
|
+
syncTrackedEvidenceAfterSuccessfulPreCommit({
|
|
703
|
+
dependencies: activeDependencies,
|
|
704
|
+
repoRoot,
|
|
705
|
+
})
|
|
706
|
+
) {
|
|
707
|
+
return 1;
|
|
708
|
+
}
|
|
571
709
|
emitSuccessfulHookGateSummary({
|
|
572
710
|
dependencies: activeDependencies,
|
|
573
711
|
stage: 'PRE_COMMIT',
|
|
@@ -594,9 +732,9 @@ export async function runPrePushStage(
|
|
|
594
732
|
const repoRoot = activeDependencies.resolveRepoRoot();
|
|
595
733
|
const manifestSnapshot = captureManifestGuardSnapshot(repoRoot);
|
|
596
734
|
activeDependencies.ensureRuntimeArtifactsIgnored(repoRoot);
|
|
735
|
+
const prePushInput = activeDependencies.readPrePushStdin();
|
|
597
736
|
const upstreamRef = activeDependencies.resolveUpstreamRef();
|
|
598
737
|
if (!upstreamRef) {
|
|
599
|
-
const prePushInput = activeDependencies.readPrePushStdin();
|
|
600
738
|
const bootstrapBaseRef = activeDependencies.resolvePrePushBootstrapBaseRef();
|
|
601
739
|
const bootstrapByPrePushStdIn = shouldAllowBootstrapPrePush(prePushInput);
|
|
602
740
|
const bootstrapByFallbackBase = !bootstrapByPrePushStdIn && bootstrapBaseRef !== 'HEAD';
|
|
@@ -691,6 +829,15 @@ export async function runPrePushStage(
|
|
|
691
829
|
return 1;
|
|
692
830
|
}
|
|
693
831
|
|
|
832
|
+
const explicitPrePushRange = resolveExplicitPrePushRange(prePushInput);
|
|
833
|
+
const prePushFromRef = explicitPrePushRange?.fromRef ?? upstreamRef;
|
|
834
|
+
const prePushToRef = explicitPrePushRange?.toRef ?? 'HEAD';
|
|
835
|
+
const historicalPrePushSddOverride = resolveHistoricalPrePushSddOverride({
|
|
836
|
+
dependencies: activeDependencies,
|
|
837
|
+
repoRoot,
|
|
838
|
+
explicitPrePushRange,
|
|
839
|
+
});
|
|
840
|
+
|
|
694
841
|
const misalignedUpstream = detectPrePushUpstreamMisalignment({
|
|
695
842
|
dependencies: activeDependencies,
|
|
696
843
|
upstreamRef,
|
|
@@ -713,8 +860,8 @@ export async function runPrePushStage(
|
|
|
713
860
|
dependencies: activeDependencies,
|
|
714
861
|
repoRoot,
|
|
715
862
|
stage: 'PRE_PUSH',
|
|
716
|
-
fromRef:
|
|
717
|
-
toRef:
|
|
863
|
+
fromRef: prePushFromRef,
|
|
864
|
+
toRef: prePushToRef,
|
|
718
865
|
})
|
|
719
866
|
) {
|
|
720
867
|
return 1;
|
|
@@ -726,9 +873,10 @@ export async function runPrePushStage(
|
|
|
726
873
|
stage: 'PRE_PUSH',
|
|
727
874
|
scope: {
|
|
728
875
|
kind: 'range',
|
|
729
|
-
fromRef:
|
|
730
|
-
toRef:
|
|
876
|
+
fromRef: prePushFromRef,
|
|
877
|
+
toRef: prePushToRef,
|
|
731
878
|
},
|
|
879
|
+
sddDecisionOverride: historicalPrePushSddOverride,
|
|
732
880
|
});
|
|
733
881
|
if (
|
|
734
882
|
enforceManifestGuard({
|
|
@@ -365,7 +365,6 @@ export const runLifecycleWatch = async (
|
|
|
365
365
|
params?.onTick?.(lastTick);
|
|
366
366
|
} else {
|
|
367
367
|
evaluations += 1;
|
|
368
|
-
const resolvedPolicy = activeDependencies.resolvePolicyForStage(stage);
|
|
369
368
|
const gateScope = toGateScope(scope);
|
|
370
369
|
const facts = await activeDependencies.resolveFactsForGateScope({
|
|
371
370
|
scope: gateScope,
|
|
@@ -374,7 +373,9 @@ export const runLifecycleWatch = async (
|
|
|
374
373
|
const changedFiles = collectChangedFilesFromFacts(facts);
|
|
375
374
|
const evaluatedFiles = collectEvaluatedFilesFromFacts(facts);
|
|
376
375
|
const scopeHasFileDelta = changedFiles.length > 0 || evaluatedFiles.length > 0;
|
|
377
|
-
const runEvaluation = async (
|
|
376
|
+
const runEvaluation = async (
|
|
377
|
+
resolvedPolicy: ResolvedStagePolicy
|
|
378
|
+
): Promise<{
|
|
378
379
|
gateExitCode: number;
|
|
379
380
|
evidence: AiEvidenceV2_1 | undefined;
|
|
380
381
|
allFindings: ReadonlyArray<SnapshotFinding>;
|
|
@@ -439,7 +440,7 @@ export const runLifecycleWatch = async (
|
|
|
439
440
|
};
|
|
440
441
|
};
|
|
441
442
|
|
|
442
|
-
let evaluation = await runEvaluation();
|
|
443
|
+
let evaluation = await runEvaluation(activeDependencies.resolvePolicyForStage(stage));
|
|
443
444
|
if (autoPolicyReconcileEnabled && evaluation.gateExitCode !== 0) {
|
|
444
445
|
const findingCodes = new Set<string>([
|
|
445
446
|
...evaluation.allFindings.map((finding) => finding.code),
|
|
@@ -455,7 +456,7 @@ export const runLifecycleWatch = async (
|
|
|
455
456
|
apply: true,
|
|
456
457
|
});
|
|
457
458
|
if (reconcile.autofix.status === 'APPLIED') {
|
|
458
|
-
evaluation = await runEvaluation();
|
|
459
|
+
evaluation = await runEvaluation(activeDependencies.resolvePolicyForStage(stage));
|
|
459
460
|
}
|
|
460
461
|
}
|
|
461
462
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
3
|
+
import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
4
4
|
import { readEvidenceResult, type EvidenceReadResult } from '../evidence/readEvidence';
|
|
5
5
|
|
|
6
6
|
export type SddEvidenceScaffoldTestStatus = 'passed' | 'failed';
|
|
@@ -80,8 +80,12 @@ const resolveRepoBoundPath = (params: {
|
|
|
80
80
|
rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
|
|
81
81
|
isAbsolute(rel)
|
|
82
82
|
) {
|
|
83
|
+
const remediation =
|
|
84
|
+
params.flagName === '--test-output'
|
|
85
|
+
? ` Try "${params.flagName}=.pumuki/runtime/${basename(params.candidatePath) || 'test-output.log'}".`
|
|
86
|
+
: '';
|
|
83
87
|
throw new Error(
|
|
84
|
-
`[pumuki][sdd] ${params.flagName} must resolve inside repository root: ${params.candidatePath}`
|
|
88
|
+
`[pumuki][sdd] ${params.flagName} must resolve inside repository root: ${params.candidatePath}.${remediation}`
|
|
85
89
|
);
|
|
86
90
|
}
|
|
87
91
|
return resolved;
|
|
@@ -24,6 +24,8 @@ const SDD_SESSION_REFRESH_COMMAND =
|
|
|
24
24
|
'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90';
|
|
25
25
|
const SDD_SESSION_OPEN_AUTO_COMMAND =
|
|
26
26
|
'npx --yes --package pumuki@latest pumuki sdd session --open --change=auto';
|
|
27
|
+
const SDD_SESSION_OPEN_EXPLICIT_COMMAND =
|
|
28
|
+
'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>';
|
|
27
29
|
const SDD_COMPLETENESS_CONTRACT_VERSION = '1.0';
|
|
28
30
|
|
|
29
31
|
const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
@@ -49,11 +51,10 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
|
|
|
49
51
|
if (availableChangeIds.length > 1) {
|
|
50
52
|
return {
|
|
51
53
|
message:
|
|
52
|
-
`SDD session is not active. Run \`${
|
|
53
|
-
`
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
fallbackCommand: SDD_SESSION_OPEN_AUTO_COMMAND,
|
|
54
|
+
`SDD session is not active. Run \`${SDD_SESSION_OPEN_EXPLICIT_COMMAND}\` ` +
|
|
55
|
+
`with one active change id. Active changes: ${availableChangeIds.join(', ')}.`,
|
|
56
|
+
command: SDD_SESSION_OPEN_EXPLICIT_COMMAND,
|
|
57
|
+
fallbackCommand: SDD_SESSION_OPEN_EXPLICIT_COMMAND,
|
|
57
58
|
availableChangeIds,
|
|
58
59
|
};
|
|
59
60
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.51",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@ export const appendAdapterReadinessNextActionsSection = (params: {
|
|
|
26
26
|
}
|
|
27
27
|
if (hasAdapterRuntimeBlocker(params.source)) {
|
|
28
28
|
params.lines.push(
|
|
29
|
-
'- Execute `docs/validation/adapter-hook-runtime-
|
|
29
|
+
'- Execute `docs/validation/adapter-hook-runtime-runbook.md`, then regenerate adapter readiness report.'
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
32
|
params.lines.push('');
|
|
@@ -41,7 +41,7 @@ GENERATED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
|
41
41
|
echo
|
|
42
42
|
echo "- [ ] Confirm reports are \`READY\`: blockers, closure-status, external-handoff, startup-unblock."
|
|
43
43
|
echo "- [ ] Publish final external handoff artifacts/URLs."
|
|
44
|
-
echo "- [ ] Update \`docs/
|
|
44
|
+
echo "- [ ] Update \`docs/tracking/historico-validacion-ruralgo-03-03-2026.md\`: mark \`P8-3\` ✅ and set \`P8-4\` 🚧."
|
|
45
45
|
echo "- [ ] Close \`P8-4\` once URLs are attached and handoff is complete."
|
|
46
46
|
echo
|
|
47
47
|
echo "## Latest Run URLs"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
FILE="${1:-docs/
|
|
4
|
+
FILE="${1:-docs/tracking/historico-validacion-ruralgo-03-03-2026.md}"
|
|
5
5
|
|
|
6
6
|
if [[ ! -f "${FILE}" ]]; then
|
|
7
7
|
echo "[progress-single-active] missing file: ${FILE}" >&2
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
+
MASTER_FILE="docs/tracking/maestro-de-seguimiento.md"
|
|
5
|
+
|
|
6
|
+
resolve_default_tracking_file() {
|
|
7
|
+
if [[ -f "${MASTER_FILE}" ]]; then
|
|
8
|
+
local active_file
|
|
9
|
+
active_file="$(
|
|
10
|
+
sed -n 's/^- Plan activo: `\([^`]*\)`.*/\1/p' "${MASTER_FILE}" | head -n 1
|
|
11
|
+
)"
|
|
12
|
+
if [[ -n "${active_file}" ]]; then
|
|
13
|
+
printf '%s\n' "${active_file}"
|
|
14
|
+
return 0
|
|
15
|
+
fi
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
printf '%s\n' "docs/tracking/plan-activo-pumuki.md"
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
if [[ "$#" -gt 0 ]]; then
|
|
5
22
|
FILES=("$@")
|
|
6
23
|
else
|
|
7
24
|
FILES=(
|
|
8
|
-
"
|
|
25
|
+
"$(resolve_default_tracking_file)"
|
|
9
26
|
)
|
|
10
27
|
fi
|
|
11
28
|
|
|
12
|
-
ACTIVE_PATTERN='^- 🚧
|
|
29
|
+
ACTIVE_PATTERN='^- 🚧 (`?P[0-9A-Za-z.-]+`?)'
|
|
13
30
|
HAS_ERROR=0
|
|
14
31
|
|
|
15
32
|
for FILE in "${FILES[@]}"; do
|
|
@@ -19,7 +19,7 @@ FOLLOW_UP_ETA="$3"
|
|
|
19
19
|
SUBMITTED_AT_UTC="${4:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}"
|
|
20
20
|
|
|
21
21
|
HANDOFF_FILE="docs/validation/consumer-startup-escalation-handoff-latest.md"
|
|
22
|
-
PROGRESS_FILE="docs/
|
|
22
|
+
PROGRESS_FILE="docs/tracking/historico-validacion-ruralgo-03-03-2026.md"
|
|
23
23
|
TODO_FILE="docs/TODO.md"
|
|
24
24
|
|
|
25
25
|
if [[ ! -f "${HANDOFF_FILE}" || ! -f "${PROGRESS_FILE}" || ! -f "${TODO_FILE}" ]]; then
|
|
@@ -29,7 +29,7 @@ export const appendPhase5BlockersBlockedNextActions = (params: {
|
|
|
29
29
|
}
|
|
30
30
|
if (hasAdapterRuntimeBlocker(params.summary)) {
|
|
31
31
|
params.lines.push(
|
|
32
|
-
'- Execute `docs/validation/adapter-hook-runtime-
|
|
32
|
+
'- Execute `docs/validation/adapter-hook-runtime-runbook.md` in a real Adapter session and regenerate reports.'
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
if (hasConsumerTriageBlocker(params.summary)) {
|