chainlesschain 0.132.0 → 0.145.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 (135) hide show
  1. package/package.json +1 -1
  2. package/src/commands/a2a.js +230 -0
  3. package/src/commands/activitypub.js +191 -0
  4. package/src/commands/agent.js +601 -0
  5. package/src/commands/audit.js +206 -0
  6. package/src/commands/bi.js +186 -0
  7. package/src/commands/bm25.js +162 -0
  8. package/src/commands/browse.js +225 -0
  9. package/src/commands/ccron.js +178 -0
  10. package/src/commands/chat.js +207 -0
  11. package/src/commands/compliance.js +420 -0
  12. package/src/commands/compt.js +176 -0
  13. package/src/commands/consol.js +237 -0
  14. package/src/commands/cowork.js +588 -0
  15. package/src/commands/crosschain.js +216 -0
  16. package/src/commands/dao.js +216 -0
  17. package/src/commands/dlp.js +206 -0
  18. package/src/commands/economy.js +211 -0
  19. package/src/commands/evolution.js +209 -0
  20. package/src/commands/evomap.js +216 -0
  21. package/src/commands/fflag.js +230 -0
  22. package/src/commands/git.js +185 -0
  23. package/src/commands/hardening.js +209 -0
  24. package/src/commands/hmemory.js +210 -0
  25. package/src/commands/incentive.js +209 -0
  26. package/src/commands/inference.js +178 -0
  27. package/src/commands/itbudget.js +161 -0
  28. package/src/commands/kg.js +206 -0
  29. package/src/commands/lowcode.js +201 -0
  30. package/src/commands/marketplace.js +206 -0
  31. package/src/commands/matrix.js +214 -0
  32. package/src/commands/mcpscaf.js +153 -0
  33. package/src/commands/meminj.js +153 -0
  34. package/src/commands/nostr.js +213 -0
  35. package/src/commands/orchestrate.js +217 -0
  36. package/src/commands/orchgov.js +156 -0
  37. package/src/commands/pdfp.js +160 -0
  38. package/src/commands/perf.js +176 -0
  39. package/src/commands/perm.js +156 -0
  40. package/src/commands/pipeline.js +211 -0
  41. package/src/commands/planmode.js +154 -0
  42. package/src/commands/privacy.js +203 -0
  43. package/src/commands/promcomp.js +166 -0
  44. package/src/commands/recommend.js +185 -0
  45. package/src/commands/reputation.js +208 -0
  46. package/src/commands/sandbox.js +206 -0
  47. package/src/commands/seshhook.js +153 -0
  48. package/src/commands/seshsearch.js +149 -0
  49. package/src/commands/seshtail.js +152 -0
  50. package/src/commands/seshu.js +160 -0
  51. package/src/commands/sganal.js +172 -0
  52. package/src/commands/siem.js +207 -0
  53. package/src/commands/sla.js +212 -0
  54. package/src/commands/slotfill.js +154 -0
  55. package/src/commands/social.js +159 -0
  56. package/src/commands/stress.js +206 -0
  57. package/src/commands/svccont.js +157 -0
  58. package/src/commands/terraform.js +206 -0
  59. package/src/commands/tms.js +183 -0
  60. package/src/commands/topiccls.js +158 -0
  61. package/src/commands/uprof.js +154 -0
  62. package/src/commands/vcheck.js +172 -0
  63. package/src/commands/webfetch.js +150 -0
  64. package/src/commands/zkp.js +218 -0
  65. package/src/harness/prompt-compressor.js +331 -0
  66. package/src/index.js +101 -1
  67. package/src/lib/a2a-protocol.js +373 -0
  68. package/src/lib/activitypub-bridge.js +343 -0
  69. package/src/lib/agent-economy.js +358 -0
  70. package/src/lib/app-builder.js +338 -0
  71. package/src/lib/audit-logger.js +321 -0
  72. package/src/lib/autonomous-agent.js +341 -0
  73. package/src/lib/bi-engine.js +339 -0
  74. package/src/lib/bm25-search.js +333 -0
  75. package/src/lib/browser-automation.js +352 -0
  76. package/src/lib/chat-core.js +336 -0
  77. package/src/lib/claude-code-bridge.js +341 -0
  78. package/src/lib/compliance-framework-reporter.js +359 -0
  79. package/src/lib/compliance-manager.js +330 -0
  80. package/src/lib/compression-telemetry.js +333 -0
  81. package/src/lib/content-recommender.js +370 -0
  82. package/src/lib/cowork-cron.js +330 -0
  83. package/src/lib/cowork-learning.js +333 -0
  84. package/src/lib/cowork-task-runner.js +362 -0
  85. package/src/lib/cowork-workflow.js +327 -0
  86. package/src/lib/cross-chain.js +365 -0
  87. package/src/lib/dao-governance.js +339 -0
  88. package/src/lib/dlp-engine.js +343 -0
  89. package/src/lib/evolution-system.js +336 -0
  90. package/src/lib/evomap-manager.js +339 -0
  91. package/src/lib/execution-backend.js +351 -0
  92. package/src/lib/feature-flags.js +330 -0
  93. package/src/lib/git-integration.js +343 -0
  94. package/src/lib/hardening-manager.js +341 -0
  95. package/src/lib/hierarchical-memory.js +341 -0
  96. package/src/lib/inference-network.js +362 -0
  97. package/src/lib/iteration-budget.js +357 -0
  98. package/src/lib/knowledge-graph.js +333 -0
  99. package/src/lib/matrix-bridge.js +339 -0
  100. package/src/lib/mcp-scaffold.js +345 -0
  101. package/src/lib/memory-injection.js +320 -0
  102. package/src/lib/nostr-bridge.js +342 -0
  103. package/src/lib/orchestrator.js +350 -0
  104. package/src/lib/pdf-parser.js +330 -0
  105. package/src/lib/perf-tuning.js +364 -0
  106. package/src/lib/permission-engine.js +319 -0
  107. package/src/lib/pipeline-orchestrator.js +345 -0
  108. package/src/lib/plan-mode.js +328 -0
  109. package/src/lib/privacy-computing.js +335 -0
  110. package/src/lib/prompt-compressor.js +1 -10
  111. package/src/lib/reputation-optimizer.js +340 -0
  112. package/src/lib/sandbox-v2.js +327 -0
  113. package/src/lib/service-container.js +342 -0
  114. package/src/lib/session-consolidator.js +352 -0
  115. package/src/lib/session-hooks.js +340 -0
  116. package/src/lib/session-search.js +334 -0
  117. package/src/lib/session-tail.js +320 -0
  118. package/src/lib/session-usage.js +329 -0
  119. package/src/lib/siem-exporter.js +352 -0
  120. package/src/lib/skill-marketplace.js +345 -0
  121. package/src/lib/sla-manager.js +341 -0
  122. package/src/lib/slot-filler.js +333 -0
  123. package/src/lib/social-graph-analytics.js +327 -0
  124. package/src/lib/social-graph.js +304 -0
  125. package/src/lib/stress-tester.js +342 -0
  126. package/src/lib/sub-agent-registry.js +359 -0
  127. package/src/lib/task-model-selector.js +333 -0
  128. package/src/lib/terraform-manager.js +333 -0
  129. package/src/lib/todo-manager.js +339 -0
  130. package/src/lib/token-incentive.js +341 -0
  131. package/src/lib/topic-classifier.js +353 -0
  132. package/src/lib/user-profile.js +325 -0
  133. package/src/lib/version-checker.js +335 -0
  134. package/src/lib/web-fetch.js +322 -0
  135. package/src/lib/zkp-engine.js +342 -0
