@wipcomputer/wip-ldm-os 0.2.13 → 0.3.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/SKILL.md CHANGED
@@ -5,7 +5,7 @@ license: MIT
5
5
  interface: [cli, skill]
6
6
  metadata:
7
7
  display-name: "LDM OS"
8
- version: "0.2.13"
8
+ version: "0.3.1"
9
9
  homepage: "https://github.com/wipcomputer/wip-ldm-os"
10
10
  author: "Parker Todd Brooks"
11
11
  category: infrastructure
package/bin/ldm.js CHANGED
@@ -9,6 +9,11 @@
9
9
  * ldm install Install/update all registered components
10
10
  * ldm doctor Check health of all extensions
11
11
  * ldm status Show LDM OS version and extension count
12
+ * ldm sessions List active sessions
13
+ * ldm msg send <to> <b> Send a message to a session
14
+ * ldm msg list List pending messages
15
+ * ldm msg broadcast <b> Send to all sessions
16
+ * ldm updates Show available updates
12
17
  * ldm --version Show version
13
18
  */
14
19
 
@@ -47,6 +52,8 @@ const JSON_OUTPUT = args.includes('--json');
47
52
  const YES_FLAG = args.includes('--yes') || args.includes('-y');
48
53
  const NONE_FLAG = args.includes('--none');
49
54
  const FIX_FLAG = args.includes('--fix');
55
+ const CLEANUP_FLAG = args.includes('--cleanup');
56
+ const CHECK_FLAG = args.includes('--check');
50
57
 
