@specatlas/core 0.1.10 → 0.1.12

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  signApproval
3
- } from "./chunk-LMJURGRU.js";
3
+ } from "./chunk-WF6H5ITI.js";
4
4
  import "./chunk-5RKNY2ZC.js";
5
5
  export {
6
6
  signApproval
@@ -6,6 +6,31 @@ import {
6
6
 
7
7
  // src/approvals.ts
8
8
  import path from "path";
9
+
10
+ // src/time.ts
11
+ function pad(value, length = 2) {
12
+ return String(value).padStart(length, "0");
13
+ }
14
+ function localDate(date = /* @__PURE__ */ new Date()) {
15
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
16
+ }
17
+ function localMonth(date = /* @__PURE__ */ new Date()) {
18
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}`;
19
+ }
20
+ function localOffset(date = /* @__PURE__ */ new Date()) {
21
+ const offset = -date.getTimezoneOffset();
22
+ const sign = offset >= 0 ? "+" : "-";
23
+ const absolute = Math.abs(offset);
24
+ return `${sign}${pad(Math.floor(absolute / 60))}:${pad(absolute % 60)}`;
25
+ }
26
+ function localStamp(date = /* @__PURE__ */ new Date()) {
27
+ return `${localDate(date)} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} ${localOffset(date)}`;
28
+ }
29
+ function localCompact(date = /* @__PURE__ */ new Date()) {
30
+ return `${localDate(date).replace(/-/g, "")}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
31
+ }
32
+
33
+ // src/approvals.ts
9
34
  import { stringify as stringifyYaml } from "yaml";
10
35
 
11
36
  // src/diagnostics.ts
@@ -199,7 +224,7 @@ async function signApproval(opts) {
199
224
  artifact: rel,
200
225
  artifactHash: artifactHash(content),
201
226
  approvedBy: opts.by.trim(),
202
- approvedAt: now.toISOString(),
227
+ approvedAt: localStamp(now),
203
228
  channel: opts.channel ?? "cli"
204
229
  };
205
230
  if (opts.note) approval.note = opts.note;
