release-skill 0.1.5 → 0.1.7

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.
Files changed (69) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +4 -4
  4. package/CHANGELOG.md +108 -0
  5. package/INSTALL.md +81 -1
  6. package/INSTALL.zh-CN.md +69 -1
  7. package/LICENSE +1 -0
  8. package/NOTICE +10 -0
  9. package/README.md +181 -8
  10. package/README.zh-CN.md +153 -8
  11. package/adapters/claude/.claude-plugin/marketplace.json +3 -3
  12. package/adapters/claude/.claude-plugin/plugin.json +2 -2
  13. package/adapters/claude/bin/release-skill.bundle.mjs +14182 -10017
  14. package/adapters/claude/bin/release-skill.mjs +24 -4
  15. package/adapters/claude/native/safe-write/binding.gyp +2 -1
  16. package/adapters/claude/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  17. package/adapters/claude/native/safe-write/prebuilds.json +1 -1
  18. package/adapters/claude/schemas/.render-manifest.json +10 -10
  19. package/adapters/claude/schemas/release-project.schema.json +118 -0
  20. package/adapters/claude/skills/release-help/SKILL.md +21 -0
  21. package/adapters/claude/skills/release-prepare/SKILL.md +17 -6
  22. package/adapters/claude/skills/release-publish/SKILL.md +3 -1
  23. package/adapters/claude/skills/release-reconcile/SKILL.md +1 -1
  24. package/adapters/codex/.codex-plugin/plugin.json +4 -4
  25. package/adapters/codex/bin/release-skill.bundle.mjs +14182 -10017
  26. package/adapters/codex/bin/release-skill.mjs +24 -4
  27. package/adapters/codex/native/safe-write/binding.gyp +2 -1
  28. package/adapters/codex/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  29. package/adapters/codex/native/safe-write/prebuilds.json +1 -1
  30. package/adapters/codex/schemas/.render-manifest.json +10 -10
  31. package/adapters/codex/schemas/release-project.schema.json +118 -0
  32. package/adapters/codex/skills/release-help/SKILL.md +21 -0
  33. package/adapters/codex/skills/release-prepare/SKILL.md +17 -6
  34. package/adapters/codex/skills/release-publish/SKILL.md +3 -1
  35. package/adapters/codex/skills/release-reconcile/SKILL.md +1 -1
  36. package/bin/release-skill-cli.mjs +163 -4
  37. package/bin/release-skill.bundle.mjs +14182 -10017
  38. package/bin/release-skill.mjs +24 -4
  39. package/native/safe-write/binding.gyp +2 -1
  40. package/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  41. package/native/safe-write/prebuilds.json +1 -1
  42. package/package.json +13 -5
  43. package/references/.render-manifest.json +4 -4
  44. package/references/02-project-config.md +24 -0
  45. package/references/05-evidence-and-errors.md +5 -0
  46. package/schemas/.render-manifest.json +10 -10
  47. package/schemas/release-project.schema.json +118 -0
  48. package/scripts/build-bundle.mjs +15 -2
  49. package/skills/release-help/SKILL.md +21 -0
  50. package/skills/release-prepare/SKILL.md +17 -6
  51. package/skills/release-publish/SKILL.md +3 -1
  52. package/skills/release-reconcile/SKILL.md +1 -1
  53. package/skills-src/release-help/SKILL.md +21 -0
  54. package/skills-src/release-prepare/SKILL.md +17 -6
  55. package/skills-src/release-publish/SKILL.md +3 -1
  56. package/skills-src/release-reconcile/SKILL.md +1 -1
  57. package/src/artifacts/transaction-journal.mjs +1126 -105
  58. package/src/artifacts/transaction.mjs +313 -130
  59. package/src/commands/docs.mjs +332 -0
  60. package/src/commands/prepare.mjs +316 -17
  61. package/src/core/errors.mjs +64 -2
  62. package/src/core/redact.mjs +206 -0
  63. package/src/docs/changelog-renderer.mjs +853 -0
  64. package/src/docs/config.mjs +337 -0
  65. package/src/docs/notes-loader.mjs +432 -0
  66. package/src/docs/notes.mjs +553 -0
  67. package/src/docs/readme-renderer.mjs +647 -0
  68. package/src/docs/refresh-planner.mjs +542 -0
  69. package/src/docs/refresh-service.mjs +675 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Centralized redaction of sensitive filesystem paths in error outputs.
