mustflow 2.107.9 → 2.108.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/dist/cli/commands/api/serve.js +73 -10
- package/dist/core/run-receipt-state.js +23 -2
- package/dist/core/secret-redaction.js +6 -1
- package/package.json +1 -1
- package/schemas/api-serve-response.schema.json +1 -0
- package/templates/default/i18n.toml +48 -12
- package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +24 -1
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +52 -14
- package/templates/default/locales/en/.mustflow/skills/admin-control-plane-safety-review/SKILL.md +200 -0
- package/templates/default/locales/en/.mustflow/skills/ai-product-readiness-review/SKILL.md +158 -0
- package/templates/default/locales/en/.mustflow/skills/auth-permission-change/SKILL.md +91 -28
- package/templates/default/locales/en/.mustflow/skills/browser-automation-reliability-review/SKILL.md +279 -0
- package/templates/default/locales/en/.mustflow/skills/ci-pipeline-triage/SKILL.md +39 -11
- package/templates/default/locales/en/.mustflow/skills/cloud-cost-guardrail-review/SKILL.md +4 -1
- package/templates/default/locales/en/.mustflow/skills/database-change-safety/SKILL.md +21 -2
- package/templates/default/locales/en/.mustflow/skills/database-migration-change/SKILL.md +25 -7
- package/templates/default/locales/en/.mustflow/skills/deployment-rollout-safety-review/SKILL.md +117 -43
- package/templates/default/locales/en/.mustflow/skills/frontend-component-library-review/SKILL.md +299 -0
- package/templates/default/locales/en/.mustflow/skills/frontend-localization-review/SKILL.md +128 -36
- package/templates/default/locales/en/.mustflow/skills/notification-delivery-integrity-review/SKILL.md +226 -0
- package/templates/default/locales/en/.mustflow/skills/payment-integrity-review/SKILL.md +34 -14
- package/templates/default/locales/en/.mustflow/skills/routes.toml +36 -0
- package/templates/default/locales/en/.mustflow/skills/small-service-platform-architecture-review/SKILL.md +273 -0
- package/templates/default/locales/en/.mustflow/skills/tauri-code-change/SKILL.md +41 -3
- package/templates/default/locales/en/.mustflow/skills/wails-code-change/SKILL.md +34 -4
- package/templates/default/manifest.toml +43 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createInterface } from 'node:readline';
|
|
2
1
|
import { apiReportActionSpec, isApiReportAction } from './actions.js';
|
|
3
2
|
import { printUsageError } from '../../lib/cli-output.js';
|
|
4
3
|
import { formatCliOptionParseError, hasParsedCliOption, parseCliOptions, } from '../../lib/option-parser.js';
|
|
5
4
|
import { isRecord } from '../../lib/command-contract.js';
|
|
6
5
|
import { t } from '../../lib/i18n.js';
|
|
7
6
|
const API_SERVE_SCHEMA_VERSION = '1';
|
|
7
|
+
const API_SERVE_MAX_LINE_CHARS = 1024 * 1024;
|
|
8
8
|
const API_SERVE_OPTIONS = [
|
|
9
9
|
{ name: '--stdio', kind: 'boolean' },
|
|
10
10
|
{ name: '--help', kind: 'boolean', aliases: ['-h'] },
|
|
@@ -53,6 +53,15 @@ function readApiServeId(request) {
|
|
|
53
53
|
}
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
|
+
function readApiServeChanged(request, id) {
|
|
57
|
+
if (!Object.hasOwn(request, 'changed')) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
if (typeof request.changed === 'boolean') {
|
|
61
|
+
return request.changed;
|
|
62
|
+
}
|
|
63
|
+
return createApiServeError(id, 'invalid_request', 'Request field "changed" must be a boolean when provided.');
|
|
64
|
+
}
|
|
56
65
|
function parseApiServeRequestLine(line) {
|
|
57
66
|
let parsed;
|
|
58
67
|
try {
|
|
@@ -72,11 +81,18 @@ function parseApiServeRequestLine(line) {
|
|
|
72
81
|
error: createApiServeError(id, 'invalid_request', 'Request must be a JSON object.'),
|
|
73
82
|
};
|
|
74
83
|
}
|
|
84
|
+
const changed = readApiServeChanged(parsed, id);
|
|
85
|
+
if (typeof changed !== 'boolean' && changed !== undefined) {
|
|
86
|
+
return {
|
|
87
|
+
request: null,
|
|
88
|
+
error: changed,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
75
91
|
return {
|
|
76
92
|
request: {
|
|
77
93
|
id,
|
|
78
94
|
action: parsed.action,
|
|
79
|
-
changed
|
|
95
|
+
changed,
|
|
80
96
|
},
|
|
81
97
|
error: null,
|
|
82
98
|
};
|
|
@@ -99,8 +115,8 @@ function createApiServeResponse(request, runtime) {
|
|
|
99
115
|
try {
|
|
100
116
|
return createApiServeSuccess(id, runtime.createReport(request.action));
|
|
101
117
|
}
|
|
102
|
-
catch
|
|
103
|
-
return createApiServeError(id, 'report_unavailable',
|
|
118
|
+
catch {
|
|
119
|
+
return createApiServeError(id, 'report_unavailable', 'Report is unavailable for this action.');
|
|
104
120
|
}
|
|
105
121
|
}
|
|
106
122
|
function writeApiServeResponse(response, reporter) {
|
|
@@ -111,6 +127,53 @@ function writeApiServeResponse(response, reporter) {
|
|
|
111
127
|
}
|
|
112
128
|
reporter.stdout(line.trimEnd());
|
|
113
129
|
}
|
|
130
|
+
async function* readApiServeInputLines(input) {
|
|
131
|
+
input.setEncoding('utf8');
|
|
132
|
+
let buffer = '';
|
|
133
|
+
let discardingOversizedLine = false;
|
|
134
|
+
for await (const chunk of input) {
|
|
135
|
+
const text = typeof chunk === 'string' ? chunk : String(chunk);
|
|
136
|
+
let start = 0;
|
|
137
|
+
while (start < text.length) {
|
|
138
|
+
const newlineIndex = text.indexOf('\n', start);
|
|
139
|
+
const segmentEnd = newlineIndex === -1 ? text.length : newlineIndex;
|
|
140
|
+
const segment = text.slice(start, segmentEnd);
|
|
141
|
+
if (discardingOversizedLine) {
|
|
142
|
+
if (newlineIndex !== -1) {
|
|
143
|
+
yield { oversized: true };
|
|
144
|
+
discardingOversizedLine = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (buffer.length + segment.length > API_SERVE_MAX_LINE_CHARS) {
|
|
148
|
+
buffer = '';
|
|
149
|
+
if (newlineIndex === -1) {
|
|
150
|
+
discardingOversizedLine = true;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
yield { oversized: true };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
buffer += segment;
|
|
158
|
+
if (newlineIndex !== -1) {
|
|
159
|
+
yield { line: buffer.endsWith('\r') ? buffer.slice(0, -1) : buffer };
|
|
160
|
+
buffer = '';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (newlineIndex === -1) {
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
start = newlineIndex + 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (discardingOversizedLine) {
|
|
170
|
+
yield { oversized: true };
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (buffer.length > 0) {
|
|
174
|
+
yield { line: buffer.endsWith('\r') ? buffer.slice(0, -1) : buffer };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
114
177
|
export async function runApiServe(args, reporter, lang, runtime) {
|
|
115
178
|
const parsed = parseCliOptions(args, API_SERVE_OPTIONS);
|
|
116
179
|
if (hasParsedCliOption(parsed, '--help')) {
|
|
@@ -125,12 +188,12 @@ export async function runApiServe(args, reporter, lang, runtime) {
|
|
|
125
188
|
printUsageError(reporter, t(lang, 'api.error.serveRequiresStdio'), 'mf api --help', runtime.getHelp(lang), lang);
|
|
126
189
|
return 1;
|
|
127
190
|
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const line =
|
|
191
|
+
for await (const inputLine of readApiServeInputLines(process.stdin)) {
|
|
192
|
+
if (inputLine.oversized) {
|
|
193
|
+
writeApiServeResponse(createApiServeError(null, 'request_too_large', `Request line exceeds ${API_SERVE_MAX_LINE_CHARS} characters.`), reporter);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const line = inputLine.line?.trim() ?? '';
|
|
134
197
|
if (line.length === 0) {
|
|
135
198
|
continue;
|
|
136
199
|
}
|
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { ensureInside, writeJsonFileInsideWithoutSymlinks } from './safe-filesystem.js';
|
|
4
4
|
const RUN_RECEIPT_SCHEMA_VERSION = '1';
|
|
5
5
|
const RUN_RECEIPT_DIR = path.join('.mustflow', 'state', 'runs');
|
|
6
|
+
const RUN_RECEIPT_DIR_POSIX = '.mustflow/state/runs';
|
|
6
7
|
const LATEST_RUN_RECEIPT_INDEX = 'latest.index.json';
|
|
7
8
|
const STATE_DIR_PREFIXES = ['run-', 'verify-'];
|
|
8
9
|
const MIN_RETAINED_RUN_DIRS = 1;
|
|
@@ -131,6 +132,24 @@ function stringField(value) {
|
|
|
131
132
|
function stringArrayField(value) {
|
|
132
133
|
return Array.isArray(value) && value.every((entry) => typeof entry === 'string') ? value : undefined;
|
|
133
134
|
}
|
|
135
|
+
function resolveReceiptPathInsideRunsDir(runsDir, receiptPath) {
|
|
136
|
+
if (path.isAbsolute(receiptPath)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const normalizedReceiptPath = receiptPath.replace(/\\/gu, '/');
|
|
140
|
+
const runsPrefix = `${RUN_RECEIPT_DIR_POSIX}/`;
|
|
141
|
+
if (!normalizedReceiptPath.startsWith(runsPrefix)) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const relativeToRunsDir = normalizedReceiptPath.slice(runsPrefix.length);
|
|
145
|
+
const parts = relativeToRunsDir.split('/');
|
|
146
|
+
if (parts.length === 0 || parts.some((part) => part.length === 0 || part === '.' || part === '..')) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const receiptAbsolutePath = path.resolve(runsDir, ...parts);
|
|
150
|
+
ensureInside(runsDir, receiptAbsolutePath);
|
|
151
|
+
return receiptAbsolutePath;
|
|
152
|
+
}
|
|
134
153
|
function createRunEntry(directory) {
|
|
135
154
|
const receipt = readJsonObject(path.join(directory.absolutePath, 'receipt.json'));
|
|
136
155
|
if (!receipt || receipt.command !== 'run' || typeof receipt.receipt_path !== 'string') {
|
|
@@ -154,8 +173,10 @@ function readVerifyIntentEntry(directory, manifest, manifestPath, manifestReceip
|
|
|
154
173
|
return null;
|
|
155
174
|
}
|
|
156
175
|
const runsDir = path.dirname(directory.absolutePath);
|
|
157
|
-
const receiptAbsolutePath =
|
|
158
|
-
|
|
176
|
+
const receiptAbsolutePath = resolveReceiptPathInsideRunsDir(runsDir, receiptPath);
|
|
177
|
+
if (!receiptAbsolutePath) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
159
180
|
const receipt = readJsonObject(receiptAbsolutePath);
|
|
160
181
|
return {
|
|
161
182
|
command: 'verify',
|
|
@@ -8,9 +8,14 @@ const SECRET_REDACTION_RULES = [
|
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
kind: 'secret_token',
|
|
11
|
-
pattern: /\b(?:sk-[A-Za-z0-
|
|
11
|
+
pattern: /\b(?:sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|AKIA[0-9A-Z]{16})\b/gu,
|
|
12
12
|
replace: () => REDACTED_SECRET_MARKER,
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
kind: 'secret_bearer_token',
|
|
16
|
+
pattern: /\b(Bearer\s+)([A-Za-z0-9._~+/=-]{24,})\b/gu,
|
|
17
|
+
replace: (_match, prefix) => `${prefix}${REDACTED_SECRET_MARKER}`,
|
|
18
|
+
},
|
|
14
19
|
];
|
|
15
20
|
export const SECRET_LIKE_PATTERNS = SECRET_REDACTION_RULES.map((rule) => {
|
|
16
21
|
const flags = rule.pattern.flags.replace('g', '');
|
package/package.json
CHANGED
|
@@ -40,7 +40,7 @@ translations.hi = { path = "locales/hi/.mustflow/context/PROJECT.md", source_rev
|
|
|
40
40
|
[documents."docs.agent-workflow"]
|
|
41
41
|
source = "locales/en/.mustflow/docs/agent-workflow.md"
|
|
42
42
|
source_locale = "en"
|
|
43
|
-
revision =
|
|
43
|
+
revision = 28
|
|
44
44
|
translations.ko = { path = "locales/ko/.mustflow/docs/agent-workflow.md", source_revision = 23, status = "needs_review" }
|
|
45
45
|
translations.zh = { path = "locales/zh/.mustflow/docs/agent-workflow.md", source_revision = 18, status = "needs_review" }
|
|
46
46
|
translations.es = { path = "locales/es/.mustflow/docs/agent-workflow.md", source_revision = 18, status = "needs_review" }
|
|
@@ -62,7 +62,7 @@ translations = {}
|
|
|
62
62
|
[documents."skills.index"]
|
|
63
63
|
source = "locales/en/.mustflow/skills/INDEX.md"
|
|
64
64
|
source_locale = "en"
|
|
65
|
-
revision =
|
|
65
|
+
revision = 207
|
|
66
66
|
translations = {}
|
|
67
67
|
|
|
68
68
|
[documents."skill.adapter-boundary"]
|
|
@@ -152,7 +152,7 @@ translations = {}
|
|
|
152
152
|
[documents."skill.payment-integrity-review"]
|
|
153
153
|
source = "locales/en/.mustflow/skills/payment-integrity-review/SKILL.md"
|
|
154
154
|
source_locale = "en"
|
|
155
|
-
revision =
|
|
155
|
+
revision = 4
|
|
156
156
|
translations = {}
|
|
157
157
|
|
|
158
158
|
[documents."skill.credit-ledger-integrity-review"]
|
|
@@ -161,6 +161,24 @@ source_locale = "en"
|
|
|
161
161
|
revision = 1
|
|
162
162
|
translations = {}
|
|
163
163
|
|
|
164
|
+
[documents."skill.notification-delivery-integrity-review"]
|
|
165
|
+
source = "locales/en/.mustflow/skills/notification-delivery-integrity-review/SKILL.md"
|
|
166
|
+
source_locale = "en"
|
|
167
|
+
revision = 1
|
|
168
|
+
translations = {}
|
|
169
|
+
|
|
170
|
+
[documents."skill.admin-control-plane-safety-review"]
|
|
171
|
+
source = "locales/en/.mustflow/skills/admin-control-plane-safety-review/SKILL.md"
|
|
172
|
+
source_locale = "en"
|
|
173
|
+
revision = 1
|
|
174
|
+
translations = {}
|
|
175
|
+
|
|
176
|
+
[documents."skill.small-service-platform-architecture-review"]
|
|
177
|
+
source = "locales/en/.mustflow/skills/small-service-platform-architecture-review/SKILL.md"
|
|
178
|
+
source_locale = "en"
|
|
179
|
+
revision = 1
|
|
180
|
+
translations = {}
|
|
181
|
+
|
|
164
182
|
[documents."skill.api-misuse-resistance-review"]
|
|
165
183
|
source = "locales/en/.mustflow/skills/api-misuse-resistance-review/SKILL.md"
|
|
166
184
|
source_locale = "en"
|
|
@@ -224,7 +242,7 @@ translations = {}
|
|
|
224
242
|
[documents."skill.ci-pipeline-triage"]
|
|
225
243
|
source = "locales/en/.mustflow/skills/ci-pipeline-triage/SKILL.md"
|
|
226
244
|
source_locale = "en"
|
|
227
|
-
revision =
|
|
245
|
+
revision = 2
|
|
228
246
|
translations = {}
|
|
229
247
|
|
|
230
248
|
[documents."skill.auth-flow-triage"]
|
|
@@ -323,10 +341,16 @@ source_locale = "en"
|
|
|
323
341
|
revision = 1
|
|
324
342
|
translations = {}
|
|
325
343
|
|
|
344
|
+
[documents."skill.frontend-component-library-review"]
|
|
345
|
+
source = "locales/en/.mustflow/skills/frontend-component-library-review/SKILL.md"
|
|
346
|
+
source_locale = "en"
|
|
347
|
+
revision = 1
|
|
348
|
+
translations = {}
|
|
349
|
+
|
|
326
350
|
[documents."skill.frontend-localization-review"]
|
|
327
351
|
source = "locales/en/.mustflow/skills/frontend-localization-review/SKILL.md"
|
|
328
352
|
source_locale = "en"
|
|
329
|
-
revision =
|
|
353
|
+
revision = 2
|
|
330
354
|
translations = {}
|
|
331
355
|
|
|
332
356
|
[documents."skill.website-task-friction-review"]
|
|
@@ -398,13 +422,13 @@ translations = {}
|
|
|
398
422
|
[documents."skill.deployment-rollout-safety-review"]
|
|
399
423
|
source = "locales/en/.mustflow/skills/deployment-rollout-safety-review/SKILL.md"
|
|
400
424
|
source_locale = "en"
|
|
401
|
-
revision =
|
|
425
|
+
revision = 3
|
|
402
426
|
translations = {}
|
|
403
427
|
|
|
404
428
|
[documents."skill.cloud-cost-guardrail-review"]
|
|
405
429
|
source = "locales/en/.mustflow/skills/cloud-cost-guardrail-review/SKILL.md"
|
|
406
430
|
source_locale = "en"
|
|
407
|
-
revision =
|
|
431
|
+
revision = 2
|
|
408
432
|
translations = {}
|
|
409
433
|
|
|
410
434
|
[documents."skill.rate-limit-integrity-review"]
|
|
@@ -464,13 +488,13 @@ translations = {}
|
|
|
464
488
|
[documents."skill.database-change-safety"]
|
|
465
489
|
source = "locales/en/.mustflow/skills/database-change-safety/SKILL.md"
|
|
466
490
|
source_locale = "en"
|
|
467
|
-
revision =
|
|
491
|
+
revision = 17
|
|
468
492
|
translations = {}
|
|
469
493
|
|
|
470
494
|
[documents."skill.database-migration-change"]
|
|
471
495
|
source = "locales/en/.mustflow/skills/database-migration-change/SKILL.md"
|
|
472
496
|
source_locale = "en"
|
|
473
|
-
revision =
|
|
497
|
+
revision = 4
|
|
474
498
|
translations = {}
|
|
475
499
|
|
|
476
500
|
[documents."skill.database-query-bottleneck-review"]
|
|
@@ -619,7 +643,7 @@ translations = {}
|
|
|
619
643
|
[documents."skill.auth-permission-change"]
|
|
620
644
|
source = "locales/en/.mustflow/skills/auth-permission-change/SKILL.md"
|
|
621
645
|
source_locale = "en"
|
|
622
|
-
revision =
|
|
646
|
+
revision = 4
|
|
623
647
|
translations = {}
|
|
624
648
|
|
|
625
649
|
[documents."skill.security-flow-review"]
|
|
@@ -799,13 +823,13 @@ translations = {}
|
|
|
799
823
|
[documents."skill.tauri-code-change"]
|
|
800
824
|
source = "locales/en/.mustflow/skills/tauri-code-change/SKILL.md"
|
|
801
825
|
source_locale = "en"
|
|
802
|
-
revision =
|
|
826
|
+
revision = 4
|
|
803
827
|
translations = {}
|
|
804
828
|
|
|
805
829
|
[documents."skill.wails-code-change"]
|
|
806
830
|
source = "locales/en/.mustflow/skills/wails-code-change/SKILL.md"
|
|
807
831
|
source_locale = "en"
|
|
808
|
-
revision =
|
|
832
|
+
revision = 2
|
|
809
833
|
translations = {}
|
|
810
834
|
|
|
811
835
|
[documents."skill.typescript-code-change"]
|
|
@@ -1167,6 +1191,12 @@ source_locale = "en"
|
|
|
1167
1191
|
revision = 2
|
|
1168
1192
|
translations = {}
|
|
1169
1193
|
|
|
1194
|
+
[documents."skill.ai-product-readiness-review"]
|
|
1195
|
+
source = "locales/en/.mustflow/skills/ai-product-readiness-review/SKILL.md"
|
|
1196
|
+
source_locale = "en"
|
|
1197
|
+
revision = 1
|
|
1198
|
+
translations = {}
|
|
1199
|
+
|
|
1170
1200
|
[documents."skill.prompt-contract-quality-review"]
|
|
1171
1201
|
source = "locales/en/.mustflow/skills/prompt-contract-quality-review/SKILL.md"
|
|
1172
1202
|
source_locale = "en"
|
|
@@ -1197,6 +1227,12 @@ source_locale = "en"
|
|
|
1197
1227
|
revision = 1
|
|
1198
1228
|
translations = {}
|
|
1199
1229
|
|
|
1230
|
+
[documents."skill.browser-automation-reliability-review"]
|
|
1231
|
+
source = "locales/en/.mustflow/skills/browser-automation-reliability-review/SKILL.md"
|
|
1232
|
+
source_locale = "en"
|
|
1233
|
+
revision = 1
|
|
1234
|
+
translations = {}
|
|
1235
|
+
|
|
1200
1236
|
[documents."skill.agent-eval-integrity-review"]
|
|
1201
1237
|
source = "locales/en/.mustflow/skills/agent-eval-integrity-review/SKILL.md"
|
|
1202
1238
|
source_locale = "en"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: docs.agent-workflow
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 28
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: workflow-policy
|
|
8
8
|
---
|
|
@@ -68,6 +68,29 @@ When multiple skills apply, follow the most specific skill for each affected sco
|
|
|
68
68
|
|
|
69
69
|
When a skill is used, report the skill name and selection reason briefly in the next user-facing update or final report. When files were created or modified, the final report must include a concise skill-selection note: list the skills used, say that no matching installed skill was found, or report that a plausible skill is missing from the installed profile. Do not create a versioned worklog solely to record skill selection.
|
|
70
70
|
|
|
71
|
+
### Script-Pack Selection
|
|
72
|
+
|
|
73
|
+
Script-pack suggestions are optional evidence helpers, not skill procedures or command authority.
|
|
74
|
+
Skills remain the primary procedure owner: select and read the matching `SKILL.md` first, then use
|
|
75
|
+
script-pack metadata only to decide whether a bounded helper would improve orientation,
|
|
76
|
+
synchronization, or review evidence.
|
|
77
|
+
|
|
78
|
+
When the command contract exposes `script_pack_list`, use it for catalog discovery only. When the
|
|
79
|
+
command contract exposes `script_pack_suggest_changed`, use it after changed files exist to get
|
|
80
|
+
optional helper suggestions from current path evidence. These discovery commands do not run helper
|
|
81
|
+
scripts, authorize new commands, or replace the skill-selection gate.
|
|
82
|
+
|
|
83
|
+
Prefer helper candidates whose `related_skills` include the selected skill, whose `phases` match the
|
|
84
|
+
current phase (`before_change`, `during_change`, `after_change`, or `review`), and whose `use_when`
|
|
85
|
+
matches the changed paths and risk. Discard a candidate when `read_only` is false, `mutates` is true,
|
|
86
|
+
network, destructive, interactive, or long-running behavior appears, required inputs are unavailable,
|
|
87
|
+
the phase does not match, or no configured oneshot command intent authorizes that exact action.
|
|
88
|
+
|
|
89
|
+
Script-pack output can focus what to inspect, but it does not replace reading `SKILL.md`, relevant
|
|
90
|
+
source files, configured verification intents, documentation review requirements, or final completion
|
|
91
|
+
evidence. Suggested helpers are not mandatory. Report skipped useful suggestions only when they were
|
|
92
|
+
relevant to the current risk but not run.
|
|
93
|
+
|
|
71
94
|
## Input Stability
|
|
72
95
|
|
|
73
96
|
Treat user instructions, local files, command contracts, and generated reports as distinct sources. Avoid conflating these sources.
|