51
58
  function readJSON(path) {
52
59
  try {
@@ -83,7 +90,10 @@ async function cmdInit() {
83
90
  join(LDM_ROOT, 'agents'),
84
91
  join(LDM_ROOT, 'memory'),
85
92
  join(LDM_ROOT, 'state'),
93
+ join(LDM_ROOT, 'sessions'),
94
+ join(LDM_ROOT, 'messages'),
86
95
  join(LDM_ROOT, 'shared', 'boot'),
96
+ join(LDM_ROOT, 'shared', 'cron'),
87
97
  ];
88
98
 
89
99
  const existing = existsSync(VERSION_PATH);
@@ -636,6 +646,8 @@ async function cmdDoctor() {
636
646
  { path: join(LDM_ROOT, 'memory'), label: 'memory/' },
637
647
  { path: join(LDM_ROOT, 'agents'), label: 'agents/' },
638
648
  { path: join(LDM_ROOT, 'state'), label: 'state/' },
649
+ { path: join(LDM_ROOT, 'sessions'), label: 'sessions/' },
650
+ { path: join(LDM_ROOT, 'messages'), label: 'messages/' },
639
651
  ];
640
652
 
641
653
  for (const s of sacred) {
@@ -716,6 +728,218 @@ function cmdStatus() {
716
728
  console.log('');
717
729
  }
718
730
 
731
+ // ── ldm sessions ──
732
+
733
+ async function cmdSessions() {
734
+ const { listSessions } = await import('../lib/sessions.mjs');
735
+ const sessions = listSessions({ includeStale: CLEANUP_FLAG });
736
+
737
+ if (CLEANUP_FLAG) {
738
+ // listSessions already cleans stale when includeStale is false.
739
+ // With --cleanup, we list stale ones so user can see them, then re-run without stale.
740
+ const stale = sessions.filter(s => !s.alive);
741
+ if (stale.length > 0) {
742
+ const { deregisterSession } = await import('../lib/sessions.mjs');
743
+ for (const s of stale) {
744
+ deregisterSession(s.name);
745
+ }
746
+ console.log(` Cleaned ${stale.length} stale session(s).`);
747
+ } else {
748
+ console.log(' No stale sessions found.');
749
+ }
750
+ console.log('');
751
+ return;
752
+ }
753
+
754
+ const live = sessions.filter(s => s.alive);
755
+
756
+ if (JSON_OUTPUT) {
757
+ console.log(JSON.stringify(live, null, 2));
758
+ return;
759
+ }
760
+
761
+ console.log('');
762
+ console.log(' Active Sessions');
763
+ console.log(' ────────────────────────────────────');
764
+
765
+ if (live.length === 0) {
766
+ console.log(' No active sessions.');
767
+ } else {
768
+ for (const s of live) {
769
+ const age = timeSince(s.startTime);
770
+ console.log(` ${s.name} agent=${s.agentId} pid=${s.pid} up=${age}`);
771
+ }
772
+ }
773
+
774
+ console.log('');
775
+ }
776
+
777
+ function timeSince(isoString) {
778
+ try {
779
+ const ms = Date.now() - new Date(isoString).getTime();
780
+ const secs = Math.floor(ms / 1000);
781
+ if (secs < 60) return `${secs}s`;
782
+ const mins = Math.floor(secs / 60);
783
+ if (mins < 60) return `${mins}m`;
784
+ const hours = Math.floor(mins / 60);
785
+ if (hours < 24) return `${hours}h ${mins % 60}m`;
786
+ const days = Math.floor(hours / 24);
787
+ return `${days}d ${hours % 24}h`;
788
+ } catch {
789
+ return '?';
790
+ }
791
+ }
792
+
793
+ // ── ldm msg ──
794
+
795
+ async function cmdMsg() {
796
+ const subcommand = args[1];
797
+
798
+ if (!subcommand || subcommand === 'list') {
799
+ return cmdMsgList();
800
+ }
801
+ if (subcommand === 'send') {
802
+ return cmdMsgSend();
803
+ }
804
+ if (subcommand === 'broadcast') {
805
+ return cmdMsgBroadcast();
806
+ }
807
+
808
+ console.error(` Unknown msg subcommand: ${subcommand}`);
809
+ console.error(' Usage: ldm msg [send <to> <body> | list | broadcast <body>]');
810
+ process.exit(1);
811
+ }
812
+
813
+ async function cmdMsgList() {
814
+ const { readMessages } = await import('../lib/messages.mjs');
815
+ const sessionName = process.env.CLAUDE_SESSION_NAME || 'unknown';
816
+ const messages = readMessages(sessionName, { markRead: false });
817
+
818
+ if (JSON_OUTPUT) {
819
+ console.log(JSON.stringify(messages, null, 2));
820
+ return;
821
+ }
822
+
823
+ console.log('');
824
+ console.log(` Messages for "${sessionName}"`);
825
+ console.log(' ────────────────────────────────────');
826
+
827
+ if (messages.length === 0) {
828
+ console.log(' No pending messages.');
829
+ } else {
830
+ for (const m of messages) {
831
+ const ts = m.timestamp?.split('T')[1]?.split('.')[0] || '';
832
+ console.log(` [${m.type}] ${ts} from=${m.from}: ${m.body}`);
833
+ }
834
+ }
835
+
836
+ console.log('');
837
+ }
838
+
839
+ async function cmdMsgSend() {
840
+ const { sendMessage } = await import('../lib/messages.mjs');
841
+ // args: ['msg', 'send', '<to>', '<body...>']
842
+ const to = args[2];
843
+ const body = args.slice(3).filter(a => !a.startsWith('--')).join(' ');
844
+
845
+ if (!to || !body) {
846
+ console.error(' Usage: ldm msg send <to> <body>');
847
+ process.exit(1);
848
+ }
849
+
850
+ const sessionName = process.env.CLAUDE_SESSION_NAME || 'ldm-cli';
851
+ const id = sendMessage({ from: sessionName, to, body, type: 'chat' });
852
+
853
+ if (id) {
854
+ console.log(` Message sent to "${to}" (id: ${id})`);
855
+ } else {
856
+ console.error(' x Failed to send message.');
857
+ process.exit(1);
858
+ }
859
+ }
860
+
861
+ async function cmdMsgBroadcast() {
862
+ const { sendMessage } = await import('../lib/messages.mjs');
863
+ // args: ['msg', 'broadcast', '<body...>']
864
+ const body = args.slice(2).filter(a => !a.startsWith('--')).join(' ');
865
+
866
+ if (!body) {
867
+ console.error(' Usage: ldm msg broadcast <body>');
868
+ process.exit(1);
869
+ }
870
+
871
+ const sessionName = process.env.CLAUDE_SESSION_NAME || 'ldm-cli';
872
+ const id = sendMessage({ from: sessionName, to: 'all', body, type: 'chat' });
873
+
874
+ if (id) {
875
+ console.log(` Broadcast sent (id: ${id})`);
876
+ } else {
877
+ console.error(' x Failed to send broadcast.');
878
+ process.exit(1);
879
+ }
880
+ }
881
+
882
+ // ── ldm updates ──
883
+
884
+ async function cmdUpdates() {
885
+ if (CHECK_FLAG) {
886
+ // Re-check npm registry
887
+ const { checkForUpdates } = await import('../lib/updates.mjs');
888
+ console.log(' Checking npm for updates...');
889
+ console.log('');
890
+ const result = checkForUpdates();
891
+
892
+ if (JSON_OUTPUT) {
893
+ console.log(JSON.stringify(result, null, 2));
894
+ return;
895
+ }
896
+
897
+ if (result.updatesAvailable === 0) {
898
+ console.log(` Checked ${result.checked} extensions. Everything is up to date.`);
899
+ } else {
900
+ console.log(` Checked ${result.checked} extensions. ${result.updatesAvailable} update(s) available:`);
901
+ console.log('');
902
+ for (const u of result.updates) {
903
+ console.log(` ${u.name}: ${u.currentVersion} -> ${u.latestVersion} (${u.packageName})`);
904
+ }
905
+ console.log('');
906
+ console.log(' Run: ldm install');
907
+ }
908
+ console.log('');
909
+ return;
910
+ }
911
+
912
+ // Show cached results
913
+ const { readUpdateManifest } = await import('../lib/updates.mjs');
914
+ const manifest = readUpdateManifest();
915
+
916
+ if (JSON_OUTPUT) {
917
+ console.log(JSON.stringify(manifest || {}, null, 2));
918
+ return;
919
+ }
920
+
921
+ console.log('');
922
+ console.log(' Available Updates');
923
+ console.log(' ────────────────────────────────────');
924
+
925
+ if (!manifest) {
926
+ console.log(' No update check has been run yet.');
927
+ console.log(' Run: ldm updates --check');
928
+ } else if (manifest.updatesAvailable === 0) {
929
+ console.log(` Everything is up to date. (checked ${manifest.checkedAt?.split('T')[0] || 'unknown'})`);
930
+ } else {
931
+ console.log(` ${manifest.updatesAvailable} update(s) available (checked ${manifest.checkedAt?.split('T')[0] || 'unknown'}):`);
932
+ console.log('');
933
+ for (const u of manifest.updates) {
934
+ console.log(` ${u.name}: ${u.currentVersion} -> ${u.latestVersion}`);
935
+ }
936
+ console.log('');
937
+ console.log(' Run: ldm install');
938
+ }
939
+
940
+ console.log('');
941
+ }
942
+
719
943
  // ── Main ──
720
944
 
721
945
  async function main() {
@@ -730,10 +954,19 @@ async function main() {
730
954
  console.log(' ldm install Update all registered extensions');
731
955
  console.log(' ldm doctor Check health of all extensions');
732
956
  console.log(' ldm status Show version and extension list');
957
+ console.log(' ldm sessions List active sessions');
958
+ console.log(' ldm sessions --cleanup Remove stale session entries');
959
+ console.log(' ldm msg send <to> <body> Send a message to a session');
960
+ console.log(' ldm msg list List pending messages');
961
+ console.log(' ldm msg broadcast <body> Send to all sessions');
962
+ console.log(' ldm updates Show available updates from cache');
963
+ console.log(' ldm updates --check Re-check npm registry for updates');
733
964
  console.log('');
734
965
  console.log(' Flags:');
735
966
  console.log(' --dry-run Show what would happen without making changes');
736
967
  console.log(' --json Output results as JSON');
968
+ console.log(' --cleanup Remove stale entries (sessions)');
969
+ console.log(' --check Re-check registry (updates)');
737
970
  console.log('');
738
971
  console.log(' Interfaces detected:');
739
972
  console.log(' CLI ... package.json bin -> npm install -g');
@@ -770,6 +1003,15 @@ async function main() {
770
1003
  case 'status':
771
1004
  cmdStatus();
772
1005
  break;
1006
+ case 'sessions':
1007
+ await cmdSessions();
1008
+ break;
1009
+ case 'msg':
1010
+ await cmdMsg();
1011
+ break;
1012
+ case 'updates':
1013
+ await cmdUpdates();
1014
+ break;
773
1015
  default:
774
1016
  console.error(` Unknown command: ${command}`);
775
1017
  console.error(` Run: ldm --help`);