@@ -926,3 +926,348 @@ export function getStats(db) {
926
926
  deploysByStrategy: deployByStrategy,
927
927
  };
928
928
  }
929
+
930
+ // ===== V2 Surface: Pipeline Orchestrator governance overlay (CLI v0.137.0) =====
931
+ export const PIPELINE_MATURITY_V2 = Object.freeze({
932
+ PENDING: "pending",
933
+ ACTIVE: "active",
934
+ PAUSED: "paused",
935
+ ARCHIVED: "archived",
936
+ });
937
+ export const PIPELINE_RUN_LIFECYCLE_V2 = Object.freeze({
938
+ QUEUED: "queued",
939
+ RUNNING: "running",
940
+ COMPLETED: "completed",
941
+ FAILED: "failed",
942
+ CANCELLED: "cancelled",
943
+ });
944
+
945
+ const _pipTrans = new Map([
946
+ [
947
+ PIPELINE_MATURITY_V2.PENDING,
948
+ new Set([PIPELINE_MATURITY_V2.ACTIVE, PIPELINE_MATURITY_V2.ARCHIVED]),
949
+ ],
950
+ [
951
+ PIPELINE_MATURITY_V2.ACTIVE,
952
+ new Set([PIPELINE_MATURITY_V2.PAUSED, PIPELINE_MATURITY_V2.ARCHIVED]),
953
+ ],
954
+ [
955
+ PIPELINE_MATURITY_V2.PAUSED,
956
+ new Set([PIPELINE_MATURITY_V2.ACTIVE, PIPELINE_MATURITY_V2.ARCHIVED]),
957
+ ],
958
+ [PIPELINE_MATURITY_V2.ARCHIVED, new Set()],
959
+ ]);
960
+ const _pipTerminal = new Set([PIPELINE_MATURITY_V2.ARCHIVED]);
961
+ const _pipRunTrans = new Map([
962
+ [
963
+ PIPELINE_RUN_LIFECYCLE_V2.QUEUED,
964
+ new Set([
965
+ PIPELINE_RUN_LIFECYCLE_V2.RUNNING,
966
+ PIPELINE_RUN_LIFECYCLE_V2.CANCELLED,
967
+ ]),
968
+ ],
969
+ [
970
+ PIPELINE_RUN_LIFECYCLE_V2.RUNNING,
971
+ new Set([
972
+ PIPELINE_RUN_LIFECYCLE_V2.COMPLETED,
973
+ PIPELINE_RUN_LIFECYCLE_V2.FAILED,
974
+ PIPELINE_RUN_LIFECYCLE_V2.CANCELLED,
975
+ ]),
976
+ ],
977
+ [PIPELINE_RUN_LIFECYCLE_V2.COMPLETED, new Set()],
978
+ [PIPELINE_RUN_LIFECYCLE_V2.FAILED, new Set()],
979
+ [PIPELINE_RUN_LIFECYCLE_V2.CANCELLED, new Set()],
980
+ ]);
981
+
982
+ const _pips = new Map();
983
+ const _pipRuns = new Map();
984
+ let _pipMaxActivePerOwner = 10;
985
+ let _pipMaxPendingPerPip = 20;
986
+ let _pipIdleMs = 3 * 24 * 60 * 60 * 1000;
987
+ let _pipRunStuckMs = 10 * 60 * 1000;
988
+
989
+ function _pipPos(n, lbl) {
990
+ const v = Math.floor(Number(n));
991
+ if (!Number.isFinite(v) || v <= 0)
992
+ throw new Error(`${lbl} must be positive integer`);
993
+ return v;
994
+ }
995
+
996
+ export function setMaxActivePipelinesPerOwnerV2(n) {
997
+ _pipMaxActivePerOwner = _pipPos(n, "maxActivePipelinesPerOwner");
998
+ }
999
+ export function getMaxActivePipelinesPerOwnerV2() {
1000
+ return _pipMaxActivePerOwner;
1001
+ }
1002
+ export function setMaxPendingPipelineRunsPerPipelineV2(n) {
1003
+ _pipMaxPendingPerPip = _pipPos(n, "maxPendingPipelineRunsPerPipeline");
1004
+ }
1005
+ export function getMaxPendingPipelineRunsPerPipelineV2() {
1006
+ return _pipMaxPendingPerPip;
1007
+ }
1008
+ export function setPipelineIdleMsV2(n) {
1009
+ _pipIdleMs = _pipPos(n, "pipelineIdleMs");
1010
+ }
1011
+ export function getPipelineIdleMsV2() {
1012
+ return _pipIdleMs;
1013
+ }
1014
+ export function setPipelineRunStuckMsV2(n) {
1015
+ _pipRunStuckMs = _pipPos(n, "pipelineRunStuckMs");
1016
+ }
1017
+ export function getPipelineRunStuckMsV2() {
1018
+ return _pipRunStuckMs;
1019
+ }
1020
+
1021
+ export function _resetStatePipelineOrchestratorV2() {
1022
+ _pips.clear();
1023
+ _pipRuns.clear();
1024
+ _pipMaxActivePerOwner = 10;
1025
+ _pipMaxPendingPerPip = 20;
1026
+ _pipIdleMs = 3 * 24 * 60 * 60 * 1000;
1027
+ _pipRunStuckMs = 10 * 60 * 1000;
1028
+ }
1029
+
1030
+ export function registerPipelineV2({ id, owner, name, metadata } = {}) {
1031
+ if (!id || typeof id !== "string") throw new Error("id is required");
1032
+ if (!owner || typeof owner !== "string") throw new Error("owner is required");
1033
+ if (_pips.has(id)) throw new Error(`pipeline ${id} already registered`);
1034
+ const now = Date.now();
1035
+ const p = {
1036
+ id,
1037
+ owner,
1038
+ name: name || id,
1039
+ status: PIPELINE_MATURITY_V2.PENDING,
1040
+ createdAt: now,
1041
+ updatedAt: now,
1042
+ activatedAt: null,
1043
+ archivedAt: null,
1044
+ lastTouchedAt: now,
1045
+ metadata: { ...(metadata || {}) },
1046
+ };
1047
+ _pips.set(id, p);
1048
+ return { ...p, metadata: { ...p.metadata } };
1049
+ }
1050
+ function _pipCheckP(from, to) {
1051
+ const a = _pipTrans.get(from);
1052
+ if (!a || !a.has(to))
1053
+ throw new Error(`invalid pipeline transition ${from} → ${to}`);
1054
+ }
1055
+ function _pipCountActive(owner) {
1056
+ let n = 0;
1057
+ for (const p of _pips.values())
1058
+ if (p.owner === owner && p.status === PIPELINE_MATURITY_V2.ACTIVE) n++;
1059
+ return n;
1060
+ }
1061
+
1062
+ export function activatePipelineV2(id) {
1063
+ const p = _pips.get(id);
1064
+ if (!p) throw new Error(`pipeline ${id} not found`);
1065
+ _pipCheckP(p.status, PIPELINE_MATURITY_V2.ACTIVE);
1066
+ const recovery = p.status === PIPELINE_MATURITY_V2.PAUSED;
1067
+ if (!recovery) {
1068
+ const c = _pipCountActive(p.owner);
1069
+ if (c >= _pipMaxActivePerOwner)
1070
+ throw new Error(
1071
+ `max active pipelines per owner (${_pipMaxActivePerOwner}) reached for ${p.owner}`,
1072
+ );
1073
+ }
1074
+ const now = Date.now();
1075
+ p.status = PIPELINE_MATURITY_V2.ACTIVE;
1076
+ p.updatedAt = now;
1077
+ p.lastTouchedAt = now;
1078
+ if (!p.activatedAt) p.activatedAt = now;
1079
+ return { ...p, metadata: { ...p.metadata } };
1080
+ }
1081
+ export function pausePipelineV2(id) {
1082
+ const p = _pips.get(id);
1083
+ if (!p) throw new Error(`pipeline ${id} not found`);
1084
+ _pipCheckP(p.status, PIPELINE_MATURITY_V2.PAUSED);
1085
+ p.status = PIPELINE_MATURITY_V2.PAUSED;
1086
+ p.updatedAt = Date.now();
1087
+ return { ...p, metadata: { ...p.metadata } };
1088
+ }
1089
+ export function archivePipelineV2(id) {
1090
+ const p = _pips.get(id);
1091
+ if (!p) throw new Error(`pipeline ${id} not found`);
1092
+ _pipCheckP(p.status, PIPELINE_MATURITY_V2.ARCHIVED);
1093
+ const now = Date.now();
1094
+ p.status = PIPELINE_MATURITY_V2.ARCHIVED;
1095
+ p.updatedAt = now;
1096
+ if (!p.archivedAt) p.archivedAt = now;
1097
+ return { ...p, metadata: { ...p.metadata } };
1098
+ }
1099
+ export function touchPipelineV2(id) {
1100
+ const p = _pips.get(id);
1101
+ if (!p) throw new Error(`pipeline ${id} not found`);
1102
+ if (_pipTerminal.has(p.status))
1103
+ throw new Error(`cannot touch terminal pipeline ${id}`);
1104
+ const now = Date.now();
1105
+ p.lastTouchedAt = now;
1106
+ p.updatedAt = now;
1107
+ return { ...p, metadata: { ...p.metadata } };
1108
+ }
1109
+ export function getPipelineV2(id) {
1110
+ const p = _pips.get(id);
1111
+ if (!p) return null;
1112
+ return { ...p, metadata: { ...p.metadata } };
1113
+ }
1114
+ export function listPipelinesV2() {
1115
+ return [..._pips.values()].map((p) => ({
1116
+ ...p,
1117
+ metadata: { ...p.metadata },
1118
+ }));
1119
+ }
1120
+
1121
+ function _pipCountPendingRuns(pid) {
1122
+ let n = 0;
1123
+ for (const r of _pipRuns.values())
1124
+ if (
1125
+ r.pipelineId === pid &&
1126
+ (r.status === PIPELINE_RUN_LIFECYCLE_V2.QUEUED ||
1127
+ r.status === PIPELINE_RUN_LIFECYCLE_V2.RUNNING)
1128
+ )
1129
+ n++;
1130
+ return n;
1131
+ }
1132
+
1133
+ export function createPipelineRunV2({
1134
+ id,
1135
+ pipelineId,
1136
+ trigger,
1137
+ metadata,
1138
+ } = {}) {
1139
+ if (!id || typeof id !== "string") throw new Error("id is required");
1140
+ if (!pipelineId || typeof pipelineId !== "string")
1141
+ throw new Error("pipelineId is required");
1142
+ if (_pipRuns.has(id)) throw new Error(`pipeline run ${id} already exists`);
1143
+ if (!_pips.has(pipelineId))
1144
+ throw new Error(`pipeline ${pipelineId} not found`);
1145
+ const pending = _pipCountPendingRuns(pipelineId);
1146
+ if (pending >= _pipMaxPendingPerPip)
1147
+ throw new Error(
1148
+ `max pending pipeline runs per pipeline (${_pipMaxPendingPerPip}) reached for ${pipelineId}`,
1149
+ );
1150
+ const now = Date.now();
1151
+ const r = {
1152
+ id,
1153
+ pipelineId,
1154
+ trigger: trigger || "manual",
1155
+ status: PIPELINE_RUN_LIFECYCLE_V2.QUEUED,
1156
+ createdAt: now,
1157
+ updatedAt: now,
1158
+ startedAt: null,
1159
+ settledAt: null,
1160
+ metadata: { ...(metadata || {}) },
1161
+ };
1162
+ _pipRuns.set(id, r);
1163
+ return { ...r, metadata: { ...r.metadata } };
1164
+ }
1165
+ function _pipCheckR(from, to) {
1166
+ const a = _pipRunTrans.get(from);
1167
+ if (!a || !a.has(to))
1168
+ throw new Error(`invalid pipeline run transition ${from} → ${to}`);
1169
+ }
1170
+ export function startPipelineRunV2(id) {
1171
+ const r = _pipRuns.get(id);
1172
+ if (!r) throw new Error(`pipeline run ${id} not found`);
1173
+ _pipCheckR(r.status, PIPELINE_RUN_LIFECYCLE_V2.RUNNING);
1174
+ const now = Date.now();
1175
+ r.status = PIPELINE_RUN_LIFECYCLE_V2.RUNNING;
1176
+ r.updatedAt = now;
1177
+ if (!r.startedAt) r.startedAt = now;
1178
+ return { ...r, metadata: { ...r.metadata } };
1179
+ }
1180
+ export function completePipelineRunV2(id) {
1181
+ const r = _pipRuns.get(id);
1182
+ if (!r) throw new Error(`pipeline run ${id} not found`);
1183
+ _pipCheckR(r.status, PIPELINE_RUN_LIFECYCLE_V2.COMPLETED);
1184
+ const now = Date.now();
1185
+ r.status = PIPELINE_RUN_LIFECYCLE_V2.COMPLETED;
1186
+ r.updatedAt = now;
1187
+ if (!r.settledAt) r.settledAt = now;
1188
+ return { ...r, metadata: { ...r.metadata } };
1189
+ }
1190
+ export function failPipelineRunV2(id, reason) {
1191
+ const r = _pipRuns.get(id);
1192
+ if (!r) throw new Error(`pipeline run ${id} not found`);
1193
+ _pipCheckR(r.status, PIPELINE_RUN_LIFECYCLE_V2.FAILED);
1194
+ const now = Date.now();
1195
+ r.status = PIPELINE_RUN_LIFECYCLE_V2.FAILED;
1196
+ r.updatedAt = now;
1197
+ if (!r.settledAt) r.settledAt = now;
1198
+ if (reason) r.metadata.failReason = String(reason);
1199
+ return { ...r, metadata: { ...r.metadata } };
1200
+ }
1201
+ export function cancelPipelineRunV2(id, reason) {
1202
+ const r = _pipRuns.get(id);
1203
+ if (!r) throw new Error(`pipeline run ${id} not found`);
1204
+ _pipCheckR(r.status, PIPELINE_RUN_LIFECYCLE_V2.CANCELLED);
1205
+ const now = Date.now();
1206
+ r.status = PIPELINE_RUN_LIFECYCLE_V2.CANCELLED;
1207
+ r.updatedAt = now;
1208
+ if (!r.settledAt) r.settledAt = now;
1209
+ if (reason) r.metadata.cancelReason = String(reason);
1210
+ return { ...r, metadata: { ...r.metadata } };
1211
+ }
1212
+ export function getPipelineRunV2(id) {
1213
+ const r = _pipRuns.get(id);
1214
+ if (!r) return null;
1215
+ return { ...r, metadata: { ...r.metadata } };
1216
+ }
1217
+ export function listPipelineRunsV2() {
1218
+ return [..._pipRuns.values()].map((r) => ({
1219
+ ...r,
1220
+ metadata: { ...r.metadata },
1221
+ }));
1222
+ }
1223
+
1224
+ export function autoPauseIdlePipelinesV2({ now } = {}) {
1225
+ const t = now ?? Date.now();
1226
+ const flipped = [];
1227
+ for (const p of _pips.values())
1228
+ if (
1229
+ p.status === PIPELINE_MATURITY_V2.ACTIVE &&
1230
+ t - p.lastTouchedAt >= _pipIdleMs
1231
+ ) {
1232
+ p.status = PIPELINE_MATURITY_V2.PAUSED;
1233
+ p.updatedAt = t;
1234
+ flipped.push(p.id);
1235
+ }
1236
+ return { flipped, count: flipped.length };
1237
+ }
1238
+ export function autoFailStuckPipelineRunsV2({ now } = {}) {
1239
+ const t = now ?? Date.now();
1240
+ const flipped = [];
1241
+ for (const r of _pipRuns.values())
1242
+ if (
1243
+ r.status === PIPELINE_RUN_LIFECYCLE_V2.RUNNING &&
1244
+ r.startedAt != null &&
1245
+ t - r.startedAt >= _pipRunStuckMs
1246
+ ) {
1247
+ r.status = PIPELINE_RUN_LIFECYCLE_V2.FAILED;
1248
+ r.updatedAt = t;
1249
+ if (!r.settledAt) r.settledAt = t;
1250
+ r.metadata.failReason = "auto-fail-stuck";
1251
+ flipped.push(r.id);
1252
+ }
1253
+ return { flipped, count: flipped.length };
1254
+ }
1255
+
1256
+ export function getPipelineOrchestratorGovStatsV2() {
1257
+ const pipelinesByStatus = {};
1258
+ for (const s of Object.values(PIPELINE_MATURITY_V2)) pipelinesByStatus[s] = 0;
1259
+ for (const p of _pips.values()) pipelinesByStatus[p.status]++;
1260
+ const runsByStatus = {};
1261
+ for (const s of Object.values(PIPELINE_RUN_LIFECYCLE_V2)) runsByStatus[s] = 0;
1262
+ for (const r of _pipRuns.values()) runsByStatus[r.status]++;
1263
+ return {
1264
+ totalPipelinesV2: _pips.size,
1265
+ totalRunsV2: _pipRuns.size,
1266
+ maxActivePipelinesPerOwner: _pipMaxActivePerOwner,
1267
+ maxPendingPipelineRunsPerPipeline: _pipMaxPendingPerPip,
1268
+ pipelineIdleMs: _pipIdleMs,
1269
+ pipelineRunStuckMs: _pipRunStuckMs,
1270
+ pipelinesByStatus,
1271
+ runsByStatus,
1272
+ };
1273
+ }
@@ -544,3 +544,331 @@ export function destroyPlanModeManager() {
544
544
  _instance = null;
545
545
  }