3
+ *
4
+ * Defect #3 fix: runtime error outputs (CLI text/JSON output and details
5
+ * structures) must never carry absolute filesystem paths (the macOS Users
6
+ * realm, the Linux home realm, the macOS private/var alias realm, temp
7
+ * roots, tmpdir fixture roots). This module is the single redaction
8
+ * authority consumed by the ReleaseError constructor choke point
9
+ * (core/errors.mjs); producers may also apply it defense-in-depth.
10
+ *
11
+ * Semantics:
12
+ * - Strings: tokens shaped like real absolute paths are replaced with the
13
+ * stable placeholder `<redacted-path>`. Three families are redacted
14
+ * fail-closed:
15
+ * (1) POSIX absolute paths (leading '/', at least two path segments) —
16
+ * unless the token classifies as a strict RFC 6901 JSON Pointer;
17
+ * (2) Windows drive-letter paths (X:\... and X:/...);
18
+ * (3) UNC paths (\\server\share...).
19
+ * Strict JSON Pointers (e.g. /frozenSnapshot/commitTimestamp,
20
+ * /units/0/version) are stable diagnostic coordinates, not filesystem
21
+ * paths, and are preserved verbatim. Relative fragments (no leading '/'),
22
+ * flag tokens (--unit), reason vocabulary (MISSING_VALUE), error codes,
23
+ * sha256 digests, stable field names, and fragment-anchored JSON pointers
24
+ * (#/required) are likewise preserved verbatim. Any other two-or-more
25
+ * segment '/'-led token stays redacted as the fail-closed default.
26
+ * - Arrays and plain objects: recursed; every string value is redacted.
27
+ * - Everything else (numbers, booleans, null, undefined, and non-plain
28
+ * objects such as Buffers/Dates/Maps) is returned untouched.
29
+ *
30
+ * Pure and zero-dependency: no imports from src/artifacts/* (no cycles, no
31
+ * cross-layer coupling); node built-ins only (none required).
32
+ *
33
+ * @module core/redact
34
+ */
35
+
36
+ /** Stable placeholder substituted for every redacted absolute path. */
37
+ export const REDACTED_PATH_PLACEHOLDER = '<redacted-path>';
38
+
39
+ // Absolute-path tokens. Three families, tried in order at each anchor point:
40
+ // (a) Windows drive-letter paths (C:\... or C:/...) — ordered before the
41
+ // POSIX alternative so a drive-letter token reaching into the Users
42
+ // realm collapses to a single placeholder instead of leaving a 'C:'
43
+ // prefix behind;
44
+ // (b) UNC paths (\\server\share...);
45
+ // (c) POSIX absolute paths: a '/' anchored at the start of the string or
46
+ // preceded by a delimiter (whitespace, quote, '=', ':', ',', '(', '[',
47
+ // '{', '<'), running until whitespace or a quote. The left boundary keeps
48
+ // redaction from firing inside relative fragments ('src/core/x.mjs'),
49
+ // fragment-anchored JSON pointers ('#/required'), or protocol-relative
50
+ // URLs ('https://x/y').
51
+ const PATH_TOKEN_RE =
52
+ /(?<=^|[\s'"=:,([{<])(?:[A-Za-z]:[\\/][^\s'"]*|\\\\[^\s'"]+|\/[^\s'"]+)/g;
53
+
54
+ // Trailing prose punctuation that may cling to a token and must survive.
55
+ const TRAILING_PUNCT_RE = /^(.*?)([.!,;:)\]}>]*)$/;
56
+
57
+ // Filesystem root directories that mark a '/'-led token as a real absolute
58
+ // path even when every segment is identifier-shaped (e.g. a temp-root or
59
+ // Users-realm path whose segments are all plain identifiers): the Unix FHS
60
+ // hierarchy, macOS realms, and common ephemeral/CI checkout roots.
61
+ // Fail-closed backstop under the JSON Pointer classifier.
62
+ const KNOWN_FS_ROOTS = new Set([
63
+ // Unix/Linux FHS
64
+ 'bin', 'boot', 'dev', 'etc', 'home', 'lib', 'lib64', 'media', 'mnt',
65
+ 'opt', 'proc', 'root', 'run', 'sbin', 'srv', 'sys', 'tmp', 'usr', 'var',
66
+ // macOS realms
67
+ 'Applications', 'Library', 'Network', 'System', 'Users', 'Volumes',
68
+ 'cores', 'private',
69
+ // common ephemeral / CI checkout roots
70
+ 'app', 'build', 'data', 'dist', 'workspace', 'workspaces',
71
+ ]);
72
+
73
+ // Strict RFC 6901 reference-token shapes as used by diagnostic JSON Pointers
74
+ // in this system: identifier-like property names and array indexes (no
75
+ // leading zeros, per RFC 6901 array indexing).
76
+ const POINTER_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
77
+ const POINTER_INDEX_RE = /^(?:0|[1-9][0-9]*)$/;
78
+
79
+ // JSON Pointer syntax and POSIX absolute-path syntax overlap. Preserve only
80
+ // the diagnostic pointer roots emitted by the plan/unit validators that need
81
+ // stable public diagnostics. A broad camelCase/array-index heuristic would
82
+ // incorrectly disclose real paths such as a custom mount with identifier-like
83
+ // segments, violating the fail-closed contract.
84
+ const DIAGNOSTIC_POINTER_ROOTS = new Set([
85
+ 'frozenSnapshot',
86
+ 'units',
87
+ ]);
88
+
89
+ /**
90
+ * Classify a '/'-led, >= 2-segment token as a strict RFC 6901 JSON Pointer
91
+ * (a stable diagnostic coordinate such as /units/0/frozenSnapshot/commitTimestamp
92
+ * or /frozenSnapshot/commitTimestamp) rather than a filesystem path.
93
+ *
94
+ * Conservative by design (fail-closed): the token qualifies only when its
95
+ * first segment belongs to an explicit diagnostic namespace and every segment
96
+ * is an identifier-like reference token or array index. Any other
97
+ * two-or-more-segment token is treated as a path and redacted.
98
+ *
99
+ * @param {string} token
100
+ * @returns {boolean}
101
+ */
102
+ function isStrictJsonPointer(token) {
103
+ const segments = token.slice(1).split('/');
104
+ if (segments.length < 2) return false;
105
+ if (KNOWN_FS_ROOTS.has(segments[0])) return false;
106
+ if (!DIAGNOSTIC_POINTER_ROOTS.has(segments[0])) return false;
107
+ for (const segment of segments) {
108
+ if (!POINTER_INDEX_RE.test(segment) && !POINTER_IDENTIFIER_RE.test(segment)) {
109
+ // Dots (file extensions), hyphens, tildes, escapes, empty segments:
110
+ // not a strict diagnostic pointer — fall back to path redaction.
111
+ return false;
112
+ }
113
+ }
114
+ return true;
115
+ }
116
+
117
+ /**
118
+ * Whether a token looks like a POSIX absolute path with >= 2 segments
119
+ * (e.g. a Users-realm path, a private/var-folders path, or a temp-root
120
+ * path) that is NOT a strict JSON Pointer. Single-segment tokens such as
121
+ * '/tmp', schema instance fragments such as '/:', and strict JSON Pointers
122
+ * such as '/frozenSnapshot/commitTimestamp' are left alone.
123
+ *
124
+ * @param {string} token
125
+ * @returns {boolean}
126
+ */
127
+ function looksLikeAbsolutePath(token) {
128
+ if (typeof token !== 'string' || token.length < 3) return false;
129
+ if (!token.startsWith('/') || token.startsWith('//')) return false;
130
+ if (!token.slice(1).includes('/')) return false;
131
+ return !isStrictJsonPointer(token);
132
+ }
133
+
134
+ /**
135
+ * Whether a token is a Windows drive-letter absolute path (X:\... or X:/...).
136
+ * Drive-letter tokens are unambiguously filesystem paths and always redact.
137
+ *
138
+ * @param {string} token
139
+ * @returns {boolean}
140
+ */
141
+ function isWindowsDrivePath(token) {
142
+ return /^[A-Za-z]:[\\/]/.test(token);
143
+ }
144
+
145
+ /**
146
+ * Whether a token is a UNC path (\\server\share...). UNC tokens are
147
+ * unambiguously filesystem paths and always redact.
148
+ *
149
+ * @param {string} token
150
+ * @returns {boolean}
151
+ */
152
+ function isUncPath(token) {
153
+ return token.startsWith('\\\\');
154
+ }
155
+
156
+ /**
157
+ * Replace absolute-path tokens in a string with the redaction placeholder.
158
+ *
159
+ * @param {string} input
160
+ * @returns {string}
161
+ */
162
+ function redactString(input) {
163
+ return input.replace(PATH_TOKEN_RE, (raw) => {
164
+ const match = TRAILING_PUNCT_RE.exec(raw);
165
+ const core = match[1];
166
+ const tail = match[2];
167
+ if (isWindowsDrivePath(core) || isUncPath(core) || looksLikeAbsolutePath(core)) {
168
+ return `${REDACTED_PATH_PLACEHOLDER}${tail}`;
169
+ }
170
+ return raw;
171
+ });
172
+ }
173
+
174
+ /**
175
+ * Deep-redact sensitive absolute paths from any error-output value.
176
+ *
177
+ * Strings have absolute-path tokens replaced with `<redacted-path>`;
178
+ * arrays and plain objects are recursed; all other values (numbers,
179
+ * booleans, null, undefined, and non-plain objects such as Buffers, Dates,
180
+ * Maps, Sets, or Error instances) are returned untouched.
181
+ *
182
+ * @param {unknown} value — message string, details object, or nested value.
183
+ * @returns {unknown} Redacted copy (plain objects/arrays are rebuilt;
184
+ * scalars and non-plain objects pass through).
185
+ */
186
+ export function redactSensitivePaths(value) {
187
+ if (typeof value === 'string') {
188
+ return redactString(value);
189
+ }
190
+ if (Array.isArray(value)) {
191
+ return value.map(redactSensitivePaths);
192
+ }
193
+ if (value !== null && typeof value === 'object') {
194
+ const proto = Object.getPrototypeOf(value);
195
+ if (proto !== Object.prototype && proto !== null) {
196
+ // Buffer, TypedArray, Date, Map, Set, class instances: leave untouched.
197
+ return value;
198
+ }
199
+ const out = {};
200
+ for (const [key, val] of Object.entries(value)) {
201
+ out[key] = redactSensitivePaths(val);
202
+ }
203
+ return out;
204
+ }
205
+ return value;
206
+ }