@senpi/runtime 3.0.9-dev.feat-strategy-compos.20260721003344 → 3.0.9-dev.feat-strategy-compos.20260722213012

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 (46) hide show
  1. package/dist/cli/composer-commands.d.ts.map +1 -1
  2. package/dist/cli/composer-commands.js +193 -41
  3. package/dist/cli/composer-commands.js.map +1 -1
  4. package/dist/cli/composer-live-read.d.ts +68 -0
  5. package/dist/cli/composer-live-read.d.ts.map +1 -0
  6. package/dist/cli/composer-live-read.js +126 -0
  7. package/dist/cli/composer-live-read.js.map +1 -0
  8. package/dist/cli/senpi-commands.d.ts.map +1 -1
  9. package/dist/cli/senpi-commands.js +8 -10
  10. package/dist/cli/senpi-commands.js.map +1 -1
  11. package/dist/cli/senpi-strategy-tool.d.ts +56 -0
  12. package/dist/cli/senpi-strategy-tool.d.ts.map +1 -0
  13. package/dist/cli/senpi-strategy-tool.js +158 -0
  14. package/dist/cli/senpi-strategy-tool.js.map +1 -0
  15. package/dist/composer/authoring/__init__.py +2 -0
  16. package/dist/composer/authoring/answers.py +52 -0
  17. package/dist/composer/authoring/archetypes/__init__.py +2 -0
  18. package/dist/composer/authoring/archetypes/contrarian_fade.py +493 -0
  19. package/dist/composer/authoring/archetypes/relative_value.py +280 -23
  20. package/dist/composer/cli.py +57 -6
  21. package/dist/composer/examples/contrarian_fade_crowd.graph.yaml +356 -0
  22. package/dist/composer/examples/rotation_cross_sectional.graph.yaml +389 -0
  23. package/dist/composer/generated/catalog.md +2 -1
  24. package/dist/composer/registry/generate.py +2 -1
  25. package/dist/composer/validator/errors.py +2 -0
  26. package/dist/composer/verbs/__init__.py +6 -0
  27. package/dist/composer/verbs/_box.py +96 -5
  28. package/dist/composer/verbs/_layout.py +37 -0
  29. package/dist/composer/verbs/_live.py +50 -6
  30. package/dist/composer/verbs/close.py +51 -6
  31. package/dist/composer/verbs/fund.py +144 -27
  32. package/dist/composer/verbs/install.py +25 -6
  33. package/dist/composer/verbs/portfolio.py +650 -0
  34. package/dist/composer/verbs/review.py +724 -0
  35. package/dist/composer/verbs/status.py +129 -2
  36. package/dist/composer/verbs/update.py +9 -3
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +22 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/runtime/composer-managed-write.d.ts +133 -0
  42. package/dist/runtime/composer-managed-write.d.ts.map +1 -0
  43. package/dist/runtime/composer-managed-write.js +369 -0
  44. package/dist/runtime/composer-managed-write.js.map +1 -0
  45. package/openclaw.plugin.json +5 -0
  46. package/package.json +2 -1
@@ -53,7 +53,7 @@ from typing import Optional
53
53
  from composer.authoring import emit
54
54
 
55
55
  from . import _box, _live
