wendkeep 0.78.0 → 0.79.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.
- package/CHANGELOG.md +41 -0
- package/README.en.md +57 -2
- package/README.md +57 -2
- package/docs/en/commands/changes-and-verification.md +66 -1
- package/docs/en/commands/operating-profiles.md +49 -5
- package/docs/en/commands/verify.md +45 -0
- package/docs/en/commands/worktrees.md +39 -4
- package/docs/pt-BR/commands/changes-and-verification.md +65 -1
- package/docs/pt-BR/commands/operating-profiles.md +51 -5
- package/docs/pt-BR/commands/verify.md +45 -0
- package/docs/pt-BR/commands/worktrees.md +38 -3
- package/hooks/active-context-store.mjs +530 -2
- package/hooks/change-core.mjs +201 -122
- package/hooks/obsidian-common.mjs +175 -9
- package/hooks/spec-core.mjs +93 -29
- package/package.json +2 -2
- package/schema/wendkeep.provenance-receipt-v2.schema.json +66 -0
- package/src/archive-operation-lock.mjs +235 -0
- package/src/change.mjs +1780 -79
- package/src/delivery.mjs +724 -67
- package/src/memory.mjs +2 -1
- package/src/provenance-gate.mjs +575 -0
- package/src/provenance-sources.mjs +547 -0
- package/src/receipt-ledger.mjs +841 -0
- package/src/release-provenance.mjs +48 -0
- package/src/worktree-cleanup.mjs +1733 -118
- package/src/worktree.mjs +94 -5
package/src/worktree.mjs
CHANGED
|
@@ -26,10 +26,35 @@ import {
|
|
|
26
26
|
worktreeIdentity,
|
|
27
27
|
} from '../packages/vault/src/worktree-metadata.mjs';
|
|
28
28
|
|
|
29
|
+
function sanitizeCliText(value) {
|
|
30
|
+
return String(value || '')
|
|
31
|
+
.replace(/\b(?:ghp|github_pat|npm_|sk-|xox[baprs]-)[A-Za-z0-9_\-]+/gi, '[redacted-token]')
|
|
32
|
+
.replace(/\b(?:token|authorization|bearer|password|secret|api[_-]?key)\s*[=:]\s*[^\s,;]+/gi, '[redacted-token]')
|
|
33
|
+
.replace(/\bBearer\s+[^\s,;]+/gi, '[redacted-token]')
|
|
34
|
+
.replace(/[A-Za-z]:\\[^\r\n"'`;|&]+/g, '[redacted-path]')
|
|
35
|
+
.replace(/(?:^|\s)\/[^\s"'`;|&]+/g, ' [redacted-path]')
|
|
36
|
+
.replace(/[\r\n\t]+/g, ' ')
|
|
37
|
+
.replace(/[;&|`$<>(){}[\]]/g, ' ')
|
|
38
|
+
.replace(/\s{2,}/g, ' ')
|
|
39
|
+
.trim()
|
|
40
|
+
.slice(0, 240);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sanitizeCliValue(value) {
|
|
44
|
+
if (typeof value === 'string') return sanitizeCliText(value);
|
|
45
|
+
if (Array.isArray(value)) return value.map((item) => sanitizeCliValue(item));
|
|
46
|
+
if (value && typeof value === 'object') {
|
|
47
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
48
|
+
sanitizeCliText(key), sanitizeCliValue(item),
|
|
49
|
+
]));
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
function worktreeError(code, message, details = {}) {
|
|
30
|
-
const error = new Error(message);
|
|
55
|
+
const error = new Error(sanitizeCliText(message));
|
|
31
56
|
error.code = code;
|
|
32
|
-
Object.assign(error, details);
|
|
57
|
+
Object.assign(error, sanitizeCliValue(details));
|
|
33
58
|
return error;
|
|
34
59
|
}
|
|
35
60
|
|
|
@@ -446,11 +471,19 @@ const ERROR_TEXT = {
|
|
|
446
471
|
WENDKEEP_WORKTREE_PR_UNAVAILABLE: 'Pull Request proof is unavailable.',
|
|
447
472
|
WENDKEEP_WORKTREE_PR_NOT_MERGED: 'Pull Request is not merged.',
|
|
448
473
|
WENDKEEP_WORKTREE_PR_MISMATCH: 'Pull Request does not match the managed branch.',
|
|
474
|
+
WENDKEEP_WORKTREE_PR_HEAD_MISMATCH: 'Pull Request head does not match the managed head.',
|
|
449
475
|
WENDKEEP_WORKTREE_PR_MERGE_UNREACHABLE: 'Pull Request merge commit is not reachable from the local base.',
|
|
476
|
+
WENDKEEP_WORKTREE_CONTEXT_MISMATCH: 'An active context belongs to another project or repository.',
|
|
450
477
|
WENDKEEP_WORKTREE_CLEANUP_BUSY: 'Worktree cleanup is already running.',
|
|
478
|
+
WENDKEEP_WORKTREE_BRANCH_UNPROVEN: 'The managed branch head could not be proven.',
|
|
451
479
|
WENDKEEP_WORKTREE_REASON_REQUIRED: 'Worktree removal requires a reason.',
|
|
452
480
|
WENDKEEP_WORKTREE_REMOTE_UNAVAILABLE: 'Remote branch state is unavailable.',
|
|
453
481
|
WENDKEEP_WORKTREE_REMOTE_DIVERGED: 'Remote branch diverged from the proven head.',
|
|
482
|
+
WENDKEEP_RECEIPT_LEDGER_CORRUPT: 'The cleanup receipt ledger is corrupt.',
|
|
483
|
+
WENDKEEP_RECEIPT_LEDGER_TRUNCATED: 'The cleanup receipt ledger is truncated.',
|
|
484
|
+
WENDKEEP_RECEIPT_LEDGER_BUSY: 'The cleanup receipt ledger is busy.',
|
|
485
|
+
WENDKEEP_RECEIPT_LEDGER_CONFLICT: 'The cleanup receipt ledger has a conflict.',
|
|
486
|
+
WENDKEEP_PROVENANCE_GATE_BLOCKED: 'Cleanup receipt provenance gate blocked the operation.',
|
|
454
487
|
WENDKEEP_WORKTREE_USAGE: 'Invalid worktree command usage.',
|
|
455
488
|
},
|
|
456
489
|
'pt-BR': {
|
|
@@ -484,11 +517,19 @@ const ERROR_TEXT = {
|
|
|
484
517
|
WENDKEEP_WORKTREE_PR_UNAVAILABLE: 'A prova do Pull Request está indisponível.',
|
|
485
518
|
WENDKEEP_WORKTREE_PR_NOT_MERGED: 'O Pull Request não está merged.',
|
|
486
519
|
WENDKEEP_WORKTREE_PR_MISMATCH: 'O Pull Request não corresponde à branch gerenciada.',
|
|
520
|
+
WENDKEEP_WORKTREE_PR_HEAD_MISMATCH: 'O head do Pull Request não corresponde ao head gerenciado.',
|
|
487
521
|
WENDKEEP_WORKTREE_PR_MERGE_UNREACHABLE: 'O merge commit do Pull Request não está alcançável pela base local.',
|
|
522
|
+
WENDKEEP_WORKTREE_CONTEXT_MISMATCH: 'Um contexto ativo pertence a outro projeto ou repositório.',
|
|
488
523
|
WENDKEEP_WORKTREE_CLEANUP_BUSY: 'A limpeza da worktree já está em andamento.',
|
|
524
|
+
WENDKEEP_WORKTREE_BRANCH_UNPROVEN: 'Não foi possível provar o head da branch gerenciada.',
|
|
489
525
|
WENDKEEP_WORKTREE_REASON_REQUIRED: 'A remoção da worktree exige um motivo.',
|
|
490
526
|
WENDKEEP_WORKTREE_REMOTE_UNAVAILABLE: 'O estado da branch remota está indisponível.',
|
|
491
527
|
WENDKEEP_WORKTREE_REMOTE_DIVERGED: 'A branch remota divergiu do head comprovado.',
|
|
528
|
+
WENDKEEP_RECEIPT_LEDGER_CORRUPT: 'O ledger de receipts de cleanup está corrompido.',
|
|
529
|
+
WENDKEEP_RECEIPT_LEDGER_TRUNCATED: 'O ledger de receipts de cleanup está truncado.',
|
|
530
|
+
WENDKEEP_RECEIPT_LEDGER_BUSY: 'O ledger de receipts de cleanup está ocupado.',
|
|
531
|
+
WENDKEEP_RECEIPT_LEDGER_CONFLICT: 'O ledger de receipts de cleanup está em conflito.',
|
|
532
|
+
WENDKEEP_PROVENANCE_GATE_BLOCKED: 'O gate de proveniência do receipt de cleanup bloqueou a operação.',
|
|
492
533
|
WENDKEEP_WORKTREE_USAGE: 'Uso inválido do comando worktree.',
|
|
493
534
|
},
|
|
494
535
|
};
|
|
@@ -498,9 +539,54 @@ function commandLocale(startDir) {
|
|
|
498
539
|
catch { return 'pt-BR'; }
|
|
499
540
|
}
|
|
500
541
|
|
|
501
|
-
function renderWorktreeError(error, locale) {
|
|
542
|
+
function renderWorktreeError(error, locale, { json = false, operation = '' } = {}) {
|
|
502
543
|
const code = error?.code || 'WENDKEEP_WORKTREE_FAILED';
|
|
503
|
-
|
|
544
|
+
const safeCode = sanitizeCliText(code) || 'WENDKEEP_WORKTREE_FAILED';
|
|
545
|
+
const localized = ERROR_TEXT[locale]?.[safeCode]
|
|
546
|
+
|| ERROR_TEXT[locale]?.WENDKEEP_WORKTREE_FAILED;
|
|
547
|
+
// The renderer receives the CLI command as the authoritative operation
|
|
548
|
+
// label. Cleanup errors also carry their internal operation name for
|
|
549
|
+
// structured diagnostics; exposing that name here would make `finish`,
|
|
550
|
+
// `remove`, and `prune` indistinguishable in the CLI contract.
|
|
551
|
+
const safeOperation = sanitizeCliText(operation || error?.operation || 'worktree') || 'worktree';
|
|
552
|
+
const operationId = sanitizeCliText(error?.operationId || error?.operation_id);
|
|
553
|
+
const state = sanitizeCliText(error?.state);
|
|
554
|
+
const blockers = sanitizeCliValue(error?.blockers || error?.blocker);
|
|
555
|
+
const firstBlocker = Array.isArray(blockers) ? blockers[0] : blockers;
|
|
556
|
+
const blocker = sanitizeCliText(
|
|
557
|
+
error?.blockerCode
|
|
558
|
+
|| firstBlocker?.code
|
|
559
|
+
|| firstBlocker?.blocker
|
|
560
|
+
|| (typeof firstBlocker === 'string' ? firstBlocker : ''),
|
|
561
|
+
);
|
|
562
|
+
const expected = sanitizeCliValue(error?.expected ?? firstBlocker?.expected ?? null);
|
|
563
|
+
const observed = sanitizeCliValue(error?.observed ?? firstBlocker?.observed ?? null);
|
|
564
|
+
const recovery = sanitizeCliText(error?.recovery || error?.repair);
|
|
565
|
+
if (json) {
|
|
566
|
+
return JSON.stringify({
|
|
567
|
+
ok: false,
|
|
568
|
+
code: safeCode,
|
|
569
|
+
error: localized,
|
|
570
|
+
operation: safeOperation,
|
|
571
|
+
...(operationId ? { operationId, operation_id: operationId } : {}),
|
|
572
|
+
...(state ? { state } : {}),
|
|
573
|
+
blocker: blocker || null,
|
|
574
|
+
...(blockers ? { blockers } : {}),
|
|
575
|
+
expected,
|
|
576
|
+
observed,
|
|
577
|
+
...(recovery ? { recovery } : {}),
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
const details = [
|
|
581
|
+
`operation=${safeOperation}`,
|
|
582
|
+
operationId && `operation_id=${operationId}`,
|
|
583
|
+
state && `state=${state}`,
|
|
584
|
+
blocker && `blocker=${blocker}`,
|
|
585
|
+
expected && `expected=${sanitizeCliText(JSON.stringify(expected))}`,
|
|
586
|
+
observed && `observed=${sanitizeCliText(JSON.stringify(observed))}`,
|
|
587
|
+
recovery && `recovery=${recovery}`,
|
|
588
|
+
].filter(Boolean);
|
|
589
|
+
return `${safeCode}: ${localized}${details.length ? ` (${details.join(' ')})` : ''}`;
|
|
504
590
|
}
|
|
505
591
|
|
|
506
592
|
function renderWorktreeLine(worktree) {
|
|
@@ -542,6 +628,7 @@ function writeWorktreeResult(payload, { json, locale, action }) {
|
|
|
542
628
|
export async function runWorktree(argv = [], dependencies = {}) {
|
|
543
629
|
let parsed;
|
|
544
630
|
let locale = 'pt-BR';
|
|
631
|
+
const jsonRequested = argv.some((arg) => arg === '--json');
|
|
545
632
|
try {
|
|
546
633
|
parsed = parseWorktreeArgv(argv);
|
|
547
634
|
const [command, ...positionals] = parsed.positional;
|
|
@@ -631,7 +718,9 @@ export async function runWorktree(argv = [], dependencies = {}) {
|
|
|
631
718
|
}
|
|
632
719
|
throw worktreeError('WENDKEEP_WORKTREE_USAGE', 'Use create, list, status, open, finish, cleanup, remove ou prune.');
|
|
633
720
|
} catch (error) {
|
|
634
|
-
|
|
721
|
+
const json = Boolean(parsed?.flags?.has('--json') || jsonRequested);
|
|
722
|
+
const operation = parsed?.positional?.[0] || 'worktree';
|
|
723
|
+
process.stderr.write(`${renderWorktreeError(error, locale, { json, operation })}\n`);
|
|
635
724
|
return 2;
|
|
636
725
|
}
|
|
637
726
|
}
|