hive-lite 0.1.3 → 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.
package/src/lib/map.js CHANGED
@@ -331,10 +331,14 @@ function summarizeFindContext(context) {
331
331
  },
332
332
  warnings: context.warnings || [],
333
333
  reviewGated: context.reviewGated || (context.explain && context.explain.reviewGated) || [],
334
+ writePlan: context.writePlan || (context.explain && context.explain.writePlan) || null,
334
335
  candidateAreas: context.candidateAreas || [],
335
336
  areaScores: context.explain && context.explain.areaScores ? context.explain.areaScores : [],
336
337
  scopeQuality: scope.quality || (context.explain ? context.explain.scopeQuality : 'unknown'),
337
338
  writableDirect: scope.writableDirect || context.writableScope || [],
339
+ selectedWritableScope: context.writableScope || [],
340
+ writableExisting: scope.writableExisting || [],
341
+ writableCreatePatterns: scope.writableCreatePatterns || [],
338
342
  writableConditional: scope.writableConditional || [],
339
343
  writableBroadFallback: scope.writableBroadFallback || [],
340
344
  forbidden: scope.forbidden || context.doNotTouch || [],
@@ -431,6 +435,12 @@ function repairFocusFromFind(findContext, userFocus) {
431
435
  if (isGenericAreaId(area)) goals.push(`replace generic area id with a focused id such as ${suggestedArea}`);
432
436
  if (warnings.includes('BROAD_WRITABLE_SCOPE')) goals.push('move broad writable scope to reviewed fallback');
433
437
  if (warnings.includes('MISSING_DIRECT_WRITABLE_SCOPE')) goals.push('add narrow writable_direct files');
438
+ if (warnings.includes('MISSING_DIRECT_NEW_FILE_SCOPE')) goals.push('add narrow writable_direct patterns or exact paths for the new peer files this intent must create');
439
+ if (warnings.includes('DIRECT_ONLY_REFERENCE_PEERS')) goals.push('move peer examples out of selected direct scope and add target create capability');
440
+ if (warnings.includes('BROAD_FALLBACK_ONLY')) goals.push('replace broad fallback-only coverage with narrow direct create capability');
441
+ if (warnings.includes('TARGET_ENTITY_MISMATCH')) goals.push('add direct scope for the requested target identity or mark old peers as references');
442
+ if (warnings.includes('MISSING_ARTIFACT_FAMILY_SCOPE')) goals.push('add writable_create_patterns for required artifact families');
443
+ if (warnings.includes('MISSING_REQUIRED_HOOK_SCOPE')) goals.push('add writable_existing hook files required by the artifact family');
434
444
  if (warnings.includes('MISSING_ENTRYPOINT')) goals.push('add durable entrypoints');
435
445
  if (warnings.includes('MISSING_VALIDATION')) goals.push('add validation profile references');
436
446
  if (warnings.includes('NO_CONFIDENT_AREA')) goals.push('create or refine a focused area');
@@ -464,6 +474,15 @@ function findContextPromptSection(findContext) {
464
474
  'Review-gated scope from find:',
465
475
  ...listLines(findContext.reviewGated, (notice) => `- ${notice.code}: ${notice.message}`),
466
476
  '',
477
+ ...(findContext.writePlan ? [
478
+ 'Write plan from find:',
479
+ ...listLines(findContext.writePlan.hypotheses || [], (item) => `- ${item.action} ${item.artifactFamily}: ${item.operation}${item.targetIdentity ? ` for ${item.targetIdentity}` : ''}`),
480
+ 'Write plan blocking warnings:',
481
+ ...listLines(findContext.writePlan.blockingWarnings || [], (item) => `- ${item.code}: ${item.message}`),
482
+ 'Reference files from write plan:',
483
+ ...listLines(findContext.writePlan.referenceFiles || [], (file) => `- ${file.path}: ${file.reason || ''}`),
484
+ '',
485
+ ] : []),
467
486
  'Candidate/area scores:',
468
487
  ...listLines(findContext.areaScores.length ? findContext.areaScores : findContext.candidateAreas, (area) => {
469
488
  const signals = area.signals && area.signals.length ? ` (${area.signals.slice(0, 3).join(', ')})` : '';
@@ -476,6 +495,15 @@ function findContextPromptSection(findContext) {
476
495
  'Current direct writable scope:',
477
496
  ...listLines(findContext.writableDirect, patternLine),
478
497
  '',
498
+ 'Selected direct writable scope for this intent:',
499
+ ...listLines(findContext.selectedWritableScope, patternLine),
500
+ '',
501
+ 'Current writable existing scope:',
502
+ ...listLines(findContext.writableExisting, patternLine),
503
+ '',
504
+ 'Current writable create patterns:',
505
+ ...listLines(findContext.writableCreatePatterns, patternLine),
506
+ '',
479
507
  'Current conditional writable scope:',
480
508
  ...listLines(findContext.writableConditional, patternLine),
481
509
  '',
@@ -541,6 +569,9 @@ function buildMapPrompt(result) {
541
569
  '- Every `writable_conditional` and `writable_broad_fallback` item must set `requires_review: true`; never output `requires_review: false` for those tiers.',
542
570
  '- Keep broad patterns like `apps/*/src/**` only under `writable_broad_fallback`, never under `writable_direct`.',
543
571
  '- `writable_direct` should use exact existing files unless there is a very small, justified pattern.',
572
+ '- Prefer `writable_existing` for exact update targets and `writable_create_patterns` for new peer files when a repo has create/update distinctions.',
573
+ '- Put copy sources and peer examples under `readable_reference`, not under selected Direct Writable for new peer intents.',
574
+ '- Use `artifact_families` to declare required create artifacts and hook files for provider/adapter/endpoint families.',
544
575
  '- Entrypoint roles must use this fixed taxonomy only: ' + roleListText() + '.',
545
576
  '- Do not invent role names. If unsure, use `role: unknown` plus a TODO note.',
546
577
  '- Add `source` and `confidence` to entrypoints when possible. Use `source: agent_draft` for your own draft and `confidence: low|medium|high`.',
@@ -594,8 +625,27 @@ function buildMapPrompt(result) {
594
625
  ' scope:',
595
626
  ' readable:',
596
627
  ' - path/to/read/**',
628
+ ' readable_reference:',
629
+ ' peer_examples:',
630
+ ' - path: path/to/ExistingPeer.ts',
631
+ ' artifact: service_impl',
632
+ ' peer_identity: Existing',
597
633
  ' writable_direct:',
598
634
  ' - path/to/real/file.ts',
635
+ ' writable_existing:',
636
+ ' - path: path/to/Registry.ts',
637
+ ' artifact: registry_hook',
638
+ ' operations:',
639
+ ' - update_existing',
640
+ ' required_when:',
641
+ ' - add_provider_proxy',
642
+ ' writable_create_patterns:',
643
+ ' - pattern: path/to/*Provider.ts',
644
+ ' artifact: service_impl',
645
+ ' operations:',
646
+ ' - create_file',
647
+ ' intent_kinds:',
648
+ ' - add_provider_proxy',
599
649
  ' writable_conditional:',
600
650
  ' - pattern: path/to/shared/**',
601
651
  ' reason: only if shared model changes are required',
@@ -623,6 +673,19 @@ function buildMapPrompt(result) {
623
673
  ' default_level: low',
624
674
  ' tags:',
625
675
  ' - ui',
676
+ ' artifact_families:',
677
+ ' provider_proxy:',
678
+ ' trigger_terms:',
679
+ ' en:',
680
+ ' - provider',
681
+ ' - proxy',
682
+ ' zh:',
683
+ ' - 提供商',
684
+ ' - 代理',
685
+ ' create_requires:',
686
+ ' - service_impl',
687
+ ' hooks:',
688
+ ' - registry_hook',
626
689
  '```',
627
690
  '',
628
691
  'Validation profile schema example:',
package/src/lib/next.js CHANGED
@@ -162,21 +162,21 @@ function applySkillPreflight(root, options, current) {
162
162
  ...current,
163
163
  phaseGuess: 'skill_preflight',
164
164
  primaryAction: action({
165
- kind: 'install_operator_skill',
166
- label: `Install ${preflight.requiredSkill}`,
167
- command: preflight.installCommand,
168
- explanation: 'The recommended next operator step requires this Hive Lite skill in the selected agent target.',
165
+ kind: 'sync_operator_skill',
166
+ label: `Sync ${preflight.requiredSkill}`,
167
+ command: preflight.syncCommand,
168
+ explanation: 'The recommended next operator step requires a current Hive Lite skill in the selected agent target.',
169
169
  }),
170
170
  secondaryActions: [
171
171
  action({
172
172
  ...blockedAction,
173
173
  enabled: false,
174
- disabledReason: `Install ${preflight.requiredSkill} first for the selected agent target.`,
174
+ disabledReason: `Sync ${preflight.requiredSkill} first for the selected agent target.`,
175
175
  }),
176
176
  ...current.secondaryActions,
177
177
  ],
178
- summaryForHuman: `需要先安装 ${preflight.requiredSkill},然后再继续 Hive Lite operator flow。`,
179
- summaryForAgent: `The selected agent target is missing ${preflight.requiredSkill}. Run skills install before using the handoff skill.`,
178
+ summaryForHuman: `需要先同步 ${preflight.requiredSkill},然后再继续 Hive Lite operator flow。`,
179
+ summaryForAgent: `The selected agent target is missing or has a stale ${preflight.requiredSkill}. Run skills sync before using the handoff skill.`,
180
180
  operatorSkillPreflight: preflight,
181
181
  };
182
182
  }
@@ -238,10 +238,10 @@ function evaluateNextAction(cwd, options = {}) {
238
238
  kind: 'run_bootstrap_skill',
239
239
  label: 'Use hive-lite-bootstrap',
240
240
  prompt: bootstrapPrompt(),
241
- explanation: 'This git repository has not been initialized for Hive Lite. Use the bootstrap skill to initialize, build the first Project Map, and prepare the setup/map commit before product work starts.',
241
+ explanation: 'This git repository is missing required Hive Lite setup files. Use the bootstrap skill to initialize or repair setup, build the first Project Map when needed, and prepare the setup/map commit before product work starts.',
242
242
  });
243
- summaryForHuman = '当前项目还没有初始化 Hive Lite。建议使用 hive-lite-bootstrap 完成首次接入:初始化、建立第一版 Project Map,并在开始第一个需求前准备 setup/map 提交。';
244
- summaryForAgent = 'Hive Lite is not initialized. Stop ordinary start/finish/map-maintainer workflows and hand off to hive-lite-bootstrap.';
243
+ summaryForHuman = '当前项目缺少 Hive Lite setup 文件。建议使用 hive-lite-bootstrap 完成首次接入或 setup 修复,并在开始第一个需求前准备 setup/map 提交。';
244
+ summaryForAgent = 'Hive Lite setup is missing or incomplete. Stop ordinary start/finish/map-maintainer workflows and hand off to hive-lite-bootstrap.';
245
245
  } else if (!workspace.canStartNewRequirement) {
246
246
  if (workspace.hive.state === 'in_progress') {
247
247
  phaseGuess = 'finish';
package/src/lib/risk.js CHANGED
@@ -54,6 +54,11 @@ function evaluateChangeRisk(change, map) {
54
54
  if (change.scope.status === 'violation') {
55
55
  blockingReasons.push(`scope violation: ${change.scope.violations.join(', ')}`);
56
56
  }
57
+ if (change.writePlanStatus && change.writePlanStatus.status === 'blocked') {
58
+ for (const reason of change.writePlanStatus.blockingReasons || []) {
59
+ blockingReasons.push(`write plan blocked: ${reason}`);
60
+ }
61
+ }
57
62
 
58
63
  const status = validationStatus(change);
59
64
  if (status === 'failed') blockingReasons.push('validation failed');
package/src/lib/scope.js CHANGED
@@ -12,6 +12,12 @@ function patternFrom(value) {
12
12
  return normalizePath((value.pattern || value.path || '').trim());
13
13
  }
14
14
 
15
+ function arrayFrom(value) {
16
+ if (Array.isArray(value)) return value.map((item) => String(item || '')).filter(Boolean);
17
+ if (value == null || value === '') return [];
18
+ return [String(value)];
19
+ }
20
+
15
21
  function normalizePattern(value, defaults = {}) {
16
22
  const pattern = patternFrom(value);
17
23
  if (!pattern) return null;
@@ -22,6 +28,13 @@ function normalizePattern(value, defaults = {}) {
22
28
  requiresReview: defaults.requiresReview === true,
23
29
  source: defaults.source || 'map',
24
30
  matchCount: defaults.matchCount == null ? null : defaults.matchCount,
31
+ artifact: defaults.artifact || null,
32
+ artifactFamily: defaults.artifactFamily || null,
33
+ operations: arrayFrom(defaults.operations),
34
+ targetIdentity: defaults.targetIdentity || null,
35
+ targetSlot: defaults.targetSlot || null,
36
+ intentKinds: arrayFrom(defaults.intentKinds),
37
+ requiredWhen: arrayFrom(defaults.requiredWhen),
25
38
  };
26
39
  }
27
40
  return {
@@ -30,6 +43,13 @@ function normalizePattern(value, defaults = {}) {
30
43
  requiresReview: value.requires_review === true || value.requiresReview === true || defaults.requiresReview === true,
31
44
  source: value.source || defaults.source || 'map',
32
45
  matchCount: value.matchCount == null ? (defaults.matchCount == null ? null : defaults.matchCount) : value.matchCount,
46
+ artifact: value.artifact || defaults.artifact || null,
47
+ artifactFamily: value.artifact_family || value.artifactFamily || defaults.artifactFamily || null,
48
+ operations: arrayFrom(value.operations || value.operation || defaults.operations),
49
+ targetIdentity: value.target_identity || value.targetIdentity || value.peer_identity || value.peerIdentity || defaults.targetIdentity || null,
50
+ targetSlot: value.target_slot || value.targetSlot || defaults.targetSlot || null,
51
+ intentKinds: arrayFrom(value.intent_kinds || value.intentKinds || defaults.intentKinds),
52
+ requiredWhen: arrayFrom(value.required_when || value.requiredWhen || defaults.requiredWhen),
33
53
  };
34
54
  }
35
55
 
@@ -93,29 +113,119 @@ function splitDirectAndBroad(root, values, defaults = {}) {
93
113
  return { direct, broad };
94
114
  }
95
115
 
116
+ function splitItemsAndBroad(root, values, defaults = {}) {
117
+ const direct = [];
118
+ const broad = [];
119
+ for (const value of values || []) {
120
+ const pattern = patternFrom(value);
121
+ if (!pattern) continue;
122
+ const classification = isBroadPattern(root, pattern);
123
+ const item = normalizePattern(value, {
124
+ ...defaults,
125
+ matchCount: classification.matchCount,
126
+ });
127
+ if (!item) continue;
128
+ if (classification.broad) {
129
+ broad.push({
130
+ ...item,
131
+ reason: item.reason || classification.reason || 'broad writable scope',
132
+ requiresReview: true,
133
+ });
134
+ } else {
135
+ direct.push(item);
136
+ }
137
+ }
138
+ return { direct, broad };
139
+ }
140
+
141
+ function flattenReferenceValues(value) {
142
+ if (!value) return [];
143
+ if (Array.isArray(value)) return value;
144
+ if (typeof value === 'object' && (value.path || value.pattern)) return [value];
145
+ if (typeof value === 'object') {
146
+ return Object.values(value).flatMap((item) => flattenReferenceValues(item));
147
+ }
148
+ return [value];
149
+ }
150
+
151
+ function normalizeReference(value, defaults = {}) {
152
+ const pattern = patternFrom(value);
153
+ if (!pattern) return null;
154
+ if (typeof value === 'string') {
155
+ return {
156
+ path: pattern,
157
+ reason: defaults.reason || '',
158
+ role: defaults.role || 'reference',
159
+ artifact: defaults.artifact || null,
160
+ artifactFamily: defaults.artifactFamily || null,
161
+ peerIdentity: defaults.peerIdentity || null,
162
+ source: defaults.source || 'readable_reference',
163
+ };
164
+ }
165
+ return {
166
+ path: pattern,
167
+ reason: value.reason || defaults.reason || '',
168
+ role: value.role || defaults.role || 'reference',
169
+ artifact: value.artifact || defaults.artifact || null,
170
+ artifactFamily: value.artifact_family || value.artifactFamily || defaults.artifactFamily || null,
171
+ peerIdentity: value.peer_identity || value.peerIdentity || value.provider || defaults.peerIdentity || null,
172
+ source: value.source || defaults.source || 'readable_reference',
173
+ };
174
+ }
175
+
176
+ function normalizeReferenceList(value, defaults = {}) {
177
+ return flattenReferenceValues(value).map((item) => normalizeReference(item, defaults)).filter(Boolean);
178
+ }
179
+
96
180
  function normalizeAreaScope(root, area = {}) {
97
181
  const configured = area.scope || {};
98
182
  const readable = (configured.readable || area.readable_scope || []).map(patternFrom).filter(Boolean);
183
+ const readableReference = normalizeReferenceList(configured.readable_reference || area.readable_reference || [], {
184
+ source: 'readable_reference',
185
+ });
99
186
  const forbidden = (configured.forbidden || area.do_not_touch || []).map(patternFrom).filter(Boolean);
100
187
 
101
188
  const directValues = configured.writable_direct || [];
189
+ const existingValues = configured.writable_existing || [];
190
+ const createValues = configured.writable_create_patterns || [];
102
191
  const conditionalValues = configured.writable_conditional || [];
103
192
  const broadValues = configured.writable_broad_fallback || [];
104
193
  const legacyWritable = !area.scope ? (area.writable_scope || []) : [];
105
194
 
106
- const directSplit = splitDirectAndBroad(root, directValues, { source: 'writable_direct' });
195
+ const directSplit = splitItemsAndBroad(root, directValues, { source: 'writable_direct' });
196
+ const existingSplit = splitItemsAndBroad(root, existingValues, {
197
+ source: 'writable_existing',
198
+ operations: ['update_existing'],
199
+ });
200
+ const createSplit = splitItemsAndBroad(root, createValues, {
201
+ source: 'writable_create_patterns',
202
+ operations: ['create_file'],
203
+ });
107
204
  const legacySplit = splitDirectAndBroad(root, legacyWritable, {
108
205
  source: 'legacy_writable_scope',
109
206
  reason: 'legacy writable_scope is broad; move this to scope.writable_broad_fallback or add writable_direct',
110
207
  });
111
208
 
112
- const writableDirect = [...directSplit.direct, ...legacySplit.direct];
209
+ const legacyDirectItems = legacySplit.direct.map((pattern) => normalizePattern(pattern, {
210
+ source: 'legacy_writable_scope',
211
+ })).filter(Boolean);
212
+ const writableDirectItems = [
213
+ ...directSplit.direct,
214
+ ...existingSplit.direct,
215
+ ...createSplit.direct,
216
+ ...legacyDirectItems,
217
+ ];
218
+ const writableDirect = writableDirectItems.map((item) => item.pattern);
219
+ const writableExisting = existingSplit.direct;
220
+ const writableCreatePatterns = createSplit.direct;
113
221
  const writableConditional = normalizePatternList(conditionalValues, {
114
222
  source: 'writable_conditional',
115
223
  requiresReview: true,
116
224
  });
117
225
  const writableBroadFallback = [
118
226
  ...directSplit.broad,
227
+ ...existingSplit.broad,
228
+ ...createSplit.broad,
119
229
  ...normalizePatternList(broadValues, {
120
230
  source: 'writable_broad_fallback',
121
231
  requiresReview: true,
@@ -139,7 +249,11 @@ function normalizeAreaScope(root, area = {}) {
139
249
 
140
250
  return {
141
251
  readable,
252
+ readableReference,
142
253
  writableDirect,
254
+ writableDirectItems,
255
+ writableExisting,
256
+ writableCreatePatterns,
143
257
  writableConditional,
144
258
  writableBroadFallback,
145
259
  forbidden,
@@ -164,5 +278,6 @@ module.exports = {
164
278
  itemPattern,
165
279
  normalizeAreaScope,
166
280
  normalizePatternList,
281
+ normalizeReferenceList,
167
282
  patternDisplay,
168
283
  };
package/src/lib/skills.js CHANGED
@@ -215,11 +215,11 @@ function targetSelection(options = {}, command = 'doctor') {
215
215
  };
216
216
  }
217
217
 
218
- function installCommandForOptions(options = {}) {
219
- if (options.path && options.path !== true) return `hive-lite skills install --path ${options.path}`;
220
- if (options.agent && options.agent !== true) return `hive-lite skills install --agent ${options.agent}`;
221
- if (options.all) return 'hive-lite skills install --agent all';
222
- return 'hive-lite skills install --agent <codex|claude|gemini>';
218
+ function syncCommandForOptions(options = {}) {
219
+ if (options.path && options.path !== true) return `hive-lite skills sync --path ${options.path}`;
220
+ if (options.agent && options.agent !== true) return `hive-lite skills sync --agent ${options.agent}`;
221
+ if (options.all) return 'hive-lite skills sync --agent all';
222
+ return 'hive-lite skills sync --agent all';
223
223
  }
224
224
 
225
225
  function skillPreflight(cwd, skillName, options = {}) {
@@ -246,7 +246,7 @@ function skillPreflight(cwd, skillName, options = {}) {
246
246
  requiredSkill: skillName,
247
247
  targetSelection: targetSelection(options, 'doctor'),
248
248
  ready: targets.length > 0 && targets.every((target) => target.status === 'current'),
249
- installCommand: installCommandForOptions(options),
249
+ syncCommand: syncCommandForOptions(options),
250
250
  targets,
251
251
  };
252
252
  }
package/src/lib/status.js CHANGED
@@ -226,8 +226,8 @@ function actionsFor(state, latestId, diffMatches) {
226
226
  }
227
227
  if (state === 'hive_init_required') {
228
228
  return [
229
- action('run_hive_init', 'Run Hive Lite init', 'hive-lite init', 'Initialize Hive Lite setup files before using Hive Lite skills.'),
230
- action('stop', 'Stop', null, 'Do not run start, finish, or map-maintainer skills until Hive Lite has been initialized.'),
229
+ action('run_bootstrap_skill', 'Use hive-lite-bootstrap', '$hive-lite-bootstrap', 'Use the first-time setup or setup repair skill before ordinary start, finish, or map-maintainer workflows.'),
230
+ action('stop', 'Stop', null, 'Do not run start, finish, or map-maintainer skills until Hive Lite setup is complete.'),
231
231
  ];
232
232
  }
233
233
  if (state === 'clean') {
@@ -314,7 +314,7 @@ function evaluateWorkspaceStatus(cwd, options = {}) {
314
314
 
315
315
  if (!initialized) {
316
316
  state = 'hive_init_required';
317
- reason = 'Hive Lite is not initialized in this git repository. Use $hive-lite-bootstrap for first-time setup, or run hive-lite init as the low-level fallback.';
317
+ reason = 'Hive Lite setup is missing or incomplete in this git repository. Use $hive-lite-bootstrap for first-time setup or setup repair.';
318
318
  } else if (dirty && latest.change) {
319
319
  if (accepted(latest.change) && !committed(latest.change) && diffMatches) {
320
320
  state = 'accepted_uncommitted';