546
546
  }
547
+
548
+ // ===== V2 Surface: Plan Mode governance overlay (CLI v0.141.0) =====
549
+ export const PLAN_PROFILE_MATURITY_V2 = Object.freeze({
550
+ PENDING: "pending",
551
+ ACTIVE: "active",
552
+ PAUSED: "paused",
553
+ ARCHIVED: "archived",
554
+ });
555
+ export const PLAN_STEP_LIFECYCLE_V2 = Object.freeze({
556
+ QUEUED: "queued",
557
+ RUNNING: "running",
558
+ COMPLETED: "completed",
559
+ FAILED: "failed",
560
+ CANCELLED: "cancelled",
561
+ });
562
+ const _planPTrans = new Map([
563
+ [
564
+ PLAN_PROFILE_MATURITY_V2.PENDING,
565
+ new Set([
566
+ PLAN_PROFILE_MATURITY_V2.ACTIVE,
567
+ PLAN_PROFILE_MATURITY_V2.ARCHIVED,
568
+ ]),
569
+ ],
570
+ [
571
+ PLAN_PROFILE_MATURITY_V2.ACTIVE,
572
+ new Set([
573
+ PLAN_PROFILE_MATURITY_V2.PAUSED,
574
+ PLAN_PROFILE_MATURITY_V2.ARCHIVED,
575
+ ]),
576
+ ],
577
+ [
578
+ PLAN_PROFILE_MATURITY_V2.PAUSED,
579
+ new Set([
580
+ PLAN_PROFILE_MATURITY_V2.ACTIVE,
581
+ PLAN_PROFILE_MATURITY_V2.ARCHIVED,
582
+ ]),
583
+ ],
584
+ [PLAN_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
585
+ ]);
586
+ const _planPTerminal = new Set([PLAN_PROFILE_MATURITY_V2.ARCHIVED]);
587
+ const _planSTrans = new Map([
588
+ [
589
+ PLAN_STEP_LIFECYCLE_V2.QUEUED,
590
+ new Set([PLAN_STEP_LIFECYCLE_V2.RUNNING, PLAN_STEP_LIFECYCLE_V2.CANCELLED]),
591
+ ],
592
+ [
593
+ PLAN_STEP_LIFECYCLE_V2.RUNNING,
594
+ new Set([
595
+ PLAN_STEP_LIFECYCLE_V2.COMPLETED,
596
+ PLAN_STEP_LIFECYCLE_V2.FAILED,
597
+ PLAN_STEP_LIFECYCLE_V2.CANCELLED,
598
+ ]),
599
+ ],
600
+ [PLAN_STEP_LIFECYCLE_V2.COMPLETED, new Set()],
601
+ [PLAN_STEP_LIFECYCLE_V2.FAILED, new Set()],
602
+ [PLAN_STEP_LIFECYCLE_V2.CANCELLED, new Set()],
603
+ ]);
604
+ const _planPsV2 = new Map();
605
+ const _planSsV2 = new Map();
606
+ let _planMaxActivePerOwner = 6,
607
+ _planMaxPendingStepsPerProfile = 15,
608
+ _planIdleMs = 7 * 24 * 60 * 60 * 1000,
609
+ _planStuckMs = 30 * 60 * 1000;
610
+ function _planPos(n, label) {
611
+ const v = Math.floor(Number(n));
612
+ if (!Number.isFinite(v) || v <= 0)
613
+ throw new Error(`${label} must be positive integer`);
614
+ return v;
615
+ }
616
+ function _planCheckP(from, to) {
617
+ const a = _planPTrans.get(from);
618
+ if (!a || !a.has(to))
619
+ throw new Error(`invalid plan profile transition ${from} → ${to}`);
620
+ }
621
+ function _planCheckS(from, to) {
622
+ const a = _planSTrans.get(from);
623
+ if (!a || !a.has(to))
624
+ throw new Error(`invalid plan step transition ${from} → ${to}`);
625
+ }
626
+ export function setMaxActivePlanProfilesPerOwnerV2(n) {
627
+ _planMaxActivePerOwner = _planPos(n, "maxActivePlanProfilesPerOwner");
628
+ }
629
+ export function getMaxActivePlanProfilesPerOwnerV2() {
630
+ return _planMaxActivePerOwner;
631
+ }
632
+ export function setMaxPendingPlanStepsPerProfileV2(n) {
633
+ _planMaxPendingStepsPerProfile = _planPos(n, "maxPendingPlanStepsPerProfile");
634
+ }
635
+ export function getMaxPendingPlanStepsPerProfileV2() {
636
+ return _planMaxPendingStepsPerProfile;
637
+ }
638
+ export function setPlanProfileIdleMsV2(n) {
639
+ _planIdleMs = _planPos(n, "planProfileIdleMs");
640
+ }
641
+ export function getPlanProfileIdleMsV2() {
642
+ return _planIdleMs;
643
+ }
644
+ export function setPlanStepStuckMsV2(n) {
645
+ _planStuckMs = _planPos(n, "planStepStuckMs");
646
+ }
647
+ export function getPlanStepStuckMsV2() {
648
+ return _planStuckMs;
649
+ }
650
+ export function _resetStatePlanModeV2() {
651
+ _planPsV2.clear();
652
+ _planSsV2.clear();
653
+ _planMaxActivePerOwner = 6;
654
+ _planMaxPendingStepsPerProfile = 15;
655
+ _planIdleMs = 7 * 24 * 60 * 60 * 1000;
656
+ _planStuckMs = 30 * 60 * 1000;
657
+ }
658
+ export function registerPlanProfileV2({ id, owner, goal, metadata } = {}) {
659
+ if (!id) throw new Error("plan profile id required");
660
+ if (!owner) throw new Error("plan profile owner required");
661
+ if (_planPsV2.has(id))
662
+ throw new Error(`plan profile ${id} already registered`);
663
+ const now = Date.now();
664
+ const p = {
665
+ id,
666
+ owner,
667
+ goal: goal || "",
668
+ status: PLAN_PROFILE_MATURITY_V2.PENDING,
669
+ createdAt: now,
670
+ updatedAt: now,
671
+ activatedAt: null,
672
+ archivedAt: null,
673
+ lastTouchedAt: now,
674
+ metadata: { ...(metadata || {}) },
675
+ };
676
+ _planPsV2.set(id, p);
677
+ return { ...p, metadata: { ...p.metadata } };
678
+ }
679
+ function _planCountActive(owner) {
680
+ let n = 0;
681
+ for (const p of _planPsV2.values())
682
+ if (p.owner === owner && p.status === PLAN_PROFILE_MATURITY_V2.ACTIVE) n++;
683
+ return n;
684
+ }
685
+ export function activatePlanProfileV2(id) {
686
+ const p = _planPsV2.get(id);
687
+ if (!p) throw new Error(`plan profile ${id} not found`);
688
+ _planCheckP(p.status, PLAN_PROFILE_MATURITY_V2.ACTIVE);
689
+ const recovery = p.status === PLAN_PROFILE_MATURITY_V2.PAUSED;
690
+ if (!recovery && _planCountActive(p.owner) >= _planMaxActivePerOwner)
691
+ throw new Error(`max active plan profiles for owner ${p.owner} reached`);
692
+ const now = Date.now();
693
+ p.status = PLAN_PROFILE_MATURITY_V2.ACTIVE;
694
+ p.updatedAt = now;
695
+ p.lastTouchedAt = now;
696
+ if (!p.activatedAt) p.activatedAt = now;
697
+ return { ...p, metadata: { ...p.metadata } };
698
+ }
699
+ export function pausePlanProfileV2(id) {
700
+ const p = _planPsV2.get(id);
701
+ if (!p) throw new Error(`plan profile ${id} not found`);
702
+ _planCheckP(p.status, PLAN_PROFILE_MATURITY_V2.PAUSED);
703
+ p.status = PLAN_PROFILE_MATURITY_V2.PAUSED;
704
+ p.updatedAt = Date.now();
705
+ return { ...p, metadata: { ...p.metadata } };
706
+ }
707
+ export function archivePlanProfileV2(id) {
708
+ const p = _planPsV2.get(id);
709
+ if (!p) throw new Error(`plan profile ${id} not found`);
710
+ _planCheckP(p.status, PLAN_PROFILE_MATURITY_V2.ARCHIVED);
711
+ const now = Date.now();
712
+ p.status = PLAN_PROFILE_MATURITY_V2.ARCHIVED;
713
+ p.updatedAt = now;
714
+ if (!p.archivedAt) p.archivedAt = now;
715
+ return { ...p, metadata: { ...p.metadata } };
716
+ }
717
+ export function touchPlanProfileV2(id) {
718
+ const p = _planPsV2.get(id);
719
+ if (!p) throw new Error(`plan profile ${id} not found`);
720
+ if (_planPTerminal.has(p.status))
721
+ throw new Error(`cannot touch terminal plan profile ${id}`);
722
+ const now = Date.now();
723
+ p.lastTouchedAt = now;
724
+ p.updatedAt = now;
725
+ return { ...p, metadata: { ...p.metadata } };
726
+ }
727
+ export function getPlanProfileV2(id) {
728
+ const p = _planPsV2.get(id);
729
+ if (!p) return null;
730
+ return { ...p, metadata: { ...p.metadata } };
731
+ }
732
+ export function listPlanProfilesV2() {
733
+ return [..._planPsV2.values()].map((p) => ({
734
+ ...p,
735
+ metadata: { ...p.metadata },
736
+ }));
737
+ }
738
+ function _planCountPending(profileId) {
739
+ let n = 0;
740
+ for (const s of _planSsV2.values())
741
+ if (
742
+ s.profileId === profileId &&
743
+ (s.status === PLAN_STEP_LIFECYCLE_V2.QUEUED ||
744
+ s.status === PLAN_STEP_LIFECYCLE_V2.RUNNING)
745
+ )
746
+ n++;
747
+ return n;
748
+ }
749
+ export function createPlanStepV2({ id, profileId, action, metadata } = {}) {
750
+ if (!id) throw new Error("plan step id required");
751
+ if (!profileId) throw new Error("plan step profileId required");
752
+ if (_planSsV2.has(id)) throw new Error(`plan step ${id} already exists`);
753
+ if (!_planPsV2.has(profileId))
754
+ throw new Error(`plan profile ${profileId} not found`);
755
+ if (_planCountPending(profileId) >= _planMaxPendingStepsPerProfile)
756
+ throw new Error(`max pending plan steps for profile ${profileId} reached`);
757
+ const now = Date.now();
758
+ const s = {
759
+ id,
760
+ profileId,
761
+ action: action || "",
762
+ status: PLAN_STEP_LIFECYCLE_V2.QUEUED,
763
+ createdAt: now,
764
+ updatedAt: now,
765
+ startedAt: null,
766
+ settledAt: null,
767
+ metadata: { ...(metadata || {}) },
768
+ };
769
+ _planSsV2.set(id, s);
770
+ return { ...s, metadata: { ...s.metadata } };
771
+ }
772
+ export function startPlanStepV2(id) {
773
+ const s = _planSsV2.get(id);
774
+ if (!s) throw new Error(`plan step ${id} not found`);
775
+ _planCheckS(s.status, PLAN_STEP_LIFECYCLE_V2.RUNNING);
776
+ const now = Date.now();
777
+ s.status = PLAN_STEP_LIFECYCLE_V2.RUNNING;
778
+ s.updatedAt = now;
779
+ if (!s.startedAt) s.startedAt = now;
780
+ return { ...s, metadata: { ...s.metadata } };
781
+ }
782
+ export function completePlanStepV2(id) {
783
+ const s = _planSsV2.get(id);
784
+ if (!s) throw new Error(`plan step ${id} not found`);
785
+ _planCheckS(s.status, PLAN_STEP_LIFECYCLE_V2.COMPLETED);
786
+ const now = Date.now();
787
+ s.status = PLAN_STEP_LIFECYCLE_V2.COMPLETED;
788
+ s.updatedAt = now;
789
+ if (!s.settledAt) s.settledAt = now;
790
+ return { ...s, metadata: { ...s.metadata } };
791
+ }
792
+ export function failPlanStepV2(id, reason) {
793
+ const s = _planSsV2.get(id);
794
+ if (!s) throw new Error(`plan step ${id} not found`);
795
+ _planCheckS(s.status, PLAN_STEP_LIFECYCLE_V2.FAILED);
796
+ const now = Date.now();
797
+ s.status = PLAN_STEP_LIFECYCLE_V2.FAILED;
798
+ s.updatedAt = now;
799
+ if (!s.settledAt) s.settledAt = now;
800
+ if (reason) s.metadata.failReason = String(reason);
801
+ return { ...s, metadata: { ...s.metadata } };
802
+ }
803
+ export function cancelPlanStepV2(id, reason) {
804
+ const s = _planSsV2.get(id);
805
+ if (!s) throw new Error(`plan step ${id} not found`);
806
+ _planCheckS(s.status, PLAN_STEP_LIFECYCLE_V2.CANCELLED);
807
+ const now = Date.now();
808
+ s.status = PLAN_STEP_LIFECYCLE_V2.CANCELLED;
809
+ s.updatedAt = now;
810
+ if (!s.settledAt) s.settledAt = now;
811
+ if (reason) s.metadata.cancelReason = String(reason);
812
+ return { ...s, metadata: { ...s.metadata } };
813
+ }
814
+ export function getPlanStepV2(id) {
815
+ const s = _planSsV2.get(id);
816
+ if (!s) return null;
817
+ return { ...s, metadata: { ...s.metadata } };
818
+ }
819
+ export function listPlanStepsV2() {
820
+ return [..._planSsV2.values()].map((s) => ({
821
+ ...s,
822
+ metadata: { ...s.metadata },
823
+ }));
824
+ }
825
+ export function autoPauseIdlePlanProfilesV2({ now } = {}) {
826
+ const t = now ?? Date.now();
827
+ const flipped = [];
828
+ for (const p of _planPsV2.values())
829
+ if (
830
+ p.status === PLAN_PROFILE_MATURITY_V2.ACTIVE &&
831
+ t - p.lastTouchedAt >= _planIdleMs
832
+ ) {
833
+ p.status = PLAN_PROFILE_MATURITY_V2.PAUSED;
834
+ p.updatedAt = t;
835
+ flipped.push(p.id);
836
+ }
837
+ return { flipped, count: flipped.length };
838
+ }
839
+ export function autoFailStuckPlanStepsV2({ now } = {}) {
840
+ const t = now ?? Date.now();
841
+ const flipped = [];
842
+ for (const s of _planSsV2.values())
843
+ if (
844
+ s.status === PLAN_STEP_LIFECYCLE_V2.RUNNING &&
845
+ s.startedAt != null &&
846
+ t - s.startedAt >= _planStuckMs
847
+ ) {
848
+ s.status = PLAN_STEP_LIFECYCLE_V2.FAILED;
849
+ s.updatedAt = t;
850
+ if (!s.settledAt) s.settledAt = t;
851
+ s.metadata.failReason = "auto-fail-stuck";
852
+ flipped.push(s.id);
853
+ }
854
+ return { flipped, count: flipped.length };
855
+ }
856
+ export function getPlanModeGovStatsV2() {
857
+ const profilesByStatus = {};
858
+ for (const v of Object.values(PLAN_PROFILE_MATURITY_V2))
859
+ profilesByStatus[v] = 0;
860
+ for (const p of _planPsV2.values()) profilesByStatus[p.status]++;
861
+ const stepsByStatus = {};
862
+ for (const v of Object.values(PLAN_STEP_LIFECYCLE_V2)) stepsByStatus[v] = 0;
863
+ for (const s of _planSsV2.values()) stepsByStatus[s.status]++;
864
+ return {
865
+ totalPlanProfilesV2: _planPsV2.size,
866
+ totalPlanStepsV2: _planSsV2.size,
867
+ maxActivePlanProfilesPerOwner: _planMaxActivePerOwner,
868
+ maxPendingPlanStepsPerProfile: _planMaxPendingStepsPerProfile,
869
+ planProfileIdleMs: _planIdleMs,
870
+ planStepStuckMs: _planStuckMs,
871
+ profilesByStatus,
872
+ stepsByStatus,
873
+ };
874
+ }