@mudraforge/statutory 2.4.1 → 2.4.2
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/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/bin/cli.js +29 -1
- package/package.json +1 -1
- package/src/index.js +74 -1
- package/types/index.d.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [2.4.2] - 2026-10-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **npm Package Update Notifier**: Lightweight, zero-dependency update notifier querying `registry.npmjs.org` with a 24-hour temporary file cache (`checkForPackageUpdate()`).
|
|
14
|
+
- **Unified `check-update` CLI Command**: Now audits both npm package code updates against the npm registry and legal rule updates against the Cloudflare Edge manifest.
|
|
15
|
+
- **Non-Intrusive Terminal Footers**: Automatically surfaces `[NOTICE]` prompts when a newer npm release is available, with opt-out support via `NO_UPDATE_NOTIFIER=1` or `CI=true`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [2.4.1] - 2026-10-24
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- **Developer Navigation & Usability**: Compact, audited Table of Contents in `README.md` targeting all key documentation sections.
|
|
23
|
+
- **Package Metadata**: Official `homepage` pointing to `https://mudraforge.in/docs` and `bugs` pointing to GitHub Issues.
|
|
24
|
+
- **Supported Application Patterns**: Documented clear integration boundaries across AI Agents (local `SKILL.md`), Finance Software (declarative threshold schemas), and Developer Tooling.
|
|
25
|
+
- **Corporate M&A Restructuring Domain**: Section 50B slump sale capital gains based on WDV net worth (Section 43(6)), Form 3CEA CA certification schema, and Section 281 clearance checklist.
|
|
26
|
+
- **Dual-Act Successor Mapping**: Section 393 (*Income-tax Act, 2025*) successor provision mapping for Section 194Q.
|
|
27
|
+
- **Cryptographic Trust Anchor & Anti-Tamper Hardening**: Ed25519 digital signature verification for remote bundles, CRL key revocation enforcement, replay protections, Windows reserved device name protection, and strict production bypass locks (36 passing regression suites).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- **Statutory Rate Enforcements**: Section 194J non-PAN deduction rate updated to the statutory 20% penalty tier under Section 206AA.
|
|
31
|
+
- **Quotas & Error Semantics**: Documented Cloudflare Edge API rate limits, error codes, and HTTP semantics.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
10
35
|
## [2.4.0] - 2026-10-22
|
|
11
36
|
|
|
12
37
|
### Added
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
| Item | Value |
|
|
17
17
|
|---|---|
|
|
18
|
-
| **Package Release** | **`v2.4.
|
|
18
|
+
| **Package Release** | **`v2.4.2`** (Public Beta) |
|
|
19
19
|
| **Knowledge Specification** | **Google Open Knowledge Format (OKF v0.2) + MudraForge Statutory Schema Extension** |
|
|
20
20
|
| **Regulatory Snapshot** | **CBDT / CBIC / MCA / MSME Baseline: October 2026** |
|
|
21
21
|
| **Corpus Quality Card** | 100% Citation Resolution (15/15 URLs) in [`docs/CORPUS_QUALITY.md`](./docs/CORPUS_QUALITY.md) |
|
package/bin/cli.js
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
checkUpdates,
|
|
17
17
|
syncOkf,
|
|
18
18
|
getLocalManifest,
|
|
19
|
+
checkForPackageUpdate,
|
|
20
|
+
STATUTORY_CLIENT_VERSION,
|
|
19
21
|
DEFAULT_LOCAL_OKF_DIR
|
|
20
22
|
} from '../src/index.js';
|
|
21
23
|
|
|
@@ -68,10 +70,36 @@ async function main() {
|
|
|
68
70
|
printHelp();
|
|
69
71
|
break;
|
|
70
72
|
}
|
|
73
|
+
|
|
74
|
+
// Non-intrusive background npm package update notice
|
|
75
|
+
if (!['check-update', 'status', 'version'].includes(command)) {
|
|
76
|
+
try {
|
|
77
|
+
const updateInfo = await checkForPackageUpdate();
|
|
78
|
+
if (updateInfo && updateInfo.updateAvailable) {
|
|
79
|
+
console.log('───────────────────────────────────────────────────────────────────────────');
|
|
80
|
+
console.log(`[NOTICE] A new version of @mudraforge/statutory is available: ${updateInfo.currentVersion} -> ${updateInfo.latestVersion}`);
|
|
81
|
+
console.log(`Run: npm install @mudraforge/statutory@latest or npx @mudraforge/statutory@latest`);
|
|
82
|
+
console.log('───────────────────────────────────────────────────────────────────────────\n');
|
|
83
|
+
}
|
|
84
|
+
} catch (_) {}
|
|
85
|
+
}
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
async function handleCheckUpdate() {
|
|
74
89
|
try {
|
|
90
|
+
console.log('\n[INFO] Checking npm package version against registry.npmjs.org...');
|
|
91
|
+
try {
|
|
92
|
+
const pkgUpdate = await checkForPackageUpdate({ cacheTtlMs: 0 });
|
|
93
|
+
if (pkgUpdate && pkgUpdate.updateAvailable) {
|
|
94
|
+
console.log('───────────────────────────────────────────────────────────────────────────');
|
|
95
|
+
console.log(`[WARN] New npm package version available: v${pkgUpdate.latestVersion} (installed: v${pkgUpdate.currentVersion})`);
|
|
96
|
+
console.log(`Run: npm install @mudraforge/statutory@latest`);
|
|
97
|
+
console.log('───────────────────────────────────────────────────────────────────────────');
|
|
98
|
+
} else if (pkgUpdate) {
|
|
99
|
+
console.log(`[OK] npm package code is up to date (v${pkgUpdate.currentVersion}).`);
|
|
100
|
+
}
|
|
101
|
+
} catch (_) {}
|
|
102
|
+
|
|
75
103
|
console.log('\n[INFO] Checking OKF knowledge substrate status against Cloudflare edge...');
|
|
76
104
|
const status = await checkUpdates();
|
|
77
105
|
console.log('───────────────────────────────────────────────────────────────────────────');
|
|
@@ -82,7 +110,7 @@ async function handleCheckUpdate() {
|
|
|
82
110
|
console.log('───────────────────────────────────────────────────────────────────────────');
|
|
83
111
|
|
|
84
112
|
if (status.isOutdated) {
|
|
85
|
-
console.log(`[WARN] New version available: v${status.latestVersion}`);
|
|
113
|
+
console.log(`[WARN] New legal data version available: v${status.latestVersion}`);
|
|
86
114
|
console.log(`Changelog: ${status.changelog}`);
|
|
87
115
|
console.log(`Run: npx @mudraforge/statutory sync to pull the latest rules.\n`);
|
|
88
116
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mudraforge/statutory",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Open Knowledge Format (OKF) client & AI Agent Skill for Indian and cross-border statutory tax provisions. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import fs from 'node:fs';
|
|
12
12
|
import path from 'node:path';
|
|
13
|
+
import os from 'node:os';
|
|
13
14
|
import crypto from 'node:crypto';
|
|
14
15
|
import { fileURLToPath } from 'node:url';
|
|
15
16
|
|
|
@@ -17,7 +18,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
17
18
|
const __dirname = path.dirname(__filename);
|
|
18
19
|
export const DEFAULT_LOCAL_OKF_DIR = path.resolve(__dirname, '..', 'okf');
|
|
19
20
|
export const DEFAULT_BASE_URL = 'https://api.mudraforge.in';
|
|
20
|
-
export const STATUTORY_CLIENT_VERSION = '2.4.
|
|
21
|
+
export const STATUTORY_CLIENT_VERSION = '2.4.2';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Pinned official release Merkle root digests.
|
|
@@ -430,6 +431,78 @@ export async function checkUpdates(options = {}) {
|
|
|
430
431
|
};
|
|
431
432
|
}
|
|
432
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Check if a newer version of the @mudraforge/statutory npm package is published on npmjs.com.
|
|
436
|
+
* Uses a lightweight cached file in os.tmpdir() to prevent frequent network roundtrips.
|
|
437
|
+
*
|
|
438
|
+
* @param {Object} [options]
|
|
439
|
+
* @param {string} [options.currentVersion] - Current installed version (defaults to STATUTORY_CLIENT_VERSION).
|
|
440
|
+
* @param {number} [options.cacheTtlMs] - Cache duration in milliseconds (default: 24 hours).
|
|
441
|
+
* @param {number} [options.timeoutMs] - Request timeout in milliseconds (default: 1500ms).
|
|
442
|
+
* @param {string} [options.registryUrl] - Registry endpoint (default: https://registry.npmjs.org/@mudraforge/statutory/latest).
|
|
443
|
+
* @returns {Promise<{ updateAvailable: boolean, currentVersion: string, latestVersion: string } | null>}
|
|
444
|
+
*/
|
|
445
|
+
export async function checkForPackageUpdate(options = {}) {
|
|
446
|
+
if (process.env.NO_UPDATE_NOTIFIER === '1' || process.env.CI === 'true') {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const currentVersion = options.currentVersion || STATUTORY_CLIENT_VERSION;
|
|
451
|
+
const cacheTtlMs = options.cacheTtlMs !== undefined ? options.cacheTtlMs : 24 * 60 * 60 * 1000;
|
|
452
|
+
const timeoutMs = options.timeoutMs || 1500;
|
|
453
|
+
const cacheFile = path.join(os.tmpdir(), '.mudraforge_statutory_npm_update.json');
|
|
454
|
+
|
|
455
|
+
let cached = null;
|
|
456
|
+
if (cacheTtlMs > 0) {
|
|
457
|
+
try {
|
|
458
|
+
if (fs.existsSync(cacheFile)) {
|
|
459
|
+
const data = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
460
|
+
if (data && typeof data.lastChecked === 'number' && (Date.now() - data.lastChecked < cacheTtlMs)) {
|
|
461
|
+
cached = data;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
} catch (_) {}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let latestVersion = cached?.latestVersion;
|
|
468
|
+
|
|
469
|
+
if (!latestVersion) {
|
|
470
|
+
try {
|
|
471
|
+
const url = options.registryUrl || 'https://registry.npmjs.org/@mudraforge/statutory/latest';
|
|
472
|
+
const res = await fetch(url, {
|
|
473
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
474
|
+
headers: { 'Accept': 'application/json' }
|
|
475
|
+
});
|
|
476
|
+
if (res.ok) {
|
|
477
|
+
const json = await res.json();
|
|
478
|
+
if (json && json.version && typeof json.version === 'string') {
|
|
479
|
+
latestVersion = json.version;
|
|
480
|
+
if (cacheTtlMs > 0) {
|
|
481
|
+
try {
|
|
482
|
+
fs.writeFileSync(cacheFile, JSON.stringify({
|
|
483
|
+
lastChecked: Date.now(),
|
|
484
|
+
latestVersion
|
|
485
|
+
}), 'utf8');
|
|
486
|
+
} catch (_) {}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
} catch (_) {
|
|
491
|
+
// Fail open and silent on network error, offline, or timeout
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (!latestVersion) return null;
|
|
497
|
+
|
|
498
|
+
const cmp = compareSemver(latestVersion, currentVersion);
|
|
499
|
+
return {
|
|
500
|
+
updateAvailable: cmp > 0,
|
|
501
|
+
currentVersion,
|
|
502
|
+
latestVersion
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
433
506
|
/**
|
|
434
507
|
* Download and synchronize the latest OKF knowledge bundle to disk.
|
|
435
508
|
* Hardened with:
|
package/types/index.d.ts
CHANGED
|
@@ -148,6 +148,12 @@ export declare function getLocalManifest(okfDir?: string): any;
|
|
|
148
148
|
export declare function lookupLocalStatute(section: string, okfDir?: string): StatutoryRecord | null;
|
|
149
149
|
export declare function computeTemporalStatus(statute: StatutoryRecord, asOfDate?: string): 'ACTIVE' | 'SUNSET_SUPERSEDED' | 'FUTURE_PENDING';
|
|
150
150
|
export declare function checkUpdates(options?: { baseUrl?: string; okfDir?: string }): Promise<UpdateInfo>;
|
|
151
|
+
export declare function checkForPackageUpdate(options?: {
|
|
152
|
+
currentVersion?: string;
|
|
153
|
+
cacheTtlMs?: number;
|
|
154
|
+
timeoutMs?: number;
|
|
155
|
+
registryUrl?: string;
|
|
156
|
+
}): Promise<{ updateAvailable: boolean; currentVersion: string; latestVersion: string } | null>;
|
|
151
157
|
export declare function syncOkf(options?: { baseUrl?: string; okfDir?: string }): Promise<SyncResult>;
|
|
152
158
|
|
|
153
159
|
export declare function lookupStatute(
|