mustflow 1.31.0 → 2.11.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.
Files changed (64) hide show
  1. package/README.md +23 -9
  2. package/dist/cli/commands/classify.js +61 -6
  3. package/dist/cli/commands/contract-lint.js +13 -4
  4. package/dist/cli/commands/dashboard.js +6 -0
  5. package/dist/cli/commands/index.js +5 -0
  6. package/dist/cli/commands/run.js +4 -1
  7. package/dist/cli/commands/verify.js +488 -43
  8. package/dist/cli/i18n/en.js +61 -10
  9. package/dist/cli/i18n/es.js +61 -10
  10. package/dist/cli/i18n/fr.js +61 -10
  11. package/dist/cli/i18n/hi.js +61 -10
  12. package/dist/cli/i18n/ko.js +61 -10
  13. package/dist/cli/i18n/zh.js +61 -10
  14. package/dist/cli/lib/dashboard-export.js +62 -12
  15. package/dist/cli/lib/dashboard-html/client-script.js +1936 -0
  16. package/dist/cli/lib/dashboard-html/locale-bootstrap.js +8 -0
  17. package/dist/cli/lib/dashboard-html/styles.js +572 -0
  18. package/dist/cli/lib/dashboard-html/template.js +134 -0
  19. package/dist/cli/lib/dashboard-html/types.js +1 -0
  20. package/dist/cli/lib/dashboard-html.js +1 -1907
  21. package/dist/cli/lib/dashboard-locale.js +37 -0
  22. package/dist/cli/lib/local-index/constants.js +48 -0
  23. package/dist/cli/lib/local-index/index.js +2256 -0
  24. package/dist/cli/lib/local-index/sql.js +15 -0
  25. package/dist/cli/lib/local-index/types.js +1 -0
  26. package/dist/cli/lib/local-index.js +1 -1911
  27. package/dist/cli/lib/run-plan.js +76 -1
  28. package/dist/cli/lib/templates.js +18 -1
  29. package/dist/cli/lib/validation/command-intents.js +11 -0
  30. package/dist/cli/lib/validation/constants.js +238 -0
  31. package/dist/cli/lib/validation/index.js +1384 -0
  32. package/dist/cli/lib/validation/primitives.js +198 -0
  33. package/dist/cli/lib/validation/test-selection.js +95 -0
  34. package/dist/cli/lib/validation/types.js +1 -0
  35. package/dist/cli/lib/validation.js +1 -1770
  36. package/dist/core/check-issues.js +6 -0
  37. package/dist/core/completion-verdict.js +209 -0
  38. package/dist/core/contract-lint.js +221 -6
  39. package/dist/core/external-evidence.js +9 -0
  40. package/dist/core/public-json-contracts.js +21 -0
  41. package/dist/core/repeated-failure.js +17 -0
  42. package/dist/core/repro-evidence.js +53 -0
  43. package/dist/core/scope-risk.js +64 -0
  44. package/dist/core/skill-route-alignment.js +20 -0
  45. package/dist/core/source-anchor-status.js +4 -1
  46. package/dist/core/test-selection.js +3 -0
  47. package/dist/core/validation-ratchet.js +52 -0
  48. package/dist/core/verification-evidence.js +249 -0
  49. package/examples/README.md +12 -4
  50. package/package.json +1 -1
  51. package/schemas/README.md +13 -3
  52. package/schemas/change-verification-report.schema.json +16 -2
  53. package/schemas/commands.schema.json +4 -0
  54. package/schemas/contract-lint-report.schema.json +29 -0
  55. package/schemas/dashboard-export.schema.json +227 -0
  56. package/schemas/latest-run-pointer.schema.json +384 -0
  57. package/schemas/run-receipt.schema.json +4 -0
  58. package/schemas/test-selection.schema.json +81 -0
  59. package/schemas/verify-report.schema.json +361 -1
  60. package/schemas/verify-run-manifest.schema.json +410 -0
  61. package/templates/default/i18n.toml +1 -1
  62. package/templates/default/locales/en/.mustflow/skills/INDEX.md +124 -29
  63. package/templates/default/locales/en/.mustflow/skills/routes.toml +289 -0
  64. package/templates/default/manifest.toml +29 -2
