@planu/cli 4.11.4 → 4.11.5
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 +6 -0
- package/dist/engine/ai-integration/gemini/gemini-md-generator.js +7 -0
- package/dist/engine/outbound-webhook-dispatcher.d.ts +2 -2
- package/dist/engine/outbound-webhook-dispatcher.js +8 -6
- package/dist/engine/web-fetcher/registry-auto-discovery.d.ts +2 -2
- package/dist/engine/web-fetcher/registry-auto-discovery.js +9 -5
- package/dist/types/docs.d.ts +4 -0
- package/dist/types/outbound-webhook.d.ts +4 -0
- package/package.json +9 -9
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -58,12 +58,19 @@ function buildSddSection(options) {
|
|
|
58
58
|
'',
|
|
59
59
|
'### Architecture Rules',
|
|
60
60
|
'',
|
|
61
|
+
'- Primary implementation stays in `src/`; Rust is an optional acceleration layer, not the default destination for every feature',
|
|
61
62
|
'- `types/` → no imports from other layers',
|
|
62
63
|
'- `engine/` → imports only from `types/`',
|
|
63
64
|
'- `storage/` → imports only from `types/`',
|
|
64
65
|
'- `tools/` → imports from `engine/` + `storage/` + `types/`',
|
|
65
66
|
'- Cross-layer violations → ESLint error',
|
|
66
67
|
'',
|
|
68
|
+
'### Release Rules',
|
|
69
|
+
'',
|
|
70
|
+
'- `main` is the authoritative release branch',
|
|
71
|
+
'- `develop` and `release` are optional mirrors that must not drift from `main`',
|
|
72
|
+
'- Run `pnpm check` and `pnpm test` before local release publishing',
|
|
73
|
+
'',
|
|
67
74
|
PLANU_SECTION_END,
|
|
68
75
|
].join('\n');
|
|
69
76
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OutboundWebhookPayload, OutboundWebhookEventType, OutboundWebhookConfig, OutboundWebhookDelivery } from '../types/index.js';
|
|
2
|
-
export declare function dispatchToWebhooks(webhooks: readonly OutboundWebhookConfig[], payload: OutboundWebhookPayload, onDelivery: (delivery: OutboundWebhookDelivery) => Promise<void
|
|
1
|
+
import type { OutboundWebhookPayload, OutboundWebhookEventType, OutboundWebhookConfig, OutboundWebhookDelivery, WebhookDispatchOptions } from '../types/index.js';
|
|
2
|
+
export declare function dispatchToWebhooks(webhooks: readonly OutboundWebhookConfig[], payload: OutboundWebhookPayload, onDelivery: (delivery: OutboundWebhookDelivery) => Promise<void>, options?: WebhookDispatchOptions): Promise<void>;
|
|
3
3
|
export declare function buildSpecLifecyclePayload(event: OutboundWebhookEventType, specId: string, specTitle: string, status: string, projectPath: string): OutboundWebhookPayload;
|
|
4
4
|
//# sourceMappingURL=outbound-webhook-dispatcher.d.ts.map
|
|
@@ -40,13 +40,15 @@ async function attemptDelivery(url, body, signature) {
|
|
|
40
40
|
// Retry logic: 3 attempts with exponential backoff (1s, 5s, 30s)
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
42
|
const RETRY_DELAYS_MS = [1_000, 5_000, 30_000];
|
|
43
|
-
async function deliverWithRetry(webhook, body, payload, onDelivery) {
|
|
43
|
+
async function deliverWithRetry(webhook, body, payload, onDelivery, options) {
|
|
44
44
|
let lastResult = null;
|
|
45
45
|
const signature = signPayload(webhook.secret, body);
|
|
46
|
-
|
|
46
|
+
const retryDelays = options.retryDelaysMs ?? RETRY_DELAYS_MS;
|
|
47
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
48
|
+
for (let attempt = 0; attempt < retryDelays.length + 1; attempt++) {
|
|
47
49
|
if (attempt > 0) {
|
|
48
|
-
const delay =
|
|
49
|
-
await
|
|
50
|
+
const delay = retryDelays[attempt - 1] ?? 0;
|
|
51
|
+
await sleep(delay);
|
|
50
52
|
}
|
|
51
53
|
lastResult = await attemptDelivery(webhook.url, body, signature);
|
|
52
54
|
if (lastResult.success) {
|
|
@@ -71,12 +73,12 @@ async function deliverWithRetry(webhook, body, payload, onDelivery) {
|
|
|
71
73
|
// ---------------------------------------------------------------------------
|
|
72
74
|
// Core dispatch (pure — no storage deps)
|
|
73
75
|
// ---------------------------------------------------------------------------
|
|
74
|
-
export async function dispatchToWebhooks(webhooks, payload, onDelivery) {
|
|
76
|
+
export async function dispatchToWebhooks(webhooks, payload, onDelivery, options = {}) {
|
|
75
77
|
if (webhooks.length === 0) {
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
const body = JSON.stringify(payload);
|
|
79
|
-
await Promise.allSettled(webhooks.map((webhook) => deliverWithRetry(webhook, body, payload, onDelivery)));
|
|
81
|
+
await Promise.allSettled(webhooks.map((webhook) => deliverWithRetry(webhook, body, payload, onDelivery, options)));
|
|
80
82
|
}
|
|
81
83
|
// ---------------------------------------------------------------------------
|
|
82
84
|
// Helper to build spec lifecycle payloads
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DiscoveredDocsEntry, DocsRegistryHealth } from '../../types/index.js';
|
|
1
|
+
import type { DiscoveredDocsEntry, DocsRegistryHealth, DocsDiscoveryOptions } from '../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Verify that a URL is alive with a HEAD request (timeout 3s).
|
|
4
4
|
* Returns true if status is 200, 301, or 302.
|
|
@@ -9,7 +9,7 @@ export declare function validateRegistryUrl(url: string): Promise<boolean>;
|
|
|
9
9
|
* Respects a 1 req/s rate limit per registry via simple delay.
|
|
10
10
|
* Returns null if not found anywhere.
|
|
11
11
|
*/
|
|
12
|
-
export declare function discoverDocsUrl(tech: string): Promise<DiscoveredDocsEntry | null>;
|
|
12
|
+
export declare function discoverDocsUrl(tech: string, options?: DocsDiscoveryOptions): Promise<DiscoveredDocsEntry | null>;
|
|
13
13
|
/**
|
|
14
14
|
* Batch validate all entries in the docs registry.
|
|
15
15
|
* Categorizes each entry as healthy (<=2s), slow (2-5s), or broken (timeout/error).
|
|
@@ -113,10 +113,14 @@ export async function validateRegistryUrl(url) {
|
|
|
113
113
|
* Respects a 1 req/s rate limit per registry via simple delay.
|
|
114
114
|
* Returns null if not found anywhere.
|
|
115
115
|
*/
|
|
116
|
-
export async function discoverDocsUrl(tech) {
|
|
117
|
-
const
|
|
116
|
+
export async function discoverDocsUrl(tech, options = {}) {
|
|
117
|
+
const rateLimitDelayMs = options.rateLimitDelayMs ?? RATE_LIMIT_DELAY_MS;
|
|
118
|
+
const sleepFn = options.sleep ?? sleep;
|
|
119
|
+
const tryWithDelay = async (fn, shouldDelay) => {
|
|
118
120
|
const result = await fn();
|
|
119
|
-
|
|
121
|
+
if (shouldDelay && rateLimitDelayMs > 0) {
|
|
122
|
+
await sleepFn(rateLimitDelayMs);
|
|
123
|
+
}
|
|
120
124
|
return result;
|
|
121
125
|
};
|
|
122
126
|
const registries = [
|
|
@@ -124,8 +128,8 @@ export async function discoverDocsUrl(tech) {
|
|
|
124
128
|
{ source: 'pypi', fn: () => tryPypi(tech) },
|
|
125
129
|
{ source: 'crates', fn: () => tryCrates(tech) },
|
|
126
130
|
];
|
|
127
|
-
for (const { source, fn } of registries) {
|
|
128
|
-
const url = await tryWithDelay(fn);
|
|
131
|
+
for (const [index, { source, fn }] of registries.entries()) {
|
|
132
|
+
const url = await tryWithDelay(fn, index < registries.length - 1);
|
|
129
133
|
if (url) {
|
|
130
134
|
const verified = await validateRegistryUrl(url);
|
|
131
135
|
return {
|
package/dist/types/docs.d.ts
CHANGED
|
@@ -285,6 +285,10 @@ export interface DocsRegistryHealth {
|
|
|
285
285
|
broken: string[];
|
|
286
286
|
slow: string[];
|
|
287
287
|
}
|
|
288
|
+
export interface DocsDiscoveryOptions {
|
|
289
|
+
rateLimitDelayMs?: number;
|
|
290
|
+
sleep?: (ms: number) => Promise<void>;
|
|
291
|
+
}
|
|
288
292
|
/** Input for validate_docs_registry tool. */
|
|
289
293
|
export interface ValidateDocsRegistryInput {
|
|
290
294
|
projectPath: string;
|
|
@@ -48,4 +48,8 @@ export interface WebhookAttemptResult {
|
|
|
48
48
|
readonly success: boolean;
|
|
49
49
|
readonly error?: string;
|
|
50
50
|
}
|
|
51
|
+
export interface WebhookDispatchOptions {
|
|
52
|
+
readonly retryDelaysMs?: readonly number[];
|
|
53
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
54
|
+
}
|
|
51
55
|
//# sourceMappingURL=outbound-webhook.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.5",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"packageName": "@planu/core"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@planu/core-darwin-arm64": "4.11.
|
|
38
|
-
"@planu/core-darwin-x64": "4.11.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.11.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.11.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.11.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.11.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.11.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.11.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.11.5",
|
|
38
|
+
"@planu/core-darwin-x64": "4.11.5",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.11.5",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.11.5",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.11.5",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.11.5",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.11.5",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.11.5"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
package/planu-native.json
CHANGED
package/planu-plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dev.planu.cli",
|
|
3
3
|
"displayName": "Planu — Spec Driven Development",
|
|
4
4
|
"description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
|
|
5
|
-
"version": "4.11.
|
|
5
|
+
"version": "4.11.5",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": [
|
|
8
8
|
"npx",
|