@mutmutco/cli 2.42.0 → 2.44.0

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.
Files changed (3) hide show
  1. package/dist/main.cjs +5066 -5715
  2. package/dist/saga.cjs +178 -190
  3. package/package.json +1 -1
package/dist/saga.cjs CHANGED
@@ -3631,7 +3631,6 @@ function buildHealth(i) {
3631
3631
  authorized: i.authorized,
3632
3632
  sagaApiUrl: i.sagaApiUrl,
3633
3633
  pendingNotes: i.pendingNotes ?? 0,
3634
- honchoPending: i.honchoPending ?? 0,
3635
3634
  key: i.key,
3636
3635
  source: i.source,
3637
3636
  problems,
@@ -3650,194 +3649,8 @@ function healthBanner(report) {
3650
3649
  }
3651
3650
  function memorySyncBanner(report) {
3652
3651
  const saga = report.pendingNotes;
3653
- const honcho = report.honchoPending;
3654
- if (saga <= 0 && honcho <= 0) return null;
3655
- const parts = [];
3656
- if (saga > 0) parts.push(`${saga} saga`);
3657
- if (honcho > 0) parts.push(`${honcho} honcho`);
3658
- return `MEMORY SYNC \u2014 ${parts.join(" + ")} write(s) queued locally \u2014 run \`mmi-cli saga flush\` / \`honcho flush\` (this device only).`;
3659
- }
3660
-
3661
- // src/saga-pending.ts
3662
- var import_node_fs4 = require("node:fs");
3663
- var import_node_path4 = require("node:path");
3664
- function classifyCaptureOutcome(r) {
3665
- if (r.threw) return "queued";
3666
- return r.ok ? "confirmed" : "failed";
3667
- }
3668
- var PENDING_MAX = 50;
3669
- var PENDING_MAX_ATTEMPTS = 10;
3670
- var PENDING_FILE = "saga-pending.jsonl";
3671
- var FLUSH_LOCK_FILE = "saga-flush.lock";
3672
- var FLUSH_LOCK_STALE_MS = 5 * 6e4;
3673
- function pendingPath(dir = ".mmi") {
3674
- return (0, import_node_path4.join)(dir, PENDING_FILE);
3675
- }
3676
- var PENDING_TMP_STALE_MS = 6e4;
3677
- function sweepStaleTmp(dir = ".mmi", now = Date.now()) {
3678
- try {
3679
- for (const name of (0, import_node_fs4.readdirSync)(dir)) {
3680
- if (!name.startsWith(`${PENDING_FILE}.`) || !name.endsWith(".tmp")) continue;
3681
- const path2 = (0, import_node_path4.join)(dir, name);
3682
- try {
3683
- if (now - (0, import_node_fs4.statSync)(path2).mtimeMs > PENDING_TMP_STALE_MS) (0, import_node_fs4.unlinkSync)(path2);
3684
- } catch {
3685
- }
3686
- }
3687
- } catch {
3688
- }
3689
- }
3690
- function flushLockPath(dir = ".mmi") {
3691
- return (0, import_node_path4.join)(dir, FLUSH_LOCK_FILE);
3692
- }
3693
- function acquireFlushLock(dir = ".mmi", now = Date.now()) {
3694
- const path2 = flushLockPath(dir);
3695
- try {
3696
- (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
3697
- (0, import_node_fs4.writeFileSync)(path2, String(process.pid), { encoding: "utf8", flag: "wx" });
3698
- return true;
3699
- } catch {
3700
- try {
3701
- if (now - (0, import_node_fs4.statSync)(path2).mtimeMs > FLUSH_LOCK_STALE_MS) {
3702
- (0, import_node_fs4.unlinkSync)(path2);
3703
- (0, import_node_fs4.writeFileSync)(path2, String(process.pid), { encoding: "utf8", flag: "wx" });
3704
- return true;
3705
- }
3706
- } catch {
3707
- }
3708
- return false;
3709
- }
3710
- }
3711
- function releaseFlushLock(dir = ".mmi") {
3712
- try {
3713
- (0, import_node_fs4.unlinkSync)(flushLockPath(dir));
3714
- } catch {
3715
- }
3716
- }
3717
- function readPending(dir = ".mmi") {
3718
- const path2 = pendingPath(dir);
3719
- if (!(0, import_node_fs4.existsSync)(path2)) return [];
3720
- const out = [];
3721
- for (const line of (0, import_node_fs4.readFileSync)(path2, "utf8").split(/\r?\n/)) {
3722
- const t = line.trim();
3723
- if (!t) continue;
3724
- try {
3725
- const e = JSON.parse(t);
3726
- if (e && typeof e.id === "string" && e.body && typeof e.body === "object") out.push(e);
3727
- } catch {
3728
- }
3729
- }
3730
- return out;
3731
- }
3732
- function writePending(entries, dir = ".mmi") {
3733
- const tmp = `${pendingPath(dir)}.${process.pid}.tmp`;
3734
- try {
3735
- (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
3736
- sweepStaleTmp(dir);
3737
- const trimmed = entries.slice(-PENDING_MAX);
3738
- const body = trimmed.map((e) => JSON.stringify(e)).join("\n");
3739
- (0, import_node_fs4.writeFileSync)(tmp, trimmed.length ? `${body}
3740
- ` : "", "utf8");
3741
- (0, import_node_fs4.renameSync)(tmp, pendingPath(dir));
3742
- } catch {
3743
- try {
3744
- (0, import_node_fs4.unlinkSync)(tmp);
3745
- } catch {
3746
- }
3747
- }
3748
- }
3749
- function enqueuePending(body, dir = ".mmi") {
3750
- try {
3751
- const id = typeof body.id === "string" ? body.id : "";
3752
- const existing = readPending(dir);
3753
- if (id && existing.some((e) => e.id === id)) return;
3754
- if (existing.length >= PENDING_MAX) {
3755
- writePending([...existing, { id, body }], dir);
3756
- return;
3757
- }
3758
- (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
3759
- sweepStaleTmp(dir);
3760
- (0, import_node_fs4.appendFileSync)(pendingPath(dir), `${JSON.stringify({ id, body })}
3761
- `, "utf8");
3762
- } catch {
3763
- }
3764
- }
3765
- function entryKey(e) {
3766
- return e.id || JSON.stringify(e.body);
3767
- }
3768
- async function drainOnce(post, dir, seen) {
3769
- const entries = readPending(dir);
3770
- if (!entries.length) return { flushed: 0, dropped: [], remaining: 0, halted: false };
3771
- let flushed = 0;
3772
- const dropped = [];
3773
- const processed = /* @__PURE__ */ new Set();
3774
- const kept = /* @__PURE__ */ new Map();
3775
- let halted = false;
3776
- for (const e of entries) {
3777
- const key = entryKey(e);
3778
- if (halted) continue;
3779
- if (seen.has(key)) {
3780
- processed.add(key);
3781
- continue;
3782
- }
3783
- const r = await post(e.body);
3784
- const outcome = classifyCaptureOutcome(r);
3785
- if (outcome === "confirmed") {
3786
- seen.add(key);
3787
- flushed++;
3788
- processed.add(key);
3789
- continue;
3790
- }
3791
- if (outcome === "failed") {
3792
- seen.add(key);
3793
- dropped.push(r);
3794
- processed.add(key);
3795
- continue;
3796
- }
3797
- const attempts = (e.attempts ?? 0) + 1;
3798
- if (attempts >= PENDING_MAX_ATTEMPTS) {
3799
- seen.add(key);
3800
- dropped.push(r);
3801
- processed.add(key);
3802
- continue;
3803
- }
3804
- kept.set(key, { ...e, attempts });
3805
- halted = true;
3806
- }
3807
- const out = [];
3808
- const written = /* @__PURE__ */ new Set();
3809
- for (const c of readPending(dir)) {
3810
- const key = entryKey(c);
3811
- if (processed.has(key) || written.has(key)) continue;
3812
- written.add(key);
3813
- out.push(kept.get(key) ?? c);
3814
- }
3815
- writePending(out, dir);
3816
- return { flushed, dropped, remaining: out.length, halted };
3817
- }
3818
- async function flushPending(post, dir = ".mmi") {
3819
- if (!acquireFlushLock(dir)) return { flushed: 0, dropped: [], remaining: readPending(dir).length, skipped: true };
3820
- let flushed = 0;
3821
- const dropped = [];
3822
- const seen = /* @__PURE__ */ new Set();
3823
- try {
3824
- for (; ; ) {
3825
- const r = await drainOnce(post, dir, seen);
3826
- flushed += r.flushed;
3827
- dropped.push(...r.dropped);
3828
- if (r.halted || r.remaining === 0) break;
3829
- if (!r.flushed && !r.dropped.length) break;
3830
- }
3831
- } finally {
3832
- releaseFlushLock(dir);
3833
- }
3834
- return { flushed, dropped, remaining: readPending(dir).length };
3835
- }
3836
-
3837
- // src/honcho-pending.ts
3838
- var HONCHO_QUEUE_DIR = ".mmi/honcho";
3839
- function readHonchoPending(dir = HONCHO_QUEUE_DIR) {
3840
- return readPending(dir);
3652
+ if (saga <= 0) return null;
3653
+ return `MEMORY SYNC \u2014 ${saga} saga write(s) queued locally \u2014 run \`mmi-cli saga flush\` (this device only).`;
3841
3654
  }
3842
3655
 
3843
3656
  // src/fetch-retry.ts
@@ -4213,6 +4026,182 @@ function formatSnapshotHuman(snapshot) {
4213
4026
  return lines.join("\n");
4214
4027
  }
4215
4028
 
4029
+ // src/saga-pending.ts
4030
+ var import_node_fs4 = require("node:fs");
4031
+ var import_node_path4 = require("node:path");
4032
+ function classifyCaptureOutcome(r) {
4033
+ if (r.threw) return "queued";
4034
+ return r.ok ? "confirmed" : "failed";
4035
+ }
4036
+ var PENDING_MAX = 50;
4037
+ var PENDING_MAX_ATTEMPTS = 10;
4038
+ var PENDING_FILE = "saga-pending.jsonl";
4039
+ var FLUSH_LOCK_FILE = "saga-flush.lock";
4040
+ var FLUSH_LOCK_STALE_MS = 5 * 6e4;
4041
+ function pendingPath(dir = ".mmi") {
4042
+ return (0, import_node_path4.join)(dir, PENDING_FILE);
4043
+ }
4044
+ var PENDING_TMP_STALE_MS = 6e4;
4045
+ function sweepStaleTmp(dir = ".mmi", now = Date.now()) {
4046
+ try {
4047
+ for (const name of (0, import_node_fs4.readdirSync)(dir)) {
4048
+ if (!name.startsWith(`${PENDING_FILE}.`) || !name.endsWith(".tmp")) continue;
4049
+ const path2 = (0, import_node_path4.join)(dir, name);
4050
+ try {
4051
+ if (now - (0, import_node_fs4.statSync)(path2).mtimeMs > PENDING_TMP_STALE_MS) (0, import_node_fs4.unlinkSync)(path2);
4052
+ } catch {
4053
+ }
4054
+ }
4055
+ } catch {
4056
+ }
4057
+ }
4058
+ function flushLockPath(dir = ".mmi") {
4059
+ return (0, import_node_path4.join)(dir, FLUSH_LOCK_FILE);
4060
+ }
4061
+ function acquireFlushLock(dir = ".mmi", now = Date.now()) {
4062
+ const path2 = flushLockPath(dir);
4063
+ try {
4064
+ (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
4065
+ (0, import_node_fs4.writeFileSync)(path2, String(process.pid), { encoding: "utf8", flag: "wx" });
4066
+ return true;
4067
+ } catch {
4068
+ try {
4069
+ if (now - (0, import_node_fs4.statSync)(path2).mtimeMs > FLUSH_LOCK_STALE_MS) {
4070
+ (0, import_node_fs4.unlinkSync)(path2);
4071
+ (0, import_node_fs4.writeFileSync)(path2, String(process.pid), { encoding: "utf8", flag: "wx" });
4072
+ return true;
4073
+ }
4074
+ } catch {
4075
+ }
4076
+ return false;
4077
+ }
4078
+ }
4079
+ function releaseFlushLock(dir = ".mmi") {
4080
+ try {
4081
+ (0, import_node_fs4.unlinkSync)(flushLockPath(dir));
4082
+ } catch {
4083
+ }
4084
+ }
4085
+ function readPending(dir = ".mmi") {
4086
+ const path2 = pendingPath(dir);
4087
+ if (!(0, import_node_fs4.existsSync)(path2)) return [];
4088
+ const out = [];
4089
+ for (const line of (0, import_node_fs4.readFileSync)(path2, "utf8").split(/\r?\n/)) {
4090
+ const t = line.trim();
4091
+ if (!t) continue;
4092
+ try {
4093
+ const e = JSON.parse(t);
4094
+ if (e && typeof e.id === "string" && e.body && typeof e.body === "object") out.push(e);
4095
+ } catch {
4096
+ }
4097
+ }
4098
+ return out;
4099
+ }
4100
+ function writePending(entries, dir = ".mmi") {
4101
+ const tmp = `${pendingPath(dir)}.${process.pid}.tmp`;
4102
+ try {
4103
+ (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
4104
+ sweepStaleTmp(dir);
4105
+ const trimmed = entries.slice(-PENDING_MAX);
4106
+ const body = trimmed.map((e) => JSON.stringify(e)).join("\n");
4107
+ (0, import_node_fs4.writeFileSync)(tmp, trimmed.length ? `${body}
4108
+ ` : "", "utf8");
4109
+ (0, import_node_fs4.renameSync)(tmp, pendingPath(dir));
4110
+ } catch {
4111
+ try {
4112
+ (0, import_node_fs4.unlinkSync)(tmp);
4113
+ } catch {
4114
+ }
4115
+ }
4116
+ }
4117
+ function enqueuePending(body, dir = ".mmi") {
4118
+ try {
4119
+ const id = typeof body.id === "string" ? body.id : "";
4120
+ const existing = readPending(dir);
4121
+ if (id && existing.some((e) => e.id === id)) return;
4122
+ if (existing.length >= PENDING_MAX) {
4123
+ writePending([...existing, { id, body }], dir);
4124
+ return;
4125
+ }
4126
+ (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
4127
+ sweepStaleTmp(dir);
4128
+ (0, import_node_fs4.appendFileSync)(pendingPath(dir), `${JSON.stringify({ id, body })}
4129
+ `, "utf8");
4130
+ } catch {
4131
+ }
4132
+ }
4133
+ function entryKey(e) {
4134
+ return e.id || JSON.stringify(e.body);
4135
+ }
4136
+ async function drainOnce(post, dir, seen) {
4137
+ const entries = readPending(dir);
4138
+ if (!entries.length) return { flushed: 0, dropped: [], remaining: 0, halted: false };
4139
+ let flushed = 0;
4140
+ const dropped = [];
4141
+ const processed = /* @__PURE__ */ new Set();
4142
+ const kept = /* @__PURE__ */ new Map();
4143
+ let halted = false;
4144
+ for (const e of entries) {
4145
+ const key = entryKey(e);
4146
+ if (halted) continue;
4147
+ if (seen.has(key)) {
4148
+ processed.add(key);
4149
+ continue;
4150
+ }
4151
+ const r = await post(e.body);
4152
+ const outcome = classifyCaptureOutcome(r);
4153
+ if (outcome === "confirmed") {
4154
+ seen.add(key);
4155
+ flushed++;
4156
+ processed.add(key);
4157
+ continue;
4158
+ }
4159
+ if (outcome === "failed") {
4160
+ seen.add(key);
4161
+ dropped.push(r);
4162
+ processed.add(key);
4163
+ continue;
4164
+ }
4165
+ const attempts = (e.attempts ?? 0) + 1;
4166
+ if (attempts >= PENDING_MAX_ATTEMPTS) {
4167
+ seen.add(key);
4168
+ dropped.push(r);
4169
+ processed.add(key);
4170
+ continue;
4171
+ }
4172
+ kept.set(key, { ...e, attempts });
4173
+ halted = true;
4174
+ }
4175
+ const out = [];
4176
+ const written = /* @__PURE__ */ new Set();
4177
+ for (const c of readPending(dir)) {
4178
+ const key = entryKey(c);
4179
+ if (processed.has(key) || written.has(key)) continue;
4180
+ written.add(key);
4181
+ out.push(kept.get(key) ?? c);
4182
+ }
4183
+ writePending(out, dir);
4184
+ return { flushed, dropped, remaining: out.length, halted };
4185
+ }
4186
+ async function flushPending(post, dir = ".mmi") {
4187
+ if (!acquireFlushLock(dir)) return { flushed: 0, dropped: [], remaining: readPending(dir).length, skipped: true };
4188
+ let flushed = 0;
4189
+ const dropped = [];
4190
+ const seen = /* @__PURE__ */ new Set();
4191
+ try {
4192
+ for (; ; ) {
4193
+ const r = await drainOnce(post, dir, seen);
4194
+ flushed += r.flushed;
4195
+ dropped.push(...r.dropped);
4196
+ if (r.halted || r.remaining === 0) break;
4197
+ if (!r.flushed && !r.dropped.length) break;
4198
+ }
4199
+ } finally {
4200
+ releaseFlushLock(dir);
4201
+ }
4202
+ return { flushed, dropped, remaining: readPending(dir).length };
4203
+ }
4204
+
4216
4205
  // src/hub-auth.ts
4217
4206
  var import_node_crypto = require("node:crypto");
4218
4207
  var import_node_fs5 = require("node:fs");
@@ -4660,7 +4649,6 @@ async function runSagaHealth(o, io = consoleIo) {
4660
4649
  authorized,
4661
4650
  sagaApiUrl: cfg.sagaApiUrl,
4662
4651
  pendingNotes: readPending().length,
4663
- honchoPending: readHonchoPending().length,
4664
4652
  memoryAgeDays
4665
4653
  });
4666
4654
  if (o.json) return io.log(JSON.stringify(report));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "2.42.0",
3
+ "version": "2.44.0",
4
4
  "description": "MMI Future CLI — delivers the org rules (whole-file), plus saga and KB access. The cross-IDE engine the plugin's SessionStart hook drives.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",