mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-08 08:53:43 +08:00
fix(install): migrate v0.10.8 OpenCode agent profiles on upgrade (#2264)
Upgrading from v0.10.8 to v0.11.0 on a machine with OpenCode reported all
three OpenCode subagent profiles as "preserved modified profile" plus an
op=agent_install error each, and the activation stopped ("one or more agent
configurations failed; the published/current executable was kept"), although
nobody had edited those files.
Root cause: #1933 (v0.11.0) added the tool_search / tool_search_regex
permissions to the rendered OpenCode profile. Install and uninstall recognise
a profile as ours only when it matches the current rendering or one of the
known released renderings (the other access mode, the v0.9.1-rc.1 Codex
shape, the pre-tier Verify file). The v0.10.8 OpenCode shape was not in that
set, so cbm_text_migrate_owned_document classified the untouched v0.10.8
files as user-modified. Reproduced end to end: install with the v0.10.8
release binary, then install with v0.11.0/main, into an isolated HOME; the
three profiles are 1729/1880/1910 bytes, the same sizes as in the report.
cbm_render_graph_profile_opencode_v0108() renders the pre-#1933 shape
(both access modes), and install/uninstall now list it as a released
rendering, so those files are upgraded in place and uninstall removes them
as owned. A profile the user actually edited is still preserved. The
released-list assembly that install and uninstall duplicated moves into one
helper, and the two legacy renderers share one implementation (cli.c drops
three raw free sites; the memory-core baseline is tightened 173 -> 170).
The Codex and OpenCode op=mcp_install errors in the same report do not
reproduce from a pristine v0.10.8 config and depend on the reporter's own
config.toml / opencode.json; they are not addressed here.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
+35
-15
@@ -498,6 +498,23 @@ static bool append_codex_profile(profile_buffer_t *buffer, cbm_graph_tier_t tier
|
||||
profile_buffer_append(buffer, "]\n");
|
||||
}
|
||||
|
||||
/* before_tool_search reproduces the v0.10.8 rendering: #1933 (v0.11.0) added
|
||||
* the tool_search / tool_search_regex permissions, and install/uninstall
|
||||
* must still recognise the older bytes as ours (#2264). */
|
||||
static bool append_opencode_profile(profile_buffer_t *buffer, cbm_graph_tier_t tier,
|
||||
cbm_graph_access_t access, const char *prompt,
|
||||
bool before_tool_search) {
|
||||
return profile_buffer_append(buffer, "---\ndescription: ") &&
|
||||
profile_buffer_append(buffer, profile_description(tier, access)) &&
|
||||
profile_buffer_append(buffer, "\nmode: subagent\npermission:\n \"*\": deny\n read: "
|
||||
"allow\n grep: allow\n glob: allow\n") &&
|
||||
(before_tool_search ||
|
||||
profile_buffer_append(buffer, " tool_search: allow\n tool_search_regex: allow\n")) &&
|
||||
(access != CBM_GRAPH_ACCESS_DIRECT ||
|
||||
append_permission_mcp_tools(buffer, CBM_GRAPH_DIALECT_OPENCODE, tier)) &&
|
||||
profile_buffer_append(buffer, "---\n") && profile_buffer_append(buffer, prompt);
|
||||
}
|
||||
|
||||
static bool render_profile_text(profile_buffer_t *buffer, cbm_graph_profile_dialect_t dialect,
|
||||
cbm_graph_tier_t tier, cbm_graph_access_t access,
|
||||
const char *binary_path, const char *prompt) {
|
||||
@@ -547,17 +564,7 @@ static bool render_profile_text(profile_buffer_t *buffer, cbm_graph_profile_dial
|
||||
}
|
||||
return true;
|
||||
case CBM_GRAPH_DIALECT_OPENCODE:
|
||||
if (!profile_buffer_append(buffer, "---\ndescription: ") ||
|
||||
!profile_buffer_append(buffer, description) ||
|
||||
!profile_buffer_append(
|
||||
buffer, "\nmode: subagent\npermission:\n \"*\": deny\n read: allow\n grep: "
|
||||
"allow\n glob: allow\n tool_search: allow\n tool_search_regex: "
|
||||
"allow\n") ||
|
||||
(direct && !append_permission_mcp_tools(buffer, dialect, tier)) ||
|
||||
!profile_buffer_append(buffer, "---\n") || !profile_buffer_append(buffer, prompt)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return append_opencode_profile(buffer, tier, access, prompt, false);
|
||||
case CBM_GRAPH_DIALECT_KILO:
|
||||
if (!profile_buffer_append(buffer, "---\ndescription: ") ||
|
||||
!profile_buffer_append(buffer, description) ||
|
||||
@@ -711,17 +718,22 @@ char *cbm_render_graph_profile(cbm_graph_profile_dialect_t dialect, cbm_graph_ti
|
||||
return profile_buffer_finish(&buffer);
|
||||
}
|
||||
|
||||
char *cbm_render_graph_profile_codex_rc1(cbm_graph_tier_t tier) {
|
||||
if (!tier_valid(tier)) {
|
||||
/* A released-but-superseded rendering, kept only so install/uninstall can
|
||||
* recognise and migrate files an older release wrote. */
|
||||
static char *render_released_profile(cbm_graph_profile_dialect_t dialect, cbm_graph_tier_t tier,
|
||||
cbm_graph_access_t access) {
|
||||
if (!tier_valid(tier) || !access_valid(access)) {
|
||||
return NULL;
|
||||
}
|
||||
char *prompt = cbm_render_graph_prompt(tier, CBM_GRAPH_ACCESS_DIRECT);
|
||||
char *prompt = cbm_render_graph_prompt(tier, access);
|
||||
if (!prompt) {
|
||||
return NULL;
|
||||
}
|
||||
profile_buffer_t buffer;
|
||||
profile_buffer_init(&buffer);
|
||||
bool ok = append_codex_profile(&buffer, tier, CBM_GRAPH_ACCESS_DIRECT, NULL, prompt, true);
|
||||
bool ok = dialect == CBM_GRAPH_DIALECT_OPENCODE
|
||||
? append_opencode_profile(&buffer, tier, access, prompt, true)
|
||||
: append_codex_profile(&buffer, tier, access, NULL, prompt, true);
|
||||
free(prompt);
|
||||
if (!ok) {
|
||||
profile_buffer_discard(&buffer);
|
||||
@@ -729,3 +741,11 @@ char *cbm_render_graph_profile_codex_rc1(cbm_graph_tier_t tier) {
|
||||
}
|
||||
return profile_buffer_finish(&buffer);
|
||||
}
|
||||
|
||||
char *cbm_render_graph_profile_opencode_v0108(cbm_graph_tier_t tier, cbm_graph_access_t access) {
|
||||
return render_released_profile(CBM_GRAPH_DIALECT_OPENCODE, tier, access);
|
||||
}
|
||||
|
||||
char *cbm_render_graph_profile_codex_rc1(cbm_graph_tier_t tier) {
|
||||
return render_released_profile(CBM_GRAPH_DIALECT_CODEX, tier, CBM_GRAPH_ACCESS_DIRECT);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ char *cbm_render_graph_profile(cbm_graph_profile_dialect_t dialect, cbm_graph_ti
|
||||
* so install/uninstall can recognize and migrate those files. */
|
||||
char *cbm_render_graph_profile_codex_rc1(cbm_graph_tier_t tier);
|
||||
|
||||
/* v0.10.8 OpenCode rendering (before the tool_search permissions of #1933),
|
||||
* kept so install/uninstall can recognize and migrate those files (#2264). */
|
||||
char *cbm_render_graph_profile_opencode_v0108(cbm_graph_tier_t tier, cbm_graph_access_t access);
|
||||
|
||||
/* Vibe stores the behavioral prompt separately from its TOML agent definition.
|
||||
* Other integrations may also use this as the canonical contract text. */
|
||||
char *cbm_render_graph_prompt(cbm_graph_tier_t tier, cbm_graph_access_t access);
|
||||
|
||||
+60
-46
@@ -8717,6 +8717,54 @@ static cbm_graph_access_t cbm_tiered_profile_set_access(cbm_tiered_profile_set_t
|
||||
: CBM_GRAPH_ACCESS_HANDOFF;
|
||||
}
|
||||
|
||||
/* Every earlier rendering of one tier's profile that install/uninstall must
|
||||
* still recognise as ours: the other access mode, the v0.9.1-rc.1 Codex
|
||||
* shape, the pre-tier Verify file, and the v0.10.8 OpenCode shape (#2264). */
|
||||
typedef struct {
|
||||
char *owned[4];
|
||||
size_t owned_count;
|
||||
const char *content[5];
|
||||
size_t count;
|
||||
} tiered_released_profiles_t;
|
||||
|
||||
static void tiered_released_profiles_keep(tiered_released_profiles_t *released, char *rendered) {
|
||||
if (rendered) {
|
||||
released->owned[released->owned_count++] = rendered;
|
||||
released->content[released->count++] = rendered;
|
||||
}
|
||||
}
|
||||
|
||||
static void tiered_released_profiles_collect(cbm_tiered_profile_set_t profiles,
|
||||
cbm_graph_tier_t tier, cbm_graph_access_t access,
|
||||
tiered_released_profiles_t *released) {
|
||||
memset(released, 0, sizeof(*released));
|
||||
cbm_graph_access_t alternate_access =
|
||||
access == CBM_GRAPH_ACCESS_DIRECT ? CBM_GRAPH_ACCESS_HANDOFF : CBM_GRAPH_ACCESS_DIRECT;
|
||||
tiered_released_profiles_keep(
|
||||
released,
|
||||
cbm_render_graph_profile(profiles.dialect, tier, alternate_access, profiles.binary_path));
|
||||
if (profiles.dialect == CBM_GRAPH_DIALECT_CODEX && access == CBM_GRAPH_ACCESS_DIRECT) {
|
||||
tiered_released_profiles_keep(released, cbm_render_graph_profile_codex_rc1(tier));
|
||||
}
|
||||
if (profiles.dialect == CBM_GRAPH_DIALECT_OPENCODE) {
|
||||
tiered_released_profiles_keep(released,
|
||||
cbm_render_graph_profile_opencode_v0108(tier, access));
|
||||
tiered_released_profiles_keep(
|
||||
released, cbm_render_graph_profile_opencode_v0108(tier, alternate_access));
|
||||
}
|
||||
if (tier == CBM_GRAPH_TIER_VERIFY && profiles.legacy_verify_content) {
|
||||
released->content[released->count++] = profiles.legacy_verify_content;
|
||||
}
|
||||
}
|
||||
|
||||
static void tiered_released_profiles_free(tiered_released_profiles_t *released) {
|
||||
for (size_t i = 0U; i < released->owned_count; i++) {
|
||||
free(released->owned[i]);
|
||||
}
|
||||
released->owned_count = 0U;
|
||||
released->count = 0U;
|
||||
}
|
||||
|
||||
static void install_tiered_agent_profiles(cbm_tiered_profile_set_t profiles, bool dry_run) {
|
||||
cbm_graph_access_t access = cbm_tiered_profile_set_access(profiles);
|
||||
for (int value = 0; value < (int)CBM_GRAPH_TIER_COUNT; value++) {
|
||||
@@ -8740,30 +8788,13 @@ static void install_tiered_agent_profiles(cbm_tiered_profile_set_t profiles, boo
|
||||
record_agent_config_error(false, profiles.label, "agent_render", path);
|
||||
continue;
|
||||
}
|
||||
cbm_graph_access_t alternate_access =
|
||||
access == CBM_GRAPH_ACCESS_DIRECT ? CBM_GRAPH_ACCESS_HANDOFF : CBM_GRAPH_ACCESS_DIRECT;
|
||||
char *alternate = cbm_render_graph_profile(profiles.dialect, tier, alternate_access,
|
||||
profiles.binary_path);
|
||||
char *codex_rc1 =
|
||||
profiles.dialect == CBM_GRAPH_DIALECT_CODEX && access == CBM_GRAPH_ACCESS_DIRECT
|
||||
? cbm_render_graph_profile_codex_rc1(tier)
|
||||
: NULL;
|
||||
const char *released[3];
|
||||
size_t released_count = 0U;
|
||||
if (alternate) {
|
||||
released[released_count++] = alternate;
|
||||
}
|
||||
if (codex_rc1) {
|
||||
released[released_count++] = codex_rc1;
|
||||
}
|
||||
if (tier == CBM_GRAPH_TIER_VERIFY && profiles.legacy_verify_content) {
|
||||
released[released_count++] = profiles.legacy_verify_content;
|
||||
}
|
||||
int result = prepare_config_parent(path)
|
||||
? cbm_text_migrate_owned_document(path, current, released, released_count)
|
||||
: CLI_ERR;
|
||||
free(codex_rc1);
|
||||
free(alternate);
|
||||
tiered_released_profiles_t released;
|
||||
tiered_released_profiles_collect(profiles, tier, access, &released);
|
||||
int result =
|
||||
prepare_config_parent(path)
|
||||
? cbm_text_migrate_owned_document(path, current, released.content, released.count)
|
||||
: CLI_ERR;
|
||||
tiered_released_profiles_free(&released);
|
||||
free(current);
|
||||
if (result != CLI_OK) {
|
||||
if (result > CLI_OK) {
|
||||
@@ -8795,28 +8826,11 @@ static void uninstall_tiered_agent_profiles(cbm_tiered_profile_set_t profiles, b
|
||||
record_agent_config_error(true, profiles.label, "agent_render", path);
|
||||
continue;
|
||||
}
|
||||
cbm_graph_access_t alternate_access =
|
||||
access == CBM_GRAPH_ACCESS_DIRECT ? CBM_GRAPH_ACCESS_HANDOFF : CBM_GRAPH_ACCESS_DIRECT;
|
||||
char *alternate = cbm_render_graph_profile(profiles.dialect, tier, alternate_access,
|
||||
profiles.binary_path);
|
||||
char *codex_rc1 =
|
||||
profiles.dialect == CBM_GRAPH_DIALECT_CODEX && access == CBM_GRAPH_ACCESS_DIRECT
|
||||
? cbm_render_graph_profile_codex_rc1(tier)
|
||||
: NULL;
|
||||
const char *released[3];
|
||||
size_t released_count = 0U;
|
||||
if (alternate) {
|
||||
released[released_count++] = alternate;
|
||||
}
|
||||
if (codex_rc1) {
|
||||
released[released_count++] = codex_rc1;
|
||||
}
|
||||
if (tier == CBM_GRAPH_TIER_VERIFY && profiles.legacy_verify_content) {
|
||||
released[released_count++] = profiles.legacy_verify_content;
|
||||
}
|
||||
int result = cbm_text_remove_owned_document_any(path, current, released, released_count);
|
||||
free(codex_rc1);
|
||||
free(alternate);
|
||||
tiered_released_profiles_t released;
|
||||
tiered_released_profiles_collect(profiles, tier, access, &released);
|
||||
int result =
|
||||
cbm_text_remove_owned_document_any(path, current, released.content, released.count);
|
||||
tiered_released_profiles_free(&released);
|
||||
free(current);
|
||||
if (result < CLI_OK) {
|
||||
record_agent_config_error(true, profiles.label, "agent_uninstall", path);
|
||||
|
||||
Reference in New Issue
Block a user