Skip to content

Commit 12664a3

Browse files
feat: add proto rm/remove command to uninstall protocol (#3)
* feat: add proto rm/remove command to uninstall protocol Implement cueme proto rm/remove command as the reverse operation of cueme proto apply. This allows users to cleanly remove the HAP protocol from agent configuration files. Features: - Add protoRemove() function to remove managed blocks - Support both 'rm' and 'remove' aliases - Automatically delete file if it becomes empty after removal - Preserve file content outside managed blocks - Handle cases where file or managed block doesn't exist Usage: cueme proto rm <agent> cueme proto remove <agent> Examples: cueme proto rm windsurf cueme proto remove kiro The command removes content between BEGIN_MARKER and END_MARKER, preserving any other content in the file. If the file only contains the managed block, it will be deleted entirely. * fix: address code review feedback Address all feedback from code review: Must-fix items: 1. Remove unused 'exists' variable in protoRemove() 2. Throw error when file deletion fails instead of returning ok - Changed from 'ok: ... but failed to delete' to throwing Error - This ensures non-zero exit code and proper error handling Improvements: 3. Removed trimEnd() to preserve original file formatting - Keep trailing whitespace/newlines as they were - Only remove the managed block itself The function now: - Cleanly removes managed blocks - Preserves original file formatting - Properly reports errors when file deletion fails - Has no unused variables
1 parent 4abf5b5 commit 12664a3

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

src/cli.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { readAllStdin } = require('./io');
22
const { handleCommand } = require('./handler');
33
const { parseTagBlocksEnvelope } = require('./envelope');
4-
const { protoApply, protoInit, protoLs, protoPath, protoRender } = require('./proto');
4+
const { protoApply, protoRemove, protoInit, protoLs, protoPath, protoRender } = require('./proto');
55
const pkg = require('../package.json');
66
const fs = require('fs');
77
const path = require('path');
@@ -99,6 +99,7 @@ async function main() {
9999
' cueme -p|--protocol',
100100
' cueme proto <agent>',
101101
' cueme proto apply <agent>',
102+
' cueme proto rm|remove <agent>',
102103
' cueme proto init',
103104
' cueme proto ls',
104105
' cueme proto path <agent>',
@@ -258,6 +259,17 @@ async function main() {
258259
return;
259260
}
260261

262+
if (action === 'rm' || action === 'remove') {
263+
const agent = pos[1];
264+
if (!agent) {
265+
process.stderr.write('error: missing <agent>\n');
266+
process.exitCode = 2;
267+
return;
268+
}
269+
process.stdout.write(protoRemove(String(agent)) + '\n');
270+
return;
271+
}
272+
261273
if (action === 'path') {
262274
const agent = pos[1];
263275
if (!agent) {

src/proto.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,48 @@ function protoApply(agent) {
399399
return `ok: applied to ${targetPath}`;
400400
}
401401

402+
function protoRemove(agent) {
403+
const cfg = readConfigOrThrow({ auto_init: true });
404+
const targetPath = resolveTargetPath({ cfg, agent });
405+
406+
let existing = '';
407+
try {
408+
existing = fs.readFileSync(targetPath, 'utf8');
409+
} catch {
410+
return `ok: file does not exist: ${targetPath}`;
411+
}
412+
413+
const beginMatch = existing.match(BEGIN_MARKER_RE);
414+
const endMatch = existing.match(END_MARKER_RE);
415+
416+
if (!beginMatch || !endMatch || endMatch.index <= beginMatch.index) {
417+
return `ok: no managed block found in: ${targetPath}`;
418+
}
419+
420+
const beginIdx = beginMatch.index;
421+
const endIdx = endMatch.index;
422+
const endLen = endMatch[0].length;
423+
424+
const before = existing.slice(0, beginIdx);
425+
const after = existing.slice(endIdx + endLen);
426+
427+
const eol = detectEol(existing);
428+
const afterTrim = after.startsWith(eol) ? after.slice(eol.length) : after;
429+
const out = before + afterTrim;
430+
431+
if (out.trim().length === 0) {
432+
try {
433+
fs.unlinkSync(targetPath);
434+
return `ok: removed managed block and deleted empty file: ${targetPath}`;
435+
} catch (err) {
436+
throw new Error(`error: failed to delete file after removing managed block: ${targetPath}: ${err.message}`);
437+
}
438+
}
439+
440+
fs.writeFileSync(targetPath, out, 'utf8');
441+
return `ok: removed managed block from: ${targetPath}`;
442+
}
443+
402444
function protoInit() {
403445
const { created, path: p, detected } = initConfigIfMissing();
404446
if (!created) return `ok: exists ${p}`;
@@ -417,6 +459,7 @@ module.exports = {
417459
END_MARKER,
418460
getPlatformKey,
419461
protoApply,
462+
protoRemove,
420463
protoInit,
421464
protoLs,
422465
protoPath,

0 commit comments

Comments
 (0)