@holoscript/core 7.0.0 → 8.0.1
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/README.md +4 -4
- package/bin/holoscript.cjs +3 -0
- package/dist/GLTFPipeline-N6B6PJ6G.cjs +38 -0
- package/dist/GLTFPipeline-P3WMNYCN.js +17 -0
- package/dist/HoloScriptPlusParser-7FBIFUFC.js +693 -0
- package/dist/HoloScriptPlusParser-A2W7OCN2.cjs +698 -0
- package/dist/HoloScriptPlusParser-F2Z56FJR.js +10 -0
- package/dist/HoloScriptPlusParser-WKHRIH6T.cjs +27 -0
- package/dist/HoloScriptRuntime-CBYJX3LZ.js +10 -0
- package/dist/HoloScriptRuntime-VJ374RER.cjs +19 -0
- package/dist/USDZExporter-3FWJ25JI.cjs +1037 -0
- package/dist/USDZExporter-D2HQLQYK.js +1035 -0
- package/dist/agents/index.cjs +19 -0
- package/dist/agents/index.d.ts +100 -0
- package/dist/agents/index.js +17 -0
- package/dist/chunk-2BSMSUCE.js +1941 -0
- package/dist/chunk-2IWC4FP7.cjs +1189 -0
- package/dist/chunk-2M2DPHKB.js +762 -0
- package/dist/chunk-2X7NGX3M.js +2426 -0
- package/dist/chunk-2YSNA2F2.cjs +1274 -0
- package/dist/chunk-3FOKASKO.cjs +348 -0
- package/dist/chunk-3WZEJHUQ.cjs +116 -0
- package/dist/chunk-4C57PR42.js +468 -0
- package/dist/chunk-4GU5GCIY.js +1384 -0
- package/dist/chunk-4N4SXXWF.js +769 -0
- package/dist/chunk-4PDEPEQW.cjs +41 -0
- package/dist/chunk-4R6SBXDB.js +45 -0
- package/dist/chunk-4SDKXQ4C.js +811 -0
- package/dist/chunk-4V2E7U7Q.cjs +2015 -0
- package/dist/chunk-5FSKKMR7.cjs +2092 -0
- package/dist/chunk-5GLCTO44.js +161 -0
- package/dist/chunk-5H2G27PK.cjs +627 -0
- package/dist/chunk-5JEU52DW.js +382 -0
- package/dist/chunk-5NWINHR5.cjs +689 -0
- package/dist/chunk-5S7RKFGR.cjs +446 -0
- package/dist/chunk-5WUNN6ZN.cjs +428 -0
- package/dist/chunk-6CTRH7HT.cjs +1985 -0
- package/dist/chunk-6EX3I5P4.cjs +130 -0
- package/dist/chunk-6Q7RC2MK.cjs +1418 -0
- package/dist/chunk-7H33U5SM.cjs +413 -0
- package/dist/chunk-7M3PNU2M.cjs +672 -0
- package/dist/chunk-7T25IEZ2.js +449 -0
- package/dist/chunk-7V4JI5TB.cjs +6947 -0
- package/dist/chunk-A6KINLZJ.js +236 -0
- package/dist/chunk-ADADVMXY.js +404 -0
- package/dist/chunk-AIA52I7T.cjs +543 -0
- package/dist/chunk-ALC6K7GL.cjs +4402 -0
- package/dist/chunk-ANXZFVY2.js +113 -0
- package/dist/chunk-AOVGZ25K.cjs +56583 -0
- package/dist/chunk-AVJHHUC5.cjs +718 -0
- package/dist/chunk-BGY3SDG3.js +4396 -0
- package/dist/chunk-BOVPWH4H.js +3857 -0
- package/dist/chunk-BRQJKJGT.cjs +20 -0
- package/dist/chunk-C37BHB7N.cjs +636 -0
- package/dist/chunk-CBJY23VL.js +126 -0
- package/dist/chunk-CCATWPXM.js +778 -0
- package/dist/chunk-CIWWXYHZ.cjs +50 -0
- package/dist/chunk-CMT5NMMS.js +669 -0
- package/dist/chunk-CR4FMIWL.cjs +1049 -0
- package/dist/chunk-CR7XRXRN.cjs +639 -0
- package/dist/chunk-CSD27UNQ.js +2176 -0
- package/dist/chunk-D3STJ56J.js +714 -0
- package/dist/chunk-DAJXW4KX.js +725 -0
- package/dist/chunk-DHO2YRIM.js +756 -0
- package/dist/chunk-DTGBOSEM.cjs +319 -0
- package/dist/chunk-E6XXE66V.js +2252 -0
- package/dist/chunk-E7JP3BS3.cjs +61 -0
- package/dist/chunk-EKBKLK7P.js +1169 -0
- package/dist/chunk-EKYL4PE3.cjs +404 -0
- package/dist/chunk-EXKSFGSX.cjs +274 -0
- package/dist/chunk-EXUP2BUM.cjs +1173 -0
- package/dist/chunk-FDSGHPAK.js +130 -0
- package/dist/chunk-FEWUHQNM.cjs +144 -0
- package/dist/chunk-FFAOS5HQ.js +70 -0
- package/dist/chunk-FGGJQRLZ.js +270 -0
- package/dist/chunk-FHP6LXJS.js +415 -0
- package/dist/chunk-FJPADH77.cjs +666 -0
- package/dist/chunk-FL33V6U7.js +421 -0
- package/dist/chunk-FYSPZT4V.cjs +169 -0
- package/dist/chunk-GIOYPNTH.js +5575 -0
- package/dist/chunk-GJNCFRJU.cjs +125 -0
- package/dist/chunk-GMP623FG.cjs +1508 -0
- package/dist/chunk-GQHQOPXZ.cjs +5580 -0
- package/dist/chunk-GTU2Z2WW.cjs +262 -0
- package/dist/chunk-GYZE55MO.js +2007 -0
- package/dist/chunk-GZG4KA4E.js +529 -0
- package/dist/chunk-H652NHX5.js +600 -0
- package/dist/chunk-HCCQLAA4.cjs +74 -0
- package/dist/chunk-HKEXJUWS.cjs +4007 -0
- package/dist/chunk-HNDK4IQU.cjs +5737 -0
- package/dist/chunk-HR2OSYVQ.js +56165 -0
- package/dist/chunk-HYNTS5CP.js +422 -0
- package/dist/chunk-I6XZ5DZF.cjs +488 -0
- package/dist/chunk-ILRBGFVD.cjs +72 -0
- package/dist/chunk-IUDGEUDO.cjs +1409 -0
- package/dist/chunk-IUTY5WQ2.cjs +424 -0
- package/dist/chunk-IVY74O6C.js +247 -0
- package/dist/chunk-IWC5DM2M.cjs +611 -0
- package/dist/chunk-J32ZJZJH.js +554 -0
- package/dist/chunk-J52VSAQ7.js +6884 -0
- package/dist/chunk-J6M4FPK5.js +421 -0
- package/dist/chunk-J7XZV333.js +844 -0
- package/dist/chunk-JBNDTXXV.cjs +2433 -0
- package/dist/chunk-JC5YBPSF.cjs +984 -0
- package/dist/chunk-JD7CIZ33.js +1949 -0
- package/dist/chunk-JIBL5LRK.js +4287 -0
- package/dist/chunk-JIYN45TV.cjs +2525 -0
- package/dist/chunk-K574J76X.cjs +457 -0
- package/dist/chunk-KHDZJE5D.cjs +2196 -0
- package/dist/chunk-KKFZ3B6J.cjs +557 -0
- package/dist/chunk-KKP7JKN4.cjs +6002 -0
- package/dist/chunk-KPJL34Y7.cjs +186 -0
- package/dist/chunk-KQCN6AKJ.cjs +3042 -0
- package/dist/chunk-L5LKKENW.cjs +424 -0
- package/dist/chunk-LHAXPADA.js +882 -0
- package/dist/chunk-LM2VU56C.cjs +37 -0
- package/dist/chunk-M56JSP4A.js +400 -0
- package/dist/chunk-MBOOR7X4.js +18 -0
- package/dist/chunk-MQWAT42R.cjs +4310 -0
- package/dist/chunk-MXFUTKCO.js +56 -0
- package/dist/chunk-MYY4PMWX.cjs +264 -0
- package/dist/chunk-N75IH2HY.js +258 -0
- package/dist/chunk-NCWCUZNS.cjs +72 -0
- package/dist/chunk-NG77ATEW.cjs +778 -0
- package/dist/chunk-NW5G5FBQ.js +215 -0
- package/dist/chunk-OBIYPYYS.cjs +1993 -0
- package/dist/chunk-OH2FAIVU.js +608 -0
- package/dist/chunk-OIQYIIO3.cjs +473 -0
- package/dist/chunk-OL46QLBJ.js +61 -0
- package/dist/chunk-OMXII44L.js +5386 -0
- package/dist/chunk-OSYNRVOV.cjs +243 -0
- package/dist/chunk-PGANYCAG.cjs +220 -0
- package/dist/chunk-PHENW4MQ.js +65 -0
- package/dist/chunk-PY37LNDP.js +686 -0
- package/dist/chunk-Q56TT7IL.js +483 -0
- package/dist/chunk-QD32ADK6.js +1046 -0
- package/dist/chunk-QPOQ7VPI.js +1491 -0
- package/dist/chunk-QPSKHBJP.js +5963 -0
- package/dist/chunk-QXH7QDSZ.js +1989 -0
- package/dist/chunk-R24NNAEG.js +1399 -0
- package/dist/chunk-R75BSDH7.cjs +50 -0
- package/dist/chunk-RARB3MBR.js +207 -0
- package/dist/chunk-ROHLEP2W.cjs +847 -0
- package/dist/chunk-S3MDHNKB.cjs +490 -0
- package/dist/chunk-S6YWHCKV.cjs +410 -0
- package/dist/chunk-SIEXCILW.js +229 -0
- package/dist/chunk-SLU6UPJI.cjs +410 -0
- package/dist/chunk-SMIWS6DE.cjs +212 -0
- package/dist/chunk-T5J7ZKP3.cjs +4885 -0
- package/dist/chunk-TDCNJHWO.js +341 -0
- package/dist/chunk-TG7O4WBC.js +406 -0
- package/dist/chunk-THCK6ECW.js +2085 -0
- package/dist/chunk-TJHVSBP2.js +439 -0
- package/dist/chunk-TVHSPJ4N.cjs +606 -0
- package/dist/chunk-TWUXUCEW.cjs +781 -0
- package/dist/chunk-U44IKGG7.cjs +5390 -0
- package/dist/chunk-UFZZ7TSN.cjs +886 -0
- package/dist/chunk-UJXISJBN.js +487 -0
- package/dist/chunk-UOIGFQXC.cjs +9750 -0
- package/dist/chunk-URG2SJLK.js +2521 -0
- package/dist/chunk-UWJHCOH2.js +623 -0
- package/dist/chunk-V6MKC2FZ.js +979 -0
- package/dist/chunk-VJ3L7CHT.cjs +169 -0
- package/dist/chunk-VMLKSV26.js +1216 -0
- package/dist/chunk-VVKVQZI6.js +55 -0
- package/dist/chunk-W6RW64BB.cjs +1219 -0
- package/dist/chunk-WKX5AMOY.js +309 -0
- package/dist/chunk-WNNE3PO3.js +34 -0
- package/dist/chunk-WRKUDAZJ.js +3038 -0
- package/dist/chunk-WRLUBRKS.cjs +1943 -0
- package/dist/chunk-WRNEH5MO.js +3169 -0
- package/dist/chunk-WRWEX5ZF.js +658 -0
- package/dist/chunk-X3GJPRVK.cjs +3246 -0
- package/dist/chunk-X3UVCWNL.cjs +2257 -0
- package/dist/chunk-XB274MW5.cjs +814 -0
- package/dist/chunk-XHIV6326.cjs +793 -0
- package/dist/chunk-XIVIE43A.cjs +729 -0
- package/dist/chunk-XJAN7CZG.cjs +432 -0
- package/dist/chunk-XKTPFXGA.js +164 -0
- package/dist/chunk-XL6INWKT.js +121 -0
- package/dist/chunk-XSFNHP2E.js +632 -0
- package/dist/chunk-XT6JY5W5.js +9684 -0
- package/dist/chunk-XUILI4KB.cjs +430 -0
- package/dist/chunk-YF2I3MV3.js +46 -0
- package/dist/chunk-YIMN575O.js +4847 -0
- package/dist/chunk-YIVFJNYV.js +176 -0
- package/dist/chunk-YKGPCZEE.cjs +237 -0
- package/dist/chunk-YN2YWTXW.js +5731 -0
- package/dist/chunk-YN6V7R3L.cjs +327 -0
- package/dist/chunk-YQELFNJV.js +39 -0
- package/dist/chunk-YVD3CSO3.js +1183 -0
- package/dist/chunk-YVOAF4ML.js +623 -0
- package/dist/chunk-YWOBW2PV.cjs +759 -0
- package/dist/chunk-YYXH45E2.js +426 -0
- package/dist/chunk-ZDSYWBIE.cjs +69 -0
- package/dist/chunk-ZU7NIRT6.js +325 -0
- package/dist/chunk-ZZ7RO2UQ.js +1243 -0
- package/dist/cli/holoscript-runner.cjs +2255 -0
- package/dist/cli/holoscript-runner.js +2230 -0
- package/dist/codebase/index.cjs +336 -0
- package/dist/codebase/index.js +331 -0
- package/dist/compiler/agent-inference.cjs +31 -0
- package/dist/compiler/agent-inference.js +8 -0
- package/dist/compiler/android-xr.cjs +24 -0
- package/dist/compiler/android-xr.js +14 -0
- package/dist/compiler/android.cjs +24 -0
- package/dist/compiler/android.js +14 -0
- package/dist/compiler/ar.cjs +23 -0
- package/dist/compiler/ar.js +11 -0
- package/dist/compiler/babylon.cjs +21 -0
- package/dist/compiler/babylon.js +15 -0
- package/dist/compiler/business-quest.cjs +43 -0
- package/dist/compiler/business-quest.js +4 -0
- package/dist/compiler/coco.cjs +27 -0
- package/dist/compiler/coco.js +4 -0
- package/dist/compiler/context.cjs +25 -0
- package/dist/compiler/context.d.ts +28 -0
- package/dist/compiler/context.js +8 -0
- package/dist/compiler/domain-block-utils.cjs +609 -0
- package/dist/compiler/domain-block-utils.js +11 -0
- package/dist/compiler/dtdl.cjs +27 -0
- package/dist/compiler/dtdl.js +11 -0
- package/dist/compiler/gltf-pipeline.cjs +39 -0
- package/dist/compiler/gltf-pipeline.js +4 -0
- package/dist/compiler/godot.cjs +18 -0
- package/dist/compiler/godot.js +12 -0
- package/dist/compiler/incremental.cjs +34 -0
- package/dist/compiler/incremental.js +9 -0
- package/dist/compiler/index.cjs +5408 -0
- package/dist/compiler/index.d.ts +334 -21
- package/dist/compiler/index.js +5069 -0
- package/dist/compiler/ios.cjs +23 -0
- package/dist/compiler/ios.js +13 -0
- package/dist/compiler/llm-provider-capabilities.cjs +25 -0
- package/dist/compiler/llm-provider-capabilities.d.ts +43 -0
- package/dist/compiler/llm-provider-capabilities.js +8 -0
- package/dist/compiler/multi-layer.cjs +24 -0
- package/dist/compiler/multi-layer.js +15 -0
- package/dist/compiler/nodetoy.cjs +23 -0
- package/dist/compiler/nodetoy.d.ts +69 -0
- package/dist/compiler/nodetoy.js +4 -0
- package/dist/compiler/openxr.cjs +19 -0
- package/dist/compiler/openxr.js +13 -0
- package/dist/compiler/playcanvas.cjs +19 -0
- package/dist/compiler/playcanvas.js +13 -0
- package/dist/compiler/r3f.cjs +39 -0
- package/dist/compiler/r3f.d.ts +22 -0
- package/dist/compiler/r3f.js +17 -0
- package/dist/compiler/remotion.cjs +23 -0
- package/dist/compiler/remotion.js +4 -0
- package/dist/compiler/reproducibility.cjs +39 -0
- package/dist/compiler/reproducibility.js +4 -0
- package/dist/compiler/sdf.cjs +24 -0
- package/dist/compiler/sdf.js +12 -0
- package/dist/compiler/semantic-scene.cjs +31 -0
- package/dist/compiler/semantic-scene.js +4 -0
- package/dist/compiler/state.cjs +21 -0
- package/dist/compiler/state.js +11 -0
- package/dist/compiler/trait-composition.cjs +30 -0
- package/dist/compiler/trait-composition.js +9 -0
- package/dist/compiler/unity.cjs +19 -0
- package/dist/compiler/unity.js +13 -0
- package/dist/compiler/unreal.cjs +23 -0
- package/dist/compiler/unreal.js +13 -0
- package/dist/compiler/urdf.cjs +52 -0
- package/dist/compiler/urdf.js +12 -0
- package/dist/compiler/usd-physics.cjs +26 -0
- package/dist/compiler/usd-physics.js +9 -0
- package/dist/compiler/visionos.cjs +19 -0
- package/dist/compiler/visionos.js +13 -0
- package/dist/compiler/vrchat.cjs +22 -0
- package/dist/compiler/vrchat.js +12 -0
- package/dist/compiler/vrr.cjs +24 -0
- package/dist/compiler/vrr.js +12 -0
- package/dist/compiler/wasm.cjs +36 -0
- package/dist/compiler/wasm.js +12 -0
- package/dist/compiler/webgpu.cjs +18 -0
- package/dist/compiler/webgpu.js +12 -0
- package/dist/coordinators/index.cjs +1266 -0
- package/dist/coordinators/index.d.ts +72 -1
- package/dist/coordinators/index.js +1259 -0
- package/dist/debugger.cjs +24 -0
- package/dist/debugger.js +11 -0
- package/dist/dist-ACXG6IH5.cjs +3113 -0
- package/dist/dist-VD4L6V7Q.js +3076 -0
- package/dist/entries/interop.cjs +64 -0
- package/dist/entries/interop.js +7 -0
- package/dist/entries/scripting.cjs +55 -0
- package/dist/entries/scripting.js +10 -0
- package/dist/hololand/index.cjs +146 -0
- package/dist/hololand/index.d.ts +70 -0
- package/dist/hololand/index.js +5 -0
- package/dist/index.cjs +44660 -0
- package/dist/index.d.ts +978 -21
- package/dist/index.js +41422 -0
- package/dist/math/tropical-spmv.cjs +45 -0
- package/dist/math/tropical-spmv.js +4 -0
- package/dist/math/vec3.cjs +57 -0
- package/dist/math/vec3.js +4 -0
- package/dist/ml-dsa-FSKBTE3W.cjs +1265 -0
- package/dist/ml-dsa-Z7JDKW4L.js +1265 -0
- package/dist/paper-0c-spike/index.cjs +150 -0
- package/dist/paper-0c-spike/index.js +141 -0
- package/dist/parser.cjs +61 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.js +12 -0
- package/dist/playwright-3AT3AKTV.cjs +98673 -0
- package/dist/playwright-VZPDVUEQ.js +98660 -0
- package/dist/reconstruction/index.cjs +153 -0
- package/dist/reconstruction/index.d.ts +29 -2
- package/dist/reconstruction/index.js +8 -0
- package/dist/runtime.cjs +316 -0
- package/dist/runtime.d.ts +61 -0
- package/dist/runtime.js +31 -0
- package/dist/self-improvement/index.cjs +563 -0
- package/dist/self-improvement/index.js +545 -0
- package/dist/src-4ROC227P.cjs +2094 -0
- package/dist/src-HCCCSYP7.js +2073 -0
- package/dist/storage/index.cjs +38 -0
- package/dist/storage/index.js +5 -0
- package/dist/testing.cjs +25 -0
- package/dist/testing.d.ts +70 -0
- package/dist/testing.js +4 -0
- package/dist/traitDocs/traitDocs.cjs +33 -0
- package/dist/traitDocs/traitDocs.js +7 -0
- package/dist/traits/botanical-lotus.cjs +177 -0
- package/dist/traits/botanical-lotus.d.ts +502 -0
- package/dist/traits/botanical-lotus.js +7 -0
- package/dist/traits/engines/index.cjs +520 -0
- package/dist/traits/engines/index.js +380 -0
- package/dist/traits/index.cjs +24548 -0
- package/dist/traits/index.d.ts +171 -35
- package/dist/traits/index.js +21638 -0
- package/dist/traits/simulation-solver-factory.cjs +13 -0
- package/dist/traits/simulation-solver-factory.d.ts +23 -0
- package/dist/traits/simulation-solver-factory.js +4 -0
- package/dist/traits/webcam-gaze.cjs +35 -0
- package/dist/traits/webcam-gaze.d.ts +17 -0
- package/dist/traits/webcam-gaze.js +4 -0
- package/dist/type-checker.cjs +19 -0
- package/dist/type-checker.js +6 -0
- package/dist/world/index.cjs +947 -0
- package/dist/world/index.d.ts +147 -0
- package/dist/world/index.js +939 -0
- package/dist/world-model/index.cjs +1446 -0
- package/dist/world-model/index.d.ts +119 -0
- package/dist/world-model/index.js +1414 -0
- package/dist/wot/index.cjs +29 -0
- package/dist/wot/index.js +4 -0
- package/package.json +93 -49
|
@@ -0,0 +1,2255 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk2YSNA2F2_cjs = require('../chunk-2YSNA2F2.cjs');
|
|
5
|
+
var chunkSLU6UPJI_cjs = require('../chunk-SLU6UPJI.cjs');
|
|
6
|
+
var chunkXHIV6326_cjs = require('../chunk-XHIV6326.cjs');
|
|
7
|
+
var chunkR75BSDH7_cjs = require('../chunk-R75BSDH7.cjs');
|
|
8
|
+
var chunkT5J7ZKP3_cjs = require('../chunk-T5J7ZKP3.cjs');
|
|
9
|
+
require('../chunk-NG77ATEW.cjs');
|
|
10
|
+
require('../chunk-WRLUBRKS.cjs');
|
|
11
|
+
require('../chunk-X3GJPRVK.cjs');
|
|
12
|
+
require('../chunk-DTGBOSEM.cjs');
|
|
13
|
+
require('../chunk-YKGPCZEE.cjs');
|
|
14
|
+
require('../chunk-6EX3I5P4.cjs');
|
|
15
|
+
var chunkE7JP3BS3_cjs = require('../chunk-E7JP3BS3.cjs');
|
|
16
|
+
require('../chunk-HCCQLAA4.cjs');
|
|
17
|
+
require('dotenv/config');
|
|
18
|
+
var fs = require('fs');
|
|
19
|
+
var path = require('path');
|
|
20
|
+
var readline = require('readline');
|
|
21
|
+
var child_process = require('child_process');
|
|
22
|
+
var crypto = require('crypto');
|
|
23
|
+
|
|
24
|
+
function _interopNamespace(e) {
|
|
25
|
+
if (e && e.__esModule) return e;
|
|
26
|
+
var n = Object.create(null);
|
|
27
|
+
if (e) {
|
|
28
|
+
Object.keys(e).forEach(function (k) {
|
|
29
|
+
if (k !== 'default') {
|
|
30
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
31
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return e[k]; }
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
n.default = e;
|
|
39
|
+
return Object.freeze(n);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
43
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
44
|
+
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
45
|
+
|
|
46
|
+
chunkE7JP3BS3_cjs.init_safeJsonParse();
|
|
47
|
+
var engineRuntimeModule;
|
|
48
|
+
async function loadEngineRuntime() {
|
|
49
|
+
engineRuntimeModule ?? (engineRuntimeModule = await import('@holoscript/engine/runtime'));
|
|
50
|
+
return engineRuntimeModule;
|
|
51
|
+
}
|
|
52
|
+
function defaultModelForProvider(provider) {
|
|
53
|
+
switch (provider) {
|
|
54
|
+
case "xai":
|
|
55
|
+
return "grok-3";
|
|
56
|
+
case "openai":
|
|
57
|
+
return "gpt-4.1";
|
|
58
|
+
case "ollama":
|
|
59
|
+
return "brittney-qwen-v23:latest";
|
|
60
|
+
case "anthropic":
|
|
61
|
+
default:
|
|
62
|
+
return "claude-sonnet-4-6";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function defaultToolProfileForProvider(provider) {
|
|
66
|
+
switch (provider) {
|
|
67
|
+
case "xai":
|
|
68
|
+
return "grok-hsplus";
|
|
69
|
+
case "anthropic":
|
|
70
|
+
return "claude-hsplus";
|
|
71
|
+
case "openai":
|
|
72
|
+
case "ollama":
|
|
73
|
+
default:
|
|
74
|
+
return "standard";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function parseProvider(value) {
|
|
78
|
+
const normalized = value?.toLowerCase();
|
|
79
|
+
if (normalized === "anthropic" || normalized === "xai" || normalized === "openai" || normalized === "ollama") {
|
|
80
|
+
return normalized;
|
|
81
|
+
}
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
84
|
+
function parseToolProfile(value) {
|
|
85
|
+
const normalized = value?.toLowerCase();
|
|
86
|
+
if (normalized === "claude-hsplus" || normalized === "grok-hsplus" || normalized === "standard") {
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
function daemonEnvDefaults() {
|
|
92
|
+
const provider = parseProvider(process.env.HOLODAEMON_PROVIDER) || "anthropic";
|
|
93
|
+
const toolProfile = parseToolProfile(process.env.HOLODAEMON_TOOL_PROFILE) || defaultToolProfileForProvider(provider);
|
|
94
|
+
const model = process.env.HOLODAEMON_MODEL || defaultModelForProvider(provider);
|
|
95
|
+
return { provider, toolProfile, model };
|
|
96
|
+
}
|
|
97
|
+
function parseArgs(argv) {
|
|
98
|
+
const args = argv.slice(2);
|
|
99
|
+
const envDefaults = daemonEnvDefaults();
|
|
100
|
+
const opts = {
|
|
101
|
+
command: "help",
|
|
102
|
+
json: false,
|
|
103
|
+
target: "headless",
|
|
104
|
+
profile: "headless",
|
|
105
|
+
debug: false,
|
|
106
|
+
watch: false,
|
|
107
|
+
daemon: false,
|
|
108
|
+
ticks: 100,
|
|
109
|
+
cycles: 15,
|
|
110
|
+
commit: false,
|
|
111
|
+
enforceGotchas: false,
|
|
112
|
+
providerRotation: false,
|
|
113
|
+
alwaysOn: false,
|
|
114
|
+
cycleIntervalSec: 30,
|
|
115
|
+
allowShell: false,
|
|
116
|
+
allowedShellCommands: [],
|
|
117
|
+
allowedHosts: [],
|
|
118
|
+
allowedPaths: [],
|
|
119
|
+
provider: envDefaults.provider,
|
|
120
|
+
toolProfile: envDefaults.toolProfile,
|
|
121
|
+
model: envDefaults.model,
|
|
122
|
+
timeout: 30,
|
|
123
|
+
sessionId: crypto.randomUUID(),
|
|
124
|
+
// Deploy defaults
|
|
125
|
+
share: false,
|
|
126
|
+
author: "",
|
|
127
|
+
license: "free",
|
|
128
|
+
serverUrl: "https://mcp.holoscript.net",
|
|
129
|
+
// Protocol publish defaults
|
|
130
|
+
publish: false,
|
|
131
|
+
mintNft: false,
|
|
132
|
+
price: "0",
|
|
133
|
+
walletKey: ""
|
|
134
|
+
};
|
|
135
|
+
let modelExplicit = false;
|
|
136
|
+
let toolProfileExplicit = false;
|
|
137
|
+
if (args.length === 0) return opts;
|
|
138
|
+
const cmd = args[0];
|
|
139
|
+
if (cmd === "run" || cmd === "test" || cmd === "compile" || cmd === "deploy" || cmd === "absorb" || cmd === "daemon" || cmd === "holodaemon" || cmd === "moltbook-daemon" || cmd === "holomesh-daemon") {
|
|
140
|
+
opts.command = cmd;
|
|
141
|
+
}
|
|
142
|
+
if (opts.command === "daemon" && args[1] === "status") {
|
|
143
|
+
opts.command = "daemon-status";
|
|
144
|
+
}
|
|
145
|
+
if (args[1] && !args[1].startsWith("--") && opts.command !== "daemon-status") {
|
|
146
|
+
opts.file = args[1];
|
|
147
|
+
}
|
|
148
|
+
for (let i = 0; i < args.length; i++) {
|
|
149
|
+
if (args[i] === "--target" && args[i + 1]) opts.target = args[++i];
|
|
150
|
+
if (args[i] === "--profile" && args[i + 1]) opts.profile = args[++i];
|
|
151
|
+
if (args[i] === "--output" && args[i + 1]) opts.output = args[++i];
|
|
152
|
+
if (args[i] === "--tier" && args[i + 1]) {
|
|
153
|
+
const tier = args[++i].toLowerCase();
|
|
154
|
+
if (["low", "med", "high", "ultra"].includes(tier)) {
|
|
155
|
+
opts.qualityTier = tier;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (args[i] === "--debug" || args[i] === "--verbose") opts.debug = true;
|
|
159
|
+
if (args[i] === "--watch" || args[i] === "-w") opts.watch = true;
|
|
160
|
+
if (args[i] === "--daemon") opts.daemon = true;
|
|
161
|
+
if (args[i] === "--ticks" && args[i + 1]) {
|
|
162
|
+
const parsed = Number(args[++i]);
|
|
163
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
164
|
+
opts.ticks = Math.floor(parsed);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (args[i] === "--cycles" && args[i + 1]) {
|
|
168
|
+
const parsed = Number(args[++i]);
|
|
169
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
170
|
+
opts.cycles = Math.floor(parsed);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (args[i] === "--commit") opts.commit = true;
|
|
174
|
+
if (args[i] === "--trial" && args[i + 1]) {
|
|
175
|
+
opts.trial = Number(args[++i]);
|
|
176
|
+
}
|
|
177
|
+
if (args[i] === "--provider" && args[i + 1]) {
|
|
178
|
+
const provider = parseProvider(args[++i]);
|
|
179
|
+
if (provider) {
|
|
180
|
+
opts.provider = provider;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (args[i] === "--tool-profile" && args[i + 1]) {
|
|
184
|
+
const profile = parseToolProfile(args[++i]);
|
|
185
|
+
if (profile) {
|
|
186
|
+
opts.toolProfile = profile;
|
|
187
|
+
toolProfileExplicit = true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (args[i] === "--model" && args[i + 1]) {
|
|
191
|
+
opts.model = args[++i];
|
|
192
|
+
modelExplicit = true;
|
|
193
|
+
}
|
|
194
|
+
if (args[i] === "--timeout" && args[i + 1]) {
|
|
195
|
+
const parsed = Number(args[++i]);
|
|
196
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
197
|
+
opts.timeout = Math.min(120, Math.max(1, Math.floor(parsed)));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (args[i] === "--focus" && args[i + 1]) {
|
|
201
|
+
opts.focus = args[++i];
|
|
202
|
+
}
|
|
203
|
+
if (args[i] === "--enforce-gotchas") opts.enforceGotchas = true;
|
|
204
|
+
if (args[i] === "--provider-rotation") opts.providerRotation = true;
|
|
205
|
+
if (args[i] === "--always-on") opts.alwaysOn = true;
|
|
206
|
+
if (args[i] === "--allow-shell") opts.allowShell = true;
|
|
207
|
+
if (args[i] === "--skills-dir" && args[i + 1]) opts.skillsDir = args[++i];
|
|
208
|
+
if (args[i] === "--cycle-interval-sec" && args[i + 1]) {
|
|
209
|
+
const parsed = Number(args[++i]);
|
|
210
|
+
if (Number.isFinite(parsed) && parsed >= 1) {
|
|
211
|
+
opts.cycleIntervalSec = Math.floor(parsed);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (args[i] === "--allow-shell-command" && args[i + 1]) {
|
|
215
|
+
opts.allowedShellCommands.push(args[++i]);
|
|
216
|
+
}
|
|
217
|
+
if (args[i] === "--allow-host" && args[i + 1]) {
|
|
218
|
+
opts.allowedHosts.push(args[++i]);
|
|
219
|
+
}
|
|
220
|
+
if (args[i] === "--allow-path" && args[i + 1]) {
|
|
221
|
+
opts.allowedPaths.push(args[++i]);
|
|
222
|
+
}
|
|
223
|
+
if (args[i] === "--json") opts.json = true;
|
|
224
|
+
if (args[i] === "--share") opts.share = true;
|
|
225
|
+
if (args[i] === "--author" && args[i + 1]) opts.author = args[++i];
|
|
226
|
+
if (args[i] === "--license" && args[i + 1]) opts.license = args[++i];
|
|
227
|
+
if (args[i] === "--server" && args[i + 1]) opts.serverUrl = args[++i];
|
|
228
|
+
if (args[i] === "--publish") opts.publish = true;
|
|
229
|
+
if (args[i] === "--mint-nft") opts.mintNft = true;
|
|
230
|
+
if (args[i] === "--price" && args[i + 1]) opts.price = args[++i];
|
|
231
|
+
if (args[i] === "--wallet-key" && args[i + 1]) opts.walletKey = args[++i];
|
|
232
|
+
}
|
|
233
|
+
if (!modelExplicit) {
|
|
234
|
+
opts.model = defaultModelForProvider(opts.provider);
|
|
235
|
+
}
|
|
236
|
+
if (!toolProfileExplicit) {
|
|
237
|
+
opts.toolProfile = defaultToolProfileForProvider(opts.provider);
|
|
238
|
+
}
|
|
239
|
+
return opts;
|
|
240
|
+
}
|
|
241
|
+
async function createDaemonLLMProvider(opts) {
|
|
242
|
+
const {
|
|
243
|
+
AnthropicAdapter,
|
|
244
|
+
XAIAdapter,
|
|
245
|
+
OpenAIAdapter,
|
|
246
|
+
LocalLLMAdapter
|
|
247
|
+
} = await import('@holoscript/llm-provider');
|
|
248
|
+
if (opts.provider === "anthropic") {
|
|
249
|
+
const adapter2 = new AnthropicAdapter({
|
|
250
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
251
|
+
defaultModel: opts.model
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
chat: async ({ system, prompt, maxTokens }) => {
|
|
255
|
+
const result = await adapter2.complete({
|
|
256
|
+
messages: [
|
|
257
|
+
{ role: "system", content: system },
|
|
258
|
+
{ role: "user", content: prompt }
|
|
259
|
+
],
|
|
260
|
+
maxTokens: maxTokens || 4096,
|
|
261
|
+
temperature: 0.2
|
|
262
|
+
});
|
|
263
|
+
return {
|
|
264
|
+
text: result.content,
|
|
265
|
+
inputTokens: result.usage?.promptTokens ?? 0,
|
|
266
|
+
outputTokens: result.usage?.completionTokens ?? 0
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (opts.provider === "xai") {
|
|
272
|
+
const adapter2 = new XAIAdapter({
|
|
273
|
+
apiKey: process.env.XAI_API_KEY || "",
|
|
274
|
+
defaultModel: opts.model
|
|
275
|
+
});
|
|
276
|
+
return {
|
|
277
|
+
chat: async ({ system, prompt, maxTokens }) => {
|
|
278
|
+
const result = await adapter2.complete({
|
|
279
|
+
messages: [
|
|
280
|
+
{ role: "system", content: system },
|
|
281
|
+
{ role: "user", content: prompt }
|
|
282
|
+
],
|
|
283
|
+
maxTokens: maxTokens || 4096,
|
|
284
|
+
temperature: 0.2
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
text: result.content,
|
|
288
|
+
inputTokens: result.usage?.promptTokens ?? 0,
|
|
289
|
+
outputTokens: result.usage?.completionTokens ?? 0
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
if (opts.provider === "openai") {
|
|
295
|
+
const adapter2 = new OpenAIAdapter({
|
|
296
|
+
apiKey: process.env.OPENAI_API_KEY || "",
|
|
297
|
+
defaultModel: opts.model,
|
|
298
|
+
...process.env.OPENAI_BASE_URL && { baseURL: process.env.OPENAI_BASE_URL }
|
|
299
|
+
});
|
|
300
|
+
return {
|
|
301
|
+
chat: async ({ system, prompt, maxTokens }) => {
|
|
302
|
+
const result = await adapter2.complete({
|
|
303
|
+
messages: [
|
|
304
|
+
{ role: "system", content: system },
|
|
305
|
+
{ role: "user", content: prompt }
|
|
306
|
+
],
|
|
307
|
+
maxTokens: maxTokens || 4096,
|
|
308
|
+
temperature: 0.2
|
|
309
|
+
});
|
|
310
|
+
return {
|
|
311
|
+
text: result.content,
|
|
312
|
+
inputTokens: result.usage?.promptTokens ?? 0,
|
|
313
|
+
outputTokens: result.usage?.completionTokens ?? 0
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const ollamaUrl = process.env.OLLAMA_BASE_URL || process.env.OLLAMA_URL;
|
|
319
|
+
if (!ollamaUrl) {
|
|
320
|
+
throw new Error(
|
|
321
|
+
"Ollama selected but OLLAMA_BASE_URL/OLLAMA_URL not set. Use --provider anthropic|xai|openai or set OLLAMA_BASE_URL in .env"
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const adapter = new LocalLLMAdapter({
|
|
325
|
+
baseURL: ollamaUrl,
|
|
326
|
+
defaultModel: opts.model,
|
|
327
|
+
timeoutMs: 12e4
|
|
328
|
+
});
|
|
329
|
+
return {
|
|
330
|
+
chat: async ({ system, prompt }) => {
|
|
331
|
+
const result = await adapter.complete({
|
|
332
|
+
messages: [
|
|
333
|
+
{ role: "system", content: system },
|
|
334
|
+
{ role: "user", content: prompt }
|
|
335
|
+
],
|
|
336
|
+
maxTokens: 4096,
|
|
337
|
+
temperature: 0.2
|
|
338
|
+
});
|
|
339
|
+
return {
|
|
340
|
+
text: result.content,
|
|
341
|
+
inputTokens: result.usage?.promptTokens ?? 0,
|
|
342
|
+
outputTokens: result.usage?.completionTokens ?? 0
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function createNodeHostCapabilities(cwd) {
|
|
348
|
+
return {
|
|
349
|
+
fileSystem: {
|
|
350
|
+
readFile: (filePath) => fs__namespace.readFileSync(path__namespace.resolve(cwd, filePath), "utf-8"),
|
|
351
|
+
writeFile: (filePath, content) => {
|
|
352
|
+
fs__namespace.writeFileSync(path__namespace.resolve(cwd, filePath), content, "utf-8");
|
|
353
|
+
},
|
|
354
|
+
deleteFile: (filePath) => {
|
|
355
|
+
fs__namespace.rmSync(path__namespace.resolve(cwd, filePath), { force: true });
|
|
356
|
+
},
|
|
357
|
+
exists: (filePath) => fs__namespace.existsSync(path__namespace.resolve(cwd, filePath))
|
|
358
|
+
},
|
|
359
|
+
process: {
|
|
360
|
+
exec: (command, args = [], options) => new Promise((resolve2, reject) => {
|
|
361
|
+
const child = child_process.spawn(command, args, {
|
|
362
|
+
cwd: options?.cwd ?? cwd,
|
|
363
|
+
env: { ...process.env, ...options?.env ?? {} },
|
|
364
|
+
shell: true,
|
|
365
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
366
|
+
});
|
|
367
|
+
let stdout = "";
|
|
368
|
+
let stderr = "";
|
|
369
|
+
let timeoutHandle = null;
|
|
370
|
+
child.stdout?.on("data", (data) => {
|
|
371
|
+
stdout += data.toString("utf-8");
|
|
372
|
+
});
|
|
373
|
+
child.stderr?.on("data", (data) => {
|
|
374
|
+
stderr += data.toString("utf-8");
|
|
375
|
+
});
|
|
376
|
+
if (options?.timeoutMs && options.timeoutMs > 0) {
|
|
377
|
+
timeoutHandle = setTimeout(() => {
|
|
378
|
+
try {
|
|
379
|
+
child.kill("SIGKILL");
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}, options.timeoutMs);
|
|
383
|
+
}
|
|
384
|
+
child.on("close", (code, signal) => {
|
|
385
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
386
|
+
resolve2({ code, signal, stdout, stderr });
|
|
387
|
+
});
|
|
388
|
+
child.on("error", (error) => {
|
|
389
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
390
|
+
reject(error);
|
|
391
|
+
});
|
|
392
|
+
})
|
|
393
|
+
},
|
|
394
|
+
network: {
|
|
395
|
+
fetch: async (url, options) => {
|
|
396
|
+
if (typeof fetch === "undefined") {
|
|
397
|
+
throw new Error("fetch is not available in this runtime");
|
|
398
|
+
}
|
|
399
|
+
const response = await fetch(url, {
|
|
400
|
+
method: options?.method,
|
|
401
|
+
headers: options?.headers,
|
|
402
|
+
body: options?.body,
|
|
403
|
+
credentials: options?.credentials
|
|
404
|
+
});
|
|
405
|
+
const headers = {};
|
|
406
|
+
response.headers.forEach((value, key) => {
|
|
407
|
+
headers[key.toLowerCase()] = value;
|
|
408
|
+
});
|
|
409
|
+
const contentType = headers["content-type"] ?? "";
|
|
410
|
+
let body;
|
|
411
|
+
let text;
|
|
412
|
+
let json;
|
|
413
|
+
if (contentType.includes("application/json")) {
|
|
414
|
+
try {
|
|
415
|
+
json = await response.json();
|
|
416
|
+
body = json;
|
|
417
|
+
} catch {
|
|
418
|
+
text = await response.text();
|
|
419
|
+
body = text;
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
text = await response.text();
|
|
423
|
+
body = text;
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
status: response.status,
|
|
427
|
+
ok: response.ok,
|
|
428
|
+
headers,
|
|
429
|
+
body,
|
|
430
|
+
text,
|
|
431
|
+
json
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function runTicks(runtime, count) {
|
|
438
|
+
for (let i = 0; i < count; i++) {
|
|
439
|
+
runtime.tick();
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function getDaemonState(runtime, key) {
|
|
443
|
+
if (typeof key === "string") {
|
|
444
|
+
if (typeof runtime.get === "function") {
|
|
445
|
+
return runtime.get(key);
|
|
446
|
+
}
|
|
447
|
+
const value = runtime.getState(key);
|
|
448
|
+
if (value && typeof value === "object" && key in value) {
|
|
449
|
+
return value[key];
|
|
450
|
+
}
|
|
451
|
+
return value;
|
|
452
|
+
}
|
|
453
|
+
if (typeof runtime.getAllState === "function") {
|
|
454
|
+
return runtime.getAllState();
|
|
455
|
+
}
|
|
456
|
+
return runtime.getState();
|
|
457
|
+
}
|
|
458
|
+
function setDaemonState(runtime, key, value) {
|
|
459
|
+
if (typeof runtime.set === "function") {
|
|
460
|
+
runtime.set(key, value);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (runtime.setState.length <= 1) {
|
|
464
|
+
runtime.setState({ [key]: value });
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
runtime.setState(key, value);
|
|
468
|
+
}
|
|
469
|
+
async function runDaemon(runtime, opts) {
|
|
470
|
+
const supportsEvents = typeof runtime.emit === "function";
|
|
471
|
+
const supportsStats = typeof runtime.getStats === "function";
|
|
472
|
+
const supportsActionRegistry = typeof runtime.registerAction === "function";
|
|
473
|
+
const supportsSubscriptions = typeof runtime.on === "function";
|
|
474
|
+
const pendingActionResolutions = /* @__PURE__ */ new Map();
|
|
475
|
+
const registeredActions = /* @__PURE__ */ new Set();
|
|
476
|
+
let nextActionId = 1;
|
|
477
|
+
const send = (message) => {
|
|
478
|
+
process.stdout.write(`${JSON.stringify(message)}
|
|
479
|
+
`);
|
|
480
|
+
};
|
|
481
|
+
const unsubscribeActionResult = supportsSubscriptions ? runtime.on("action:result", (payload) => {
|
|
482
|
+
send({
|
|
483
|
+
type: "daemon:action_result",
|
|
484
|
+
payload
|
|
485
|
+
});
|
|
486
|
+
}) : () => {
|
|
487
|
+
};
|
|
488
|
+
send({
|
|
489
|
+
type: "daemon:ready",
|
|
490
|
+
profile: opts.profile,
|
|
491
|
+
supportsEvents,
|
|
492
|
+
supportsStats,
|
|
493
|
+
supportsActionRegistry
|
|
494
|
+
});
|
|
495
|
+
const rl = readline__namespace.createInterface({
|
|
496
|
+
input: process.stdin,
|
|
497
|
+
output: process.stdout,
|
|
498
|
+
terminal: false
|
|
499
|
+
});
|
|
500
|
+
const close = () => {
|
|
501
|
+
for (const [, pending] of pendingActionResolutions) {
|
|
502
|
+
clearTimeout(pending.timer);
|
|
503
|
+
pending.reject(new Error("Daemon shutting down"));
|
|
504
|
+
}
|
|
505
|
+
pendingActionResolutions.clear();
|
|
506
|
+
try {
|
|
507
|
+
unsubscribeActionResult();
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
runtime.stop();
|
|
512
|
+
} catch {
|
|
513
|
+
}
|
|
514
|
+
rl.close();
|
|
515
|
+
};
|
|
516
|
+
process.once("SIGINT", () => {
|
|
517
|
+
send({ type: "daemon:stopped", reason: "SIGINT" });
|
|
518
|
+
close();
|
|
519
|
+
});
|
|
520
|
+
process.once("SIGTERM", () => {
|
|
521
|
+
send({ type: "daemon:stopped", reason: "SIGTERM" });
|
|
522
|
+
close();
|
|
523
|
+
});
|
|
524
|
+
rl.on("line", (line) => {
|
|
525
|
+
const raw = line.trim();
|
|
526
|
+
if (!raw) return;
|
|
527
|
+
let command;
|
|
528
|
+
try {
|
|
529
|
+
command = chunkE7JP3BS3_cjs.readJson(raw);
|
|
530
|
+
} catch {
|
|
531
|
+
send({ type: "daemon:error", error: "Invalid JSON command" });
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
const op = command?.op;
|
|
535
|
+
switch (op) {
|
|
536
|
+
case "tick": {
|
|
537
|
+
const count = Number.isFinite(command?.count) ? Math.max(0, Math.floor(command.count)) : 1;
|
|
538
|
+
runTicks(runtime, count);
|
|
539
|
+
send({ type: "daemon:ok", op, ticked: count, stats: runtime.getStats?.() });
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
case "emit": {
|
|
543
|
+
if (!supportsEvents) {
|
|
544
|
+
send({ type: "daemon:error", op, error: "Runtime does not expose emit()" });
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
runtime.emit(command.event, command.payload);
|
|
548
|
+
send({ type: "daemon:ok", op, event: command.event });
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
case "state:get": {
|
|
552
|
+
const key = command?.key;
|
|
553
|
+
const value = getDaemonState(runtime, key);
|
|
554
|
+
send({ type: "daemon:ok", op, key, value });
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
case "state:set": {
|
|
558
|
+
const key = command?.key;
|
|
559
|
+
if (typeof key === "string") {
|
|
560
|
+
setDaemonState(runtime, key, command.value);
|
|
561
|
+
send({ type: "daemon:ok", op, key });
|
|
562
|
+
} else {
|
|
563
|
+
send({ type: "daemon:error", op, error: "state:set requires string key" });
|
|
564
|
+
}
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
case "stats": {
|
|
568
|
+
send({ type: "daemon:ok", op, stats: runtime.getStats?.() });
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
case "action:register": {
|
|
572
|
+
if (!supportsActionRegistry) {
|
|
573
|
+
send({ type: "daemon:error", op, error: "Runtime does not expose registerAction()" });
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
const actionName = command?.name;
|
|
577
|
+
if (typeof actionName !== "string" || actionName.trim() === "") {
|
|
578
|
+
send({ type: "daemon:error", op, error: "action:register requires non-empty name" });
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
runtime.registerAction(
|
|
582
|
+
actionName,
|
|
583
|
+
(params, blackboard) => {
|
|
584
|
+
const actionRequestId = `daemon-action-${nextActionId++}`;
|
|
585
|
+
const timeoutMs = Number.isFinite(command?.timeoutMs) ? Math.max(1, Math.floor(command.timeoutMs)) : 3e4;
|
|
586
|
+
return new Promise((resolve2, reject) => {
|
|
587
|
+
const timer = setTimeout(() => {
|
|
588
|
+
pendingActionResolutions.delete(actionRequestId);
|
|
589
|
+
resolve2(false);
|
|
590
|
+
send({
|
|
591
|
+
type: "daemon:action_timeout",
|
|
592
|
+
action: actionName,
|
|
593
|
+
actionRequestId,
|
|
594
|
+
timeoutMs
|
|
595
|
+
});
|
|
596
|
+
}, timeoutMs);
|
|
597
|
+
pendingActionResolutions.set(actionRequestId, {
|
|
598
|
+
resolve: resolve2,
|
|
599
|
+
reject,
|
|
600
|
+
timer,
|
|
601
|
+
runtimeRequestId: actionRequestId,
|
|
602
|
+
actionName
|
|
603
|
+
});
|
|
604
|
+
send({
|
|
605
|
+
type: "daemon:action_request",
|
|
606
|
+
action: actionName,
|
|
607
|
+
actionRequestId,
|
|
608
|
+
params,
|
|
609
|
+
blackboard
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
registeredActions.add(actionName);
|
|
615
|
+
send({ type: "daemon:ok", op, name: actionName });
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
case "action:list": {
|
|
619
|
+
send({
|
|
620
|
+
type: "daemon:ok",
|
|
621
|
+
op,
|
|
622
|
+
actions: [...registeredActions],
|
|
623
|
+
pending: pendingActionResolutions.size
|
|
624
|
+
});
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
case "action:reply": {
|
|
628
|
+
const actionRequestId = command?.actionRequestId;
|
|
629
|
+
if (typeof actionRequestId !== "string") {
|
|
630
|
+
send({ type: "daemon:error", op, error: "action:reply requires actionRequestId" });
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
const pending = pendingActionResolutions.get(actionRequestId);
|
|
634
|
+
if (!pending) {
|
|
635
|
+
send({ type: "daemon:error", op, error: `Unknown actionRequestId: ${actionRequestId}` });
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
clearTimeout(pending.timer);
|
|
639
|
+
pendingActionResolutions.delete(actionRequestId);
|
|
640
|
+
const status = command?.status;
|
|
641
|
+
const success = typeof command?.success === "boolean" ? command.success : status === "success" || status === "true";
|
|
642
|
+
pending.resolve(Boolean(success));
|
|
643
|
+
send({ type: "daemon:ok", op, actionRequestId, success: Boolean(success) });
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
case "action:unregister": {
|
|
647
|
+
if (!supportsActionRegistry) {
|
|
648
|
+
send({ type: "daemon:error", op, error: "Runtime does not expose registerAction()" });
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
const actionName = command?.name;
|
|
652
|
+
if (typeof actionName !== "string" || actionName.trim() === "") {
|
|
653
|
+
send({ type: "daemon:error", op, error: "action:unregister requires non-empty name" });
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
runtime.registerAction(actionName, () => false);
|
|
657
|
+
registeredActions.delete(actionName);
|
|
658
|
+
send({ type: "daemon:ok", op, name: actionName });
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
case "stop": {
|
|
662
|
+
send({ type: "daemon:stopped", reason: "command" });
|
|
663
|
+
close();
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
default:
|
|
667
|
+
send({ type: "daemon:error", error: `Unknown op: ${String(op)}` });
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
await new Promise((resolve2) => {
|
|
671
|
+
rl.once("close", () => resolve2());
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
async function runScript(opts) {
|
|
675
|
+
if (!opts.file) {
|
|
676
|
+
console.error("Error: No input file specified");
|
|
677
|
+
process.exit(1);
|
|
678
|
+
}
|
|
679
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
680
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
681
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
682
|
+
process.exit(1);
|
|
683
|
+
}
|
|
684
|
+
const source = fs__namespace.readFileSync(filePath, "utf-8");
|
|
685
|
+
const ext = path__namespace.extname(filePath);
|
|
686
|
+
console.log(`[holoscript] Running ${path__namespace.basename(filePath)} (target: ${opts.target})`);
|
|
687
|
+
const parseResult = chunkT5J7ZKP3_cjs.parse(source);
|
|
688
|
+
const ast = parseResult.ast;
|
|
689
|
+
if (opts.debug) {
|
|
690
|
+
console.log(`[holoscript] Parsed ${ast.body?.length || 0} top-level nodes`);
|
|
691
|
+
console.log(`[holoscript] File type: ${ext}`);
|
|
692
|
+
}
|
|
693
|
+
const { createHeadlessRuntime, getProfile, HEADLESS_PROFILE } = await loadEngineRuntime();
|
|
694
|
+
const profile = opts.profile === "headless" ? HEADLESS_PROFILE : getProfile(opts.profile);
|
|
695
|
+
const runtime = createHeadlessRuntime(ast, {
|
|
696
|
+
profile,
|
|
697
|
+
tickRate: 10,
|
|
698
|
+
debug: opts.debug,
|
|
699
|
+
hostCapabilities: createNodeHostCapabilities(path__namespace.dirname(filePath))
|
|
700
|
+
});
|
|
701
|
+
chunk2YSNA2F2_cjs.registerStdlib(
|
|
702
|
+
runtime,
|
|
703
|
+
{
|
|
704
|
+
policy: {
|
|
705
|
+
rootDir: path__namespace.dirname(filePath),
|
|
706
|
+
allowedPaths: opts.allowedPaths.length > 0 ? opts.allowedPaths : ["compositions", "data", "src", "packages"],
|
|
707
|
+
maxFileBytes: 2 * 1024 * 1024,
|
|
708
|
+
allowShell: opts.allowShell,
|
|
709
|
+
allowedShellCommands: opts.allowedShellCommands,
|
|
710
|
+
maxShellOutputBytes: 100 * 1024,
|
|
711
|
+
shellTimeoutMs: 6e4,
|
|
712
|
+
allowNetwork: opts.allowedHosts.length > 0,
|
|
713
|
+
allowedHosts: opts.allowedHosts
|
|
714
|
+
},
|
|
715
|
+
hostCapabilities: createNodeHostCapabilities(path__namespace.dirname(filePath))
|
|
716
|
+
}
|
|
717
|
+
);
|
|
718
|
+
new chunkSLU6UPJI_cjs.InteropContext(path__namespace.dirname(filePath));
|
|
719
|
+
if (opts.debug) {
|
|
720
|
+
console.log(`[holoscript] Profile: ${profile.name}`);
|
|
721
|
+
console.log(`[holoscript] Interop context: ${path__namespace.dirname(filePath)}`);
|
|
722
|
+
}
|
|
723
|
+
runtime.start();
|
|
724
|
+
if (opts.daemon) {
|
|
725
|
+
if (opts.debug) {
|
|
726
|
+
console.log("[holoscript] Entering daemon mode");
|
|
727
|
+
}
|
|
728
|
+
await runDaemon(runtime, opts);
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
runTicks(runtime, opts.ticks);
|
|
732
|
+
runtime.stop();
|
|
733
|
+
const stats = runtime.getStats();
|
|
734
|
+
console.log(
|
|
735
|
+
`[holoscript] Complete \u2014 ${stats.tickCount} ticks, ${stats.nodesProcessed} nodes processed`
|
|
736
|
+
);
|
|
737
|
+
if (opts.watch) {
|
|
738
|
+
console.log(`[holoscript] Watching for changes... (Ctrl+C to stop)`);
|
|
739
|
+
const watcher = new chunkXHIV6326_cjs.HotReloadWatcher({
|
|
740
|
+
watchPaths: [path__namespace.dirname(filePath)],
|
|
741
|
+
extensions: [".hs", ".hsplus", ".holo"],
|
|
742
|
+
debounceMs: 300,
|
|
743
|
+
mode: "soft"
|
|
744
|
+
});
|
|
745
|
+
watcher.on("reload", async (event) => {
|
|
746
|
+
console.log(`
|
|
747
|
+
[holoscript] File changed: ${path__namespace.basename(event.filePath)}`);
|
|
748
|
+
console.log(`[holoscript] Re-running ${path__namespace.basename(filePath)}...`);
|
|
749
|
+
try {
|
|
750
|
+
const newSource = fs__namespace.readFileSync(filePath, "utf-8");
|
|
751
|
+
const newParseResult = chunkT5J7ZKP3_cjs.parse(newSource);
|
|
752
|
+
const newAst = newParseResult.ast;
|
|
753
|
+
const newRuntime = createHeadlessRuntime(newAst, {
|
|
754
|
+
profile: opts.profile === "headless" ? HEADLESS_PROFILE : getProfile(opts.profile),
|
|
755
|
+
tickRate: 10,
|
|
756
|
+
debug: opts.debug,
|
|
757
|
+
hostCapabilities: createNodeHostCapabilities(path__namespace.dirname(filePath))
|
|
758
|
+
});
|
|
759
|
+
newRuntime.start();
|
|
760
|
+
runTicks(newRuntime, opts.ticks);
|
|
761
|
+
newRuntime.stop();
|
|
762
|
+
const newStats = newRuntime.getStats();
|
|
763
|
+
console.log(
|
|
764
|
+
`[holoscript] Complete \u2014 ${newStats.tickCount} ticks, ${newStats.nodesProcessed} nodes`
|
|
765
|
+
);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
console.error(`[holoscript] Error:`, err.message);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
watcher.start();
|
|
771
|
+
await new Promise(() => {
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async function testScript(opts) {
|
|
776
|
+
if (!opts.file) {
|
|
777
|
+
console.error("Error: No test file specified");
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
781
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
782
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
783
|
+
process.exit(1);
|
|
784
|
+
}
|
|
785
|
+
const source = fs__namespace.readFileSync(filePath, "utf-8");
|
|
786
|
+
console.log(`[holoscript test] Running tests in ${path__namespace.basename(filePath)}`);
|
|
787
|
+
const parseResult = chunkT5J7ZKP3_cjs.parse(source);
|
|
788
|
+
const ast = parseResult.ast;
|
|
789
|
+
const { createHeadlessRuntime, HEADLESS_PROFILE } = await loadEngineRuntime();
|
|
790
|
+
const profile = HEADLESS_PROFILE;
|
|
791
|
+
const runtime = createHeadlessRuntime(ast, { profile, tickRate: 10, debug: opts.debug });
|
|
792
|
+
runtime.start();
|
|
793
|
+
const runtimeAccess = runtime;
|
|
794
|
+
for (let i = 0; i < 50; i++) runtimeAccess.tick();
|
|
795
|
+
const runner = new chunkXHIV6326_cjs.ScriptTestRunner({
|
|
796
|
+
debug: opts.debug,
|
|
797
|
+
runtimeState: runtimeAccess.getState()
|
|
798
|
+
});
|
|
799
|
+
const scriptResults = runner.runTestsFromSource(source, filePath);
|
|
800
|
+
const runtimeState = runtimeAccess.getState();
|
|
801
|
+
const compositionState = Object.keys(runtimeState).length > 0 ? runtimeState : chunk2YSNA2F2_cjs.CompositionTestRunner.extractStateFromSource(source);
|
|
802
|
+
const computedDefs = chunk2YSNA2F2_cjs.CompositionTestRunner.extractComputedFromSource(source);
|
|
803
|
+
const compositionRunner = new chunk2YSNA2F2_cjs.CompositionTestRunner(compositionState, computedDefs, {
|
|
804
|
+
debug: opts.debug
|
|
805
|
+
});
|
|
806
|
+
const compositionResults = compositionRunner.runTestsFromSource(source);
|
|
807
|
+
const results = [...scriptResults, ...compositionResults];
|
|
808
|
+
const passed = results.filter((r) => r.status === "passed").length;
|
|
809
|
+
const failed = results.filter((r) => r.status === "failed").length;
|
|
810
|
+
const skipped = results.filter((r) => r.status === "skipped").length;
|
|
811
|
+
console.log("");
|
|
812
|
+
for (const result of results) {
|
|
813
|
+
const icon = result.status === "passed" ? "\u2713" : result.status === "failed" ? "\u2717" : "\u25CB";
|
|
814
|
+
const color = result.status === "passed" ? "\x1B[32m" : result.status === "failed" ? "\x1B[31m" : "\x1B[33m";
|
|
815
|
+
console.log(` ${color}${icon}\x1B[0m ${result.name} (${result.durationMs}ms)`);
|
|
816
|
+
if (result.error) {
|
|
817
|
+
console.log(` \x1B[31m${result.error}\x1B[0m`);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
console.log("");
|
|
821
|
+
console.log(
|
|
822
|
+
`Tests: ${passed} passed, ${failed} failed, ${skipped} skipped (${results.length} total)`
|
|
823
|
+
);
|
|
824
|
+
if (failed > 0) process.exit(1);
|
|
825
|
+
}
|
|
826
|
+
function compileScript(opts) {
|
|
827
|
+
if (!opts.file) {
|
|
828
|
+
console.error("Error: No input file specified");
|
|
829
|
+
process.exit(1);
|
|
830
|
+
}
|
|
831
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
832
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
833
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
834
|
+
process.exit(1);
|
|
835
|
+
}
|
|
836
|
+
const source = fs__namespace.readFileSync(filePath, "utf-8");
|
|
837
|
+
if (opts.enforceGotchas) {
|
|
838
|
+
const gotchaRe = /@gotcha\s*\{([^}]+)\}/g;
|
|
839
|
+
let gMatch;
|
|
840
|
+
const criticals = [];
|
|
841
|
+
while ((gMatch = gotchaRe.exec(source)) !== null) {
|
|
842
|
+
const block = gMatch[1];
|
|
843
|
+
const sevMatch = block.match(/severity:\s*"([^"]*)"/i);
|
|
844
|
+
const severity = sevMatch?.[1] || "warning";
|
|
845
|
+
if (severity === "critical") {
|
|
846
|
+
const warnMatch = block.match(/warning:\s*"([^"]*)"/i);
|
|
847
|
+
const mitMatch = block.match(/mitigation:\s*"([^"]*)"/i);
|
|
848
|
+
criticals.push({
|
|
849
|
+
warning: warnMatch?.[1] || "Unknown critical gotcha",
|
|
850
|
+
mitigation: mitMatch?.[1] || "No mitigation specified"
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (criticals.length > 0) {
|
|
855
|
+
console.error(
|
|
856
|
+
`[holoscript compile] BLOCKED by ${criticals.length} critical @gotcha violation(s):`
|
|
857
|
+
);
|
|
858
|
+
for (const g of criticals) {
|
|
859
|
+
console.error(` \u2717 ${g.warning}`);
|
|
860
|
+
console.error(` mitigation: ${g.mitigation}`);
|
|
861
|
+
}
|
|
862
|
+
process.exit(1);
|
|
863
|
+
}
|
|
864
|
+
console.log(`[holoscript compile] @gotcha check passed (no critical violations)`);
|
|
865
|
+
}
|
|
866
|
+
const compileResult = chunkT5J7ZKP3_cjs.parse(source);
|
|
867
|
+
if (!compileResult.success) {
|
|
868
|
+
console.error(`[holoscript compile] Failed to parse: ${compileResult.errors?.[0]?.message}`);
|
|
869
|
+
process.exit(1);
|
|
870
|
+
}
|
|
871
|
+
const ast = compileResult.ast;
|
|
872
|
+
const outputPath = opts.output || filePath.replace(/\.(hs|hsplus|holo)$/, `.${opts.target === "python" ? "py" : "js"}`);
|
|
873
|
+
console.log(
|
|
874
|
+
`[holoscript compile] ${path__namespace.basename(filePath)} \u2192 ${opts.target} \u2192 ${path__namespace.basename(outputPath)}`
|
|
875
|
+
);
|
|
876
|
+
let output;
|
|
877
|
+
switch (opts.target) {
|
|
878
|
+
case "node":
|
|
879
|
+
output = generateNodeTarget(ast);
|
|
880
|
+
break;
|
|
881
|
+
case "python":
|
|
882
|
+
output = generatePythonTarget(ast);
|
|
883
|
+
break;
|
|
884
|
+
default:
|
|
885
|
+
output = JSON.stringify(ast, null, 2);
|
|
886
|
+
}
|
|
887
|
+
fs__namespace.writeFileSync(outputPath, output, "utf-8");
|
|
888
|
+
console.log(`[holoscript compile] Written to ${outputPath}`);
|
|
889
|
+
}
|
|
890
|
+
function generateNodeTarget(ast) {
|
|
891
|
+
const lines = [
|
|
892
|
+
"// Auto-generated by holoscript compile --target node",
|
|
893
|
+
"// Source: HoloScript composition",
|
|
894
|
+
`"use strict";`,
|
|
895
|
+
""
|
|
896
|
+
];
|
|
897
|
+
if (ast.root && ast.root.children) {
|
|
898
|
+
for (const node of ast.root.children) {
|
|
899
|
+
if (node.type === "composition" || node.type === "ObjectDeclaration") {
|
|
900
|
+
const name = node.name || "default";
|
|
901
|
+
lines.push(`// ${node.type}: ${name}`);
|
|
902
|
+
lines.push(`module.exports.${name} = ${JSON.stringify(node, null, 2)};`);
|
|
903
|
+
lines.push("");
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return lines.join("\n");
|
|
908
|
+
}
|
|
909
|
+
function generatePythonTarget(ast) {
|
|
910
|
+
const lines = [
|
|
911
|
+
"# Auto-generated by holoscript compile --target python",
|
|
912
|
+
"# Source: HoloScript composition",
|
|
913
|
+
"import json",
|
|
914
|
+
""
|
|
915
|
+
];
|
|
916
|
+
if (ast.root && ast.root.children) {
|
|
917
|
+
for (const node of ast.root.children) {
|
|
918
|
+
if (node.type === "composition" || node.type === "ObjectDeclaration") {
|
|
919
|
+
const name = node.name || "default_obj";
|
|
920
|
+
lines.push(`# ${node.type}: ${name}`);
|
|
921
|
+
lines.push(`${name} = json.loads('''${JSON.stringify(node)}''')`);
|
|
922
|
+
lines.push("");
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return lines.join("\n");
|
|
927
|
+
}
|
|
928
|
+
async function deployScript(opts) {
|
|
929
|
+
if (!opts.file) {
|
|
930
|
+
console.error("Error: No source file specified");
|
|
931
|
+
console.error(
|
|
932
|
+
"Usage: holoscript deploy <file> [--share] [--publish] [--price <eth>] [--mint-nft] [--author <name>] [--license <type>] [--server <url>]"
|
|
933
|
+
);
|
|
934
|
+
process.exit(1);
|
|
935
|
+
}
|
|
936
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
937
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
938
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
939
|
+
process.exit(1);
|
|
940
|
+
}
|
|
941
|
+
const source = fs__namespace.readFileSync(filePath, "utf-8");
|
|
942
|
+
const fileName = path__namespace.basename(filePath);
|
|
943
|
+
const title = path__namespace.basename(filePath, path__namespace.extname(filePath));
|
|
944
|
+
console.log(`Parsing ${fileName}...`);
|
|
945
|
+
const ast = chunkT5J7ZKP3_cjs.parse(source);
|
|
946
|
+
if (ast.errors && ast.errors.length > 0) {
|
|
947
|
+
console.error("Parse errors:");
|
|
948
|
+
for (const err of ast.errors) {
|
|
949
|
+
console.error(` ${err.message || err}`);
|
|
950
|
+
}
|
|
951
|
+
process.exit(1);
|
|
952
|
+
}
|
|
953
|
+
const license = opts.license || "free";
|
|
954
|
+
const provenance = chunkR75BSDH7_cjs.generateProvenance(source, ast, {
|
|
955
|
+
author: opts.author || "anonymous",
|
|
956
|
+
license
|
|
957
|
+
});
|
|
958
|
+
console.log(
|
|
959
|
+
`Provenance: ${provenance.publishMode} | hash: ${provenance.hash.slice(0, 12)}... | license: ${provenance.license}`
|
|
960
|
+
);
|
|
961
|
+
if (provenance.imports.length > 0) {
|
|
962
|
+
const importedLicenses = provenance.imports.map((imp) => ({
|
|
963
|
+
path: imp.path,
|
|
964
|
+
license: "free"
|
|
965
|
+
}));
|
|
966
|
+
const licenseCheck = chunk2YSNA2F2_cjs.checkLicenseCompatibility(license, importedLicenses);
|
|
967
|
+
if (licenseCheck.warnings.length > 0) {
|
|
968
|
+
for (const w of licenseCheck.warnings) {
|
|
969
|
+
console.log(` Warning: ${w}`);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (!licenseCheck.compatible) {
|
|
973
|
+
console.error("License compatibility errors:");
|
|
974
|
+
for (const e of licenseCheck.errors) {
|
|
975
|
+
console.error(` ${e}`);
|
|
976
|
+
}
|
|
977
|
+
process.exit(1);
|
|
978
|
+
}
|
|
979
|
+
if (licenseCheck.forcedLicense) {
|
|
980
|
+
console.log(` License forced to "${licenseCheck.forcedLicense}" by imports`);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const serverUrl = opts.serverUrl.replace(/\/$/, "");
|
|
984
|
+
if (opts.publish) {
|
|
985
|
+
const priceWei = chunk2YSNA2F2_cjs.ethToWei(opts.price || "0");
|
|
986
|
+
const importChain = provenance.imports.map((imp, i) => ({
|
|
987
|
+
contentHash: imp.hash || `import-${i}`,
|
|
988
|
+
author: imp.author || imp.path,
|
|
989
|
+
depth: 1,
|
|
990
|
+
children: []
|
|
991
|
+
}));
|
|
992
|
+
const revenuePreview = chunk2YSNA2F2_cjs.calculateRevenueDistribution(
|
|
993
|
+
priceWei,
|
|
994
|
+
provenance.author || "anonymous",
|
|
995
|
+
importChain
|
|
996
|
+
);
|
|
997
|
+
console.log("\nRevenue distribution:");
|
|
998
|
+
for (const line of chunk2YSNA2F2_cjs.formatRevenueDistribution(revenuePreview)) {
|
|
999
|
+
console.log(` ${line}`);
|
|
1000
|
+
}
|
|
1001
|
+
console.log(`
|
|
1002
|
+
Publishing to protocol at ${serverUrl}...`);
|
|
1003
|
+
const metadataBody = JSON.stringify({
|
|
1004
|
+
contentHash: provenance.hash,
|
|
1005
|
+
provenance: {
|
|
1006
|
+
hash: provenance.hash,
|
|
1007
|
+
author: provenance.author,
|
|
1008
|
+
license: provenance.license,
|
|
1009
|
+
publishMode: provenance.publishMode,
|
|
1010
|
+
imports: provenance.imports,
|
|
1011
|
+
created: provenance.created
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
try {
|
|
1015
|
+
const metaRes = await fetch(`${serverUrl}/api/protocol/metadata`, {
|
|
1016
|
+
method: "POST",
|
|
1017
|
+
headers: { "Content-Type": "application/json" },
|
|
1018
|
+
body: metadataBody
|
|
1019
|
+
});
|
|
1020
|
+
if (!metaRes.ok) {
|
|
1021
|
+
const text = await metaRes.text();
|
|
1022
|
+
console.error(`Metadata storage failed (${metaRes.status}): ${text}`);
|
|
1023
|
+
process.exit(1);
|
|
1024
|
+
}
|
|
1025
|
+
} catch (err) {
|
|
1026
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1027
|
+
console.error(`Metadata storage failed: ${msg}`);
|
|
1028
|
+
process.exit(1);
|
|
1029
|
+
}
|
|
1030
|
+
const protocolBody = JSON.stringify({
|
|
1031
|
+
contentHash: provenance.hash,
|
|
1032
|
+
author: provenance.author || "anonymous",
|
|
1033
|
+
importHashes: provenance.imports.map((imp) => imp.hash).filter(Boolean),
|
|
1034
|
+
license: provenance.license,
|
|
1035
|
+
publishMode: provenance.publishMode,
|
|
1036
|
+
price: opts.price || "0",
|
|
1037
|
+
referralBps: chunk2YSNA2F2_cjs.PROTOCOL_CONSTANTS.DEFAULT_REFERRAL_BPS,
|
|
1038
|
+
metadataURI: `${serverUrl}/metadata/${provenance.hash}`,
|
|
1039
|
+
mintAsNFT: opts.mintNft,
|
|
1040
|
+
// Include scene data for CDN deploy
|
|
1041
|
+
code: source,
|
|
1042
|
+
title,
|
|
1043
|
+
description: `Published from CLI: ${fileName}`
|
|
1044
|
+
});
|
|
1045
|
+
try {
|
|
1046
|
+
const pubRes = await fetch(`${serverUrl}/api/protocol`, {
|
|
1047
|
+
method: "POST",
|
|
1048
|
+
headers: { "Content-Type": "application/json" },
|
|
1049
|
+
body: protocolBody
|
|
1050
|
+
});
|
|
1051
|
+
if (!pubRes.ok) {
|
|
1052
|
+
const text = await pubRes.text();
|
|
1053
|
+
console.error(`Protocol publish failed (${pubRes.status}): ${text}`);
|
|
1054
|
+
process.exit(1);
|
|
1055
|
+
}
|
|
1056
|
+
const pubResult = await pubRes.json();
|
|
1057
|
+
console.log("\nPublished to HoloScript Protocol!");
|
|
1058
|
+
console.log(` Hash: ${pubResult.contentHash}`);
|
|
1059
|
+
console.log(` ID: ${pubResult.protocolId}`);
|
|
1060
|
+
console.log(` Collect: ${pubResult.collectUrl}`);
|
|
1061
|
+
console.log(` Registry: ${pubResult.registryUrl}`);
|
|
1062
|
+
if (pubResult.sceneUrl) {
|
|
1063
|
+
console.log(` Scene: ${pubResult.sceneUrl}`);
|
|
1064
|
+
}
|
|
1065
|
+
if (pubResult.embedUrl) {
|
|
1066
|
+
console.log(` Embed: ${pubResult.embedUrl}`);
|
|
1067
|
+
}
|
|
1068
|
+
if (priceWei > 0n) {
|
|
1069
|
+
console.log(` Price: ${opts.price} ETH`);
|
|
1070
|
+
} else {
|
|
1071
|
+
console.log(" Price: Free collect");
|
|
1072
|
+
}
|
|
1073
|
+
if (opts.mintNft) {
|
|
1074
|
+
console.log(" NFT: Zora mint requested");
|
|
1075
|
+
}
|
|
1076
|
+
} catch (err) {
|
|
1077
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1078
|
+
console.error(`Protocol publish failed: ${msg}`);
|
|
1079
|
+
console.error(
|
|
1080
|
+
"Is the server running? Try: holoscript deploy <file> --publish --server http://localhost:3000"
|
|
1081
|
+
);
|
|
1082
|
+
process.exit(1);
|
|
1083
|
+
}
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const endpoint = `${serverUrl}/api/deploy`;
|
|
1087
|
+
console.log(`Deploying to ${serverUrl}...`);
|
|
1088
|
+
const body = JSON.stringify({
|
|
1089
|
+
code: source,
|
|
1090
|
+
title,
|
|
1091
|
+
description: `Deployed from CLI: ${fileName}`,
|
|
1092
|
+
author: provenance.author,
|
|
1093
|
+
license: provenance.license,
|
|
1094
|
+
provenance: {
|
|
1095
|
+
hash: provenance.hash,
|
|
1096
|
+
publishMode: provenance.publishMode,
|
|
1097
|
+
imports: provenance.imports
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
try {
|
|
1101
|
+
const res = await fetch(endpoint, {
|
|
1102
|
+
method: "POST",
|
|
1103
|
+
headers: { "Content-Type": "application/json" },
|
|
1104
|
+
body
|
|
1105
|
+
});
|
|
1106
|
+
if (!res.ok) {
|
|
1107
|
+
const text = await res.text();
|
|
1108
|
+
console.error(`Deploy failed (${res.status}): ${text}`);
|
|
1109
|
+
process.exit(1);
|
|
1110
|
+
}
|
|
1111
|
+
const result = await res.json();
|
|
1112
|
+
console.log("\nDeployed successfully!");
|
|
1113
|
+
console.log(` ID: ${result.id}`);
|
|
1114
|
+
console.log(` URL: ${result.url}`);
|
|
1115
|
+
console.log(` Embed: ${result.embed}`);
|
|
1116
|
+
console.log(` API: ${result.api}`);
|
|
1117
|
+
if (result.provenance) {
|
|
1118
|
+
console.log(` Mode: ${result.provenance.publishMode}`);
|
|
1119
|
+
console.log(` Hash: ${result.provenance.hash}`);
|
|
1120
|
+
}
|
|
1121
|
+
if (opts.share) {
|
|
1122
|
+
console.log(`
|
|
1123
|
+
Share URL: ${result.url}`);
|
|
1124
|
+
}
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1127
|
+
console.error(`Deploy failed: ${msg}`);
|
|
1128
|
+
console.error(
|
|
1129
|
+
"Is the server running? Try: holoscript deploy <file> --server http://localhost:3000"
|
|
1130
|
+
);
|
|
1131
|
+
process.exit(1);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
function absorbScript(opts) {
|
|
1135
|
+
if (!opts.file) {
|
|
1136
|
+
console.error("Error: No source file specified");
|
|
1137
|
+
process.exit(1);
|
|
1138
|
+
}
|
|
1139
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
1140
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
1141
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
1142
|
+
process.exit(1);
|
|
1143
|
+
}
|
|
1144
|
+
const content = fs__namespace.readFileSync(filePath, "utf-8");
|
|
1145
|
+
const ext = path__namespace.extname(filePath).toLowerCase();
|
|
1146
|
+
const langMap = {
|
|
1147
|
+
".py": "python",
|
|
1148
|
+
".ts": "typescript",
|
|
1149
|
+
".tsx": "typescript",
|
|
1150
|
+
".js": "javascript",
|
|
1151
|
+
".jsx": "javascript",
|
|
1152
|
+
".mjs": "javascript"
|
|
1153
|
+
};
|
|
1154
|
+
const language = langMap[ext];
|
|
1155
|
+
if (!language) {
|
|
1156
|
+
console.error(
|
|
1157
|
+
`Error: Unsupported file type '${ext}'. Supported: .py, .ts, .tsx, .js, .jsx, .mjs`
|
|
1158
|
+
);
|
|
1159
|
+
process.exit(1);
|
|
1160
|
+
}
|
|
1161
|
+
const outputPath = opts.output || filePath.replace(/\.\w+$/, ".hsplus");
|
|
1162
|
+
console.log(
|
|
1163
|
+
`[holoscript absorb] ${path__namespace.basename(filePath)} (${language}) \u2192 ${path__namespace.basename(outputPath)}`
|
|
1164
|
+
);
|
|
1165
|
+
const processor = new chunkXHIV6326_cjs.AbsorbProcessor();
|
|
1166
|
+
const result = processor.absorb({ language, filePath, content });
|
|
1167
|
+
fs__namespace.writeFileSync(outputPath, result.generatedHSPlus, "utf-8");
|
|
1168
|
+
console.log(`[holoscript absorb] Extracted:`);
|
|
1169
|
+
console.log(` ${result.functions.length} functions`);
|
|
1170
|
+
console.log(` ${result.classes.length} classes`);
|
|
1171
|
+
console.log(` ${result.imports.length} imports`);
|
|
1172
|
+
console.log(` ${result.constants.length} constants`);
|
|
1173
|
+
if (result.warnings.length > 0) {
|
|
1174
|
+
console.log(`
|
|
1175
|
+
Warnings:`);
|
|
1176
|
+
for (const w of result.warnings) {
|
|
1177
|
+
console.log(` \u26A0 ${w}`);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
console.log(`[holoscript absorb] Written to ${outputPath}`);
|
|
1181
|
+
}
|
|
1182
|
+
function findGitRoot(startDir) {
|
|
1183
|
+
let dir = startDir;
|
|
1184
|
+
while (dir !== path__namespace.dirname(dir)) {
|
|
1185
|
+
if (fs__namespace.existsSync(path__namespace.join(dir, ".git"))) return dir;
|
|
1186
|
+
dir = path__namespace.dirname(dir);
|
|
1187
|
+
}
|
|
1188
|
+
return startDir;
|
|
1189
|
+
}
|
|
1190
|
+
function sleep(ms) {
|
|
1191
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1192
|
+
}
|
|
1193
|
+
function extractEconomyConfig(ast) {
|
|
1194
|
+
const result = {};
|
|
1195
|
+
let found = false;
|
|
1196
|
+
function walk(node) {
|
|
1197
|
+
if (!node || typeof node !== "object") return;
|
|
1198
|
+
const obj = node;
|
|
1199
|
+
if (Array.isArray(obj.traits)) {
|
|
1200
|
+
for (const trait of obj.traits) {
|
|
1201
|
+
const t = trait;
|
|
1202
|
+
if (t.name === "economy" && typeof t.config === "object" && t.config) {
|
|
1203
|
+
const cfg = t.config;
|
|
1204
|
+
if (typeof cfg.budget === "number") result.budget = cfg.budget;
|
|
1205
|
+
if (typeof cfg.default_spend_limit === "number")
|
|
1206
|
+
result.default_spend_limit = cfg.default_spend_limit;
|
|
1207
|
+
if (typeof cfg.initial_balance === "number") result.initial_balance = cfg.initial_balance;
|
|
1208
|
+
if (typeof cfg.task_completion_reward === "number")
|
|
1209
|
+
result.task_completion_reward = cfg.task_completion_reward;
|
|
1210
|
+
found = true;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
if (Array.isArray(obj.directives)) {
|
|
1215
|
+
for (const dir of obj.directives) {
|
|
1216
|
+
const d = dir;
|
|
1217
|
+
if ((d.type === "trait" || d.type === "ObjectTrait") && d.name === "economy" && typeof d.config === "object" && d.config) {
|
|
1218
|
+
const cfg = d.config;
|
|
1219
|
+
if (typeof cfg.budget === "number") result.budget = cfg.budget;
|
|
1220
|
+
if (typeof cfg.default_spend_limit === "number")
|
|
1221
|
+
result.default_spend_limit = cfg.default_spend_limit;
|
|
1222
|
+
if (typeof cfg.initial_balance === "number") result.initial_balance = cfg.initial_balance;
|
|
1223
|
+
if (typeof cfg.task_completion_reward === "number")
|
|
1224
|
+
result.task_completion_reward = cfg.task_completion_reward;
|
|
1225
|
+
found = true;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
if (Array.isArray(obj.body)) obj.body.forEach(walk);
|
|
1230
|
+
if (Array.isArray(obj.children)) obj.children.forEach(walk);
|
|
1231
|
+
if (Array.isArray(obj.objects)) obj.objects.forEach(walk);
|
|
1232
|
+
}
|
|
1233
|
+
walk(ast);
|
|
1234
|
+
return found ? result : void 0;
|
|
1235
|
+
}
|
|
1236
|
+
function loadRuntimeSkillActions(skillsDir, opts, host, repoRoot, debug = false) {
|
|
1237
|
+
const actions = {};
|
|
1238
|
+
if (!fs__namespace.existsSync(skillsDir)) return actions;
|
|
1239
|
+
const files = fs__namespace.readdirSync(skillsDir).filter((name) => name.endsWith(".hsplus")).map((name) => path__namespace.join(skillsDir, name));
|
|
1240
|
+
for (const file of files) {
|
|
1241
|
+
const content = fs__namespace.readFileSync(file, "utf-8");
|
|
1242
|
+
const actionRe = /action\s+"([^"]+)"\s*\{([\s\S]*?)\}/g;
|
|
1243
|
+
let match;
|
|
1244
|
+
while ((match = actionRe.exec(content)) !== null) {
|
|
1245
|
+
const actionName = match[1].trim();
|
|
1246
|
+
const block = match[2];
|
|
1247
|
+
const commandMatch = block.match(/command\s*:\s*["']([^"']+)["']/);
|
|
1248
|
+
if (!commandMatch) continue;
|
|
1249
|
+
const command = commandMatch[1].trim();
|
|
1250
|
+
const argMatch = block.match(/args\s*:\s*\[([^\]]*)\]/);
|
|
1251
|
+
const bakedArgs = [];
|
|
1252
|
+
if (argMatch) {
|
|
1253
|
+
const argValueRe = /["']([^"']+)["']/g;
|
|
1254
|
+
let argToken;
|
|
1255
|
+
while ((argToken = argValueRe.exec(argMatch[1])) !== null) {
|
|
1256
|
+
bakedArgs.push(argToken[1]);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
actions[actionName] = async (params, bb, ctx) => {
|
|
1260
|
+
if (!opts.allowShell) {
|
|
1261
|
+
bb.skill_error = `Skill ${actionName} blocked: shell disabled`;
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
if (opts.allowedShellCommands.length > 0) {
|
|
1265
|
+
const executable = command.split(/\s+/)[0].toLowerCase();
|
|
1266
|
+
const allowed = opts.allowedShellCommands.some((c) => c.toLowerCase() === executable);
|
|
1267
|
+
if (!allowed) {
|
|
1268
|
+
bb.skill_error = `Skill ${actionName} blocked: command ${executable} not allowlisted`;
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
const runtimeArgs = Array.isArray(params.args) ? params.args.filter((v) => typeof v === "string") : [];
|
|
1273
|
+
const timeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) ? Math.max(1e3, Math.min(3e5, Math.floor(params.timeoutMs))) : 6e4;
|
|
1274
|
+
const result = await host.exec(command, [...bakedArgs, ...runtimeArgs], {
|
|
1275
|
+
cwd: repoRoot,
|
|
1276
|
+
timeoutMs
|
|
1277
|
+
});
|
|
1278
|
+
bb.skill_last_action = actionName;
|
|
1279
|
+
bb.skill_last_code = result.code ?? -1;
|
|
1280
|
+
bb.skill_last_stdout = result.stdout.slice(0, 5e4);
|
|
1281
|
+
bb.skill_last_stderr = result.stderr.slice(0, 5e4);
|
|
1282
|
+
ctx.emit("daemon:skill:executed", { actionName, code: result.code, file });
|
|
1283
|
+
return result.code === 0;
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (debug) {
|
|
1288
|
+
console.log(
|
|
1289
|
+
`[daemon] Loaded ${Object.keys(actions).length} runtime skill action(s) from ${skillsDir}`
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
return actions;
|
|
1293
|
+
}
|
|
1294
|
+
async function daemonScript(opts) {
|
|
1295
|
+
if (!opts.file) {
|
|
1296
|
+
console.error("Error: No composition file specified");
|
|
1297
|
+
process.exit(1);
|
|
1298
|
+
}
|
|
1299
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
1300
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
1301
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
1302
|
+
process.exit(1);
|
|
1303
|
+
}
|
|
1304
|
+
const { createDaemonActions, getDaemonFileState } = await import('@holoscript/absorb-service/daemon');
|
|
1305
|
+
const repoRoot = findGitRoot(path__namespace.dirname(filePath));
|
|
1306
|
+
const source = fs__namespace.readFileSync(filePath, "utf-8");
|
|
1307
|
+
const parseResult = chunkT5J7ZKP3_cjs.parse(source);
|
|
1308
|
+
if (!parseResult.success || !parseResult.ast) {
|
|
1309
|
+
const errors = parseResult.errors?.map((e) => e.message).join(", ") || "unknown";
|
|
1310
|
+
console.error(`[daemon] Parse failed: ${errors}`);
|
|
1311
|
+
process.exit(1);
|
|
1312
|
+
}
|
|
1313
|
+
const compositionAST = parseResult.ast;
|
|
1314
|
+
console.log(`[daemon] Composition: ${path__namespace.basename(filePath)}`);
|
|
1315
|
+
console.log(`[daemon] Repo root: ${repoRoot}`);
|
|
1316
|
+
console.log(
|
|
1317
|
+
`[daemon] Cycles: ${opts.cycles} | Commit: ${opts.commit} | Timeout: ${opts.timeout}min | Provider: ${opts.provider} | Model: ${opts.model} | Tool profile: ${opts.toolProfile} | Always-on: ${opts.alwaysOn} | Cycle interval: ${opts.cycleIntervalSec}s`
|
|
1318
|
+
);
|
|
1319
|
+
const stateDir = path__namespace.join(repoRoot, ".holoscript");
|
|
1320
|
+
if (!fs__namespace.existsSync(stateDir)) fs__namespace.mkdirSync(stateDir, { recursive: true });
|
|
1321
|
+
const lockFile = path__namespace.join(stateDir, "daemon.lock");
|
|
1322
|
+
const lockData = { pid: process.pid, time: Date.now(), heartbeat: Date.now() };
|
|
1323
|
+
if (fs__namespace.existsSync(lockFile)) {
|
|
1324
|
+
try {
|
|
1325
|
+
const existing = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(lockFile, "utf-8"));
|
|
1326
|
+
const staleMs = 12e4;
|
|
1327
|
+
if (Date.now() - existing.heartbeat < staleMs) {
|
|
1328
|
+
console.error(
|
|
1329
|
+
`[daemon] Another daemon is running (PID ${existing.pid}). Remove ${lockFile} to force.`
|
|
1330
|
+
);
|
|
1331
|
+
process.exit(1);
|
|
1332
|
+
}
|
|
1333
|
+
console.log(`[daemon] Reclaiming stale lock from PID ${existing.pid}`);
|
|
1334
|
+
} catch {
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
fs__namespace.writeFileSync(lockFile, JSON.stringify(lockData), "utf-8");
|
|
1338
|
+
const heartbeatTimer = setInterval(() => {
|
|
1339
|
+
try {
|
|
1340
|
+
fs__namespace.writeFileSync(lockFile, JSON.stringify({ ...lockData, heartbeat: Date.now() }), "utf-8");
|
|
1341
|
+
} catch {
|
|
1342
|
+
}
|
|
1343
|
+
}, 3e4);
|
|
1344
|
+
const fileWatchers = [];
|
|
1345
|
+
const cleanup = () => {
|
|
1346
|
+
clearInterval(heartbeatTimer);
|
|
1347
|
+
for (const watcher of fileWatchers) {
|
|
1348
|
+
try {
|
|
1349
|
+
watcher.close();
|
|
1350
|
+
} catch {
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
try {
|
|
1354
|
+
fs__namespace.rmSync(lockFile, { force: true });
|
|
1355
|
+
} catch {
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1358
|
+
process.once("SIGINT", cleanup);
|
|
1359
|
+
process.once("SIGTERM", cleanup);
|
|
1360
|
+
process.once("uncaughtException", (err) => {
|
|
1361
|
+
cleanup();
|
|
1362
|
+
console.error("[daemon] Uncaught:", err);
|
|
1363
|
+
process.exit(1);
|
|
1364
|
+
});
|
|
1365
|
+
process.once("unhandledRejection", (err) => {
|
|
1366
|
+
cleanup();
|
|
1367
|
+
console.error("[daemon] Unhandled:", err);
|
|
1368
|
+
process.exit(1);
|
|
1369
|
+
});
|
|
1370
|
+
const host = {
|
|
1371
|
+
readFile: (p) => fs__namespace.readFileSync(path__namespace.resolve(repoRoot, p), "utf-8"),
|
|
1372
|
+
writeFile: (p, c) => {
|
|
1373
|
+
const resolved = path__namespace.resolve(repoRoot, p);
|
|
1374
|
+
fs__namespace.mkdirSync(path__namespace.dirname(resolved), { recursive: true });
|
|
1375
|
+
fs__namespace.writeFileSync(resolved, c, "utf-8");
|
|
1376
|
+
},
|
|
1377
|
+
exists: (p) => fs__namespace.existsSync(path__namespace.resolve(repoRoot, p)),
|
|
1378
|
+
exec: (cmd, args = [], execOpts = {}) => new Promise((resolve2, reject) => {
|
|
1379
|
+
const child = child_process.spawn(cmd, args, {
|
|
1380
|
+
cwd: execOpts.cwd ?? repoRoot,
|
|
1381
|
+
shell: true,
|
|
1382
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1383
|
+
});
|
|
1384
|
+
let stdout = "";
|
|
1385
|
+
let stderr = "";
|
|
1386
|
+
let timer = null;
|
|
1387
|
+
child.stdout?.on("data", (d) => {
|
|
1388
|
+
stdout += d.toString("utf-8");
|
|
1389
|
+
});
|
|
1390
|
+
child.stderr?.on("data", (d) => {
|
|
1391
|
+
stderr += d.toString("utf-8");
|
|
1392
|
+
});
|
|
1393
|
+
if (execOpts.timeoutMs && execOpts.timeoutMs > 0) {
|
|
1394
|
+
timer = setTimeout(() => {
|
|
1395
|
+
try {
|
|
1396
|
+
child.kill("SIGKILL");
|
|
1397
|
+
} catch {
|
|
1398
|
+
}
|
|
1399
|
+
}, execOpts.timeoutMs);
|
|
1400
|
+
}
|
|
1401
|
+
child.on("close", (code) => {
|
|
1402
|
+
if (timer) clearTimeout(timer);
|
|
1403
|
+
resolve2({ code, stdout, stderr });
|
|
1404
|
+
});
|
|
1405
|
+
child.on("error", reject);
|
|
1406
|
+
})
|
|
1407
|
+
};
|
|
1408
|
+
const skillsDirRel = opts.skillsDir || "compositions/skills";
|
|
1409
|
+
const skillsDirAbs = path__namespace.resolve(repoRoot, skillsDirRel);
|
|
1410
|
+
if (!fs__namespace.existsSync(skillsDirAbs)) {
|
|
1411
|
+
fs__namespace.mkdirSync(skillsDirAbs, { recursive: true });
|
|
1412
|
+
}
|
|
1413
|
+
let runtimeSkillActions = loadRuntimeSkillActions(skillsDirAbs, opts, host, repoRoot, opts.debug);
|
|
1414
|
+
let activeRuntime = null;
|
|
1415
|
+
const reloadRuntimeSkills = () => {
|
|
1416
|
+
runtimeSkillActions = loadRuntimeSkillActions(skillsDirAbs, opts, host, repoRoot, opts.debug);
|
|
1417
|
+
if (activeRuntime) {
|
|
1418
|
+
for (const [name, handler] of Object.entries(runtimeSkillActions)) {
|
|
1419
|
+
activeRuntime.registerAction(name, handler);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
try {
|
|
1424
|
+
const watcher = fs__namespace.watch(skillsDirAbs, { persistent: false }, () => {
|
|
1425
|
+
reloadRuntimeSkills();
|
|
1426
|
+
});
|
|
1427
|
+
fileWatchers.push(watcher);
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
if (opts.debug) {
|
|
1430
|
+
console.warn(
|
|
1431
|
+
`[daemon] Skill watcher unavailable for ${skillsDirAbs}: ${error.message}`
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
const llm = await createDaemonLLMProvider(opts);
|
|
1436
|
+
const defaultFocusRotation = [
|
|
1437
|
+
"typefix",
|
|
1438
|
+
"coverage",
|
|
1439
|
+
"typefix",
|
|
1440
|
+
"lint",
|
|
1441
|
+
"target-sweep",
|
|
1442
|
+
"trait-sampling",
|
|
1443
|
+
"runtime-matrix",
|
|
1444
|
+
"absorb-roundtrip",
|
|
1445
|
+
"typefix",
|
|
1446
|
+
"all"
|
|
1447
|
+
];
|
|
1448
|
+
const focusRotation = getASTBlackboardValue(compositionAST, "focus_rotation") ?? defaultFocusRotation;
|
|
1449
|
+
const providerRotationEnabled = getASTBlackboardValue(compositionAST, "provider_rotation_enabled") ?? opts.providerRotation;
|
|
1450
|
+
const rotationProviders = getASTBlackboardValue(compositionAST, "provider_rotation") ?? ["anthropic", "xai"];
|
|
1451
|
+
const quarantineThreshold = getASTBlackboardValue(compositionAST, "quarantine_threshold") ?? 3;
|
|
1452
|
+
const economyConfig = extractEconomyConfig(compositionAST);
|
|
1453
|
+
if (economyConfig && opts.debug) {
|
|
1454
|
+
console.log(`[daemon] Economy config from composition:`, economyConfig);
|
|
1455
|
+
}
|
|
1456
|
+
const config = {
|
|
1457
|
+
repoRoot,
|
|
1458
|
+
commit: opts.commit,
|
|
1459
|
+
model: opts.model,
|
|
1460
|
+
provider: opts.provider,
|
|
1461
|
+
toolProfile: opts.toolProfile,
|
|
1462
|
+
verbose: opts.debug,
|
|
1463
|
+
trial: opts.trial,
|
|
1464
|
+
focusRotation,
|
|
1465
|
+
stateDir,
|
|
1466
|
+
quarantineThreshold,
|
|
1467
|
+
skillsDir: opts.skillsDir,
|
|
1468
|
+
toolPolicy: {
|
|
1469
|
+
allowShell: opts.allowShell,
|
|
1470
|
+
allowedShellCommands: opts.allowedShellCommands,
|
|
1471
|
+
allowedHosts: opts.allowedHosts,
|
|
1472
|
+
allowedPaths: opts.allowedPaths
|
|
1473
|
+
},
|
|
1474
|
+
economyConfig,
|
|
1475
|
+
sessionId: opts.sessionId
|
|
1476
|
+
};
|
|
1477
|
+
const stateFile = path__namespace.join(stateDir, "daemon-state.json");
|
|
1478
|
+
const telemetryFile = path__namespace.join(stateDir, "daemon-telemetry.jsonl");
|
|
1479
|
+
const daemonStateDefaults = {
|
|
1480
|
+
totalCycles: 0,
|
|
1481
|
+
focusIndex: 0,
|
|
1482
|
+
bestQuality: 0,
|
|
1483
|
+
lastQuality: 0,
|
|
1484
|
+
totalCostUSD: 0,
|
|
1485
|
+
totalInputTokens: 0,
|
|
1486
|
+
totalOutputTokens: 0,
|
|
1487
|
+
typeErrorBaseline: 0,
|
|
1488
|
+
lastFocus: "",
|
|
1489
|
+
lastCycleTimeISO: ""
|
|
1490
|
+
};
|
|
1491
|
+
let daemonState = { ...daemonStateDefaults };
|
|
1492
|
+
if (fs__namespace.existsSync(stateFile)) {
|
|
1493
|
+
try {
|
|
1494
|
+
daemonState = { ...daemonState, ...chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(stateFile, "utf-8")) };
|
|
1495
|
+
} catch {
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
const fileStateFile = path__namespace.join(stateDir, "daemon-file-state.json");
|
|
1499
|
+
if (fs__namespace.existsSync(fileStateFile)) {
|
|
1500
|
+
try {
|
|
1501
|
+
const fileState = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(fileStateFile, "utf-8"));
|
|
1502
|
+
config.committedFiles = fileState.committed || [];
|
|
1503
|
+
config.failedFiles = fileState.failures || {};
|
|
1504
|
+
} catch {
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
if (daemonState.typeErrorBaseline > 0) {
|
|
1508
|
+
config.typeErrorBaseline = daemonState.typeErrorBaseline;
|
|
1509
|
+
}
|
|
1510
|
+
let daemonResult = createDaemonActions(host, llm, config);
|
|
1511
|
+
let actions = daemonResult.actions;
|
|
1512
|
+
try {
|
|
1513
|
+
await llm.chat({ system: "reply ok", prompt: "ok", maxTokens: 1 });
|
|
1514
|
+
console.log("[daemon] API key validated");
|
|
1515
|
+
} catch (err) {
|
|
1516
|
+
console.error(`[daemon] API key validation failed: ${err.message}`);
|
|
1517
|
+
cleanup();
|
|
1518
|
+
process.exit(1);
|
|
1519
|
+
}
|
|
1520
|
+
const { createHeadlessRuntime, HEADLESS_PROFILE } = await loadEngineRuntime();
|
|
1521
|
+
let convergenceStreak = 0;
|
|
1522
|
+
const CONVERGENCE_THRESHOLD = 3;
|
|
1523
|
+
let cycle = 0;
|
|
1524
|
+
while (opts.alwaysOn || cycle < opts.cycles) {
|
|
1525
|
+
let focusIdx = daemonState.focusIndex % focusRotation.length;
|
|
1526
|
+
let focus = opts.focus || focusRotation[focusIdx];
|
|
1527
|
+
if (!opts.focus) {
|
|
1528
|
+
const wisdomFile = path__namespace.join(stateDir, "accumulated-wisdom.json");
|
|
1529
|
+
let wisdomEntries = [];
|
|
1530
|
+
try {
|
|
1531
|
+
if (fs__namespace.existsSync(wisdomFile)) {
|
|
1532
|
+
wisdomEntries = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(wisdomFile, "utf-8"));
|
|
1533
|
+
}
|
|
1534
|
+
} catch {
|
|
1535
|
+
}
|
|
1536
|
+
const STALE_THRESHOLD = 3;
|
|
1537
|
+
let attempts = 0;
|
|
1538
|
+
while (attempts < focusRotation.length) {
|
|
1539
|
+
const focusHistory = wisdomEntries.filter((w) => w.focus === focus);
|
|
1540
|
+
const lastN = focusHistory.slice(-STALE_THRESHOLD);
|
|
1541
|
+
const isStale = lastN.length >= STALE_THRESHOLD && lastN.every((w) => (w.delta || 0) === 0);
|
|
1542
|
+
if (!isStale) break;
|
|
1543
|
+
console.log(
|
|
1544
|
+
`[daemon] Skipping stale focus "${focus}" (${STALE_THRESHOLD} consecutive zero-delta cycles)`
|
|
1545
|
+
);
|
|
1546
|
+
focusIdx = (focusIdx + 1) % focusRotation.length;
|
|
1547
|
+
focus = focusRotation[focusIdx];
|
|
1548
|
+
attempts++;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
config.cycleFocus = focus;
|
|
1552
|
+
config.daemonFile = filePath;
|
|
1553
|
+
config.qualityBefore = daemonState.lastQuality;
|
|
1554
|
+
const cycleStart = Date.now();
|
|
1555
|
+
if (providerRotationEnabled) {
|
|
1556
|
+
const cycleProvider = rotationProviders[cycle % rotationProviders.length];
|
|
1557
|
+
const cycleModel = defaultModelForProvider(cycleProvider);
|
|
1558
|
+
const cycleToolProfile = defaultToolProfileForProvider(cycleProvider);
|
|
1559
|
+
const cycleOpts = {
|
|
1560
|
+
...opts,
|
|
1561
|
+
provider: cycleProvider,
|
|
1562
|
+
model: cycleModel};
|
|
1563
|
+
const cycleLlm = await createDaemonLLMProvider(cycleOpts);
|
|
1564
|
+
config.provider = cycleProvider;
|
|
1565
|
+
config.model = cycleModel;
|
|
1566
|
+
config.toolProfile = cycleToolProfile;
|
|
1567
|
+
daemonResult = createDaemonActions(host, cycleLlm, config);
|
|
1568
|
+
actions = daemonResult.actions;
|
|
1569
|
+
console.log(
|
|
1570
|
+
`
|
|
1571
|
+
[daemon] === Cycle ${cycle + 1}${opts.alwaysOn ? "" : `/${opts.cycles}`} | Focus: ${focus} | Provider: ${cycleProvider} (${cycleModel}) ===`
|
|
1572
|
+
);
|
|
1573
|
+
} else {
|
|
1574
|
+
console.log(
|
|
1575
|
+
`
|
|
1576
|
+
[daemon] === Cycle ${cycle + 1}${opts.alwaysOn ? "" : `/${opts.cycles}`} | Focus: ${focus} ===`
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
const cycleAST = chunkE7JP3BS3_cjs.jsonClone(compositionAST);
|
|
1580
|
+
materializeTraits(cycleAST);
|
|
1581
|
+
const bbValues = {
|
|
1582
|
+
focus,
|
|
1583
|
+
cycleNumber: daemonState.totalCycles + cycle,
|
|
1584
|
+
daemon_file: filePath,
|
|
1585
|
+
quality_before: daemonState.lastQuality
|
|
1586
|
+
};
|
|
1587
|
+
setASTBlackboard(cycleAST, bbValues);
|
|
1588
|
+
if (opts.debug) {
|
|
1589
|
+
console.log(`[daemon] Blackboard injection: focus=${focus}, daemon_file=${filePath}`);
|
|
1590
|
+
}
|
|
1591
|
+
const runtime = createHeadlessRuntime(cycleAST, {
|
|
1592
|
+
profile: HEADLESS_PROFILE,
|
|
1593
|
+
tickRate: 10,
|
|
1594
|
+
debug: opts.debug,
|
|
1595
|
+
hostCapabilities: createNodeHostCapabilities(repoRoot)
|
|
1596
|
+
});
|
|
1597
|
+
activeRuntime = runtime;
|
|
1598
|
+
for (const [name, handler] of Object.entries(actions)) {
|
|
1599
|
+
runtime.registerAction(name, handler);
|
|
1600
|
+
}
|
|
1601
|
+
for (const [name, handler] of Object.entries(runtimeSkillActions)) {
|
|
1602
|
+
runtime.registerAction(name, handler);
|
|
1603
|
+
}
|
|
1604
|
+
daemonResult.wireTraitListeners(runtime);
|
|
1605
|
+
const maxWaitMs = opts.timeout * 60 * 1e3;
|
|
1606
|
+
const btResult = await new Promise(
|
|
1607
|
+
(resolve2) => {
|
|
1608
|
+
let resolved = false;
|
|
1609
|
+
const timeout = setTimeout(() => {
|
|
1610
|
+
if (!resolved) {
|
|
1611
|
+
resolved = true;
|
|
1612
|
+
resolve2({ status: "timeout", blackboard: {} });
|
|
1613
|
+
}
|
|
1614
|
+
}, maxWaitMs);
|
|
1615
|
+
runtime.on("bt_complete", (payload) => {
|
|
1616
|
+
if (!resolved) {
|
|
1617
|
+
resolved = true;
|
|
1618
|
+
clearTimeout(timeout);
|
|
1619
|
+
const p = payload;
|
|
1620
|
+
resolve2({
|
|
1621
|
+
status: p?.status || "unknown",
|
|
1622
|
+
blackboard: p?.blackboard || {}
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
runtime.start();
|
|
1627
|
+
}
|
|
1628
|
+
);
|
|
1629
|
+
const btStatus = btResult.status;
|
|
1630
|
+
const btBlackboard = btResult.blackboard;
|
|
1631
|
+
const durationSec = ((Date.now() - cycleStart) / 1e3).toFixed(1);
|
|
1632
|
+
const stats = runtime.getStats();
|
|
1633
|
+
const inputTokens = btBlackboard.inputTokens || 0;
|
|
1634
|
+
const outputTokens = btBlackboard.outputTokens || 0;
|
|
1635
|
+
const qualityAfter = btBlackboard.quality_after || daemonState.lastQuality;
|
|
1636
|
+
const costUSD = inputTokens * 3 / 1e6 + outputTokens * 15 / 1e6;
|
|
1637
|
+
const committed = btBlackboard.committed_count || 0;
|
|
1638
|
+
const qualityDelta = qualityAfter - (config.qualityBefore || 0);
|
|
1639
|
+
runtime.emit("daemon:cycle_raw_telemetry", {
|
|
1640
|
+
focus,
|
|
1641
|
+
ticks: stats.updateCount,
|
|
1642
|
+
inputTokens,
|
|
1643
|
+
outputTokens,
|
|
1644
|
+
qualityBefore: daemonState.lastQuality,
|
|
1645
|
+
qualityAfter,
|
|
1646
|
+
costUSD,
|
|
1647
|
+
committed: committed > 0
|
|
1648
|
+
});
|
|
1649
|
+
runtime.emit("daemon:raw_quality", { value: qualityAfter, focus });
|
|
1650
|
+
const totalTokens = inputTokens + outputTokens;
|
|
1651
|
+
const costEfficiency = costUSD > 0 ? Math.min(1, qualityAfter * totalTokens / (costUSD * 5e5)) : qualityAfter;
|
|
1652
|
+
runtime.emit("feedback:update_metric", { name: "cost_efficiency", value: costEfficiency });
|
|
1653
|
+
const candidateCount = Array.isArray(btBlackboard.candidates) ? btBlackboard.candidates.length : 0;
|
|
1654
|
+
const emergenceRatio = candidateCount > 0 ? Math.min(1, committed / candidateCount) : 0;
|
|
1655
|
+
runtime.emit("feedback:update_metric", { name: "emergence_ratio", value: emergenceRatio });
|
|
1656
|
+
const wisdomCount = btBlackboard.wisdomCount || 0;
|
|
1657
|
+
const regenerativeHealth = Math.min(1, wisdomCount / 200);
|
|
1658
|
+
runtime.emit("feedback:update_metric", {
|
|
1659
|
+
name: "regenerative_health",
|
|
1660
|
+
value: regenerativeHealth
|
|
1661
|
+
});
|
|
1662
|
+
runtime.stop();
|
|
1663
|
+
activeRuntime = null;
|
|
1664
|
+
const telemetryRecord = {
|
|
1665
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1666
|
+
cycleNumber: daemonState.totalCycles + 1,
|
|
1667
|
+
focus,
|
|
1668
|
+
provider: config.provider,
|
|
1669
|
+
model: config.model,
|
|
1670
|
+
btStatus,
|
|
1671
|
+
ticks: stats.updateCount,
|
|
1672
|
+
inputTokens,
|
|
1673
|
+
outputTokens,
|
|
1674
|
+
totalTokens,
|
|
1675
|
+
costUSD,
|
|
1676
|
+
qualityBefore: config.qualityBefore || 0,
|
|
1677
|
+
qualityAfter,
|
|
1678
|
+
qualityDelta,
|
|
1679
|
+
typeErrors: btBlackboard.quality_typeErrors ?? null,
|
|
1680
|
+
testsPassed: btBlackboard.quality_testsPassed ?? null,
|
|
1681
|
+
testsTotal: btBlackboard.quality_testsTotal ?? null,
|
|
1682
|
+
committedCount: committed,
|
|
1683
|
+
candidateCount,
|
|
1684
|
+
wisdomCount,
|
|
1685
|
+
durationSec: Number(durationSec)
|
|
1686
|
+
};
|
|
1687
|
+
fs__namespace.appendFileSync(telemetryFile, `${JSON.stringify(telemetryRecord)}
|
|
1688
|
+
`, "utf-8");
|
|
1689
|
+
console.log(
|
|
1690
|
+
`[daemon] Cycle ${cycle + 1} done in ${durationSec}s | ${stats.updateCount} ticks | BT: ${btStatus} | quality: ${qualityAfter.toFixed(3)}`
|
|
1691
|
+
);
|
|
1692
|
+
daemonState.totalCycles++;
|
|
1693
|
+
daemonState.focusIndex = (focusIdx + 1) % focusRotation.length;
|
|
1694
|
+
daemonState.lastQuality = qualityAfter;
|
|
1695
|
+
if (qualityAfter > daemonState.bestQuality) {
|
|
1696
|
+
daemonState.bestQuality = qualityAfter;
|
|
1697
|
+
}
|
|
1698
|
+
daemonState.totalInputTokens += inputTokens;
|
|
1699
|
+
daemonState.totalOutputTokens += outputTokens;
|
|
1700
|
+
daemonState.totalCostUSD += costUSD;
|
|
1701
|
+
daemonState.lastFocus = focus;
|
|
1702
|
+
daemonState.lastCycleTimeISO = (/* @__PURE__ */ new Date()).toISOString();
|
|
1703
|
+
const cycleTypeErrors = btBlackboard.typeErrorBaseline || btBlackboard.typeErrorCount || 0;
|
|
1704
|
+
if (daemonState.typeErrorBaseline === 0 && cycleTypeErrors > 0) {
|
|
1705
|
+
daemonState.typeErrorBaseline = cycleTypeErrors;
|
|
1706
|
+
config.typeErrorBaseline = cycleTypeErrors;
|
|
1707
|
+
console.log(`[daemon] Established type error baseline: ${cycleTypeErrors}`);
|
|
1708
|
+
}
|
|
1709
|
+
fs__namespace.writeFileSync(stateFile, JSON.stringify(daemonState, null, 2), "utf-8");
|
|
1710
|
+
const fileState = getDaemonFileState(repoRoot);
|
|
1711
|
+
fs__namespace.writeFileSync(fileStateFile, JSON.stringify(fileState, null, 2), "utf-8");
|
|
1712
|
+
if (qualityDelta <= 0 && committed === 0) {
|
|
1713
|
+
convergenceStreak++;
|
|
1714
|
+
if (convergenceStreak >= CONVERGENCE_THRESHOLD) {
|
|
1715
|
+
console.log(
|
|
1716
|
+
`[daemon] Plateau detected \u2014 ${convergenceStreak} consecutive zero-delta cycles. Escalating strategy.`
|
|
1717
|
+
);
|
|
1718
|
+
convergenceStreak = 0;
|
|
1719
|
+
const oldThreshold = config.quarantineThreshold || 3;
|
|
1720
|
+
config.quarantineThreshold = oldThreshold + 2;
|
|
1721
|
+
console.log(
|
|
1722
|
+
`[daemon] Raised quarantine threshold: ${oldThreshold} \u2192 ${config.quarantineThreshold}`
|
|
1723
|
+
);
|
|
1724
|
+
if (!opts.focus) {
|
|
1725
|
+
const typefixIdx = focusRotation.indexOf("typefix");
|
|
1726
|
+
if (typefixIdx >= 0) {
|
|
1727
|
+
daemonState.focusIndex = typefixIdx;
|
|
1728
|
+
console.log(`[daemon] Forcing next cycle to 'typefix' focus`);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
if (config.quarantineThreshold >= quarantineThreshold + 4) {
|
|
1732
|
+
console.log(
|
|
1733
|
+
`[daemon] Escalated twice with no progress. Stopping to avoid wasting tokens.`
|
|
1734
|
+
);
|
|
1735
|
+
break;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
} else {
|
|
1739
|
+
convergenceStreak = 0;
|
|
1740
|
+
}
|
|
1741
|
+
cycle++;
|
|
1742
|
+
if (opts.alwaysOn && opts.cycleIntervalSec > 0) {
|
|
1743
|
+
console.log(`[daemon] Sleeping ${opts.cycleIntervalSec}s before next cycle...`);
|
|
1744
|
+
await sleep(opts.cycleIntervalSec * 1e3);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
cleanup();
|
|
1748
|
+
console.log(`
|
|
1749
|
+
[daemon] Completed ${cycle} cycle(s).`);
|
|
1750
|
+
console.log(
|
|
1751
|
+
`[daemon] Best quality: ${daemonState.bestQuality.toFixed(3)} | Total cost: $${daemonState.totalCostUSD.toFixed(3)} | Total cycles: ${daemonState.totalCycles}`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
function materializeTraits(ast) {
|
|
1755
|
+
const walk = (node) => {
|
|
1756
|
+
if (!node || typeof node !== "object") return;
|
|
1757
|
+
const n = node;
|
|
1758
|
+
const traits = /* @__PURE__ */ new Map();
|
|
1759
|
+
if (Array.isArray(n.directives)) {
|
|
1760
|
+
for (const directive of n.directives) {
|
|
1761
|
+
const d = directive;
|
|
1762
|
+
if (d.type === "trait" && typeof d.name === "string") {
|
|
1763
|
+
traits.set(d.name, d.config ?? {});
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
if (traits.size > 0) {
|
|
1768
|
+
n.traits = traits;
|
|
1769
|
+
} else if (n.traits && !(n.traits instanceof Map)) {
|
|
1770
|
+
delete n.traits;
|
|
1771
|
+
}
|
|
1772
|
+
for (const key of ["body", "children", "nodes", "members"]) {
|
|
1773
|
+
if (Array.isArray(n[key])) {
|
|
1774
|
+
n[key].forEach(walk);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
if (n.root && typeof n.root === "object") {
|
|
1778
|
+
walk(n.root);
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
walk(ast);
|
|
1782
|
+
}
|
|
1783
|
+
function setASTBlackboard(ast, values) {
|
|
1784
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
1785
|
+
let found = false;
|
|
1786
|
+
const walk = (node) => {
|
|
1787
|
+
if (found || !node || typeof node !== "object") return;
|
|
1788
|
+
const obj = node;
|
|
1789
|
+
if (visited.has(obj)) return;
|
|
1790
|
+
visited.add(obj);
|
|
1791
|
+
if (obj.blackboard && typeof obj.blackboard === "object" && !Array.isArray(obj.blackboard)) {
|
|
1792
|
+
Object.assign(obj.blackboard, values);
|
|
1793
|
+
found = true;
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
for (const key of Object.keys(obj)) {
|
|
1797
|
+
const val = obj[key];
|
|
1798
|
+
if (val && typeof val === "object") {
|
|
1799
|
+
if (Array.isArray(val)) {
|
|
1800
|
+
for (const item of val) walk(item);
|
|
1801
|
+
} else if (val instanceof Map) {
|
|
1802
|
+
for (const v of val.values()) walk(v);
|
|
1803
|
+
} else {
|
|
1804
|
+
walk(val);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
if (found) return;
|
|
1808
|
+
}
|
|
1809
|
+
};
|
|
1810
|
+
walk(ast);
|
|
1811
|
+
}
|
|
1812
|
+
function getASTBlackboardValue(ast, key) {
|
|
1813
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
1814
|
+
let result = void 0;
|
|
1815
|
+
const walk = (node) => {
|
|
1816
|
+
if (result !== void 0 || !node || typeof node !== "object") return;
|
|
1817
|
+
const obj = node;
|
|
1818
|
+
if (visited.has(obj)) return;
|
|
1819
|
+
visited.add(obj);
|
|
1820
|
+
if (obj.blackboard && typeof obj.blackboard === "object" && !Array.isArray(obj.blackboard)) {
|
|
1821
|
+
const bb = obj.blackboard;
|
|
1822
|
+
if (key in bb) {
|
|
1823
|
+
result = bb[key];
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
for (const k of Object.keys(obj)) {
|
|
1828
|
+
const val = obj[k];
|
|
1829
|
+
if (val && typeof val === "object") {
|
|
1830
|
+
if (Array.isArray(val)) {
|
|
1831
|
+
for (const item of val) walk(item);
|
|
1832
|
+
} else if (!(val instanceof Map)) {
|
|
1833
|
+
walk(val);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
if (result !== void 0) return;
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
walk(ast);
|
|
1840
|
+
return result;
|
|
1841
|
+
}
|
|
1842
|
+
async function holoMeshDaemonScript(opts) {
|
|
1843
|
+
if (!opts.file) {
|
|
1844
|
+
console.error("Error: No composition file specified");
|
|
1845
|
+
console.error("Usage: holoscript holomesh-daemon compositions/holomesh-agent.hsplus [options]");
|
|
1846
|
+
process.exit(1);
|
|
1847
|
+
}
|
|
1848
|
+
const filePath = path__namespace.resolve(opts.file);
|
|
1849
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
1850
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
1851
|
+
process.exit(1);
|
|
1852
|
+
}
|
|
1853
|
+
if (!process.env.HOLOSCRIPT_API_KEY) {
|
|
1854
|
+
console.error("[holomesh-daemon] HOLOSCRIPT_API_KEY environment variable is required");
|
|
1855
|
+
process.exit(1);
|
|
1856
|
+
}
|
|
1857
|
+
const rawSource = fs__namespace.readFileSync(filePath, "utf-8");
|
|
1858
|
+
const source = rawSource.replace(/^#(version|target|mode)\s+.*/gm, "");
|
|
1859
|
+
const parseResult = chunkT5J7ZKP3_cjs.parse(source);
|
|
1860
|
+
if (!parseResult.success || !parseResult.ast) {
|
|
1861
|
+
const errors = parseResult.errors?.map((e) => e.message).join(", ") || "unknown";
|
|
1862
|
+
console.error(`[holomesh-daemon] Parse failed: ${errors}`);
|
|
1863
|
+
process.exit(1);
|
|
1864
|
+
}
|
|
1865
|
+
const compositionAST = parseResult.ast;
|
|
1866
|
+
const stateDir = path__namespace.resolve(path__namespace.dirname(filePath), ".holoscript");
|
|
1867
|
+
if (!fs__namespace.existsSync(stateDir)) fs__namespace.mkdirSync(stateDir, { recursive: true });
|
|
1868
|
+
const stateFile = path__namespace.join(stateDir, "holomesh-state.json");
|
|
1869
|
+
console.log(`[holomesh-daemon] Composition: ${path__namespace.basename(filePath)}`);
|
|
1870
|
+
console.log(`[holomesh-daemon] Cycles: ${opts.cycles} | Always-on: ${opts.alwaysOn}`);
|
|
1871
|
+
const lockFile = path__namespace.join(stateDir, "holomesh-daemon.lock");
|
|
1872
|
+
const lockData = { pid: process.pid, time: Date.now(), heartbeat: Date.now() };
|
|
1873
|
+
if (fs__namespace.existsSync(lockFile)) {
|
|
1874
|
+
try {
|
|
1875
|
+
const existing = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(lockFile, "utf-8"));
|
|
1876
|
+
if (Date.now() - existing.heartbeat < 12e4) {
|
|
1877
|
+
console.error(
|
|
1878
|
+
`[holomesh-daemon] Another daemon is running (PID ${existing.pid}). Remove ${lockFile} to force.`
|
|
1879
|
+
);
|
|
1880
|
+
process.exit(1);
|
|
1881
|
+
}
|
|
1882
|
+
console.log(`[holomesh-daemon] Reclaiming stale lock from PID ${existing.pid}`);
|
|
1883
|
+
} catch {
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
fs__namespace.writeFileSync(lockFile, JSON.stringify(lockData), "utf-8");
|
|
1887
|
+
const heartbeatTimer = setInterval(() => {
|
|
1888
|
+
try {
|
|
1889
|
+
fs__namespace.writeFileSync(lockFile, JSON.stringify({ ...lockData, heartbeat: Date.now() }), "utf-8");
|
|
1890
|
+
} catch {
|
|
1891
|
+
}
|
|
1892
|
+
}, 3e4);
|
|
1893
|
+
const cleanup = () => {
|
|
1894
|
+
clearInterval(heartbeatTimer);
|
|
1895
|
+
try {
|
|
1896
|
+
fs__namespace.rmSync(lockFile, { force: true });
|
|
1897
|
+
} catch {
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
process.once("SIGINT", cleanup);
|
|
1901
|
+
process.once("SIGTERM", cleanup);
|
|
1902
|
+
let createHoloMeshDaemonActions;
|
|
1903
|
+
let HoloMeshOrchestratorClient;
|
|
1904
|
+
try {
|
|
1905
|
+
let actionsModule;
|
|
1906
|
+
let clientModule;
|
|
1907
|
+
try {
|
|
1908
|
+
actionsModule = await import('@holoscript/mcp-server/holomesh/agent/holomesh-daemon-actions');
|
|
1909
|
+
clientModule = await import('@holoscript/mcp-server/holomesh/orchestrator-client');
|
|
1910
|
+
} catch {
|
|
1911
|
+
const actionsPath = "../../../mcp-server/src/holomesh/agent/holomesh-daemon-actions";
|
|
1912
|
+
const clientPath = "../../../mcp-server/src/holomesh/orchestrator-client";
|
|
1913
|
+
actionsModule = await import(actionsPath);
|
|
1914
|
+
clientModule = await import(clientPath);
|
|
1915
|
+
}
|
|
1916
|
+
createHoloMeshDaemonActions = actionsModule.createHoloMeshDaemonActions;
|
|
1917
|
+
HoloMeshOrchestratorClient = clientModule.HoloMeshOrchestratorClient;
|
|
1918
|
+
} catch (err) {
|
|
1919
|
+
console.error(`[holomesh-daemon] Failed to import holomesh modules: ${err.message}`);
|
|
1920
|
+
console.error("[holomesh-daemon] Ensure @holoscript/mcp-server is installed");
|
|
1921
|
+
cleanup();
|
|
1922
|
+
process.exit(1);
|
|
1923
|
+
}
|
|
1924
|
+
const meshConfig = {
|
|
1925
|
+
orchestratorUrl: process.env.MCP_ORCHESTRATOR_URL || "https://mcp-orchestrator-production-45f9.up.railway.app",
|
|
1926
|
+
apiKey: process.env.HOLOSCRIPT_API_KEY,
|
|
1927
|
+
workspace: process.env.HOLOMESH_WORKSPACE || "ai-ecosystem",
|
|
1928
|
+
agentName: process.env.HOLOMESH_AGENT_NAME || "holomesh-agent",
|
|
1929
|
+
discoveryIntervalMs: 5 * 60 * 1e3,
|
|
1930
|
+
inboxIntervalMs: 60 * 1e3,
|
|
1931
|
+
maxContributionsPerCycle: 5,
|
|
1932
|
+
maxQueriesPerCycle: 3,
|
|
1933
|
+
budgetCapUSD: parseFloat(process.env.HOLOMESH_BUDGET_CAP || "5")
|
|
1934
|
+
};
|
|
1935
|
+
const client = new HoloMeshOrchestratorClient(meshConfig);
|
|
1936
|
+
const v2Enabled = process.env.HOLOMESH_V2_ENABLED === "true";
|
|
1937
|
+
const localAgentDid = process.env.HOLOMESH_AGENT_DID || (v2Enabled ? `did:holo:${meshConfig.agentName}` : void 0);
|
|
1938
|
+
const walletEnabled = process.env.HOLOMESH_WALLET_ENABLED === "true";
|
|
1939
|
+
const walletTestnet = process.env.HOLOMESH_WALLET_TESTNET === "true";
|
|
1940
|
+
const { actions, wireTraitListeners } = createHoloMeshDaemonActions(client, {
|
|
1941
|
+
stateFile,
|
|
1942
|
+
verbose: opts.debug,
|
|
1943
|
+
v2Enabled,
|
|
1944
|
+
localAgentDid,
|
|
1945
|
+
localMcpUrl: process.env.HOLOMESH_LOCAL_MCP_URL || "https://mcp.holoscript.net",
|
|
1946
|
+
crdtSnapshotPath: v2Enabled ? path__namespace.join(path__namespace.dirname(stateFile), "holomesh-crdt.bin") : void 0,
|
|
1947
|
+
peerStorePath: v2Enabled ? path__namespace.join(path__namespace.dirname(stateFile), "holomesh-peers.json") : void 0,
|
|
1948
|
+
walletEnabled,
|
|
1949
|
+
walletTestnet
|
|
1950
|
+
});
|
|
1951
|
+
console.log(
|
|
1952
|
+
`[holomesh-daemon] ${Object.keys(actions).length} action handlers registered${v2Enabled ? ` (V2 P2P enabled, DID: ${localAgentDid})` : ""}${walletEnabled ? " (V3 Wallet enabled)" : ""}`
|
|
1953
|
+
);
|
|
1954
|
+
const { createHeadlessRuntime, HEADLESS_PROFILE } = await loadEngineRuntime();
|
|
1955
|
+
let cycle = 0;
|
|
1956
|
+
while (opts.alwaysOn || cycle < opts.cycles) {
|
|
1957
|
+
console.log(
|
|
1958
|
+
`
|
|
1959
|
+
[holomesh-daemon] === Cycle ${cycle + 1}${opts.alwaysOn ? "" : `/${opts.cycles}`} ===`
|
|
1960
|
+
);
|
|
1961
|
+
const cycleAST = chunkE7JP3BS3_cjs.jsonClone(compositionAST);
|
|
1962
|
+
materializeTraits(cycleAST);
|
|
1963
|
+
const runtime = createHeadlessRuntime(cycleAST, {
|
|
1964
|
+
profile: HEADLESS_PROFILE,
|
|
1965
|
+
tickRate: 1,
|
|
1966
|
+
debug: opts.debug,
|
|
1967
|
+
hostCapabilities: createNodeHostCapabilities(path__namespace.dirname(filePath))
|
|
1968
|
+
});
|
|
1969
|
+
for (const [name, handler] of Object.entries(actions)) {
|
|
1970
|
+
runtime.registerAction(name, handler);
|
|
1971
|
+
}
|
|
1972
|
+
wireTraitListeners(runtime);
|
|
1973
|
+
const maxWaitMs = (opts.timeout ?? 5) * 60 * 1e3;
|
|
1974
|
+
const btResult = await new Promise((resolve2) => {
|
|
1975
|
+
let resolved = false;
|
|
1976
|
+
const timeout = setTimeout(() => {
|
|
1977
|
+
if (!resolved) {
|
|
1978
|
+
resolved = true;
|
|
1979
|
+
resolve2({ status: "timeout" });
|
|
1980
|
+
}
|
|
1981
|
+
}, maxWaitMs);
|
|
1982
|
+
runtime.on("bt_complete", () => {
|
|
1983
|
+
if (!resolved) {
|
|
1984
|
+
resolved = true;
|
|
1985
|
+
clearTimeout(timeout);
|
|
1986
|
+
resolve2({ status: "complete" });
|
|
1987
|
+
}
|
|
1988
|
+
});
|
|
1989
|
+
runtime.start();
|
|
1990
|
+
});
|
|
1991
|
+
runtime.stop();
|
|
1992
|
+
console.log(`[holomesh-daemon] Cycle ${cycle + 1} ${btResult.status}`);
|
|
1993
|
+
cycle++;
|
|
1994
|
+
if (opts.alwaysOn || cycle < opts.cycles) {
|
|
1995
|
+
const intervalSec = opts.cycleIntervalSec > 0 ? opts.cycleIntervalSec : 120;
|
|
1996
|
+
const jitter = 1 + (Math.random() * 2 - 1) * 0.3;
|
|
1997
|
+
const waitMs = Math.round(intervalSec * 1e3 * jitter);
|
|
1998
|
+
console.log(`[holomesh-daemon] Waiting ${Math.round(waitMs / 1e3)}s before next cycle...`);
|
|
1999
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
cleanup();
|
|
2003
|
+
console.log("[holomesh-daemon] Done");
|
|
2004
|
+
}
|
|
2005
|
+
async function daemonStatus(jsonOutput = false) {
|
|
2006
|
+
const repoRoot = findGitRoot(process.cwd());
|
|
2007
|
+
const stateDir = path__namespace.join(repoRoot, ".holoscript");
|
|
2008
|
+
if (!fs__namespace.existsSync(stateDir)) {
|
|
2009
|
+
if (jsonOutput) {
|
|
2010
|
+
console.log(
|
|
2011
|
+
JSON.stringify({
|
|
2012
|
+
status: "missing_state_dir",
|
|
2013
|
+
running: false,
|
|
2014
|
+
stateDir
|
|
2015
|
+
})
|
|
2016
|
+
);
|
|
2017
|
+
} else {
|
|
2018
|
+
console.log("[daemon status] No state directory found. Run a daemon cycle first.");
|
|
2019
|
+
}
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2022
|
+
const lockFile = path__namespace.join(stateDir, "daemon.lock");
|
|
2023
|
+
let isRunning = false;
|
|
2024
|
+
let lockPid = 0;
|
|
2025
|
+
let lastHeartbeat = 0;
|
|
2026
|
+
if (fs__namespace.existsSync(lockFile)) {
|
|
2027
|
+
try {
|
|
2028
|
+
const lock = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(lockFile, "utf-8"));
|
|
2029
|
+
lockPid = lock.pid;
|
|
2030
|
+
lastHeartbeat = lock.heartbeat;
|
|
2031
|
+
isRunning = Date.now() - lastHeartbeat < 12e4;
|
|
2032
|
+
} catch {
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
const stateFile = path__namespace.join(stateDir, "daemon-state.json");
|
|
2036
|
+
let ds = {};
|
|
2037
|
+
if (fs__namespace.existsSync(stateFile)) {
|
|
2038
|
+
try {
|
|
2039
|
+
ds = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(stateFile, "utf-8"));
|
|
2040
|
+
} catch {
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
const fileStateFile = path__namespace.join(stateDir, "daemon-file-state.json");
|
|
2044
|
+
let fileState = {
|
|
2045
|
+
committed: [],
|
|
2046
|
+
failures: {}
|
|
2047
|
+
};
|
|
2048
|
+
if (fs__namespace.existsSync(fileStateFile)) {
|
|
2049
|
+
try {
|
|
2050
|
+
fileState = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(fileStateFile, "utf-8"));
|
|
2051
|
+
} catch {
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
const wisdomFile = path__namespace.join(stateDir, "accumulated-wisdom.json");
|
|
2055
|
+
let wisdomCount = 0;
|
|
2056
|
+
if (fs__namespace.existsSync(wisdomFile)) {
|
|
2057
|
+
try {
|
|
2058
|
+
wisdomCount = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(wisdomFile, "utf-8")).length;
|
|
2059
|
+
} catch {
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
const ledgerFile = path__namespace.join(stateDir, "fix-ledger.json");
|
|
2063
|
+
let ledger = [];
|
|
2064
|
+
if (fs__namespace.existsSync(ledgerFile)) {
|
|
2065
|
+
try {
|
|
2066
|
+
ledger = chunkE7JP3BS3_cjs.readJson(fs__namespace.readFileSync(ledgerFile, "utf-8"));
|
|
2067
|
+
} catch {
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const telemetryFile = path__namespace.join(stateDir, "daemon-telemetry.jsonl");
|
|
2071
|
+
let telemetryCount = 0;
|
|
2072
|
+
let lastTelemetry;
|
|
2073
|
+
if (fs__namespace.existsSync(telemetryFile)) {
|
|
2074
|
+
try {
|
|
2075
|
+
const lines = fs__namespace.readFileSync(telemetryFile, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2076
|
+
telemetryCount = lines.length;
|
|
2077
|
+
if (lines.length > 0) {
|
|
2078
|
+
lastTelemetry = chunkE7JP3BS3_cjs.readJson(lines[lines.length - 1]);
|
|
2079
|
+
}
|
|
2080
|
+
} catch {
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
const totalCycles = ds.totalCycles || 0;
|
|
2084
|
+
const lastFocus = ds.lastFocus || "n/a";
|
|
2085
|
+
const lastCycleTime = ds.lastCycleTimeISO ? new Date(ds.lastCycleTimeISO).toLocaleString() : "never";
|
|
2086
|
+
const bestQ = Number(ds.bestQuality || 0).toFixed(3);
|
|
2087
|
+
const lastQ = Number(ds.lastQuality || 0).toFixed(3);
|
|
2088
|
+
const baseline = ds.typeErrorBaseline ? `${ds.typeErrorBaseline} type errors` : "not yet measured";
|
|
2089
|
+
const totalCost = Number(ds.totalCostUSD || 0);
|
|
2090
|
+
const tokIn = Number(ds.totalInputTokens || 0);
|
|
2091
|
+
const tokOut = Number(ds.totalOutputTokens || 0);
|
|
2092
|
+
const quarantined = Object.values(fileState.failures).filter((n) => n >= 3).length;
|
|
2093
|
+
if (jsonOutput) {
|
|
2094
|
+
console.log(
|
|
2095
|
+
JSON.stringify({
|
|
2096
|
+
status: "ok",
|
|
2097
|
+
running: isRunning,
|
|
2098
|
+
pid: lockPid || null,
|
|
2099
|
+
heartbeatAgeSec: lastHeartbeat > 0 ? Math.round((Date.now() - lastHeartbeat) / 1e3) : null,
|
|
2100
|
+
stateDir,
|
|
2101
|
+
session: {
|
|
2102
|
+
totalCycles,
|
|
2103
|
+
lastFocus,
|
|
2104
|
+
lastCycleTimeISO: ds.lastCycleTimeISO || null
|
|
2105
|
+
},
|
|
2106
|
+
quality: {
|
|
2107
|
+
best: Number(bestQ),
|
|
2108
|
+
last: Number(lastQ),
|
|
2109
|
+
baselineTypeErrors: ds.typeErrorBaseline || 0
|
|
2110
|
+
},
|
|
2111
|
+
cost: {
|
|
2112
|
+
totalUSD: totalCost,
|
|
2113
|
+
tokensIn: tokIn,
|
|
2114
|
+
tokensOut: tokOut
|
|
2115
|
+
},
|
|
2116
|
+
files: {
|
|
2117
|
+
committed: fileState.committed.length,
|
|
2118
|
+
quarantined
|
|
2119
|
+
},
|
|
2120
|
+
wisdomCount,
|
|
2121
|
+
telemetry: {
|
|
2122
|
+
file: telemetryFile,
|
|
2123
|
+
count: telemetryCount,
|
|
2124
|
+
last: lastTelemetry || null
|
|
2125
|
+
},
|
|
2126
|
+
recentLedger: ledger.slice(-5)
|
|
2127
|
+
})
|
|
2128
|
+
);
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
const G = "\x1B[32m";
|
|
2132
|
+
const Y = "\x1B[33m";
|
|
2133
|
+
const R = "\x1B[0m";
|
|
2134
|
+
const B = "\x1B[1m";
|
|
2135
|
+
const runStatus = isRunning ? `${G}\u25CF RUNNING${R} (PID ${lockPid}, heartbeat ${Math.round((Date.now() - lastHeartbeat) / 1e3)}s ago)` : `${Y}\u25CB IDLE${R}`;
|
|
2136
|
+
console.log(`
|
|
2137
|
+
${B}HoloDaemon Status${R} ${runStatus}`);
|
|
2138
|
+
console.log(` State dir: ${stateDir}
|
|
2139
|
+
`);
|
|
2140
|
+
console.log(`${B}Session${R}`);
|
|
2141
|
+
console.log(` Total cycles: ${totalCycles}`);
|
|
2142
|
+
console.log(` Last focus: ${lastFocus}`);
|
|
2143
|
+
console.log(` Last cycle: ${lastCycleTime}`);
|
|
2144
|
+
console.log(`
|
|
2145
|
+
${B}Quality${R}`);
|
|
2146
|
+
console.log(` Best: ${bestQ}`);
|
|
2147
|
+
console.log(` Last: ${lastQ}`);
|
|
2148
|
+
console.log(` Baseline: ${baseline}`);
|
|
2149
|
+
const totalCostDisplay = totalCost.toFixed(4);
|
|
2150
|
+
const tokInDisplay = tokIn.toLocaleString();
|
|
2151
|
+
const tokOutDisplay = tokOut.toLocaleString();
|
|
2152
|
+
console.log(`
|
|
2153
|
+
${B}Cost${R}`);
|
|
2154
|
+
console.log(` Total: $${totalCostDisplay}`);
|
|
2155
|
+
console.log(` Tokens in: ${tokInDisplay}`);
|
|
2156
|
+
console.log(` Tokens out: ${tokOutDisplay}`);
|
|
2157
|
+
console.log(`
|
|
2158
|
+
${B}Files${R}`);
|
|
2159
|
+
console.log(` Committed: ${fileState.committed.length}`);
|
|
2160
|
+
console.log(` Quarantined: ${quarantined}`);
|
|
2161
|
+
console.log(` Wisdom: ${wisdomCount} entries`);
|
|
2162
|
+
console.log(` Telemetry: ${telemetryCount} entries`);
|
|
2163
|
+
const recent = ledger.slice(-5);
|
|
2164
|
+
if (recent.length > 0) {
|
|
2165
|
+
console.log(`
|
|
2166
|
+
${B}Recent Ledger Entries${R} (last ${recent.length})`);
|
|
2167
|
+
for (const entry of recent) {
|
|
2168
|
+
const ts = entry.timestamp ? new Date(entry.timestamp).toLocaleString() : "?";
|
|
2169
|
+
const file = entry.candidate ? path__namespace.basename(entry.candidate) : "?";
|
|
2170
|
+
const result = entry.result === "committed" ? `${G}committed${R}` : entry.result === "rolled_back" ? `${Y}rolled_back${R}` : entry.result || "?";
|
|
2171
|
+
const sha = entry.commitSha ? ` (${entry.commitSha.slice(0, 7)})` : "";
|
|
2172
|
+
console.log(` ${ts} ${file} ${result}${sha} focus:${entry.focus || "?"}`);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
console.log("");
|
|
2176
|
+
}
|
|
2177
|
+
function showHelp() {
|
|
2178
|
+
console.log(`
|
|
2179
|
+
HoloScript CLI \u2014 Headless Runner v5.0
|
|
2180
|
+
|
|
2181
|
+
Usage:
|
|
2182
|
+
holoscript run <file> [--target node|python|ros2] [--profile headless|minimal|full] [--ticks <n>] [--daemon] [--debug]
|
|
2183
|
+
holoscript test <file> [--debug]
|
|
2184
|
+
holoscript compile <file> [--target node|python] [--output <path>] [--enforce-gotchas]
|
|
2185
|
+
holoscript deploy <file> [--share] [--publish] [--price <eth>] [--mint-nft] [--wallet-key <key>] [--author <name>] [--license <type>] [--server <url>]
|
|
2186
|
+
holoscript absorb <file> [--output <path>] [--debug]
|
|
2187
|
+
holoscript daemon <file> [--provider anthropic|xai|openai|ollama] [--tool-profile claude-hsplus|grok-hsplus|standard] [--cycles <n>] [--commit] [--model <model>] [--trial <n>] [--provider-rotation] [--always-on] [--cycle-interval-sec <n>] [--skills-dir <path>] [--allow-shell] [--allow-shell-command <cmd>] [--allow-host <host>] [--allow-path <path>] [--debug]
|
|
2188
|
+
holoscript daemon status [--json]
|
|
2189
|
+
|
|
2190
|
+
Environment defaults (daemon):
|
|
2191
|
+
HOLODAEMON_PROVIDER anthropic|xai|openai|ollama
|
|
2192
|
+
HOLODAEMON_TOOL_PROFILE claude-hsplus|grok-hsplus|standard
|
|
2193
|
+
HOLODAEMON_MODEL model identifier for selected provider
|
|
2194
|
+
|
|
2195
|
+
Supported file types:
|
|
2196
|
+
.hs Agent templates, behavior trees, event handlers
|
|
2197
|
+
.hsplus Full language with modules, types, async/await
|
|
2198
|
+
.holo Spatial compositions (optional render target)
|
|
2199
|
+
|
|
2200
|
+
Examples:
|
|
2201
|
+
holoscript run agent.hs --target node --debug
|
|
2202
|
+
holoscript run agent.hs --daemon
|
|
2203
|
+
holoscript test tests.hs
|
|
2204
|
+
holoscript compile service.hsplus --target python --output service.py
|
|
2205
|
+
holoscript compile world.holo --enforce-gotchas
|
|
2206
|
+
holoscript absorb legacy.py --output agent.hsplus
|
|
2207
|
+
holoscript daemon compositions/self-improve-daemon.hsplus --cycles 15 --commit
|
|
2208
|
+
holoscript daemon compositions/self-improve-daemon.hsplus --provider xai --model grok-3
|
|
2209
|
+
holoscript daemon compositions/self-improve-daemon.hsplus --provider anthropic --tool-profile claude-hsplus
|
|
2210
|
+
holoscript daemon compositions/self-improve-daemon.hsplus --provider-rotation --cycles 10
|
|
2211
|
+
holoscript daemon status
|
|
2212
|
+
`);
|
|
2213
|
+
}
|
|
2214
|
+
async function main() {
|
|
2215
|
+
const opts = parseArgs(process.argv);
|
|
2216
|
+
switch (opts.command) {
|
|
2217
|
+
case "run":
|
|
2218
|
+
await runScript(opts);
|
|
2219
|
+
break;
|
|
2220
|
+
case "test":
|
|
2221
|
+
await testScript(opts);
|
|
2222
|
+
break;
|
|
2223
|
+
case "compile":
|
|
2224
|
+
compileScript(opts);
|
|
2225
|
+
break;
|
|
2226
|
+
case "deploy":
|
|
2227
|
+
await deployScript(opts);
|
|
2228
|
+
break;
|
|
2229
|
+
case "absorb":
|
|
2230
|
+
absorbScript(opts);
|
|
2231
|
+
break;
|
|
2232
|
+
case "daemon":
|
|
2233
|
+
case "holodaemon":
|
|
2234
|
+
await daemonScript(opts);
|
|
2235
|
+
break;
|
|
2236
|
+
case "holomesh-daemon":
|
|
2237
|
+
await holoMeshDaemonScript(opts);
|
|
2238
|
+
break;
|
|
2239
|
+
case "daemon-status":
|
|
2240
|
+
await daemonStatus(opts.json);
|
|
2241
|
+
break;
|
|
2242
|
+
case "help":
|
|
2243
|
+
default:
|
|
2244
|
+
showHelp();
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
main().catch((err) => {
|
|
2248
|
+
console.error("[holoscript] Fatal error:", err.message);
|
|
2249
|
+
process.exit(1);
|
|
2250
|
+
});
|
|
2251
|
+
|
|
2252
|
+
exports.daemonScript = daemonScript;
|
|
2253
|
+
exports.holoMeshDaemonScript = holoMeshDaemonScript;
|
|
2254
|
+
//# sourceMappingURL=holoscript-runner.cjs.map
|
|
2255
|
+
//# sourceMappingURL=holoscript-runner.cjs.map
|