56
- from ._box import ListFn, runtime_running, wallet_match
56
+ from ._box import ListFn, PositionsFn, runtime_running, wallet_match
57
57
  from ._live import (
58
58
  LiveState,
59
59
  SystemStateFn,
@@ -64,13 +64,17 @@ from ._live import (
64
64
  )
65
65
  from ._layout import (
66
66
  COMPOSER_DIR,
67
+ KIND_MANAGED,
68
+ KIND_MANUAL,
67
69
  LEGACY_STRATEGIES_DIR,
68
70
  archives_dir,
69
71
  canonical_graph_path,
70
72
  canonical_releases_dir,
71
73
  canonical_staged_dir,
74
+ canonical_wallet_json,
72
75
  is_canonical_graph,
73
76
  iter_release_dirs,
77
+ read_strategy_kind,
74
78
  resolve_wallet_json,
75
79
  runtime_state_dir,
76
80
  )
@@ -86,6 +90,10 @@ INSTALLABLE = "installable"
86
90
  INSTALLED_UNREGISTERED = "installed_unregistered"
87
91
  INSTALLED_STOPPED = "installed_stopped"
88
92
  INSTALLED_RUNNING = "installed_running"
93
+ # J3: a MANUAL strategy — a funded wallet with NO graph/runtime, under the composer record system.
94
+ # It has its own terminal-ish position (there is no lifecycle to advance): the sanctioned action is
95
+ # to edit positions directly via MCP, or `composer close` to tear it down.
96
+ MANUAL = "manual"
89
97
 
90
98
  # Honest liveness caveat appended to a running install (process-level ≠ functional liveness).
91
99
  LIVE_NOT_CHECKED = (
@@ -103,6 +111,7 @@ _NEXT = {
103
111
  INSTALLED_UNREGISTERED: ("composer install", "landed on the box but the runtime was never registered (interrupted install) — re-run `composer install` to finish it."),
104
112
  INSTALLED_STOPPED: ("composer install", "installed + registered but the runtime is NOT running — re-run `composer install`, or check `openclaw senpi runtime list`."),
105
113
  INSTALLED_RUNNING: ("(none)", "installed and running — observe the live tick (`openclaw senpi state -r <id>` for functional liveness)."),
114
+ MANUAL: ("(none)", "manual strategy — a wallet with NO runtime; edit positions directly via MCP (the sanctioned path for this kind), or `composer close` to tear it down and return funds."),
106
115
  }
107
116
 
108
117
 
@@ -185,6 +194,14 @@ class StatusResult:
185
194
  live: Optional[LiveState] = None
186
195
  sizing: dict = field(default_factory=dict)
187
196
  unmanaged_runtimes: list[str] = field(default_factory=list)
197
+ # J3: the strategy KIND predicate (managed = a graph strategy; manual = a wallet with no
198
+ # runtime). Carried in --json on every on-box status row so hooks/doctrine (J4/J5) get a
199
+ # machine-readable kind. The manual fields below are populated only for a MANUAL strategy.
200
+ kind: str = KIND_MANAGED
201
+ wallet: Optional[str] = None
202
+ strategy_id: Optional[str] = None # the backend strategy-record pointer (manual)
203
+ manual_positions: Optional[list[dict]] = None # None = not read; [] = read + flat
204
+ manual_positions_reason: str = "" # why positions are unavailable (LOUD, never assumed)
188
205
 
189
206
  @property
190
207
  def next_verb(self) -> str:
@@ -199,6 +216,8 @@ class StatusResult:
199
216
  return next((i for i in self.installs if i.is_current), None)
200
217
 
201
218
  def to_json(self) -> dict:
219
+ if self.position == MANUAL:
220
+ return self._manual_to_json()
202
221
  out = {
203
222
  "verb": "status",
204
223
  "target": self.target,
@@ -225,6 +244,9 @@ class StatusResult:
225
244
  out["paths"] = self.paths
226
245
  if self.split_warning:
227
246
  out["split_warning"] = self.split_warning
247
+ # J3 predicate: the kind rides on every ON-BOX status row (state root known) so hooks and
248
+ # doctrine (J4/J5) can branch on managed-vs-manual without re-deriving it.
249
+ out["kind"] = self.kind
228
250
  if self.unmanaged_runtimes:
229
251
  out["unmanaged_runtimes"] = self.unmanaged_runtimes
230
252
  if self.live is not None:
@@ -234,7 +256,32 @@ class StatusResult:
234
256
  out["live"] = live
235
257
  return out
236
258
 
259
+ def _manual_to_json(self) -> dict:
260
+ """The MANUAL-kind status shape (J3): a wallet + backend-record pointer, honest about the
261
+ absence of a runtime, and the wallet's open positions when the seam is wired."""
262
+ return {
263
+ "verb": "status",
264
+ "target": self.target,
265
+ "exists": True,
266
+ "position": MANUAL,
267
+ "kind": KIND_MANUAL,
268
+ "strategy": self.strategy,
269
+ "wallet": self.wallet,
270
+ "strategy_id": self.strategy_id,
271
+ "runtime": "none (manual by design — no runtime)",
272
+ "positions": {
273
+ "available": self.manual_positions is not None,
274
+ "reason": self.manual_positions_reason,
275
+ "positions": list(self.manual_positions or []),
276
+ },
277
+ "sanctioned_writes": "direct MCP position edits on this wallet",
278
+ "next_verb": self.next_verb,
279
+ "next": self.next_hint,
280
+ }
281
+
237
282
  def render(self) -> str:
283
+ if self.position == MANUAL:
284
+ return self._render_manual()
238
285
  lines = [f"status: {self.target}", f" position : {self.position}"]
239
286
  if self.exists:
240
287
  lines.append(f" provenance : {self.provenance}")
@@ -280,6 +327,40 @@ class StatusResult:
280
327
  lines.append(f" next : {self.next_hint}")
281
328
  return "\n".join(lines) + "\n"
282
329
 
330
+ def _render_manual(self) -> str:
331
+ """The MANUAL-kind view (J3): render what IS true — wallet, backend-record pointer, an
332
+ honest 'no runtime — manual by design', and the wallet's open positions via the live seam.
333
+ There are NO protection lines: a manual strategy has no runtime/DSL, so direct MCP position
334
+ edits are the sanctioned path (stated plainly, never a false 'unprotected' alarm)."""
335
+ lines = [
336
+ f"status: {self.target}",
337
+ " position : manual",
338
+ " kind : manual (a wallet under the composer record system — NO graph/runtime)",
339
+ f" wallet : {self.wallet or 'unknown'}",
340
+ ]
341
+ if self.strategy_id:
342
+ lines.append(f" record : backend strategyId {self.strategy_id}")
343
+ lines.append(" runtime : none — manual by design (no runtime is installed for a manual "
344
+ "strategy)")
345
+ # positions from the live seam (the wallet's clearinghouse state) — LOUD when unavailable.
346
+ if self.manual_positions is None:
347
+ reason = self.manual_positions_reason or "no positions source wired"
348
+ lines.append(f" positions : not read ({reason})")
349
+ elif not self.manual_positions:
350
+ lines.append(" positions : none open on this wallet")
351
+ else:
352
+ lines.append(f" positions : {len(self.manual_positions)} open on this wallet:")
353
+ for p in self.manual_positions:
354
+ asset = p.get("coin") or p.get("asset") or "?"
355
+ dex = p.get("dex")
356
+ book = f"@{dex}" if dex and dex != "main" else ""
357
+ sz = p.get("szi") if p.get("szi") is not None else p.get("size")
358
+ lines.append(f" - {asset}{book} size={sz}")
359
+ lines.append(" writes : direct MCP position edits on this wallet are the SANCTIONED "
360
+ "path for a manual strategy (there is no runtime to route through).")
361
+ lines.append(f" next : {self.next_hint}")
362
+ return "\n".join(lines) + "\n"
363
+
283
364
  def _render_live(self) -> list[str]:
284
365
  """The H2 live block: scanners in strategy language, per-position protection in plain ROE,
285
366
  and the risk gates + sizing. Unavailable degrades LOUD (CMP259), never silent."""
@@ -595,12 +676,58 @@ def _attach_live(result: StatusResult, state_dir, list_fn: ListFn,
595
676
  runtime_id=ci.runtime_id)
596
677
 
597
678
 
679
+ def _build_manual_status(label: str, strategy: str, state_dir: Path,
680
+ positions_fn: Optional[PositionsFn]) -> StatusResult:
681
+ """The MANUAL-kind status result (J3): read wallet + backend-record pointer from wallet.json,
682
+ and — when the positions seam is wired — the wallet's open positions (the live truth for a
683
+ manual strategy, which has no runtime). Unavailable positions are LOUD (never assumed flat)."""
684
+ wj_path, _layout = resolve_wallet_json(str(state_dir), strategy)
685
+ wallet: Optional[str] = None
686
+ strategy_id: Optional[str] = None
687
+ if wj_path is not None:
688
+ try:
689
+ rec = json.loads(wj_path.read_text(encoding="utf-8"))
690
+ wallet = str(rec.get("wallet")) if rec.get("wallet") else None
691
+ strategy_id = rec.get("strategyId")
692
+ except (OSError, json.JSONDecodeError):
693
+ pass
694
+
695
+ r = StatusResult(target=label, position=MANUAL, exists=True, kind=KIND_MANUAL,
696
+ strategy=strategy, wallet=wallet, strategy_id=strategy_id)
697
+
698
+ # positions via the existing clearinghouse seam (by wallet) — only when wired + a wallet is
699
+ # known. Default None => not read (LOUD), the composer never fans this per-wallet read out on its
700
+ # own; the rim / a test injects it.
701
+ if positions_fn is not None and wallet:
702
+ try:
703
+ res = positions_fn(wallet)
704
+ except Exception as e: # noqa: BLE001 — a seam fault must not crash status
705
+ r.manual_positions = None
706
+ r.manual_positions_reason = f"positions read raised ({e})"
707
+ else:
708
+ if res.verified:
709
+ r.manual_positions = list(res.positions)
710
+ else:
711
+ r.manual_positions = None
712
+ r.manual_positions_reason = res.reason or "positions unverifiable"
713
+ elif not wallet:
714
+ r.manual_positions_reason = "no wallet recorded in wallet.json"
715
+ return r
716
+
717
+
598
718
  def run_status(target, out_dir=None, *, state_dir=None,
599
719
  list_fn: ListFn = _box.default_list_runtimes,
600
- state_fn: SystemStateFn = _live.default_system_state) -> StatusResult:
720
+ state_fn: SystemStateFn = _live.default_system_state,
721
+ positions_fn: Optional[PositionsFn] = None) -> StatusResult:
601
722
  text, label, staged_dir, strategy = _resolve(target, out_dir, state_dir)
602
723
 
603
724
  if text is None:
725
+ # J3: a MANUAL strategy has NO graph (text is None) but a canonical wallet.json marked
726
+ # ``kind: manual``. Render its wallet-only view rather than the ABSENT "run `composer new`"
727
+ # (a manual strategy is legitimately graph-less). Needs the state root to find the marker.
728
+ if state_dir is not None and staged_dir is None \
729
+ and read_strategy_kind(state_dir, strategy) == KIND_MANUAL:
730
+ return _build_manual_status(label, strategy, Path(state_dir), positions_fn)
604
731
  # A bare strategy name / graph that does not exist yet, but the box has state for it: still
605
732
  # emit the install chain + path map so the operator can see what is on the box (G8b).
606
733
  if state_dir is not None and staged_dir is None:
@@ -437,7 +437,13 @@ def run_update(
437
437
  Location(),
438
438
  ), strategy=strategy, wallet=wallet)
439
439
 
440
- # (2) FIND the runtime(s) bound to this wallet.
440
+ # (2) FIND the runtime(s) bound to this wallet. The discovery read may come from a rim-served
441
+ # snapshot (J9); the post-delete CONFIRM below must re-read FRESH — a snapshot predates the delete
442
+ # and would falsely see the just-deleted runtime as still live (CMP245). Only the PRODUCTION
443
+ # default seam is redirected to a fresh shell; an INJECTED seam (tests) serves both unchanged.
444
+ confirm_list_fn: ListFn = (
445
+ _box.list_runtimes_fresh if list_fn is _box.default_list_runtimes else list_fn
446
+ )
441
447
  runtimes = list_fn()
442
448
  matches = [r for r in runtimes if wallet_match(r.get("wallet"), wallet)]
443
449
 
@@ -585,9 +591,9 @@ def run_update(
585
591
  Location(),
586
592
  )],
