iranti-control-plane 0.5.5 → 0.5.6

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/bin/iranti-cp.js CHANGED
@@ -319,11 +319,24 @@ function spawnControlPlane({ port, openBrowser, detached }) {
319
319
  // Windows Terminal never attaches. This is only needed for the detached
320
320
  // (background) case; foreground start keeps stdio:inherit as usual.
321
321
  if (process.platform === 'win32' && detached) {
322
- const child = spawn(
323
- 'cmd',
324
- ['/d', '/s', '/c', 'start', '', '/b', process.execPath, BUNDLE],
325
- { env, detached: true, stdio: 'ignore', windowsHide: true },
326
- );
322
+ // On Windows, spawning node.exe directly causes Windows Terminal (wt.exe)
323
+ // to attach and flash a tab. Routing through a hidden cmd process (via
324
+ // windowsHide:true + detached:true) prevents attachment because cmd gets
325
+ // CREATE_NO_WINDOW, and node.exe run as cmd's synchronous child (no
326
+ // start /b) — inherits that no-console state.
327
+ //
328
+ // We also cannot pass env vars via spawn({env}) because the env block on
329
+ // the outer cmd is not forwarded to node by the OS process-creation chain.
330
+ // A temp batch file with explicit SET commands is the reliable workaround.
331
+ const batPath = require('path').join(require('os').tmpdir(), `iranti-cp-${Date.now()}.bat`);
332
+ const batLines = ['@echo off'];
333
+ if (port) batLines.push(`SET CONTROL_PLANE_PORT=${String(port)}`);
334
+ if (!openBrowser) batLines.push('SET IRANTI_CP_NO_OPEN=1');
335
+ batLines.push(`"${process.execPath}" "${BUNDLE}"`);
336
+ require('fs').writeFileSync(batPath, batLines.join('\r\n') + '\r\n');
337
+ const child = spawn('cmd', ['/d', '/s', '/c', batPath], {
338
+ detached: true, stdio: 'ignore', windowsHide: true,
339
+ });
327
340
  child.unref();
328
341
  return child;
329
342
  }
@@ -36844,6 +36844,59 @@ kbRouter.get("/kb/entity-types", async (req, res, next) => {
36844
36844
  next(err);
36845
36845
  }
36846
36846
  });
36847
+ kbRouter.get("/rules", async (req, res, next) => {
36848
+ try {
36849
+ await withRequestQueryable(req, async (db) => {
36850
+ const result = await db.query(
36851
+ `SELECT id, "entityId", key, "valueSummary", properties, "updatedAt"
36852
+ FROM knowledge_base
36853
+ WHERE "entityType" = 'rule'
36854
+ ORDER BY "updatedAt" DESC`
36855
+ );
36856
+ const rules = result.rows.map((row) => {
36857
+ const props = row.properties && typeof row.properties === "object" && !Array.isArray(row.properties) ? row.properties : null;
36858
+ return {
36859
+ id: row.id,
36860
+ ruleId: row.entityId,
36861
+ key: row.key,
36862
+ rule: row.valueSummary ?? "",
36863
+ triggers: Array.isArray(props?.triggers) ? props.triggers : [],
36864
+ enforcement: props?.enforcement ?? "soft",
36865
+ scope: props?.scope ?? "project",
36866
+ updatedAt: toIso(row.updatedAt)
36867
+ };
36868
+ });
36869
+ res.json({ total: rules.length, rules });
36870
+ });
36871
+ } catch (err) {
36872
+ next(err);
36873
+ }
36874
+ });
36875
+ kbRouter.delete("/rules/:ruleId", async (req, res, next) => {
36876
+ try {
36877
+ await withRequestQueryable(req, async (db) => {
36878
+ const ruleId = req.params.ruleId?.trim();
36879
+ if (!ruleId) {
36880
+ throw createApiError("ruleId is required", "INVALID_PARAM", 400);
36881
+ }
36882
+ const result = await db.query(
36883
+ `SELECT id FROM knowledge_base WHERE "entityType" = 'rule' AND "entityId" = $1`,
36884
+ [ruleId]
36885
+ );
36886
+ if (result.rows.length === 0) {
36887
+ throw createApiError(`Rule '${ruleId}' not found`, "RULE_NOT_FOUND", 404);
36888
+ }
36889
+ const ids = result.rows.map((r) => r.id);
36890
+ await db.query(
36891
+ `DELETE FROM knowledge_base WHERE id = ANY($1::int[])`,
36892
+ [ids]
36893
+ );
36894
+ res.json({ deleted: ruleId, entriesRemoved: ids.length });
36895
+ });
36896
+ } catch (err) {
36897
+ next(err);
36898
+ }
36899
+ });
36847
36900
  kbRouter.use(errorHandler);
36848
36901
 
36849
36902
  // src/server/routes/control-plane/instances.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iranti-control-plane",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Operator control plane for Iranti - local-first agent memory management",
5
5
  "bin": {
6
6
  "iranti-cp": "bin/iranti-cp.js"