feat(skill-learning): merge plugin skill updates
This commit is contained in:
@ -109,6 +109,77 @@ class PluginManager:
|
||||
results[state.plugin_id] = self._sync_plugin(state, manifest)
|
||||
return results
|
||||
|
||||
def pause(self, plugin_id: str) -> PluginState:
|
||||
with self.write_lock.acquire(timeout_seconds=10):
|
||||
state = self._require_state(plugin_id)
|
||||
state.updates_paused = True
|
||||
self.state_store.upsert_plugin(state)
|
||||
return state
|
||||
|
||||
def resume(self, plugin_id: str) -> PluginState:
|
||||
with self.write_lock.acquire(timeout_seconds=10):
|
||||
state = self._require_state(plugin_id)
|
||||
state.updates_paused = False
|
||||
self.state_store.upsert_plugin(state)
|
||||
return self.sync_enabled().get(plugin_id) or self._require_state(plugin_id)
|
||||
|
||||
def disable(self, plugin_id: str, *, disable_linked_skills: bool) -> PluginState:
|
||||
if not disable_linked_skills:
|
||||
raise ValueError("disable_linked_skills confirmation is required")
|
||||
with self.write_lock.acquire(timeout_seconds=10):
|
||||
state = self._require_state(plugin_id)
|
||||
for skill_name in list(state.skills):
|
||||
self.publisher.disable(skill_name, actor="plugin-manager", reason=f"plugin_disabled:{plugin_id}")
|
||||
state.skills[skill_name].status = "disabled"
|
||||
state.enabled = False
|
||||
state.updates_paused = True
|
||||
state.status = "disabled"
|
||||
self.state_store.upsert_plugin(state)
|
||||
return state
|
||||
|
||||
def adopt(self, plugin_id: str, skill_name: str) -> SkillSpec:
|
||||
with self.write_lock.acquire(timeout_seconds=10):
|
||||
state = self._require_state(plugin_id)
|
||||
if skill_name not in state.skills:
|
||||
raise ValueError(f"Plugin skill binding not found: {plugin_id}/{skill_name}")
|
||||
spec = self.skill_store.get_skill_spec(skill_name)
|
||||
if spec is None:
|
||||
raise ValueError(f"Skill spec not found: {skill_name}")
|
||||
spec.source_kind = "managed"
|
||||
spec.status = SkillStatus.ACTIVE.value
|
||||
spec.updated_at = _utc_now()
|
||||
marker = f"adopted_from_plugin:{plugin_id}"
|
||||
if marker not in spec.lineage:
|
||||
spec.lineage.append(marker)
|
||||
self.skill_store.write_skill_spec(spec)
|
||||
del state.skills[skill_name]
|
||||
if not state.skills:
|
||||
state.status = "adopted"
|
||||
state.enabled = False
|
||||
self.state_store.upsert_plugin(state)
|
||||
self.publisher._refresh_indexes(skill_name, spec.status)
|
||||
return spec
|
||||
|
||||
def on_skill_published(self, draft: SkillDraft, published: SkillVersion | SkillSpec) -> None:
|
||||
if draft.proposal_kind != "plugin_skill_update" or not isinstance(published, SkillVersion):
|
||||
return
|
||||
plugin_id = str(draft.provenance.get("plugin_id") or "")
|
||||
skill_name = str(draft.provenance.get("skill_name") or draft.skill_name)
|
||||
tree_hash = str(draft.provenance.get("new_upstream_tree_hash") or "")
|
||||
if not plugin_id or not skill_name or not tree_hash:
|
||||
raise ValueError("Plugin publish acknowledgement is missing provenance")
|
||||
state = self._require_state(plugin_id)
|
||||
binding = state.skills.get(skill_name) or PluginSkillBinding()
|
||||
binding.accepted_upstream_tree_hash = tree_hash
|
||||
binding.observed_upstream_tree_hash = tree_hash
|
||||
binding.accepted_beaver_version = published.version
|
||||
binding.current_beaver_version = published.version
|
||||
binding.pending_candidate_id = None
|
||||
binding.status = "synced"
|
||||
state.skills[skill_name] = binding
|
||||
state.status = "synced"
|
||||
self.state_store.upsert_plugin(state)
|
||||
|
||||
def _prepare_initial_mirror(
|
||||
self,
|
||||
manifest: PluginManifest,
|
||||
@ -174,6 +245,12 @@ class PluginManager:
|
||||
)
|
||||
return prepared
|
||||
|
||||
def _require_state(self, plugin_id: str) -> PluginState:
|
||||
state = self.state_store.get_plugin(plugin_id)
|
||||
if state is None:
|
||||
raise ValueError(f"Unknown plugin state: {plugin_id}")
|
||||
return state
|
||||
|
||||
def _sync_plugin(self, state: PluginState, manifest: PluginManifest) -> PluginState:
|
||||
transaction = PluginSkillTransaction(self.workspace)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user