@@ -233,6 +258,11 @@ export {
233
258
  sha256,
234
259
  artifactHash,
235
260
  shortHash,
261
+ localDate,
262
+ localMonth,
263
+ localOffset,
264
+ localStamp,
265
+ localCompact,
236
266
  changeMetaSchema,
237
267
  parseChangeMeta,
238
268
  approvalsSchema,
package/dist/index.d.ts CHANGED
@@ -588,6 +588,12 @@ declare function sha256(content: string | Uint8Array): string;
588
588
  declare function artifactHash(markdown: string): string;
589
589
  declare function shortHash(hash: string): string;
590
590
 
591
+ declare function localDate(date?: Date): string;
592
+ declare function localMonth(date?: Date): string;
593
+ declare function localOffset(date?: Date): string;
594
+ declare function localStamp(date?: Date): string;
595
+ declare function localCompact(date?: Date): string;
596
+
591
597
  declare const REQ_HEAD_RE: RegExp;
592
598
  declare const SCENARIO_HEAD_RE: RegExp;
593
599
  declare const RULE_RE: RegExp;
@@ -1694,4 +1700,4 @@ declare function livingRequirementsMap(specs: Array<{
1694
1700
  }>): Map<string, Requirement>;
1695
1701
  declare function runCiGate(opts: CiOptions): Promise<CiResult>;
1696
1702
 
1697
- export { type AdoptDomain, type AdoptOptions, type AdoptResult, type AgingBucket, type AnalyzeOptions, type AnalyzePackSummary, type AnalyzeResult, type Approval, type ApprovalStatus, type ApprovalsFile, type ApprovalsIndex, type ApproveFromGithubOptions, type ApproveFromGithubResult, type ArchiveOptions, type ArchiveResult, type AtlasConfig, type AttentionItem, BLOCK_HEAD_RE, BUILTIN_PACKS, type BlockWavePlan, CONFIG_FILE, CORE_VERSION, type CaptureResult, type Change, type ChangeMeta, type ChangeMetrics, type ChangeState, type CiCheck, type CiExtraCheck, type CiOptions, type CiResult, type Delta, type DeltaOp, type DeriveInput, type DerivedState, type DetectionResult, type Diagnostic, type DoctorReport, type Domain, type Evidence, type EvidenceMethod, type EvidenceResult, type ExecOptions, type ExecResult, type FoldOutcome, type FrontmatterResult, type GhRunner, type GitHubRepo, type InitOptions, type InitResult, type IssueBodyInput, type Lane, type Language, type LinkedIssue, type LintOptions, type LoadedConfig, type MockupCheckResult, type MockupManifest, type MockupPlan, type MockupPlanScreen, type MockupScreen, type NewChangeOptions, type NewChangeResult, type NextAction, type Override, type Pack, type PackCheck, type PackCheckResult, type PackCheckType, type PackEvaluation, type PresentOptions, type PresentResult, type ProfileMatch, REQ_HEAD_RE, REQ_ID_RE, RULE_ID_RE, RULE_RE, RUN_EVENT_TYPES, type RecordEvidenceOptions, type RecordEvidenceResult, type Rename, type Requirement, type RiskLevel, type Rule, type RunEvent, type RunEventType, type RunRecord, type RunState, type RunStatus, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SDD_DIR, SLUG_RE, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, adoptWorkspace, appendRunEvent, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, collectMetrics, commentIssue, compareTaskIds, computeInputsHash, configToYaml, copyFile, countBySeverity, createChange, createIssue, createRun, defaultConfig, deriveState, detectProfiles, detectRepo, detectionToYaml, diag, editIssue, emitFrontmatter, ensureDir, ensureSddDirs, esc, evaluatePacks, evidenceSummary, exists, findLinkedIssue, findWorkspaceRoot, firstToken, foldDelta, generatePresentation, generateRunId, getNumber, getString, ghAuthStatus, ghAvailable, hasErrors, hasShellMetacharacters, indexMarkdown, initWorkspace, inline, isCommandAllowed, isDirectory, issueBody, issueLabels, laneOrDefault, lintDelta, lintMockupHtml, lintMockupManifest, lintRequirement, lintSpec, lintTasks, lintVerify, listChangeSlugs, listDir, listDirs, listRuns, livingRequirementsMap, loadActiveProfile, loadApprovals, loadChange, loadConfig, loadDetectedBest, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, packFindings, parseApprovals, parseChangeMeta, parseConfig, parseDelta, parseFrontmatter, parseGitHubRemote, parseIssueUrl, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planWaves, profileSchema, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, runAnalyze, runCiGate, runDoctor, runProcess, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stateLabel, syncGithubIssue, templatesFor, toPosix, tokensFile, updateMockupScreenshots, updateRunStatus, verifyApproval, walkFiles, writeConfig, writeMockupManifest, writeMockupPlan, writeText };
1703
+ export { type AdoptDomain, type AdoptOptions, type AdoptResult, type AgingBucket, type AnalyzeOptions, type AnalyzePackSummary, type AnalyzeResult, type Approval, type ApprovalStatus, type ApprovalsFile, type ApprovalsIndex, type ApproveFromGithubOptions, type ApproveFromGithubResult, type ArchiveOptions, type ArchiveResult, type AtlasConfig, type AttentionItem, BLOCK_HEAD_RE, BUILTIN_PACKS, type BlockWavePlan, CONFIG_FILE, CORE_VERSION, type CaptureResult, type Change, type ChangeMeta, type ChangeMetrics, type ChangeState, type CiCheck, type CiExtraCheck, type CiOptions, type CiResult, type Delta, type DeltaOp, type DeriveInput, type DerivedState, type DetectionResult, type Diagnostic, type DoctorReport, type Domain, type Evidence, type EvidenceMethod, type EvidenceResult, type ExecOptions, type ExecResult, type FoldOutcome, type FrontmatterResult, type GhRunner, type GitHubRepo, type InitOptions, type InitResult, type IssueBodyInput, type Lane, type Language, type LinkedIssue, type LintOptions, type LoadedConfig, type MockupCheckResult, type MockupManifest, type MockupPlan, type MockupPlanScreen, type MockupScreen, type NewChangeOptions, type NewChangeResult, type NextAction, type Override, type Pack, type PackCheck, type PackCheckResult, type PackCheckType, type PackEvaluation, type PresentOptions, type PresentResult, type ProfileMatch, REQ_HEAD_RE, REQ_ID_RE, RULE_ID_RE, RULE_RE, RUN_EVENT_TYPES, type RecordEvidenceOptions, type RecordEvidenceResult, type Rename, type Requirement, type RiskLevel, type Rule, type RunEvent, type RunEventType, type RunRecord, type RunState, type RunStatus, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SDD_DIR, SLUG_RE, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, adoptWorkspace, appendRunEvent, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, collectMetrics, commentIssue, compareTaskIds, computeInputsHash, configToYaml, copyFile, countBySeverity, createChange, createIssue, createRun, defaultConfig, deriveState, detectProfiles, detectRepo, detectionToYaml, diag, editIssue, emitFrontmatter, ensureDir, ensureSddDirs, esc, evaluatePacks, evidenceSummary, exists, findLinkedIssue, findWorkspaceRoot, firstToken, foldDelta, generatePresentation, generateRunId, getNumber, getString, ghAuthStatus, ghAvailable, hasErrors, hasShellMetacharacters, indexMarkdown, initWorkspace, inline, isCommandAllowed, isDirectory, issueBody, issueLabels, laneOrDefault, lintDelta, lintMockupHtml, lintMockupManifest, lintRequirement, lintSpec, lintTasks, lintVerify, listChangeSlugs, listDir, listDirs, listRuns, livingRequirementsMap, loadActiveProfile, loadApprovals, loadChange, loadConfig, loadDetectedBest, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, localCompact, localDate, localMonth, localOffset, localStamp, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, packFindings, parseApprovals, parseChangeMeta, parseConfig, parseDelta, parseFrontmatter, parseGitHubRemote, parseIssueUrl, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planWaves, profileSchema, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, runAnalyze, runCiGate, runDoctor, runProcess, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stateLabel, syncGithubIssue, templatesFor, toPosix, tokensFile, updateMockupScreenshots, updateRunStatus, verifyApproval, walkFiles, writeConfig, writeMockupManifest, writeMockupPlan, writeText };
package/dist/index.js CHANGED
@@ -6,12 +6,17 @@ import {
6
6
  countBySeverity,
7
7
  diag,
8
8
  hasErrors,
9
+ localCompact,
10
+ localDate,
11
+ localMonth,
12
+ localOffset,
13
+ localStamp,
9
14
  parseApprovals,
10
15
  parseChangeMeta,
11
16
  sha256,
12
17
  shortHash,
13
18
  signApproval
14
- } from "./chunk-LMJURGRU.js";
19
+ } from "./chunk-WF6H5ITI.js";
15
20
  import {
16
21
  copyFile,
17
22
  ensureDir,
@@ -1969,7 +1974,7 @@ async function approveFromGithub(opts) {
1969
1974
  if (!by) {
1970
1975
  return { approved: false, label, issueNumber: number, diagnostics: [diag("ATLAS-GH-011", "error", "No se pudo determinar qui\xE9n aprueba (--by ni `gh api user`)")] };
1971
1976
  }
1972
- const { signApproval: signApproval2 } = await import("./approvals-4QHIT7F6.js");
1977
+ const { signApproval: signApproval2 } = await import("./approvals-2PO6223I.js");
1973
1978
  const signed = await signApproval2({
1974
1979
  root: opts.root,
1975
1980
  artifact: path5.posix.join("changes", opts.slug, "spec.md"),
@@ -2122,7 +2127,7 @@ ${exec.stderr}`);
2122
2127
  scenario,
2123
2128
  method,
2124
2129
  result,
2125
- date: (opts.now ?? /* @__PURE__ */ new Date()).toISOString(),
2130
+ date: localStamp(opts.now),
2126
2131
  by: opts.by.trim(),
2127
2132
  line: 0
2128
2133
  };
@@ -2192,7 +2197,7 @@ var RUN_EVENT_TYPES = [
2192
2197
  "run_completed"
2193
2198
  ];
2194
2199
  function generateRunId(now = /* @__PURE__ */ new Date()) {
2195
- const iso = now.toISOString().replace(/[-:T]/g, "").slice(0, 14);
2200
+ const iso = localCompact(now);
2196
2201
  return `${iso.slice(0, 8)}-${iso.slice(8, 14)}-${randomBytes(3).toString("hex")}`;
2197
2202
  }
2198
2203
  function runsDir(root) {
@@ -2205,8 +2210,8 @@ async function createRun(root, slug, phase, inputs, now = /* @__PURE__ */ new Da
2205
2210
  slug,
2206
2211
  phase,
2207
2212
  status: "active",
2208
- startedAt: now.toISOString(),
2209
- updatedAt: now.toISOString()
2213
+ startedAt: localStamp(now),
2214
+ updatedAt: localStamp(now)
2210
2215
  };
2211
2216
  if (inputs) state.inputs = inputs;
2212
2217
  const dir = path7.join(runsDir(root), runId);
@@ -2218,7 +2223,7 @@ async function createRun(root, slug, phase, inputs, now = /* @__PURE__ */ new Da
2218
2223
  return state;
2219
2224
  }
2220
2225
  async function appendRunEvent(root, runId, type, data, now = /* @__PURE__ */ new Date()) {
2221
- const event = { eventId: randomBytes(4).toString("hex"), at: now.toISOString(), type };
2226
+ const event = { eventId: randomBytes(4).toString("hex"), at: localStamp(now), type };
2222
2227
  if (data) event.data = data;
2223
2228
  const file = path7.join(runsDir(root), runId, "events.jsonl");
2224
2229
  const previous = await readTextIfExists(file) ?? "";
@@ -2232,7 +2237,7 @@ async function updateRunStatus(root, runId, status, now = /* @__PURE__ */ new Da
2232
2237
  if (raw === void 0) return;
2233
2238
  const state = JSON.parse(raw);
2234
2239
  state.status = status;
2235
- state.updatedAt = now.toISOString();
2240
+ state.updatedAt = localStamp(now);
2236
2241
  await writeText(file, `${JSON.stringify(state, null, 2)}
2237
2242
  `);
2238
2243
  }
@@ -2465,7 +2470,7 @@ async function writeMockupPlan(root, slug, plan, now = /* @__PURE__ */ new Date(
2465
2470
  if (await exists(file)) return file;
2466
2471
  const doc = {
2467
2472
  schema_version: 1,
2468
- generated_at: now.toISOString(),
2473
+ generated_at: localStamp(now),
2469
2474
  platform: plan.platform,
2470
2475
  screens: plan.screens.map((s) => ({ id: s.id, title: s.title, file: s.file, illustrates: s.illustrates, states: s.states, breakpoints: s.breakpoints }))
2471
2476
  };
@@ -2481,7 +2486,7 @@ async function writeMockupManifest(root, slug, plan, inputsHash, now = /* @__PUR
2481
2486
  level: "hifi",
2482
2487
  platform: plan.platform,
2483
2488
  inputs_hash: inputsHash,
2484
- generated_at: now.toISOString(),
2489
+ generated_at: localStamp(now),
2485
2490
  screens: plan.screens.map((s) => ({ id: s.id, title: s.title, file: s.file, illustrates: s.illustrates, states: s.states, breakpoints: s.breakpoints })),
2486
2491
  screenshots: []
2487
2492
  };
@@ -2930,7 +2935,7 @@ async function runAnalyze(opts) {
2930
2935
  if (packs) result.packs = packs;
2931
2936
  if (opts.write !== false) {
2932
2937
  const file = path10.join(change.dir, "analyze.md");
2933
- await writeText(file, renderAnalyze(change, result, (opts.now ?? /* @__PURE__ */ new Date()).toISOString()));
2938
+ await writeText(file, renderAnalyze(change, result, localStamp(opts.now)));
2934
2939
  result.path = file;
2935
2940
  }
2936
2941
  return result;
@@ -3072,7 +3077,7 @@ async function collectMetrics(root, now = /* @__PURE__ */ new Date()) {
3072
3077
  archived: archivedEntries.length
3073
3078
  };
3074
3079
  return {
3075
- generatedAt: now.toISOString(),
3080
+ generatedAt: localStamp(now),
3076
3081
  project: config.project.name,
3077
3082
  root: resolved,
3078
3083
  changes,
@@ -3132,7 +3137,7 @@ async function generatePresentation(opts) {
3132
3137
  project: config.project.name,
3133
3138
  version: change.delta.sectionsFound.length,
3134
3139
  hash,
3135
- generatedAt: now.toISOString(),
3140
+ generatedAt: localStamp(now),
3136
3141
  proposalHtml: proposalBody ? renderMarkdown(proposalBody) : `<p><em>${labels.noProposal}</em></p>`,
3137
3142
  requirements: change.delta ? [...change.delta.added.map((r) => ({ req: r, kind: "added" })), ...change.delta.modified.map((r) => ({ req: r, kind: "modified" }))] : [],
3138
3143
  evidence: new Map((change.verify?.evidence ?? []).map((e) => [e.scenario, e.result])),
@@ -3514,7 +3519,7 @@ function baselineSpec(domain, files) {
3514
3519
  lines.push(`domain: ${domain}`);
3515
3520
  lines.push(`title: ${title}`);
3516
3521
  lines.push("version: 1");
3517
- lines.push(`updated: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`);
3522
+ lines.push(`updated: ${localDate()}`);
3518
3523
  lines.push("---");
3519
3524
  lines.push("");
3520
3525
  lines.push(`# ${title}`);
@@ -3535,7 +3540,7 @@ function adoptReport(input) {
3535
3540
  lines.push(es ? "# Adopci\xF3n (brownfield)" : "# Adoption (brownfield)");
3536
3541
  lines.push("");
3537
3542
  lines.push(es ? `- Proyecto: ${input.config.project.name}` : `- Project: ${input.config.project.name}`);
3538
- lines.push(es ? `- Generado: ${input.now.toISOString()}` : `- Generated: ${input.now.toISOString()}`);
3543
+ lines.push(es ? `- Generado: ${localStamp(input.now)}` : `- Generated: ${localStamp(input.now)}`);
3539
3544
  lines.push(es ? `- Archivos de c\xF3digo inventariados: ${input.files} (de ${input.inventoried} archivos totales)` : `- Inventoried source files: ${input.files} (of ${input.inventoried} total files)`);
3540
3545
  if (input.detection) lines.push(es ? `- Stack detectado: ${input.detection.name} (${input.detection.score} puntos)` : `- Detected stack: ${input.detection.name} (${input.detection.score})`);
3541
3546
  lines.push("");
@@ -3590,7 +3595,7 @@ async function initWorkspace(opts) {
3590
3595
  created.push(path14.join(sddDir, "glossary.md"));
3591
3596
  const detected = await detectIfPossible(root, opts.profilesDir);
3592
3597
  if (detected) {
3593
- const yaml = detectionToYaml(detected, (opts.now ?? /* @__PURE__ */ new Date()).toISOString());
3598
+ const yaml = detectionToYaml(detected, localStamp(opts.now));
3594
3599
  await writeText(path14.join(sddDir, "profiles", "detected.yaml"), yaml);
3595
3600
  created.push(path14.join(sddDir, "profiles", "detected.yaml"));
3596
3601
  if (detected.best) {
@@ -3669,7 +3674,7 @@ async function createChange(opts) {
3669
3674
  title,
3670
3675
  domain,
3671
3676
  lane,
3672
- created: (opts.now ?? /* @__PURE__ */ new Date()).toISOString().slice(0, 10)
3677
+ created: localDate(opts.now)
3673
3678
  };
3674
3679
  await ensureDir(dir);
3675
3680
  const templates = templatesFor(language);
@@ -3780,7 +3785,7 @@ async function archiveChange(opts) {
3780
3785
  return { slug: opts.slug, fold: emptyFold, diagnostics, dryRun: opts.dryRun ?? false };
3781
3786
  }
3782
3787
  const nowFix = opts.now ?? /* @__PURE__ */ new Date();
3783
- const targetFix = path16.join(root, ".sdd", "changes", "archive", `${nowFix.toISOString().slice(0, 7)}-${opts.slug}`);
3788
+ const targetFix = path16.join(root, ".sdd", "changes", "archive", `${localMonth(nowFix)}-${opts.slug}`);
3784
3789
  if (await exists(targetFix)) {
3785
3790
  diagnostics.push(diag("ATLAS-ARCH-002", "error", `Ya existe un cambio archivado en ${targetFix}`, { path: targetFix }));
3786
3791
  return { slug: opts.slug, fold: emptyFold, diagnostics, dryRun: opts.dryRun ?? false };
@@ -3821,7 +3826,7 @@ version: 0
3821
3826
  title: fm.data["title"] ?? change.meta.title ?? domain,
3822
3827
  owner: fm.data["owner"],
3823
3828
  version: version + 1,
3824
- updated: now.toISOString().slice(0, 10)
3829
+ updated: localDate(now)
3825
3830
  };
3826
3831
  for (const key of Object.keys(nextFm)) if (nextFm[key] === void 0) delete nextFm[key];
3827
3832
  const body = fold.content.replace(/^[\r\n]+/, "").trimEnd() + "\n";
@@ -3830,7 +3835,7 @@ ${Object.entries(nextFm).map(([k, v]) => `${k}: ${String(v)}`).join("\n")}
3830
3835
  ---
3831
3836
 
3832
3837
  ${body}`;
3833
- const month = now.toISOString().slice(0, 7);
3838
+ const month = localMonth(now);
3834
3839
  const archiveDir = path16.join(root, ".sdd", "changes", "archive");
3835
3840
  const target = path16.join(archiveDir, `${month}-${opts.slug}`);
3836
3841
  if (await exists(target)) {
@@ -4079,6 +4084,11 @@ export {
4079
4084
  loadProjectPacks,
4080
4085
  loadSpecs,
4081
4086
  loadWorkspace,
4087
+ localCompact,
4088
+ localDate,
4089
+ localMonth,
4090
+ localOffset,
4091
+ localStamp,
4082
4092
  matchGlob,
4083
4093
  mockupManifestSchema,
4084
4094
  mockupsDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specatlas/core",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Kernel determinista de SpecAtlas: parsing, validación, trazabilidad, olas y ciclo de vida",
5
5
  "license": "MIT",
6
6
  "type": "module",