@@ -4,6 +4,7 @@ import { resolveSafeProjectCwd } from '../../core/command-cwd.js';
4
4
  import { resolveCommandEnv } from '../../core/command-env.js';
5
5
  import { evaluateCommandIntentEligibility, } from '../../core/command-intent-eligibility.js';
6
6
  import { isRecord, readPositiveInteger, readString, readStringArray, } from '../../core/config-loading.js';
7
+ import { t } from './i18n.js';
7
8
  function getSuccessExitCodes(intent) {
8
9
  const value = intent.success_exit_codes;
9
10
  if (!Array.isArray(value) || value.length === 0 || value.some((entry) => !Number.isInteger(entry))) {
@@ -95,6 +96,10 @@ function readRunIntentMetadata(contract, intent) {
95
96
  envPolicy: env.policy,
96
97
  envAllowlist: env.allowlist,
97
98
  testTargets: [],
99
+ manualStartHint: readString(intent, 'manual_start_hint') ?? null,
100
+ healthCheckUrl: readString(intent, 'health_check_url') ?? null,
101
+ stopInstruction: readString(intent, 'stop_instruction') ?? null,
102
+ relatedOneshotChecks: readStringArray(intent, 'related_oneshot_checks') ?? [],
98
103
  };
99
104
  }
100
105
  function createBlockedRunPlan(contract, intentName, intent, eligibility, reasonCode, detail) {
@@ -127,6 +132,11 @@ function createBlockedRunPlan(contract, intentName, intent, eligibility, reasonC
127
132
  envPolicy: metadata?.envPolicy ?? null,
128
133
  envAllowlist: metadata?.envAllowlist ?? [],
129
134
  testTargets: [],
135
+ suggestedIntentSnippet: createSuggestedIntentSnippet(intentName, metadata, reasonCode),
136
+ manualStartHint: metadata?.manualStartHint ?? null,
137
+ healthCheckUrl: metadata?.healthCheckUrl ?? null,
138
+ stopInstruction: metadata?.stopInstruction ?? null,
139
+ relatedOneshotChecks: metadata?.relatedOneshotChecks ?? [],
130
140
  };
131
141
  }
132
142
  export function createRunPlan(projectRoot, contract, intentName, options = {}) {
@@ -179,8 +189,53 @@ export function createRunPlan(projectRoot, contract, intentName, options = {}) {
179
189
  envPolicy: metadata.envPolicy,
180
190
  envAllowlist: metadata.envAllowlist,
181
191
  testTargets,
192
+ suggestedIntentSnippet: null,
193
+ manualStartHint: metadata.manualStartHint,
194
+ healthCheckUrl: metadata.healthCheckUrl,
195
+ stopInstruction: metadata.stopInstruction,
196
+ relatedOneshotChecks: metadata.relatedOneshotChecks,
182
197
  };
183
198
  }
199
+ function formatTomlString(value) {
200
+ return JSON.stringify(value);
201
+ }
202
+ function formatTomlStringArray(values) {
203
+ return `[${values.map(formatTomlString).join(', ')}]`;
204
+ }
205
+ function createSuggestedIntentSnippet(intentName, metadata, reasonCode) {
206
+ if (!/^[A-Za-z0-9_-]+$/u.test(intentName)) {
207
+ return null;
208
+ }
209
+ let commandLines;
210
+ if (reasonCode === 'blocked_shell_background_pattern') {
211
+ commandLines = [`argv = ${formatTomlStringArray(['TODO_REPLACE_WITH_FINITE_COMMAND'])}`];
212
+ }
213
+ else if (metadata?.shellCommand) {
214
+ commandLines = [`mode = "shell"`, `cmd = ${formatTomlString(metadata.shellCommand)}`];
215
+ }
216
+ else {
217
+ commandLines = [`argv = ${formatTomlStringArray(metadata?.commandArgv ?? ['TODO_REPLACE_WITH_COMMAND'])}`];
218
+ }
219
+ const lifecycle = metadata?.lifecycle && metadata.lifecycle !== 'oneshot' ? metadata.lifecycle : 'oneshot';
220
+ const configuredCwd = reasonCode === 'cwd_outside_project' ? '.' : metadata?.configuredCwd ?? '.';
221
+ return [
222
+ `[intents.${intentName}]`,
223
+ `status = "manual_only"`,
224
+ `lifecycle = ${formatTomlString(lifecycle)}`,
225
+ `run_policy = "requires_explicit_user_request"`,
226
+ `description = "TODO: describe when this intent should run."`,
227
+ ...commandLines,
228
+ `cwd = ${formatTomlString(configuredCwd)}`,
229
+ `timeout_seconds = ${metadata?.timeoutSeconds ?? 600}`,
230
+ `stdin = "closed"`,
231
+ `success_exit_codes = ${metadata?.successExitCodes ? `[${metadata.successExitCodes.join(', ')}]` : '[0]'}`,
232
+ `writes = ${metadata?.writes ? formatTomlStringArray(metadata.writes) : '[]'}`,
233
+ `network = ${metadata?.network ?? false}`,
234
+ `destructive = ${metadata?.destructive ?? false}`,
235
+ `reason = "Review this suggested intent before enabling agent execution."`,
236
+ `agent_action = "do_not_guess_report_missing"`,
237
+ ].join('\n');
238
+ }
184
239
  export function createRunPreview(plan, previewMode) {
185
240
  return {
186
241
  schema_version: '1',
@@ -213,9 +268,14 @@ export function createRunPreview(plan, previewMode) {
213
268
  env_allowlist: plan.envAllowlist,
214
269
  test_targets: plan.testTargets,
215
270
  success_exit_codes: plan.successExitCodes,
271
+ suggested_intent_snippet: plan.suggestedIntentSnippet,
272
+ manual_start_hint: plan.manualStartHint,
273
+ health_check_url: plan.healthCheckUrl,
274
+ stop_instruction: plan.stopInstruction,
275
+ related_oneshot_checks: plan.relatedOneshotChecks,
216
276
  };
217
277
  }
218
- export function renderRunPreviewText(plan, previewMode) {
278
+ export function renderRunPreviewText(plan, previewMode, lang = 'en') {
219
279
  const lines = [
220
280
  `mf run ${previewMode}`,
221
281
  `Intent: ${plan.intentName}`,
@@ -223,6 +283,21 @@ export function renderRunPreviewText(plan, previewMode) {
223
283
  ];
224
284
  if (!plan.ok) {
225
285
  lines.push(`Reason: ${plan.reasonCode}${plan.detail ? ` (${plan.detail})` : ''}`);
286
+ if (plan.suggestedIntentSnippet) {
287
+ lines.push('', `${t(lang, 'run.label.suggestedIntentSnippet')}:`, plan.suggestedIntentSnippet);
288
+ }
289
+ if (plan.manualStartHint) {
290
+ lines.push('', `Manual start: ${plan.manualStartHint}`);
291
+ }
292
+ if (plan.healthCheckUrl) {
293
+ lines.push(`Health check: ${plan.healthCheckUrl}`);
294
+ }
295
+ if (plan.stopInstruction) {
296
+ lines.push(`Stop: ${plan.stopInstruction}`);
297
+ }
298
+ if (plan.relatedOneshotChecks.length > 0) {
299
+ lines.push(`Related oneshot checks: ${plan.relatedOneshotChecks.join(', ')}`);
300
+ }
226
301
  return lines.join('\n');
227
302
  }
228
303
  lines.push(`Mode: ${plan.mode}`);
@@ -79,6 +79,21 @@ function filterSkillIndexContent(content, selectedSkills) {
79
79
  })
80
80
  .join('\n');
81
81
  }
82
+ function filterSkillRouteMetadataContent(content, selectedSkills) {
83
+ const selectedSkillSet = new Set(selectedSkills);
84
+ let keepCurrentRoute = true;
85
+ return content
86
+ .split(/\r?\n/u)
87
+ .filter((line) => {
88
+ const match = /^\[routes\."([^"]+)"\]\s*$/u.exec(line.trim());
89
+ if (match) {
90
+ keepCurrentRoute = selectedSkillSet.has(match[1] ?? '');
91
+ return keepCurrentRoute;
92
+ }
93
+ return keepCurrentRoute;
94
+ })
95
+ .join('\n');
96
+ }
82
97
  function isAllowedTemplateCreateTarget(relativePath) {
83
98
  const normalizedPath = normalizeTemplateTargetPath(relativePath);
84
99
  if (normalizedPath.startsWith('/') ||
@@ -176,7 +191,9 @@ export function getTemplateFiles(template, locale = template.manifest.defaultLoc
176
191
  const indexSourcePath = localizedPath ?? fallbackLocalePath ?? commonPath;
177
192
  const content = relativePath === '.mustflow/skills/INDEX.md'
178
193
  ? filterSkillIndexContent(readFileSync(indexSourcePath, 'utf8'), selectedSkills)
179
- : undefined;
194
+ : relativePath === '.mustflow/skills/routes.toml'
195
+ ? filterSkillRouteMetadataContent(readFileSync(indexSourcePath, 'utf8'), selectedSkills)
196
+ : undefined;
180
197
  if (localizedPath) {
181
198
  return {
182
199
  relativePath,
@@ -0,0 +1,11 @@
1
+ import { isRecord } from '../command-contract.js';
2
+ export function isDeclaredCommandIntent(commandsToml, intentName) {
3
+ return Boolean(commandsToml && isRecord(commandsToml.intents) && isRecord(commandsToml.intents[intentName]));
4
+ }
5
+ export function isConfiguredCommandIntent(commandsToml, intentName) {
6
+ if (!commandsToml || !isRecord(commandsToml.intents)) {
7
+ return false;
8
+ }
9
+ const intent = commandsToml.intents[intentName];
10
+ return isRecord(intent) && intent.status === 'configured';
11
+ }
@@ -0,0 +1,238 @@
1
+ import { COMMIT_MESSAGE_STYLES, TEST_AUTHORING_POLICIES } from '../preferences-options.js';
2
+ import { VERSION_SOURCE_AUTHORITIES, VERSION_SOURCE_KINDS, } from '../../../core/version-sources.js';
3
+ import { SKILL_ROUTE_CATEGORY_LABELS } from '../../../core/skill-route-alignment.js';
4
+ export { SKILL_ROUTE_CATEGORY_LABELS };
5
+ export const REQUIRED_SKILL_SECTION_IDS = [
6
+ 'purpose',
7
+ 'use-when',
8
+ 'do-not-use-when',
9
+ 'required-inputs',
10
+ 'preconditions',
11
+ 'allowed-edits',
12
+ 'procedure',
13
+ 'postconditions',
14
+ 'verification',
15
+ 'failure-handling',
16
+ 'output-format',
17
+ ];
18
+ export const SKILL_SECTION_MARKER_PATTERN = /^<!--\s*mustflow-section:\s*([a-z][a-z0-9-]*)\s*-->\s*\r?\n##\s+.+$/gimu;
19
+ export const TEST_SELECTION_CONFIG_PATH = '.mustflow/config/test-selection.toml';
20
+ export const REQUIRED_FILES = [
21
+ 'AGENTS.md',
22
+ '.mustflow/config/mustflow.toml',
23
+ '.mustflow/config/commands.toml',
24
+ '.mustflow/skills/INDEX.md',
25
+ ];
26
+ export const ALLOWED_MAP_MODES = new Set(['anchors_only']);
27
+ export const ALLOWED_MAP_PRIVACY_LEVELS = new Set(['minimal']);
28
+ export const ALLOWED_CONTEXT_READ_POLICIES = new Set(['task_relevant_only']);
29
+ export const ALLOWED_CONTEXT_AUTHORITIES = new Set(['contextual']);
30
+ export const ALLOWED_CONTEXT_DOCUMENT_AUTHORITIES = new Set(['contextual', 'derived', 'external', 'router']);
31
+ export const CAPABILITY_STATE_FIELDS = ['repo_map', 'preferences', 'context', 'local_index', 'work_items', 'services'];
32
+ export const CAPABILITY_BOOLEAN_FIELDS = ['workflow', 'command_contract', 'skills'];
33
+ export const ALLOWED_CAPABILITY_STATES = new Set(['disabled', 'optional', 'required', 'generated_optional']);
34
+ export const REQUIRED_AGENT_LOOP_PHASES = ['orient', 'plan', 'act', 'verify', 'report', 'handoff'];
35
+ export const ALLOWED_HANDOFF_MODES = new Set(['report_only', 'work_item_optional']);
36
+ export const ALLOWED_PROJECT_PROFILES = new Set(['minimal', 'patterns', 'oss', 'team', 'product', 'library']);
37
+ export const RELEASE_VERSIONING_BOOLEAN_FIELDS = [
38
+ 'impact_check',
39
+ 'suggest_bump',
40
+ 'auto_bump',
41
+ 'require_user_confirmation',
42
+ 'sync_template_version',
43
+ 'sync_docs_examples',
44
+ 'sync_tests',
45
+ ];
46
+ export const FORBIDDEN_RELEASE_VERSIONING_CONTRACT_FIELDS = [
47
+ 'path',
48
+ 'paths',
49
+ 'source',
50
+ 'sources',
51
+ 'version_source',
52
+ 'version_sources',
53
+ 'authority',
54
+ 'kind',
55
+ 'command_intents',
56
+ 'run_policy',
57
+ 'argv',
58
+ 'cmd',
59
+ 'release',
60
+ 'tag',
61
+ 'push',
62
+ 'commit',
63
+ ];
64
+ export const ALLOWED_VERSION_SOURCE_KINDS = new Set(VERSION_SOURCE_KINDS);
65
+ export const ALLOWED_VERSION_SOURCE_AUTHORITIES = new Set(VERSION_SOURCE_AUTHORITIES);
66
+ export const ALLOWED_COMMIT_MESSAGE_STYLES = new Set(COMMIT_MESSAGE_STYLES);
67
+ export const VERIFICATION_SELECTION_BOOLEAN_FIELDS = [
68
+ 'prefer_related_tests',
69
+ 'skip_docs_only_full_test',
70
+ 'skip_low_risk_code_full_test',
71
+ 'skip_translation_only_full_test',
72
+ 'skip_copy_only_full_test',
73
+ 'report_skipped',
74
+ ];
75
+ export const FORBIDDEN_VERIFICATION_SELECTION_AUTHORITY_FIELDS = [
76
+ 'intents',
77
+ 'command_intents',
78
+ 'required_after',
79
+ 'status',
80
+ 'lifecycle',
81
+ 'run_policy',
82
+ 'argv',
83
+ 'cmd',
84
+ 'writes',
85
+ 'network',
86
+ 'destructive',
87
+ ];
88
+ export const ALLOWED_VERIFICATION_SELECTION_STRATEGIES = new Set(['risk_based', 'targeted', 'full']);
89
+ export const ALLOWED_TEST_SELECTION_RISKS = new Set(['low', 'medium', 'high', 'release_sensitive', 'security_sensitive']);
90
+ export const FORBIDDEN_TEST_SELECTION_COMMAND_AUTHORITY_FIELDS = [
91
+ 'argv',
92
+ 'cmd',
93
+ 'command',
94
+ 'commands',
95
+ 'command_intents',
96
+ 'destructive',
97
+ 'intents',
98
+ 'lifecycle',
99
+ 'network',
100
+ 'required_after',
101
+ 'run_policy',
102
+ 'status',
103
+ 'writes',
104
+ ];
105
+ export const TEST_AUTHORING_BOOLEAN_FIELDS = ['prefer_existing_tests', 'require_new_test_rationale'];
106
+ export const ALLOWED_TEST_AUTHORING_POLICIES = new Set(TEST_AUTHORING_POLICIES);
107
+ export const ALLOWED_TESTING_POLICIES = new Set(['behavior_contract']);
108
+ export const ALLOWED_TEST_DELETION_REASONS = new Set([
109
+ 'behavior_removed',
110
+ 'public_contract_changed',
111
+ 'duplicate_coverage',
112
+ 'implementation_detail_removed',
113
+ 'obsolete_snapshot',
114
+ ]);
115
+ export const FORBIDDEN_TEST_DELETION_REASONS = new Set([
116
+ 'only_to_make_tests_pass',
117
+ 'without_behavior_rationale',
118
+ 'without_reporting',
119
+ 'without_running_relevant_validation',
120
+ ]);
121
+ export const ALLOWED_STALE_TEST_ACTIONS = new Set(['update_remove_or_report']);
122
+ export const ALLOWED_HARNESS_MODES = new Set(['single_session', 'long_running_optional']);
123
+ export const ALLOWED_HARNESS_FRESH_CONTEXT_MODES = new Set(['hash_check_before_reread', 'reread']);
124
+ export const ALLOWED_HARNESS_PHASES = new Set(['plan', 'work', 'verify', 'judge', 'handoff']);
125
+ export const ALLOWED_PROMPT_CACHE_STRATEGIES = new Set(['stable_prefix']);
126
+ export const ALLOWED_PROMPT_CACHE_STABLE_PREFIX_POLICIES = new Set(['hash_verified']);
127
+ export const ALLOWED_PROMPT_CACHE_TASK_READ_POLICIES = new Set(['task_relevant_only']);
128
+ export const ALLOWED_BUDGET_LIMIT_ACTIONS = new Set(['stop_and_handoff', 'stop_and_report']);
129
+ export const ALLOWED_APPROVAL_GATES = new Set([
130
+ 'git_commit',
131
+ 'git_push',
132
+ 'dependency_install',
133
+ 'dependency_upgrade',
134
+ 'network_access',
135
+ 'database_migration',
136
+ 'destructive_command',
137
+ 'secret_access',
138
+ 'release',
139
+ 'cross_repository_change',
140
+ ]);
141
+ export const ALLOWED_APPROVAL_ACTIONS = new Set(['stop_and_request_approval']);
142
+ export const ALLOWED_ISOLATION_PREFERENCES = new Set(['none', 'git_worktree', 'sandbox']);
143
+ export const ALLOWED_REFRESH_MODES = new Set(['checkpoint']);
144
+ export const ALLOWED_REFRESH_METHODS = new Set(['hash_check', 'reread_if_changed']);
145
+ export const ALLOWED_REFRESH_STATE_STORES = new Set(['none', 'cache']);
146
+ export const ALLOWED_COMPACTION_STRATEGIES = new Set(['tiered']);
147
+ export const ALLOWED_COMPACTION_STATE_STORES = new Set(['none', 'cache']);
148
+ export const ALLOWED_COMPACTION_CATEGORIES = new Set([
149
+ 'decisions',
150
+ 'constraints',
151
+ 'open_questions',
152
+ 'files_discussed',
153
+ 'commands_discussed',
154
+ 'risks',
155
+ 'next_steps',
156
+ 'rejected_options',
157
+ ]);
158
+ export const ALLOWED_COMPACTION_LONG_LIMIT_ACTIONS = new Set(['recompact_oldest', 'delete_oldest', 'archive_oldest']);
159
+ export const ALLOWED_COMPACTION_RAW_LIMIT_ACTIONS = new Set(['prune_after_compaction', 'report']);
160
+ export const ALLOWED_REFRESH_CHECKPOINTS = new Set([
161
+ 'session_start',
162
+ 'task_start',
163
+ 'before_first_edit',
164
+ 'before_command_run',
165
+ 'after_instruction_file_change',
166
+ 'root_change',
167
+ 'after_compaction',
168
+ 'before_final_report',
169
+ ]);
170
+ export const ALLOWED_TRANSLATION_POLICIES = new Set([
171
+ 'source_only',
172
+ 'update_source_mark_targets_stale',
173
+ 'machine_translate_requires_review',
174
+ ]);
175
+ export const RAW_COMMAND_FENCE_PATTERN = /```(?:sh|bash|shell|zsh|powershell|ps1|cmd)\s+[\s\S]*?```/giu;
176
+ export const SKILL_COMMAND_PERMISSION_CLAIM_PATTERNS = [
177
+ /\b(?:this\s+skill|skill\s+documents?|skills?)\s+(?:authorizes?|grants?|allows?|permits?)\s+(?:agents?\s+)?(?:to\s+)?(?:run|execute)\b/iu,
178
+ /\b(?:agents?\s+)?(?:may|can|are\s+allowed\s+to|is\s+allowed\s+to|is\s+permitted\s+to|have\s+permission\s+to)\s+(?:run|execute)\s+(?:raw\s+)?(?:shell\s+)?commands?\b/iu,
179
+ /\bcommand\s+execution\s+(?:is\s+)?(?:authorized|allowed|permitted)\s+by\s+(?:this\s+)?skill\b/iu,
180
+ ];
181
+ export const ROUTER_INDEX_PROCEDURE_SECTION_PATTERN = /^##\s+(?:Use When|Do Not Use When|Required Inputs|Preconditions|Allowed Edits|Procedure|Postconditions|Verification|Failure Handling|Output Format|사용 조건|사용하지 않는 경우|필요한 입력|사전 조건|허용 수정 범위|절차|사후 조건|검증|실패 대응|출력 형식)\s*$/imu;
182
+ export const ROUTER_INDEX_FILES = ['.mustflow/skills/INDEX.md', '.mustflow/context/INDEX.md'];
183
+ export const SKILL_INDEX_PATH = '.mustflow/skills/INDEX.md';
184
+ export const SKILL_ROUTES_METADATA_PATH = '.mustflow/skills/routes.toml';
185
+ export const SUPPORTED_SKILL_SCHEMA_VERSION = '1';
186
+ export const SKILL_PACK_ID_PATTERN = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/u;
187
+ export const ALLOWED_SKILL_ROUTE_CATEGORIES = new Set(Object.keys(SKILL_ROUTE_CATEGORY_LABELS));
188
+ export const ALLOWED_SKILL_ROUTE_TYPES = new Set(['primary', 'adjunct', 'event', 'authoring']);
189
+ export const ALLOWED_SKILL_ROUTE_PROFILES = new Set(['minimal', 'patterns', 'oss', 'team', 'product', 'library']);
190
+ export const CONTEXT_AUTHORITY_DRIFT_PATTERNS = [
191
+ /^##\s+(?:Command Policy|Command Permissions|Allowed Commands|Denied Commands|File Edit Policy|Protected Paths|Forbidden Files|Execution Rules|Mandatory Rules|Binding Rules|명령 정책|명령 권한|허용 명령|금지 명령|파일 편집 정책|보호 경로|금지 파일|실행 규칙|필수 규칙)\s*$/imu,
192
+ /\b(?:must not|do not|never)\s+(?:edit|modify|write|delete)\s+(?:files?\s+)?(?:outside|under|inside|in)\b/iu,
193
+ ];
194
+ export const REPO_MAP_DOC_ID = 'repo-map';
195
+ export const REPO_MAP_LIFECYCLE = 'generated';
196
+ export const REPO_MAP_GENERATOR = 'mustflow';
197
+ export const REPO_MAP_RELATIVE_ROOT = '.';
198
+ export const REPO_MAP_SOURCE_POLICY = 'anchors_only';
199
+ export const REPO_MAP_PRIVACY_MODE = 'minimal';
200
+ export const REPO_MAP_SOURCE_FINGERPRINT_PATTERN = /^sha256:[a-f0-9]{64}$/u;
201
+ export const SKILL_RESOURCE_MANIFEST = 'resources.toml';
202
+ export const SKILL_RESOURCE_ROOTS = new Set(['references', 'assets', 'scripts']);
203
+ export const ALLOWED_SKILL_RESOURCE_TYPES = new Set(['reference', 'asset', 'script']);
204
+ export const SKILL_RESOURCE_TYPE_BY_ROOT = {
205
+ references: 'reference',
206
+ assets: 'asset',
207
+ scripts: 'script',
208
+ };
209
+ export const REQUIRED_SKILL_SCRIPT_RUN_POLICY = 'requires_command_contract';
210
+ export const VOLATILE_REPO_MAP_PATTERNS = [
211
+ /\bGenerated\s+(?:at|on):/iu,
212
+ /\bLast\s+updated:/iu,
213
+ /\bUpdated\s+at:/iu,
214
+ /\bgenerated_at\b/iu,
215
+ /\btimestamp\b/iu,
216
+ /\bfile\s+count\b/iu,
217
+ /\bchanged\s+files\b/iu,
218
+ ];
219
+ export const REPO_MAP_REMOTE_OR_BRANCH_PATTERNS = [
220
+ /https?:\/\//iu,
221
+ /\bgit@/iu,
222
+ /^\s*(?:Remote|Branch):/imu,
223
+ ];
224
+ export const LOCAL_ABSOLUTE_PATH_PATTERNS = [
225
+ /\b[A-Za-z]:\\(?:Users|Documents and Settings)\\/iu,
226
+ /(?:^|[\s"'(])\/(?:Users|home)\/[A-Za-z0-9._-]+\/[^\s)"']*/imu,
227
+ ];
228
+ export const SECRET_LIKE_CONTEXT_PATTERNS = [
229
+ /\b(?:api[_-]?key|api[_-]?token|access[_-]?token|auth[_-]?token|secret|password|passwd|private[_-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_./+=:-]{8,}/iu,
230
+ /\b(?:sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|AKIA[0-9A-Z]{16})\b/u,
231
+ ];
232
+ export const DESIGN_TOKEN_DEFINITION_PATTERNS = [
233
+ /^\s*(?:colors?|palette|spacing|radius|radii|typography|fonts?|shadows?|breakpoints?)\s*[:=]\s*(?:\{|\[|["']?#|\d)/imu,
234
+ /^\s*(?:primary|secondary|accent|background|foreground|surface|brand|text|muted)\s*[:=]\s*["']?#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})\b/imu,
235
+ /^\s*--[a-z0-9-]+:\s*[^;]+;/imu,
236
+ /^\s*(?:border[_-]?radius|font[_-]?(?:family|size)|line[_-]?height|space[-_]\d+)\s*[:=]\s*/imu,
237
+ ];
238
+ export const LOCAL_TASK_STATE_ROOTS = new Set(['worklogs', 'plans', 'tasks', 'work-items']);