587
593
  message="old runtime delete failed; strategy unchanged.", **base_kw)
588
- # CONFIRM gone (mirror close.py's invariant confirm).
594
+ # CONFIRM gone (mirror close.py's invariant confirm) — FRESH read, never a rim snapshot (J9).
589
595
  if any(wallet_match(r.get("wallet"), wallet) and r.get("name") == old_runtime_id
590
- for r in list_fn()):
596
+ for r in confirm_list_fn()):
591
597
  return UpdateResult(
592
598
  target=target, verdict=FAILED,
593
599
  errors=[TeachingError(
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  * that reason. Keeping every export in a single file (this one) avoids
12
12
  * the loader's relative-import path entirely.
13
13
  */
14
+ import { type GatewayToolDefinition } from "./cli/senpi-strategy-tool.js";
14
15
  import type { RuntimeSystemState } from "./health/index.js";
15
16
  import type { SenpiEventBus } from "./dsl/events/index.js";
16
17
  import type { IntakeContext } from "./runtime-api/intake/intake-context.js";
@@ -131,13 +132,14 @@ interface PluginApi {
131
132
  }) => void, opts?: {
132
133
  commands: string[];
133
134
  }): void;
135
+ registerTool?(tool: GatewayToolDefinition): void;
134
136
  registerGatewayMethod(name: string, handler: (ctx: {
135
137
  respond: (ok: boolean, value: unknown) => void;
136
138
  params?: Record<string, unknown>;
137
139
  }) => void | Promise<void>, opts?: {
138
140
  scope?: OperatorScope;
139
141
  }): void;
140
- on(hookName: string, handler: (...args: unknown[]) => void | Promise<void>, opts?: {
142
+ on(hookName: string, handler: (...args: unknown[]) => unknown, opts?: {
141
143
  priority?: number;
142
144
  }): void;
143
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import { SenpiClient } from "./senpi/client.js";
17
17
  import { AuditQueryError } from "./runtime/audit-query.types.js";
18
18
  import { buildRuntimeStateDir, archiveStateDir } from "./runtime/state-layout.js";
19
19
  import { registerSenpiCli } from "./cli/senpi-commands.js";
20
+ import { createSenpiStrategyTool } from "./cli/senpi-strategy-tool.js";
20
21
  import { readSenpiCliStore, resolveSenpiApiKeyFromStore, resolveSenpiBaseStateDir, resolveTelegramChatIdFromStore, } from "./cli/senpi-cli-config.js";
21
22
  import { getDefaultStateDir } from "./runtime/default-state-dir.js";
22
23
  import { createNotificationService } from "./runtime/notifications.js";
@@ -34,6 +35,7 @@ import { VERSION } from "./version.js";
34
35
  import { resolvePackageName } from "./runtime/auto-update/resolve-package-name.js";
35
36
  import { runOpenClawPluginsUpdate } from "./runtime/auto-update/run-update-command.js";
36
37
  import { registerSpanHooks } from "./telemetry/spans/index.js";
38
+ import { registerComposerWriteAnnotationHook } from "./runtime/composer-managed-write.js";
37
39
  import { initDefaultPiiRedactor } from "./telemetry/spans/redact-pii.js";
38
40
  import { initOtelSdk, shutdownOtelSdk } from "./telemetry/otel-sdk.js";
39
41
  import { getLogLevel, getLogLevelSource, parseLogLevel, setErrorNotifier, setLogLevel, } from "./utils/logger.js";
@@ -318,6 +320,19 @@ const senpiRuntimePlugin = {
318
320
  err: err instanceof Error ? err.message : String(err),
319
321
  });
320
322
  }
323
+ // J4 — composer-managed position-write annotation. Point the "side door"
324
+ // (direct backend MCP position/protection edits) back at the sanctioned
325
+ // record path (graph spec.protection → composer check → composer update).
326
+ // Pointer-only: annotates the result, never blocks or damages the data path.
327
+ try {
328
+ registerComposerWriteAnnotationHook({ api, baseStateDir });
329
+ pluginLogger.info("[senpi-runtime] composer-managed write annotation hooks registered");
330
+ }
331
+ catch (err) {
332
+ pluginLogger.warn("[senpi-runtime] failed to register composer-managed write annotation hooks", {
333
+ err: err instanceof Error ? err.message : String(err),
334
+ });
335
+ }
321
336
  const runtimeHandles = new Map();
322
337
  let apiHandle;
323
338
  // Supervised scanner state — module-scoped so stop() can reach them.
@@ -714,6 +729,13 @@ const senpiRuntimePlugin = {
714
729
  pluginLogger.info("[senpi-runtime] CLI registrar callback invoked — attaching senpi subcommands to program");
715
730
  registerSenpiCli(ctx.program, baseStateDir);
716
731
  }, { commands: ["senpi"] });
732
+ if (typeof api.registerTool === "function") {
733
+ pluginLogger.info("[senpi-runtime] registering senpi_strategy gateway tool");
734
+ api.registerTool(createSenpiStrategyTool(baseStateDir));
735
+ }
736
+ else {
737
+ pluginLogger.warn("[senpi-runtime] api.registerTool unavailable on this openclaw version — senpi_strategy gateway tool NOT registered; strategy routing falls back to the exec CLI");
738
+ }
717
739
  /** Gateway respond accepts (ok, payload?, error?) with error as { code, message }; plugin SDK types may omit the third arg. */
718
740
  api.registerGatewayMethod("senpi.installRuntime", async (ctx) => {
719
741
  const { params } = ctx;