@humanclaw/humanclaw 1.0.0 → 1.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 CHANGED
@@ -54,8 +54,8 @@ npm install -g @humanclaw/humanclaw
54
54
 
55
55
  ```bash
56
56
  humanclaw serve
57
- # 服务运行在 http://localhost:3000
58
- # Dashboard 看板:http://localhost:3000
57
+ # 服务运行在 http://localhost:2026
58
+ # Dashboard 看板:http://localhost:2026
59
59
  ```
60
60
 
61
61
  ### 注册物理节点
@@ -93,7 +93,7 @@ humanclaw status
93
93
  ### 创建任务示例
94
94
 
95
95
  ```bash
96
- curl -X POST http://localhost:3000/api/v1/jobs/create \
96
+ curl -X POST http://localhost:2026/api/v1/jobs/create \
97
97
  -H "Content-Type: application/json" \
98
98
  -d '{
99
99
  "original_prompt": "完成首页重构",
@@ -111,7 +111,7 @@ curl -X POST http://localhost:3000/api/v1/jobs/create \
111
111
  ### 提交交付物
112
112
 
113
113
  ```bash
114
- curl -X POST http://localhost:3000/api/v1/tasks/resume \
114
+ curl -X POST http://localhost:2026/api/v1/tasks/resume \
115
115
  -H "Content-Type: application/json" \
116
116
  -d '{
117
117
  "trace_id": "TK-9527",
package/README_EN.md CHANGED
@@ -54,8 +54,8 @@ npm install -g @humanclaw/humanclaw
54
54
 
55
55
  ```bash
56
56
  humanclaw serve
57
- # Server runs at http://localhost:3000
58
- # Dashboard: http://localhost:3000
57
+ # Server runs at http://localhost:2026
58
+ # Dashboard: http://localhost:2026
59
59
  ```
60
60
 
61
61
  ### Register a Physical Node
@@ -93,7 +93,7 @@ humanclaw status
93
93
  ### Create Job Example
94
94
 
95
95
  ```bash
96
- curl -X POST http://localhost:3000/api/v1/jobs/create \
96
+ curl -X POST http://localhost:2026/api/v1/jobs/create \
97
97
  -H "Content-Type: application/json" \
98
98
  -d '{
99
99
  "original_prompt": "Rebuild the homepage",
@@ -111,7 +111,7 @@ curl -X POST http://localhost:3000/api/v1/jobs/create \
111
111
  ### Submit Deliverable
112
112
 
113
113
  ```bash
114
- curl -X POST http://localhost:3000/api/v1/tasks/resume \
114
+ curl -X POST http://localhost:2026/api/v1/tasks/resume \
115
115
  -H "Content-Type: application/json" \
116
116
  -d '{
117
117
  "trace_id": "TK-9527",
package/dist/index.js CHANGED
@@ -8,8 +8,6 @@ import chalk from "chalk";
8
8
  // src/server.ts
9
9
  import express from "express";
10
10
  import cors from "cors";
11
- import path2 from "path";
12
- import fs2 from "fs";
13
11
 
14
12
  // src/db/connection.ts
15
13
  import Database from "better-sqlite3";
@@ -567,8 +565,224 @@ router4.post("/:job_id/sync", async (req, res) => {
567
565
  });
568
566
  var sync_default = router4;
569
567
 
568
+ // src/dashboard.ts
569
+ function getDashboardHtml() {
570
+ return `<!DOCTYPE html>
571
+ <html lang="zh-CN">
572
+ <head>
573
+ <meta charset="UTF-8"/>
574
+ <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
575
+ <title>HumanClaw - Async Physical Node Orchestration</title>
576
+ <style>
577
+ :root{--bg:#0a0a0f;--surface:#14141f;--surface-hover:#1a1a2e;--border:#2a2a3e;--text:#e0e0e8;--text-dim:#8888a0;--accent:#00d4ff;--green:#22c55e;--yellow:#eab308;--red:#ef4444;--purple:#a855f7;--font-mono:'JetBrains Mono','Fira Code',monospace;--font-sans:'Inter',-apple-system,sans-serif}
578
+ *{margin:0;padding:0;box-sizing:border-box}
579
+ body{background:var(--bg);color:var(--text);font-family:var(--font-sans);min-height:100vh}
580
+ header{padding:24px 32px 8px;border-bottom:1px solid var(--border)}
581
+ header h1{font-family:var(--font-mono);font-size:24px;color:var(--accent);letter-spacing:2px}
582
+ .subtitle{color:var(--text-dim);font-size:13px;margin-top:4px}
583
+ nav{display:flex;gap:0;border-bottom:1px solid var(--border);padding:0 32px}
584
+ .tab{background:none;border:none;color:var(--text-dim);padding:12px 20px;font-size:14px;cursor:pointer;border-bottom:2px solid transparent;transition:all .2s;font-family:var(--font-sans)}
585
+ .tab:hover{color:var(--text)}
586
+ .tab.active{color:var(--accent);border-bottom-color:var(--accent)}
587
+ main{padding:24px 32px}
588
+ .panel{display:none}.panel.active{display:block}
589
+ .fleet-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
590
+ .agent-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:20px;transition:border-color .2s}
591
+ .agent-card:hover{border-color:var(--accent)}
592
+ .agent-header{display:flex;align-items:center;gap:10px;margin-bottom:12px}
593
+ .status-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
594
+ .status-dot.IDLE{background:var(--green);box-shadow:0 0 8px var(--green)}
595
+ .status-dot.BUSY{background:var(--yellow);box-shadow:0 0 8px var(--yellow)}
596
+ .status-dot.OFFLINE{background:var(--red);box-shadow:0 0 8px var(--red)}
597
+ .status-dot.OOM{background:var(--purple);box-shadow:0 0 8px var(--purple)}
598
+ .agent-name{font-weight:600;font-size:16px}
599
+ .agent-id{color:var(--text-dim);font-family:var(--font-mono);font-size:12px}
600
+ .agent-caps{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
601
+ .cap-tag{background:var(--surface-hover);border:1px solid var(--border);border-radius:4px;padding:2px 8px;font-size:12px;color:var(--accent)}
602
+ .agent-metrics{margin-top:12px;font-size:12px;color:var(--text-dim)}
603
+ .job-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:20px;margin-bottom:16px}
604
+ .job-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
605
+ .job-title{font-weight:600;font-size:15px}
606
+ .job-id{font-family:var(--font-mono);font-size:12px;color:var(--text-dim)}
607
+ .progress-bar{background:var(--surface-hover);border-radius:4px;height:6px;margin:8px 0 16px;overflow:hidden}
608
+ .progress-fill{background:var(--accent);height:100%;border-radius:4px;transition:width .3s ease}
609
+ .progress-label{font-size:12px;color:var(--text-dim);margin-bottom:4px}
610
+ .kanban{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
611
+ .kanban-lane{min-height:60px}
612
+ .lane-title{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:1px;margin-bottom:8px;padding-bottom:4px;border-bottom:2px solid var(--border)}
613
+ .lane-title.dispatched{color:var(--yellow);border-color:var(--yellow)}
614
+ .lane-title.overdue{color:var(--red);border-color:var(--red)}
615
+ .lane-title.resolved{color:var(--green);border-color:var(--green)}
616
+ .task-card{background:var(--surface-hover);border:1px solid var(--border);border-radius:6px;padding:10px 12px;margin-bottom:8px;font-size:13px}
617
+ .task-trace{font-family:var(--font-mono);font-size:11px;color:var(--accent);margin-bottom:4px}
618
+ .task-desc{color:var(--text);margin-bottom:4px}
619
+ .task-meta{font-size:11px;color:var(--text-dim)}
620
+ .terminal-section{max-width:640px}
621
+ .terminal-section h2{font-size:16px;margin-bottom:16px;color:var(--accent);font-family:var(--font-mono)}
622
+ .form-group{margin-bottom:16px}
623
+ .form-group label{display:block;font-size:13px;color:var(--text-dim);margin-bottom:6px}
624
+ .form-group input,.form-group textarea{width:100%;background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:10px 14px;color:var(--text);font-size:14px;font-family:var(--font-mono);outline:none;transition:border-color .2s}
625
+ .form-group input:focus,.form-group textarea:focus{border-color:var(--accent)}
626
+ .form-group textarea{min-height:120px;resize:vertical}
627
+ .btn-group{display:flex;gap:12px;margin-top:20px}
628
+ .btn{padding:10px 24px;border:none;border-radius:6px;font-size:14px;font-weight:600;cursor:pointer;transition:opacity .2s}
629
+ .btn:hover{opacity:.85}
630
+ .btn:disabled{opacity:.5;cursor:not-allowed}
631
+ .btn-primary{background:var(--accent);color:var(--bg)}
632
+ .btn-danger{background:var(--red);color:#fff}
633
+ .toast{position:fixed;bottom:24px;right:24px;padding:12px 20px;border-radius:8px;font-size:14px;z-index:1000;animation:slide-in .3s ease}
634
+ .toast.success{background:var(--green);color:#fff}
635
+ .toast.error{background:var(--red);color:#fff}
636
+ @keyframes slide-in{from{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}
637
+ .empty{color:var(--text-dim);text-align:center;padding:40px 0;font-size:14px}
638
+ .fleet-summary{display:flex;gap:16px;margin-bottom:20px}
639
+ .summary-item{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 20px;text-align:center}
640
+ .summary-value{font-size:24px;font-weight:700;font-family:var(--font-mono)}
641
+ .summary-label{font-size:11px;color:var(--text-dim);text-transform:uppercase;letter-spacing:1px;margin-top:2px}
642
+ </style>
643
+ </head>
644
+ <body>
645
+ <header>
646
+ <h1>HumanClaw</h1>
647
+ <p class="subtitle">Async Physical Node Orchestration Framework</p>
648
+ </header>
649
+ <nav>
650
+ <button class="tab active" data-panel="fleet">Carbon Compute Pool</button>
651
+ <button class="tab" data-panel="pipeline">Task Pipeline</button>
652
+ <button class="tab" data-panel="terminal">I/O Terminal</button>
653
+ </nav>
654
+ <main>
655
+ <section id="fleet" class="panel active"></section>
656
+ <section id="pipeline" class="panel"></section>
657
+ <section id="terminal" class="panel"></section>
658
+ </main>
659
+ <script>
660
+ const API='/api/v1';
661
+ function esc(s){const d=document.createElement('div');d.textContent=s;return d.innerHTML}
662
+
663
+ // \u2500\u2500\u2500 Fleet \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
664
+ async function loadFleet(el){
665
+ el.innerHTML='<div class="empty">Loading...</div>';
666
+ try{
667
+ const r=await fetch(API+'/nodes/status');
668
+ const d=await r.json();
669
+ let h='<div class="fleet-summary">';
670
+ h+='<div class="summary-item"><div class="summary-value">'+d.total+'</div><div class="summary-label">Total</div></div>';
671
+ h+='<div class="summary-item"><div class="summary-value" style="color:var(--green)">'+d.idle+'</div><div class="summary-label">Idle</div></div>';
672
+ h+='<div class="summary-item"><div class="summary-value" style="color:var(--yellow)">'+d.busy+'</div><div class="summary-label">Busy</div></div>';
673
+ h+='<div class="summary-item"><div class="summary-value" style="color:var(--red)">'+d.offline+'</div><div class="summary-label">Offline</div></div>';
674
+ h+='<div class="summary-item"><div class="summary-value" style="color:var(--purple)">'+d.oom+'</div><div class="summary-label">OOM</div></div>';
675
+ h+='</div>';
676
+ if(!d.agents.length){el.innerHTML=h+'<div class="empty">No physical nodes registered. Use CLI: humanclaw agent add</div>';return}
677
+ h+='<div class="fleet-grid">';
678
+ for(const a of d.agents){
679
+ h+='<div class="agent-card"><div class="agent-header"><span class="status-dot '+a.status+'"></span><span class="agent-name">'+esc(a.name)+'</span></div>';
680
+ h+='<div class="agent-id">'+a.agent_id+'</div><div class="agent-caps">';
681
+ for(const c of a.capabilities)h+='<span class="cap-tag">'+esc(c)+'</span>';
682
+ h+='</div><div class="agent-metrics">Active tasks: '+a.active_task_count;
683
+ if(a.avg_delivery_hours!==null)h+=' | Avg delivery: '+a.avg_delivery_hours+'h';
684
+ h+='</div></div>';
685
+ }
686
+ h+='</div>';
687
+ el.innerHTML=h;
688
+ }catch{el.innerHTML='<div class="empty">Failed to load fleet data</div>'}
689
+ }
690
+
691
+ // \u2500\u2500\u2500 Pipeline \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
692
+ function taskCard(t){
693
+ return '<div class="task-card"><div class="task-trace">'+t.trace_id+'</div><div class="task-desc">'+esc(t.todo_description)+'</div><div class="task-meta">Assignee: '+t.assignee_id+' | Deadline: '+new Date(t.deadline).toLocaleString()+'</div></div>';
694
+ }
695
+ async function loadPipeline(el){
696
+ el.innerHTML='<div class="empty">Loading...</div>';
697
+ try{
698
+ const r=await fetch(API+'/jobs/active');
699
+ const d=await r.json();
700
+ if(!d.jobs.length){el.innerHTML='<div class="empty">No active jobs. Create one via the API or CLI.</div>';return}
701
+ let h='';
702
+ for(const j of d.jobs){
703
+ const res=j.tasks.filter(t=>t.status==='RESOLVED').length;
704
+ const tot=j.tasks.length;
705
+ const pct=tot?Math.round(res/tot*100):0;
706
+ const dispatched=j.tasks.filter(t=>t.status==='DISPATCHED'||t.status==='PENDING');
707
+ const overdue=j.tasks.filter(t=>t.status==='OVERDUE');
708
+ const done=j.tasks.filter(t=>t.status==='RESOLVED');
709
+ h+='<div class="job-card"><div class="job-header"><span class="job-title">'+esc(j.original_prompt)+'</span><span class="job-id">'+j.job_id+'</span></div>';
710
+ h+='<div class="progress-label">'+res+'/'+tot+' completed ('+pct+'%)</div>';
711
+ h+='<div class="progress-bar"><div class="progress-fill" style="width:'+pct+'%"></div></div>';
712
+ h+='<div class="kanban"><div class="kanban-lane"><div class="lane-title dispatched">Dispatched ('+dispatched.length+')</div>'+dispatched.map(taskCard).join('')+'</div>';
713
+ h+='<div class="kanban-lane"><div class="lane-title overdue">Overdue ('+overdue.length+')</div>'+overdue.map(taskCard).join('')+'</div>';
714
+ h+='<div class="kanban-lane"><div class="lane-title resolved">Resolved ('+done.length+')</div>'+done.map(taskCard).join('')+'</div></div></div>';
715
+ }
716
+ el.innerHTML=h;
717
+ }catch{el.innerHTML='<div class="empty">Failed to load pipeline data</div>'}
718
+ }
719
+
720
+ // \u2500\u2500\u2500 Terminal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
721
+ function showToast(msg,type){
722
+ const old=document.querySelector('.toast');if(old)old.remove();
723
+ const t=document.createElement('div');t.className='toast '+type;t.textContent=msg;document.body.appendChild(t);
724
+ setTimeout(()=>t.remove(),3000);
725
+ }
726
+ function loadTerminal(el){
727
+ el.innerHTML='<div class="terminal-section"><h2>&gt; I/O Resolution Terminal</h2>'
728
+ +'<div class="form-group"><label for="trace-id">Trace ID</label><input type="text" id="trace-id" placeholder="e.g. TK-9527"/></div>'
729
+ +'<div class="form-group"><label for="result-text">Delivery Payload (text)</label><textarea id="result-text" placeholder="Paste the worker\\'s deliverable, summary, or code here..."></textarea></div>'
730
+ +'<div class="btn-group"><button class="btn btn-primary" id="btn-submit">Submit &amp; Resume</button><button class="btn btn-danger" id="btn-reject">Reject &amp; Retry</button></div></div>';
731
+ document.getElementById('btn-submit').addEventListener('click',async()=>{
732
+ const tid=document.getElementById('trace-id').value.trim();
733
+ const txt=document.getElementById('result-text').value.trim();
734
+ if(!tid){showToast('Trace ID is required','error');return}
735
+ if(!txt){showToast('Delivery payload is required','error');return}
736
+ try{
737
+ const r=await fetch(API+'/tasks/resume',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({trace_id:tid,result_data:{text:txt}})});
738
+ const d=await r.json();
739
+ if(!r.ok){showToast(d.error||'Failed','error');return}
740
+ showToast(d.job_complete?'Task resolved! Job complete.':'Task '+tid+' resolved.','success');
741
+ document.getElementById('trace-id').value='';document.getElementById('result-text').value='';
742
+ }catch{showToast('Network error','error')}
743
+ });
744
+ document.getElementById('btn-reject').addEventListener('click',async()=>{
745
+ const tid=document.getElementById('trace-id').value.trim();
746
+ if(!tid){showToast('Trace ID is required','error');return}
747
+ try{
748
+ const r=await fetch(API+'/tasks/reject',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({trace_id:tid})});
749
+ const d=await r.json();
750
+ if(!r.ok){showToast(d.error||'Failed','error');return}
751
+ showToast('Task '+tid+' rejected and deadline extended.','success');
752
+ document.getElementById('trace-id').value='';document.getElementById('result-text').value='';
753
+ }catch{showToast('Network error','error')}
754
+ });
755
+ }
756
+
757
+ // \u2500\u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
758
+ const tabs=document.querySelectorAll('.tab');
759
+ const panels=document.querySelectorAll('.panel');
760
+ function load(id){
761
+ const el=document.getElementById(id);
762
+ if(id==='fleet')loadFleet(el);
763
+ else if(id==='pipeline')loadPipeline(el);
764
+ else if(id==='terminal')loadTerminal(el);
765
+ }
766
+ tabs.forEach(t=>t.addEventListener('click',()=>{
767
+ tabs.forEach(x=>x.classList.remove('active'));
768
+ panels.forEach(x=>x.classList.remove('active'));
769
+ t.classList.add('active');
770
+ const id=t.dataset.panel;
771
+ document.getElementById(id).classList.add('active');
772
+ load(id);
773
+ }));
774
+ load('fleet');
775
+ setInterval(()=>{
776
+ const a=document.querySelector('.tab.active');
777
+ if(a&&a.dataset.panel!=='terminal')load(a.dataset.panel);
778
+ },10000);
779
+ </script>
780
+ </body>
781
+ </html>`;
782
+ }
783
+
570
784
  // src/server.ts
571
- function createServer(port = 3e3) {
785
+ function createServer(port = 2026) {
572
786
  const db2 = getDb();
573
787
  initSchema(db2);
574
788
  const app = express();
@@ -578,19 +792,10 @@ function createServer(port = 3e3) {
578
792
  app.use("/api/v1/jobs", jobs_default);
579
793
  app.use("/api/v1/tasks", tasks_default);
580
794
  app.use("/api/v1/jobs", sync_default);
581
- const uiDistPath = path2.join(import.meta.dirname, "..", "dist", "ui");
582
- const uiDevPath = path2.join(import.meta.dirname, "..", "ui");
583
- if (fs2.existsSync(uiDistPath)) {
584
- app.use(express.static(uiDistPath));
585
- app.get("/", (_req, res) => {
586
- res.sendFile(path2.join(uiDistPath, "index.html"));
587
- });
588
- } else if (fs2.existsSync(uiDevPath)) {
589
- app.use(express.static(uiDevPath));
590
- app.get("/", (_req, res) => {
591
- res.sendFile(path2.join(uiDevPath, "index.html"));
592
- });
593
- }
795
+ const dashboardHtml = getDashboardHtml();
796
+ app.get("/", (_req, res) => {
797
+ res.type("html").send(dashboardHtml);
798
+ });
594
799
  app.use(
595
800
  (err, _req, res, _next) => {
596
801
  console.error("Server error:", err.message);
@@ -599,7 +804,7 @@ function createServer(port = 3e3) {
599
804
  );
600
805
  return { app, port };
601
806
  }
602
- function startServer(port = 3e3) {
807
+ function startServer(port = 2026) {
603
808
  const { app } = createServer(port);
604
809
  app.listen(port, () => {
605
810
  console.log(`
@@ -615,7 +820,7 @@ var program = new Command();
615
820
  program.name("humanclaw").description(
616
821
  "Async physical node orchestration framework - treating humans as distributed worker nodes"
617
822
  ).version("1.0.0");
618
- program.command("serve").description("Start the HumanClaw server").option("-p, --port <port>", "Server port", "3000").action((opts) => {
823
+ program.command("serve").description("Start the HumanClaw server").option("-p, --port <port>", "Server port", "2026").action((opts) => {
619
824
  const port = parseInt(opts.port, 10);
620
825
  startServer(port);
621
826
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/db/connection.ts","../src/db/schema.ts","../src/routes/nodes.ts","../src/models/agent.ts","../src/utils/trace-id.ts","../src/routes/jobs.ts","../src/models/task.ts","../src/models/job.ts","../src/services/dispatch.ts","../src/routes/tasks.ts","../src/services/resume.ts","../src/routes/sync.ts","../src/services/aggregation.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport { startServer } from './server.js';\nimport { getDb } from './db/connection.js';\nimport { initSchema } from './db/schema.js';\nimport { createAgent, listAgents } from './models/agent.js';\nimport { listActiveJobs } from './models/job.js';\nimport { markOverdueTasks } from './models/task.js';\nimport { generateId } from './utils/trace-id.js';\nimport type { AgentStatus } from './models/types.js';\n\nconst program = new Command();\n\nprogram\n .name('humanclaw')\n .description(\n 'Async physical node orchestration framework - treating humans as distributed worker nodes'\n )\n .version('1.0.0');\n\n// ─── serve ───────────────────────────────────────────────────────────────────\n\nprogram\n .command('serve')\n .description('Start the HumanClaw server')\n .option('-p, --port <port>', 'Server port', '3000')\n .action(opts => {\n const port = parseInt(opts.port, 10);\n startServer(port);\n });\n\n// ─── agent ───────────────────────────────────────────────────────────────────\n\nconst agentCmd = program\n .command('agent')\n .description('Manage physical nodes (HumanAgent)');\n\nagentCmd\n .command('add')\n .description('Register a new physical node')\n .action(async () => {\n const db = getDb();\n initSchema(db);\n\n p.intro(chalk.bgCyan(' Register New Physical Node '));\n\n const name = await p.text({\n message: 'Node alias (name):',\n placeholder: 'e.g. Frontend Lao Li',\n validate: v => (!v ? 'Name is required' : undefined),\n });\n\n if (p.isCancel(name)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const capInput = await p.text({\n message: 'Capabilities (comma-separated):',\n placeholder: 'e.g. UI/UX, Frontend Dev, Stress Resistant',\n validate: v => (!v ? 'At least one capability required' : undefined),\n });\n\n if (p.isCancel(capInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const capabilities = (capInput as string)\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n const agent = createAgent({\n agent_id: generateId('emp'),\n name: name as string,\n capabilities,\n status: 'IDLE',\n });\n\n p.outro(\n `${chalk.green('Node registered!')} ID: ${chalk.bold(agent.agent_id)}`\n );\n });\n\nagentCmd\n .command('list')\n .description('Show fleet status')\n .action(() => {\n const db = getDb();\n initSchema(db);\n\n const agents = listAgents();\n if (agents.length === 0) {\n console.log(chalk.dim(' No physical nodes registered.'));\n return;\n }\n\n const statusIcon: Record<AgentStatus, string> = {\n IDLE: '🟢',\n BUSY: '🟡',\n OFFLINE: '🔴',\n OOM: '🟣',\n };\n\n console.log(chalk.bold('\\n Carbon Compute Pool\\n'));\n\n for (const agent of agents) {\n const icon = statusIcon[agent.status];\n const caps = agent.capabilities.join(', ');\n console.log(\n ` ${icon} ${chalk.bold(agent.name)} (${chalk.dim(agent.agent_id)})`\n );\n console.log(` Capabilities: ${chalk.cyan(caps)}`);\n console.log(` Status: ${agent.status}\\n`);\n }\n });\n\n// ─── status ──────────────────────────────────────────────────────────────────\n\nprogram\n .command('status')\n .description('Show active jobs overview')\n .action(() => {\n const db = getDb();\n initSchema(db);\n\n markOverdueTasks();\n const jobs = listActiveJobs();\n\n if (jobs.length === 0) {\n console.log(chalk.dim('\\n No active jobs.\\n'));\n return;\n }\n\n console.log(chalk.bold('\\n Async Orchestration Dashboard\\n'));\n\n for (const job of jobs) {\n const resolved = job.tasks.filter(t => t.status === 'RESOLVED').length;\n const total = job.tasks.length;\n const pct = Math.round((resolved / total) * 100);\n const bar = '█'.repeat(Math.round(pct / 5)) + '░'.repeat(20 - Math.round(pct / 5));\n\n console.log(` ${chalk.bold(job.job_id)} - ${job.original_prompt}`);\n console.log(` Progress: [${bar}] ${resolved}/${total} (${pct}%)`);\n\n for (const task of job.tasks) {\n const statusColor =\n task.status === 'RESOLVED'\n ? chalk.green\n : task.status === 'OVERDUE'\n ? chalk.red\n : chalk.yellow;\n console.log(\n ` ${statusColor(task.status.padEnd(10))} ${task.trace_id} -> ${chalk.dim(task.assignee_id)}`\n );\n console.log(` ${task.todo_description}`);\n }\n console.log();\n }\n });\n\nprogram.parse();\n","import express from 'express';\nimport cors from 'cors';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { getDb } from './db/connection.js';\nimport { initSchema } from './db/schema.js';\nimport nodesRouter from './routes/nodes.js';\nimport jobsRouter from './routes/jobs.js';\nimport tasksRouter from './routes/tasks.js';\nimport syncRouter from './routes/sync.js';\n\nexport function createServer(port = 3000) {\n // Initialize database\n const db = getDb();\n initSchema(db);\n\n const app = express();\n\n // Middleware\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n // API routes\n app.use('/api/v1/nodes', nodesRouter);\n app.use('/api/v1/jobs', jobsRouter);\n app.use('/api/v1/tasks', tasksRouter);\n app.use('/api/v1/jobs', syncRouter);\n\n // Serve dashboard UI (static files)\n const uiDistPath = path.join(import.meta.dirname, '..', 'dist', 'ui');\n const uiDevPath = path.join(import.meta.dirname, '..', 'ui');\n\n if (fs.existsSync(uiDistPath)) {\n app.use(express.static(uiDistPath));\n app.get('/', (_req, res) => {\n res.sendFile(path.join(uiDistPath, 'index.html'));\n });\n } else if (fs.existsSync(uiDevPath)) {\n app.use(express.static(uiDevPath));\n app.get('/', (_req, res) => {\n res.sendFile(path.join(uiDevPath, 'index.html'));\n });\n }\n\n // Error handler\n app.use(\n (\n err: Error,\n _req: express.Request,\n res: express.Response,\n _next: express.NextFunction\n ) => {\n console.error('Server error:', err.message);\n res.status(500).json({ error: 'Internal server error' });\n }\n );\n\n return { app, port };\n}\n\nexport function startServer(port = 3000) {\n const { app } = createServer(port);\n\n app.listen(port, () => {\n console.log(`\\n HumanClaw server running at http://localhost:${port}`);\n console.log(` Dashboard: http://localhost:${port}`);\n console.log(` API base: http://localhost:${port}/api/v1\\n`);\n });\n}\n","import Database from 'better-sqlite3';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nlet db: Database.Database | null = null;\n\nconst DEFAULT_DB_PATH = path.join(\n process.env.HUMANCLAW_DATA_DIR ?? process.cwd(),\n 'humanclaw.db'\n);\n\nexport function getDb(dbPath?: string): Database.Database {\n if (db) return db;\n\n const resolvedPath = dbPath ?? DEFAULT_DB_PATH;\n const dir = path.dirname(resolvedPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n db = new Database(resolvedPath);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n\n return db;\n}\n\nexport function createInMemoryDb(): Database.Database {\n const memDb = new Database(':memory:');\n memDb.pragma('foreign_keys = ON');\n return memDb;\n}\n\nexport function closeDb(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n\nexport function setDb(newDb: Database.Database): void {\n db = newDb;\n}\n","import type Database from 'better-sqlite3';\n\nexport function initSchema(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS agents (\n agent_id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n capabilities TEXT NOT NULL DEFAULT '[]',\n status TEXT NOT NULL DEFAULT 'IDLE'\n CHECK (status IN ('IDLE', 'BUSY', 'OFFLINE', 'OOM')),\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS jobs (\n job_id TEXT PRIMARY KEY,\n original_prompt TEXT NOT NULL,\n openclaw_callback TEXT NOT NULL DEFAULT '',\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS tasks (\n trace_id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL REFERENCES jobs(job_id) ON DELETE CASCADE,\n assignee_id TEXT NOT NULL REFERENCES agents(agent_id),\n todo_description TEXT NOT NULL,\n deadline TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'PENDING'\n CHECK (status IN ('PENDING', 'DISPATCHED', 'RESOLVED', 'OVERDUE')),\n result_data TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_tasks_job_id ON tasks(job_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_assignee_id ON tasks(assignee_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\n `);\n}\n","import { Router } from 'express';\nimport {\n listAgentsWithMetrics,\n createAgent,\n updateAgentStatus,\n deleteAgent,\n} from '../models/agent.js';\nimport { generateId } from '../utils/trace-id.js';\nimport type { AgentStatus } from '../models/types.js';\n\nconst router = Router();\n\n// GET /api/v1/nodes/status - Fleet status with metrics\nrouter.get('/status', (_req, res) => {\n const agents = listAgentsWithMetrics();\n res.json({\n total: agents.length,\n idle: agents.filter(a => a.status === 'IDLE').length,\n busy: agents.filter(a => a.status === 'BUSY').length,\n offline: agents.filter(a => a.status === 'OFFLINE').length,\n oom: agents.filter(a => a.status === 'OOM').length,\n agents,\n });\n});\n\n// POST /api/v1/nodes - Register a new agent\nrouter.post('/', (req, res) => {\n const { name, capabilities, status } = req.body;\n\n if (!name || !Array.isArray(capabilities)) {\n res.status(400).json({ error: 'name and capabilities[] are required' });\n return;\n }\n\n const agent = createAgent({\n agent_id: generateId('emp'),\n name,\n capabilities,\n status: (status as AgentStatus) ?? 'IDLE',\n });\n\n res.status(201).json(agent);\n});\n\n// PATCH /api/v1/nodes/:agent_id/status - Update agent status\nrouter.patch('/:agent_id/status', (req, res) => {\n const { agent_id } = req.params;\n const { status } = req.body;\n\n const validStatuses: AgentStatus[] = ['IDLE', 'BUSY', 'OFFLINE', 'OOM'];\n if (!validStatuses.includes(status)) {\n res.status(400).json({\n error: `Invalid status. Must be one of: ${validStatuses.join(', ')}`,\n });\n return;\n }\n\n const updated = updateAgentStatus(agent_id, status);\n if (!updated) {\n res.status(404).json({ error: `Agent not found: ${agent_id}` });\n return;\n }\n\n res.json({ agent_id, status });\n});\n\n// DELETE /api/v1/nodes/:agent_id\nrouter.delete('/:agent_id', (req, res) => {\n const { agent_id } = req.params;\n const deleted = deleteAgent(agent_id);\n if (!deleted) {\n res.status(404).json({ error: `Agent not found: ${agent_id}` });\n return;\n }\n res.json({ deleted: agent_id });\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type {\n HumanAgent,\n AgentRow,\n AgentStatus,\n AgentWithMetrics,\n} from './types.js';\n\nfunction rowToAgent(row: AgentRow): HumanAgent {\n return {\n ...row,\n capabilities: JSON.parse(row.capabilities) as string[],\n };\n}\n\nexport function createAgent(\n agent: Omit<HumanAgent, 'created_at'>,\n db?: Database.Database\n): HumanAgent {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n conn\n .prepare(\n `INSERT INTO agents (agent_id, name, capabilities, status, created_at)\n VALUES (?, ?, ?, ?, ?)`\n )\n .run(\n agent.agent_id,\n agent.name,\n JSON.stringify(agent.capabilities),\n agent.status,\n now\n );\n return { ...agent, created_at: now };\n}\n\nexport function getAgent(\n agentId: string,\n db?: Database.Database\n): HumanAgent | undefined {\n const conn = db ?? getDb();\n const row = conn\n .prepare('SELECT * FROM agents WHERE agent_id = ?')\n .get(agentId) as AgentRow | undefined;\n return row ? rowToAgent(row) : undefined;\n}\n\nexport function listAgents(db?: Database.Database): HumanAgent[] {\n const conn = db ?? getDb();\n const rows = conn.prepare('SELECT * FROM agents ORDER BY created_at').all() as AgentRow[];\n return rows.map(rowToAgent);\n}\n\nexport function updateAgentStatus(\n agentId: string,\n status: AgentStatus,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('UPDATE agents SET status = ? WHERE agent_id = ?')\n .run(status, agentId);\n return result.changes > 0;\n}\n\nexport function deleteAgent(\n agentId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('DELETE FROM agents WHERE agent_id = ?')\n .run(agentId);\n return result.changes > 0;\n}\n\nexport function listAgentsWithMetrics(\n db?: Database.Database\n): AgentWithMetrics[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare(\n `SELECT\n a.*,\n COUNT(CASE WHEN t.status IN ('DISPATCHED', 'PENDING') THEN 1 END) AS active_task_count,\n AVG(\n CASE WHEN t.status = 'RESOLVED'\n THEN (julianday(t.updated_at) - julianday(t.created_at)) * 24\n END\n ) AS avg_delivery_hours\n FROM agents a\n LEFT JOIN tasks t ON a.agent_id = t.assignee_id\n GROUP BY a.agent_id\n ORDER BY a.created_at`\n )\n .all() as (AgentRow & { active_task_count: number; avg_delivery_hours: number | null })[];\n\n return rows.map(row => ({\n ...rowToAgent(row),\n active_task_count: row.active_task_count,\n avg_delivery_hours: row.avg_delivery_hours\n ? Math.round(row.avg_delivery_hours * 100) / 100\n : null,\n }));\n}\n","import { nanoid } from 'nanoid';\n\nexport function generateTraceId(): string {\n const num = Math.floor(Math.random() * 10000)\n .toString()\n .padStart(4, '0');\n return `TK-${num}`;\n}\n\nexport function generateId(prefix: string): string {\n return `${prefix}_${nanoid(8)}`;\n}\n","import { Router } from 'express';\nimport { dispatchJob } from '../services/dispatch.js';\nimport { listActiveJobs, getJobWithTasks } from '../models/job.js';\nimport { markOverdueTasks } from '../models/task.js';\nimport type { CreateJobRequest } from '../models/types.js';\n\nconst router = Router();\n\n// POST /api/v1/jobs/create - Create and dispatch a new job\nrouter.post('/create', (req, res) => {\n const body = req.body as CreateJobRequest;\n\n if (!body.original_prompt || !Array.isArray(body.tasks) || body.tasks.length === 0) {\n res.status(400).json({\n error: 'original_prompt and non-empty tasks[] are required',\n });\n return;\n }\n\n for (const task of body.tasks) {\n if (!task.assignee_id || !task.todo_description || !task.deadline) {\n res.status(400).json({\n error: 'Each task requires assignee_id, todo_description, and deadline',\n });\n return;\n }\n }\n\n try {\n const job = dispatchJob(body);\n res.status(201).json(job);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\n// GET /api/v1/jobs/active - List active jobs for kanban\nrouter.get('/active', (_req, res) => {\n // Mark overdue tasks before returning\n markOverdueTasks();\n const jobs = listActiveJobs();\n res.json({ jobs });\n});\n\n// GET /api/v1/jobs/:job_id - Get a single job with tasks\nrouter.get('/:job_id', (req, res) => {\n const { job_id } = req.params;\n const job = getJobWithTasks(job_id);\n if (!job) {\n res.status(404).json({ error: `Job not found: ${job_id}` });\n return;\n }\n res.json(job);\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type { HumanTask, TaskRow, TaskStatus } from './types.js';\n\nfunction rowToTask(row: TaskRow): HumanTask {\n return {\n ...row,\n payload: JSON.parse(row.payload) as Record<string, unknown>,\n result_data: row.result_data ? JSON.parse(row.result_data) : null,\n };\n}\n\nexport function createTask(\n task: Omit<HumanTask, 'created_at' | 'updated_at' | 'result_data'>,\n db?: Database.Database\n): HumanTask {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n conn\n .prepare(\n `INSERT INTO tasks (trace_id, job_id, assignee_id, todo_description, deadline, payload, status, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n task.trace_id,\n task.job_id,\n task.assignee_id,\n task.todo_description,\n task.deadline,\n JSON.stringify(task.payload),\n task.status,\n now,\n now\n );\n return { ...task, result_data: null, created_at: now, updated_at: now };\n}\n\nexport function getTask(\n traceId: string,\n db?: Database.Database\n): HumanTask | undefined {\n const conn = db ?? getDb();\n const row = conn\n .prepare('SELECT * FROM tasks WHERE trace_id = ?')\n .get(traceId) as TaskRow | undefined;\n return row ? rowToTask(row) : undefined;\n}\n\nexport function listTasksByJob(\n jobId: string,\n db?: Database.Database\n): HumanTask[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare('SELECT * FROM tasks WHERE job_id = ? ORDER BY created_at')\n .all(jobId) as TaskRow[];\n return rows.map(rowToTask);\n}\n\nexport function listTasksByAssignee(\n assigneeId: string,\n db?: Database.Database\n): HumanTask[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare('SELECT * FROM tasks WHERE assignee_id = ? ORDER BY created_at')\n .all(assigneeId) as TaskRow[];\n return rows.map(rowToTask);\n}\n\nexport function updateTaskStatus(\n traceId: string,\n status: TaskStatus,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare('UPDATE tasks SET status = ?, updated_at = ? WHERE trace_id = ?')\n .run(status, now, traceId);\n return result.changes > 0;\n}\n\nexport function resolveTask(\n traceId: string,\n resultData: unknown,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'RESOLVED', result_data = ?, updated_at = ?\n WHERE trace_id = ? AND status IN ('DISPATCHED', 'OVERDUE')`\n )\n .run(JSON.stringify(resultData), now, traceId);\n return result.changes > 0;\n}\n\nexport function markOverdueTasks(db?: Database.Database): number {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'OVERDUE', updated_at = ?\n WHERE status = 'DISPATCHED' AND deadline < ?`\n )\n .run(now, now);\n return result.changes;\n}\n\nexport function resetTaskDeadline(\n traceId: string,\n newDeadline: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'DISPATCHED', deadline = ?, result_data = NULL, updated_at = ?\n WHERE trace_id = ?`\n )\n .run(newDeadline, now, traceId);\n return result.changes > 0;\n}\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type { OrchestrationJob, JobRow, JobWithTasks } from './types.js';\nimport { listTasksByJob } from './task.js';\n\nexport function createJob(\n job: OrchestrationJob,\n db?: Database.Database\n): OrchestrationJob {\n const conn = db ?? getDb();\n conn\n .prepare(\n `INSERT INTO jobs (job_id, original_prompt, openclaw_callback, created_at)\n VALUES (?, ?, ?, ?)`\n )\n .run(job.job_id, job.original_prompt, job.openclaw_callback, job.created_at);\n return job;\n}\n\nexport function getJob(\n jobId: string,\n db?: Database.Database\n): OrchestrationJob | undefined {\n const conn = db ?? getDb();\n return conn\n .prepare('SELECT * FROM jobs WHERE job_id = ?')\n .get(jobId) as JobRow | undefined;\n}\n\nexport function getJobWithTasks(\n jobId: string,\n db?: Database.Database\n): JobWithTasks | undefined {\n const conn = db ?? getDb();\n const job = conn\n .prepare('SELECT * FROM jobs WHERE job_id = ?')\n .get(jobId) as JobRow | undefined;\n if (!job) return undefined;\n\n const tasks = listTasksByJob(jobId, conn);\n return { ...job, tasks };\n}\n\nexport function listActiveJobs(db?: Database.Database): JobWithTasks[] {\n const conn = db ?? getDb();\n const jobs = conn\n .prepare(\n `SELECT DISTINCT j.*\n FROM jobs j\n INNER JOIN tasks t ON j.job_id = t.job_id\n WHERE t.status != 'RESOLVED'\n ORDER BY j.created_at DESC`\n )\n .all() as JobRow[];\n\n // Also include jobs where all tasks are resolved but not yet synced\n const allJobs = conn\n .prepare('SELECT * FROM jobs ORDER BY created_at DESC')\n .all() as JobRow[];\n\n const activeJobIds = new Set(jobs.map(j => j.job_id));\n const result: JobWithTasks[] = [];\n\n for (const job of allJobs) {\n const tasks = listTasksByJob(job.job_id, conn);\n if (tasks.length > 0) {\n result.push({ ...job, tasks });\n }\n }\n\n return result;\n}\n\nexport function isJobComplete(\n jobId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const row = conn\n .prepare(\n `SELECT COUNT(*) as total,\n SUM(CASE WHEN status = 'RESOLVED' THEN 1 ELSE 0 END) as resolved\n FROM tasks WHERE job_id = ?`\n )\n .get(jobId) as { total: number; resolved: number };\n return row.total > 0 && row.total === row.resolved;\n}\n\nexport function deleteJob(\n jobId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('DELETE FROM jobs WHERE job_id = ?')\n .run(jobId);\n return result.changes > 0;\n}\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { createJob } from '../models/job.js';\nimport { createTask } from '../models/task.js';\nimport { getAgent, updateAgentStatus } from '../models/agent.js';\nimport { generateTraceId, generateId } from '../utils/trace-id.js';\nimport type { CreateJobRequest, JobWithTasks } from '../models/types.js';\n\nexport function dispatchJob(\n request: CreateJobRequest,\n db?: Database.Database\n): JobWithTasks {\n const conn = db ?? getDb();\n const jobId = generateId('job');\n const now = new Date().toISOString();\n\n // Validate all assignees exist\n for (const taskReq of request.tasks) {\n const agent = getAgent(taskReq.assignee_id, conn);\n if (!agent) {\n throw new Error(`Agent not found: ${taskReq.assignee_id}`);\n }\n if (agent.status === 'OFFLINE') {\n throw new Error(`Agent is offline: ${taskReq.assignee_id} (${agent.name})`);\n }\n }\n\n // Create the job\n const job = createJob(\n {\n job_id: jobId,\n original_prompt: request.original_prompt,\n openclaw_callback: request.openclaw_callback,\n created_at: now,\n },\n conn\n );\n\n // Create and dispatch all tasks\n const tasks = request.tasks.map(taskReq => {\n const traceId = generateTraceId();\n const task = createTask(\n {\n trace_id: traceId,\n job_id: jobId,\n assignee_id: taskReq.assignee_id,\n todo_description: taskReq.todo_description,\n deadline: taskReq.deadline,\n payload: taskReq.payload ?? {},\n status: 'DISPATCHED',\n },\n conn\n );\n\n // Mark the agent as busy\n updateAgentStatus(taskReq.assignee_id, 'BUSY', conn);\n\n return task;\n });\n\n return { ...job, tasks };\n}\n","import { Router } from 'express';\nimport { resumeTask, rejectTask } from '../services/resume.js';\n\nconst router = Router();\n\n// POST /api/v1/tasks/resume - Submit result for a task\nrouter.post('/resume', (req, res) => {\n const { trace_id, result_data } = req.body;\n\n if (!trace_id) {\n res.status(400).json({ error: 'trace_id is required' });\n return;\n }\n\n if (result_data === undefined) {\n res.status(400).json({ error: 'result_data is required' });\n return;\n }\n\n try {\n const result = resumeTask(trace_id, result_data);\n res.json({\n task: result.task,\n job_complete: result.jobComplete,\n job: result.job ?? null,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\n// POST /api/v1/tasks/reject - Reject and retry a task\nrouter.post('/reject', (req, res) => {\n const { trace_id, new_deadline } = req.body;\n\n if (!trace_id) {\n res.status(400).json({ error: 'trace_id is required' });\n return;\n }\n\n try {\n const task = rejectTask(trace_id, new_deadline);\n res.json({ task });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { getTask, resolveTask, resetTaskDeadline } from '../models/task.js';\nimport { isJobComplete, getJobWithTasks } from '../models/job.js';\nimport { updateAgentStatus } from '../models/agent.js';\nimport { listTasksByAssignee } from '../models/task.js';\nimport type { HumanTask, JobWithTasks } from '../models/types.js';\n\nexport interface ResumeResult {\n task: HumanTask;\n jobComplete: boolean;\n job: JobWithTasks | undefined;\n}\n\nexport function resumeTask(\n traceId: string,\n resultData: unknown,\n db?: Database.Database\n): ResumeResult {\n const conn = db ?? getDb();\n\n // Validate trace_id exists\n const task = getTask(traceId, conn);\n if (!task) {\n throw new Error(`Task not found: ${traceId}`);\n }\n\n if (task.status === 'RESOLVED') {\n throw new Error(`Task already resolved: ${traceId}`);\n }\n\n if (task.status === 'PENDING') {\n throw new Error(`Task not yet dispatched: ${traceId}`);\n }\n\n // Resolve the task\n const updated = resolveTask(traceId, resultData, conn);\n if (!updated) {\n throw new Error(`Failed to resolve task: ${traceId}`);\n }\n\n // Check if the agent has other active tasks; if not, mark IDLE\n const activeTasks = listTasksByAssignee(task.assignee_id, conn).filter(\n t => t.status === 'DISPATCHED' || t.status === 'PENDING'\n );\n if (activeTasks.length === 0) {\n updateAgentStatus(task.assignee_id, 'IDLE', conn);\n }\n\n // Check if the whole job is now complete\n const jobComplete = isJobComplete(task.job_id, conn);\n const job = jobComplete ? getJobWithTasks(task.job_id, conn) : undefined;\n\n const resolvedTask = getTask(traceId, conn)!;\n\n return { task: resolvedTask, jobComplete, job };\n}\n\nexport function rejectTask(\n traceId: string,\n newDeadline?: string,\n db?: Database.Database\n): HumanTask {\n const conn = db ?? getDb();\n\n const task = getTask(traceId, conn);\n if (!task) {\n throw new Error(`Task not found: ${traceId}`);\n }\n\n // Default: extend deadline by 24h from now\n const deadline =\n newDeadline ?? new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();\n\n resetTaskDeadline(traceId, deadline, conn);\n\n return getTask(traceId, conn)!;\n}\n","import { Router } from 'express';\nimport { aggregateJob, syncToOpenClaw } from '../services/aggregation.js';\n\nconst router = Router();\n\n// POST /api/v1/jobs/:job_id/sync - Aggregate and sync to OpenClaw\nrouter.post('/:job_id/sync', async (req, res) => {\n const { job_id } = req.params;\n\n try {\n const aggregation = aggregateJob(job_id);\n const syncResult = await syncToOpenClaw(aggregation);\n\n res.json({\n aggregation,\n sync: syncResult,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { getJobWithTasks, isJobComplete } from '../models/job.js';\nimport type { JobWithTasks } from '../models/types.js';\n\nexport interface AggregationResult {\n job_id: string;\n original_prompt: string;\n openclaw_callback: string;\n results: Array<{\n trace_id: string;\n assignee_id: string;\n todo_description: string;\n result_data: unknown;\n }>;\n aggregated_at: string;\n}\n\nexport function aggregateJob(\n jobId: string,\n db?: Database.Database\n): AggregationResult {\n const conn = db ?? getDb();\n\n const job = getJobWithTasks(jobId, conn);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n if (!isJobComplete(jobId, conn)) {\n const resolved = job.tasks.filter(t => t.status === 'RESOLVED').length;\n throw new Error(\n `Job not complete: ${resolved}/${job.tasks.length} tasks resolved`\n );\n }\n\n return {\n job_id: job.job_id,\n original_prompt: job.original_prompt,\n openclaw_callback: job.openclaw_callback,\n results: job.tasks.map(t => ({\n trace_id: t.trace_id,\n assignee_id: t.assignee_id,\n todo_description: t.todo_description,\n result_data: t.result_data,\n })),\n aggregated_at: new Date().toISOString(),\n };\n}\n\nexport async function syncToOpenClaw(\n aggregation: AggregationResult\n): Promise<{ success: boolean; message: string }> {\n if (!aggregation.openclaw_callback) {\n return {\n success: true,\n message: 'No OpenClaw callback configured, skipping sync',\n };\n }\n\n try {\n const response = await fetch(aggregation.openclaw_callback, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(aggregation),\n });\n\n if (!response.ok) {\n return {\n success: false,\n message: `OpenClaw sync failed: ${response.status} ${response.statusText}`,\n };\n }\n\n return { success: true, message: 'Synced to OpenClaw successfully' };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return { success: false, message: `OpenClaw sync error: ${message}` };\n }\n}\n"],"mappings":"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","names":["path","fs","db","db","Router","db","db","db","db","db","router","Router","Router","db","router","Router","Router","db","router","Router","db","path","fs","db"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/db/connection.ts","../src/db/schema.ts","../src/routes/nodes.ts","../src/models/agent.ts","../src/utils/trace-id.ts","../src/routes/jobs.ts","../src/models/task.ts","../src/models/job.ts","../src/services/dispatch.ts","../src/routes/tasks.ts","../src/services/resume.ts","../src/routes/sync.ts","../src/services/aggregation.ts","../src/dashboard.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport { startServer } from './server.js';\nimport { getDb } from './db/connection.js';\nimport { initSchema } from './db/schema.js';\nimport { createAgent, listAgents } from './models/agent.js';\nimport { listActiveJobs } from './models/job.js';\nimport { markOverdueTasks } from './models/task.js';\nimport { generateId } from './utils/trace-id.js';\nimport type { AgentStatus } from './models/types.js';\n\nconst program = new Command();\n\nprogram\n .name('humanclaw')\n .description(\n 'Async physical node orchestration framework - treating humans as distributed worker nodes'\n )\n .version('1.0.0');\n\n// ─── serve ───────────────────────────────────────────────────────────────────\n\nprogram\n .command('serve')\n .description('Start the HumanClaw server')\n .option('-p, --port <port>', 'Server port', '2026')\n .action(opts => {\n const port = parseInt(opts.port, 10);\n startServer(port);\n });\n\n// ─── agent ───────────────────────────────────────────────────────────────────\n\nconst agentCmd = program\n .command('agent')\n .description('Manage physical nodes (HumanAgent)');\n\nagentCmd\n .command('add')\n .description('Register a new physical node')\n .action(async () => {\n const db = getDb();\n initSchema(db);\n\n p.intro(chalk.bgCyan(' Register New Physical Node '));\n\n const name = await p.text({\n message: 'Node alias (name):',\n placeholder: 'e.g. Frontend Lao Li',\n validate: v => (!v ? 'Name is required' : undefined),\n });\n\n if (p.isCancel(name)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const capInput = await p.text({\n message: 'Capabilities (comma-separated):',\n placeholder: 'e.g. UI/UX, Frontend Dev, Stress Resistant',\n validate: v => (!v ? 'At least one capability required' : undefined),\n });\n\n if (p.isCancel(capInput)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n const capabilities = (capInput as string)\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n const agent = createAgent({\n agent_id: generateId('emp'),\n name: name as string,\n capabilities,\n status: 'IDLE',\n });\n\n p.outro(\n `${chalk.green('Node registered!')} ID: ${chalk.bold(agent.agent_id)}`\n );\n });\n\nagentCmd\n .command('list')\n .description('Show fleet status')\n .action(() => {\n const db = getDb();\n initSchema(db);\n\n const agents = listAgents();\n if (agents.length === 0) {\n console.log(chalk.dim(' No physical nodes registered.'));\n return;\n }\n\n const statusIcon: Record<AgentStatus, string> = {\n IDLE: '🟢',\n BUSY: '🟡',\n OFFLINE: '🔴',\n OOM: '🟣',\n };\n\n console.log(chalk.bold('\\n Carbon Compute Pool\\n'));\n\n for (const agent of agents) {\n const icon = statusIcon[agent.status];\n const caps = agent.capabilities.join(', ');\n console.log(\n ` ${icon} ${chalk.bold(agent.name)} (${chalk.dim(agent.agent_id)})`\n );\n console.log(` Capabilities: ${chalk.cyan(caps)}`);\n console.log(` Status: ${agent.status}\\n`);\n }\n });\n\n// ─── status ──────────────────────────────────────────────────────────────────\n\nprogram\n .command('status')\n .description('Show active jobs overview')\n .action(() => {\n const db = getDb();\n initSchema(db);\n\n markOverdueTasks();\n const jobs = listActiveJobs();\n\n if (jobs.length === 0) {\n console.log(chalk.dim('\\n No active jobs.\\n'));\n return;\n }\n\n console.log(chalk.bold('\\n Async Orchestration Dashboard\\n'));\n\n for (const job of jobs) {\n const resolved = job.tasks.filter(t => t.status === 'RESOLVED').length;\n const total = job.tasks.length;\n const pct = Math.round((resolved / total) * 100);\n const bar = '█'.repeat(Math.round(pct / 5)) + '░'.repeat(20 - Math.round(pct / 5));\n\n console.log(` ${chalk.bold(job.job_id)} - ${job.original_prompt}`);\n console.log(` Progress: [${bar}] ${resolved}/${total} (${pct}%)`);\n\n for (const task of job.tasks) {\n const statusColor =\n task.status === 'RESOLVED'\n ? chalk.green\n : task.status === 'OVERDUE'\n ? chalk.red\n : chalk.yellow;\n console.log(\n ` ${statusColor(task.status.padEnd(10))} ${task.trace_id} -> ${chalk.dim(task.assignee_id)}`\n );\n console.log(` ${task.todo_description}`);\n }\n console.log();\n }\n });\n\nprogram.parse();\n","import express from 'express';\nimport cors from 'cors';\nimport { getDb } from './db/connection.js';\nimport { initSchema } from './db/schema.js';\nimport nodesRouter from './routes/nodes.js';\nimport jobsRouter from './routes/jobs.js';\nimport tasksRouter from './routes/tasks.js';\nimport syncRouter from './routes/sync.js';\nimport { getDashboardHtml } from './dashboard.js';\n\nexport function createServer(port = 2026) {\n // Initialize database\n const db = getDb();\n initSchema(db);\n\n const app = express();\n\n // Middleware\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n // API routes\n app.use('/api/v1/nodes', nodesRouter);\n app.use('/api/v1/jobs', jobsRouter);\n app.use('/api/v1/tasks', tasksRouter);\n app.use('/api/v1/jobs', syncRouter);\n\n // Serve dashboard as inline HTML (no build step needed)\n const dashboardHtml = getDashboardHtml();\n app.get('/', (_req, res) => {\n res.type('html').send(dashboardHtml);\n });\n\n // Error handler\n app.use(\n (\n err: Error,\n _req: express.Request,\n res: express.Response,\n _next: express.NextFunction\n ) => {\n console.error('Server error:', err.message);\n res.status(500).json({ error: 'Internal server error' });\n }\n );\n\n return { app, port };\n}\n\nexport function startServer(port = 2026) {\n const { app } = createServer(port);\n\n app.listen(port, () => {\n console.log(`\\n HumanClaw server running at http://localhost:${port}`);\n console.log(` Dashboard: http://localhost:${port}`);\n console.log(` API base: http://localhost:${port}/api/v1\\n`);\n });\n}\n","import Database from 'better-sqlite3';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nlet db: Database.Database | null = null;\n\nconst DEFAULT_DB_PATH = path.join(\n process.env.HUMANCLAW_DATA_DIR ?? process.cwd(),\n 'humanclaw.db'\n);\n\nexport function getDb(dbPath?: string): Database.Database {\n if (db) return db;\n\n const resolvedPath = dbPath ?? DEFAULT_DB_PATH;\n const dir = path.dirname(resolvedPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n db = new Database(resolvedPath);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n\n return db;\n}\n\nexport function createInMemoryDb(): Database.Database {\n const memDb = new Database(':memory:');\n memDb.pragma('foreign_keys = ON');\n return memDb;\n}\n\nexport function closeDb(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n\nexport function setDb(newDb: Database.Database): void {\n db = newDb;\n}\n","import type Database from 'better-sqlite3';\n\nexport function initSchema(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS agents (\n agent_id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n capabilities TEXT NOT NULL DEFAULT '[]',\n status TEXT NOT NULL DEFAULT 'IDLE'\n CHECK (status IN ('IDLE', 'BUSY', 'OFFLINE', 'OOM')),\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS jobs (\n job_id TEXT PRIMARY KEY,\n original_prompt TEXT NOT NULL,\n openclaw_callback TEXT NOT NULL DEFAULT '',\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS tasks (\n trace_id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL REFERENCES jobs(job_id) ON DELETE CASCADE,\n assignee_id TEXT NOT NULL REFERENCES agents(agent_id),\n todo_description TEXT NOT NULL,\n deadline TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'PENDING'\n CHECK (status IN ('PENDING', 'DISPATCHED', 'RESOLVED', 'OVERDUE')),\n result_data TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_tasks_job_id ON tasks(job_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_assignee_id ON tasks(assignee_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\n `);\n}\n","import { Router } from 'express';\nimport {\n listAgentsWithMetrics,\n createAgent,\n updateAgentStatus,\n deleteAgent,\n} from '../models/agent.js';\nimport { generateId } from '../utils/trace-id.js';\nimport type { AgentStatus } from '../models/types.js';\n\nconst router = Router();\n\n// GET /api/v1/nodes/status - Fleet status with metrics\nrouter.get('/status', (_req, res) => {\n const agents = listAgentsWithMetrics();\n res.json({\n total: agents.length,\n idle: agents.filter(a => a.status === 'IDLE').length,\n busy: agents.filter(a => a.status === 'BUSY').length,\n offline: agents.filter(a => a.status === 'OFFLINE').length,\n oom: agents.filter(a => a.status === 'OOM').length,\n agents,\n });\n});\n\n// POST /api/v1/nodes - Register a new agent\nrouter.post('/', (req, res) => {\n const { name, capabilities, status } = req.body;\n\n if (!name || !Array.isArray(capabilities)) {\n res.status(400).json({ error: 'name and capabilities[] are required' });\n return;\n }\n\n const agent = createAgent({\n agent_id: generateId('emp'),\n name,\n capabilities,\n status: (status as AgentStatus) ?? 'IDLE',\n });\n\n res.status(201).json(agent);\n});\n\n// PATCH /api/v1/nodes/:agent_id/status - Update agent status\nrouter.patch('/:agent_id/status', (req, res) => {\n const { agent_id } = req.params;\n const { status } = req.body;\n\n const validStatuses: AgentStatus[] = ['IDLE', 'BUSY', 'OFFLINE', 'OOM'];\n if (!validStatuses.includes(status)) {\n res.status(400).json({\n error: `Invalid status. Must be one of: ${validStatuses.join(', ')}`,\n });\n return;\n }\n\n const updated = updateAgentStatus(agent_id, status);\n if (!updated) {\n res.status(404).json({ error: `Agent not found: ${agent_id}` });\n return;\n }\n\n res.json({ agent_id, status });\n});\n\n// DELETE /api/v1/nodes/:agent_id\nrouter.delete('/:agent_id', (req, res) => {\n const { agent_id } = req.params;\n const deleted = deleteAgent(agent_id);\n if (!deleted) {\n res.status(404).json({ error: `Agent not found: ${agent_id}` });\n return;\n }\n res.json({ deleted: agent_id });\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type {\n HumanAgent,\n AgentRow,\n AgentStatus,\n AgentWithMetrics,\n} from './types.js';\n\nfunction rowToAgent(row: AgentRow): HumanAgent {\n return {\n ...row,\n capabilities: JSON.parse(row.capabilities) as string[],\n };\n}\n\nexport function createAgent(\n agent: Omit<HumanAgent, 'created_at'>,\n db?: Database.Database\n): HumanAgent {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n conn\n .prepare(\n `INSERT INTO agents (agent_id, name, capabilities, status, created_at)\n VALUES (?, ?, ?, ?, ?)`\n )\n .run(\n agent.agent_id,\n agent.name,\n JSON.stringify(agent.capabilities),\n agent.status,\n now\n );\n return { ...agent, created_at: now };\n}\n\nexport function getAgent(\n agentId: string,\n db?: Database.Database\n): HumanAgent | undefined {\n const conn = db ?? getDb();\n const row = conn\n .prepare('SELECT * FROM agents WHERE agent_id = ?')\n .get(agentId) as AgentRow | undefined;\n return row ? rowToAgent(row) : undefined;\n}\n\nexport function listAgents(db?: Database.Database): HumanAgent[] {\n const conn = db ?? getDb();\n const rows = conn.prepare('SELECT * FROM agents ORDER BY created_at').all() as AgentRow[];\n return rows.map(rowToAgent);\n}\n\nexport function updateAgentStatus(\n agentId: string,\n status: AgentStatus,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('UPDATE agents SET status = ? WHERE agent_id = ?')\n .run(status, agentId);\n return result.changes > 0;\n}\n\nexport function deleteAgent(\n agentId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('DELETE FROM agents WHERE agent_id = ?')\n .run(agentId);\n return result.changes > 0;\n}\n\nexport function listAgentsWithMetrics(\n db?: Database.Database\n): AgentWithMetrics[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare(\n `SELECT\n a.*,\n COUNT(CASE WHEN t.status IN ('DISPATCHED', 'PENDING') THEN 1 END) AS active_task_count,\n AVG(\n CASE WHEN t.status = 'RESOLVED'\n THEN (julianday(t.updated_at) - julianday(t.created_at)) * 24\n END\n ) AS avg_delivery_hours\n FROM agents a\n LEFT JOIN tasks t ON a.agent_id = t.assignee_id\n GROUP BY a.agent_id\n ORDER BY a.created_at`\n )\n .all() as (AgentRow & { active_task_count: number; avg_delivery_hours: number | null })[];\n\n return rows.map(row => ({\n ...rowToAgent(row),\n active_task_count: row.active_task_count,\n avg_delivery_hours: row.avg_delivery_hours\n ? Math.round(row.avg_delivery_hours * 100) / 100\n : null,\n }));\n}\n","import { nanoid } from 'nanoid';\n\nexport function generateTraceId(): string {\n const num = Math.floor(Math.random() * 10000)\n .toString()\n .padStart(4, '0');\n return `TK-${num}`;\n}\n\nexport function generateId(prefix: string): string {\n return `${prefix}_${nanoid(8)}`;\n}\n","import { Router } from 'express';\nimport { dispatchJob } from '../services/dispatch.js';\nimport { listActiveJobs, getJobWithTasks } from '../models/job.js';\nimport { markOverdueTasks } from '../models/task.js';\nimport type { CreateJobRequest } from '../models/types.js';\n\nconst router = Router();\n\n// POST /api/v1/jobs/create - Create and dispatch a new job\nrouter.post('/create', (req, res) => {\n const body = req.body as CreateJobRequest;\n\n if (!body.original_prompt || !Array.isArray(body.tasks) || body.tasks.length === 0) {\n res.status(400).json({\n error: 'original_prompt and non-empty tasks[] are required',\n });\n return;\n }\n\n for (const task of body.tasks) {\n if (!task.assignee_id || !task.todo_description || !task.deadline) {\n res.status(400).json({\n error: 'Each task requires assignee_id, todo_description, and deadline',\n });\n return;\n }\n }\n\n try {\n const job = dispatchJob(body);\n res.status(201).json(job);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\n// GET /api/v1/jobs/active - List active jobs for kanban\nrouter.get('/active', (_req, res) => {\n // Mark overdue tasks before returning\n markOverdueTasks();\n const jobs = listActiveJobs();\n res.json({ jobs });\n});\n\n// GET /api/v1/jobs/:job_id - Get a single job with tasks\nrouter.get('/:job_id', (req, res) => {\n const { job_id } = req.params;\n const job = getJobWithTasks(job_id);\n if (!job) {\n res.status(404).json({ error: `Job not found: ${job_id}` });\n return;\n }\n res.json(job);\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type { HumanTask, TaskRow, TaskStatus } from './types.js';\n\nfunction rowToTask(row: TaskRow): HumanTask {\n return {\n ...row,\n payload: JSON.parse(row.payload) as Record<string, unknown>,\n result_data: row.result_data ? JSON.parse(row.result_data) : null,\n };\n}\n\nexport function createTask(\n task: Omit<HumanTask, 'created_at' | 'updated_at' | 'result_data'>,\n db?: Database.Database\n): HumanTask {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n conn\n .prepare(\n `INSERT INTO tasks (trace_id, job_id, assignee_id, todo_description, deadline, payload, status, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(\n task.trace_id,\n task.job_id,\n task.assignee_id,\n task.todo_description,\n task.deadline,\n JSON.stringify(task.payload),\n task.status,\n now,\n now\n );\n return { ...task, result_data: null, created_at: now, updated_at: now };\n}\n\nexport function getTask(\n traceId: string,\n db?: Database.Database\n): HumanTask | undefined {\n const conn = db ?? getDb();\n const row = conn\n .prepare('SELECT * FROM tasks WHERE trace_id = ?')\n .get(traceId) as TaskRow | undefined;\n return row ? rowToTask(row) : undefined;\n}\n\nexport function listTasksByJob(\n jobId: string,\n db?: Database.Database\n): HumanTask[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare('SELECT * FROM tasks WHERE job_id = ? ORDER BY created_at')\n .all(jobId) as TaskRow[];\n return rows.map(rowToTask);\n}\n\nexport function listTasksByAssignee(\n assigneeId: string,\n db?: Database.Database\n): HumanTask[] {\n const conn = db ?? getDb();\n const rows = conn\n .prepare('SELECT * FROM tasks WHERE assignee_id = ? ORDER BY created_at')\n .all(assigneeId) as TaskRow[];\n return rows.map(rowToTask);\n}\n\nexport function updateTaskStatus(\n traceId: string,\n status: TaskStatus,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare('UPDATE tasks SET status = ?, updated_at = ? WHERE trace_id = ?')\n .run(status, now, traceId);\n return result.changes > 0;\n}\n\nexport function resolveTask(\n traceId: string,\n resultData: unknown,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'RESOLVED', result_data = ?, updated_at = ?\n WHERE trace_id = ? AND status IN ('DISPATCHED', 'OVERDUE')`\n )\n .run(JSON.stringify(resultData), now, traceId);\n return result.changes > 0;\n}\n\nexport function markOverdueTasks(db?: Database.Database): number {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'OVERDUE', updated_at = ?\n WHERE status = 'DISPATCHED' AND deadline < ?`\n )\n .run(now, now);\n return result.changes;\n}\n\nexport function resetTaskDeadline(\n traceId: string,\n newDeadline: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const now = new Date().toISOString();\n const result = conn\n .prepare(\n `UPDATE tasks\n SET status = 'DISPATCHED', deadline = ?, result_data = NULL, updated_at = ?\n WHERE trace_id = ?`\n )\n .run(newDeadline, now, traceId);\n return result.changes > 0;\n}\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport type { OrchestrationJob, JobRow, JobWithTasks } from './types.js';\nimport { listTasksByJob } from './task.js';\n\nexport function createJob(\n job: OrchestrationJob,\n db?: Database.Database\n): OrchestrationJob {\n const conn = db ?? getDb();\n conn\n .prepare(\n `INSERT INTO jobs (job_id, original_prompt, openclaw_callback, created_at)\n VALUES (?, ?, ?, ?)`\n )\n .run(job.job_id, job.original_prompt, job.openclaw_callback, job.created_at);\n return job;\n}\n\nexport function getJob(\n jobId: string,\n db?: Database.Database\n): OrchestrationJob | undefined {\n const conn = db ?? getDb();\n return conn\n .prepare('SELECT * FROM jobs WHERE job_id = ?')\n .get(jobId) as JobRow | undefined;\n}\n\nexport function getJobWithTasks(\n jobId: string,\n db?: Database.Database\n): JobWithTasks | undefined {\n const conn = db ?? getDb();\n const job = conn\n .prepare('SELECT * FROM jobs WHERE job_id = ?')\n .get(jobId) as JobRow | undefined;\n if (!job) return undefined;\n\n const tasks = listTasksByJob(jobId, conn);\n return { ...job, tasks };\n}\n\nexport function listActiveJobs(db?: Database.Database): JobWithTasks[] {\n const conn = db ?? getDb();\n const jobs = conn\n .prepare(\n `SELECT DISTINCT j.*\n FROM jobs j\n INNER JOIN tasks t ON j.job_id = t.job_id\n WHERE t.status != 'RESOLVED'\n ORDER BY j.created_at DESC`\n )\n .all() as JobRow[];\n\n // Also include jobs where all tasks are resolved but not yet synced\n const allJobs = conn\n .prepare('SELECT * FROM jobs ORDER BY created_at DESC')\n .all() as JobRow[];\n\n const activeJobIds = new Set(jobs.map(j => j.job_id));\n const result: JobWithTasks[] = [];\n\n for (const job of allJobs) {\n const tasks = listTasksByJob(job.job_id, conn);\n if (tasks.length > 0) {\n result.push({ ...job, tasks });\n }\n }\n\n return result;\n}\n\nexport function isJobComplete(\n jobId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const row = conn\n .prepare(\n `SELECT COUNT(*) as total,\n SUM(CASE WHEN status = 'RESOLVED' THEN 1 ELSE 0 END) as resolved\n FROM tasks WHERE job_id = ?`\n )\n .get(jobId) as { total: number; resolved: number };\n return row.total > 0 && row.total === row.resolved;\n}\n\nexport function deleteJob(\n jobId: string,\n db?: Database.Database\n): boolean {\n const conn = db ?? getDb();\n const result = conn\n .prepare('DELETE FROM jobs WHERE job_id = ?')\n .run(jobId);\n return result.changes > 0;\n}\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { createJob } from '../models/job.js';\nimport { createTask } from '../models/task.js';\nimport { getAgent, updateAgentStatus } from '../models/agent.js';\nimport { generateTraceId, generateId } from '../utils/trace-id.js';\nimport type { CreateJobRequest, JobWithTasks } from '../models/types.js';\n\nexport function dispatchJob(\n request: CreateJobRequest,\n db?: Database.Database\n): JobWithTasks {\n const conn = db ?? getDb();\n const jobId = generateId('job');\n const now = new Date().toISOString();\n\n // Validate all assignees exist\n for (const taskReq of request.tasks) {\n const agent = getAgent(taskReq.assignee_id, conn);\n if (!agent) {\n throw new Error(`Agent not found: ${taskReq.assignee_id}`);\n }\n if (agent.status === 'OFFLINE') {\n throw new Error(`Agent is offline: ${taskReq.assignee_id} (${agent.name})`);\n }\n }\n\n // Create the job\n const job = createJob(\n {\n job_id: jobId,\n original_prompt: request.original_prompt,\n openclaw_callback: request.openclaw_callback,\n created_at: now,\n },\n conn\n );\n\n // Create and dispatch all tasks\n const tasks = request.tasks.map(taskReq => {\n const traceId = generateTraceId();\n const task = createTask(\n {\n trace_id: traceId,\n job_id: jobId,\n assignee_id: taskReq.assignee_id,\n todo_description: taskReq.todo_description,\n deadline: taskReq.deadline,\n payload: taskReq.payload ?? {},\n status: 'DISPATCHED',\n },\n conn\n );\n\n // Mark the agent as busy\n updateAgentStatus(taskReq.assignee_id, 'BUSY', conn);\n\n return task;\n });\n\n return { ...job, tasks };\n}\n","import { Router } from 'express';\nimport { resumeTask, rejectTask } from '../services/resume.js';\n\nconst router = Router();\n\n// POST /api/v1/tasks/resume - Submit result for a task\nrouter.post('/resume', (req, res) => {\n const { trace_id, result_data } = req.body;\n\n if (!trace_id) {\n res.status(400).json({ error: 'trace_id is required' });\n return;\n }\n\n if (result_data === undefined) {\n res.status(400).json({ error: 'result_data is required' });\n return;\n }\n\n try {\n const result = resumeTask(trace_id, result_data);\n res.json({\n task: result.task,\n job_complete: result.jobComplete,\n job: result.job ?? null,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\n// POST /api/v1/tasks/reject - Reject and retry a task\nrouter.post('/reject', (req, res) => {\n const { trace_id, new_deadline } = req.body;\n\n if (!trace_id) {\n res.status(400).json({ error: 'trace_id is required' });\n return;\n }\n\n try {\n const task = rejectTask(trace_id, new_deadline);\n res.json({ task });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { getTask, resolveTask, resetTaskDeadline } from '../models/task.js';\nimport { isJobComplete, getJobWithTasks } from '../models/job.js';\nimport { updateAgentStatus } from '../models/agent.js';\nimport { listTasksByAssignee } from '../models/task.js';\nimport type { HumanTask, JobWithTasks } from '../models/types.js';\n\nexport interface ResumeResult {\n task: HumanTask;\n jobComplete: boolean;\n job: JobWithTasks | undefined;\n}\n\nexport function resumeTask(\n traceId: string,\n resultData: unknown,\n db?: Database.Database\n): ResumeResult {\n const conn = db ?? getDb();\n\n // Validate trace_id exists\n const task = getTask(traceId, conn);\n if (!task) {\n throw new Error(`Task not found: ${traceId}`);\n }\n\n if (task.status === 'RESOLVED') {\n throw new Error(`Task already resolved: ${traceId}`);\n }\n\n if (task.status === 'PENDING') {\n throw new Error(`Task not yet dispatched: ${traceId}`);\n }\n\n // Resolve the task\n const updated = resolveTask(traceId, resultData, conn);\n if (!updated) {\n throw new Error(`Failed to resolve task: ${traceId}`);\n }\n\n // Check if the agent has other active tasks; if not, mark IDLE\n const activeTasks = listTasksByAssignee(task.assignee_id, conn).filter(\n t => t.status === 'DISPATCHED' || t.status === 'PENDING'\n );\n if (activeTasks.length === 0) {\n updateAgentStatus(task.assignee_id, 'IDLE', conn);\n }\n\n // Check if the whole job is now complete\n const jobComplete = isJobComplete(task.job_id, conn);\n const job = jobComplete ? getJobWithTasks(task.job_id, conn) : undefined;\n\n const resolvedTask = getTask(traceId, conn)!;\n\n return { task: resolvedTask, jobComplete, job };\n}\n\nexport function rejectTask(\n traceId: string,\n newDeadline?: string,\n db?: Database.Database\n): HumanTask {\n const conn = db ?? getDb();\n\n const task = getTask(traceId, conn);\n if (!task) {\n throw new Error(`Task not found: ${traceId}`);\n }\n\n // Default: extend deadline by 24h from now\n const deadline =\n newDeadline ?? new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();\n\n resetTaskDeadline(traceId, deadline, conn);\n\n return getTask(traceId, conn)!;\n}\n","import { Router } from 'express';\nimport { aggregateJob, syncToOpenClaw } from '../services/aggregation.js';\n\nconst router = Router();\n\n// POST /api/v1/jobs/:job_id/sync - Aggregate and sync to OpenClaw\nrouter.post('/:job_id/sync', async (req, res) => {\n const { job_id } = req.params;\n\n try {\n const aggregation = aggregateJob(job_id);\n const syncResult = await syncToOpenClaw(aggregation);\n\n res.json({\n aggregation,\n sync: syncResult,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(400).json({ error: message });\n }\n});\n\nexport default router;\n","import type Database from 'better-sqlite3';\nimport { getDb } from '../db/connection.js';\nimport { getJobWithTasks, isJobComplete } from '../models/job.js';\nimport type { JobWithTasks } from '../models/types.js';\n\nexport interface AggregationResult {\n job_id: string;\n original_prompt: string;\n openclaw_callback: string;\n results: Array<{\n trace_id: string;\n assignee_id: string;\n todo_description: string;\n result_data: unknown;\n }>;\n aggregated_at: string;\n}\n\nexport function aggregateJob(\n jobId: string,\n db?: Database.Database\n): AggregationResult {\n const conn = db ?? getDb();\n\n const job = getJobWithTasks(jobId, conn);\n if (!job) {\n throw new Error(`Job not found: ${jobId}`);\n }\n\n if (!isJobComplete(jobId, conn)) {\n const resolved = job.tasks.filter(t => t.status === 'RESOLVED').length;\n throw new Error(\n `Job not complete: ${resolved}/${job.tasks.length} tasks resolved`\n );\n }\n\n return {\n job_id: job.job_id,\n original_prompt: job.original_prompt,\n openclaw_callback: job.openclaw_callback,\n results: job.tasks.map(t => ({\n trace_id: t.trace_id,\n assignee_id: t.assignee_id,\n todo_description: t.todo_description,\n result_data: t.result_data,\n })),\n aggregated_at: new Date().toISOString(),\n };\n}\n\nexport async function syncToOpenClaw(\n aggregation: AggregationResult\n): Promise<{ success: boolean; message: string }> {\n if (!aggregation.openclaw_callback) {\n return {\n success: true,\n message: 'No OpenClaw callback configured, skipping sync',\n };\n }\n\n try {\n const response = await fetch(aggregation.openclaw_callback, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(aggregation),\n });\n\n if (!response.ok) {\n return {\n success: false,\n message: `OpenClaw sync failed: ${response.status} ${response.statusText}`,\n };\n }\n\n return { success: true, message: 'Synced to OpenClaw successfully' };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n return { success: false, message: `OpenClaw sync error: ${message}` };\n }\n}\n","export function getDashboardHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\"/>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"/>\n<title>HumanClaw - Async Physical Node Orchestration</title>\n<style>\n:root{--bg:#0a0a0f;--surface:#14141f;--surface-hover:#1a1a2e;--border:#2a2a3e;--text:#e0e0e8;--text-dim:#8888a0;--accent:#00d4ff;--green:#22c55e;--yellow:#eab308;--red:#ef4444;--purple:#a855f7;--font-mono:'JetBrains Mono','Fira Code',monospace;--font-sans:'Inter',-apple-system,sans-serif}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{background:var(--bg);color:var(--text);font-family:var(--font-sans);min-height:100vh}\nheader{padding:24px 32px 8px;border-bottom:1px solid var(--border)}\nheader h1{font-family:var(--font-mono);font-size:24px;color:var(--accent);letter-spacing:2px}\n.subtitle{color:var(--text-dim);font-size:13px;margin-top:4px}\nnav{display:flex;gap:0;border-bottom:1px solid var(--border);padding:0 32px}\n.tab{background:none;border:none;color:var(--text-dim);padding:12px 20px;font-size:14px;cursor:pointer;border-bottom:2px solid transparent;transition:all .2s;font-family:var(--font-sans)}\n.tab:hover{color:var(--text)}\n.tab.active{color:var(--accent);border-bottom-color:var(--accent)}\nmain{padding:24px 32px}\n.panel{display:none}.panel.active{display:block}\n.fleet-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}\n.agent-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:20px;transition:border-color .2s}\n.agent-card:hover{border-color:var(--accent)}\n.agent-header{display:flex;align-items:center;gap:10px;margin-bottom:12px}\n.status-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}\n.status-dot.IDLE{background:var(--green);box-shadow:0 0 8px var(--green)}\n.status-dot.BUSY{background:var(--yellow);box-shadow:0 0 8px var(--yellow)}\n.status-dot.OFFLINE{background:var(--red);box-shadow:0 0 8px var(--red)}\n.status-dot.OOM{background:var(--purple);box-shadow:0 0 8px var(--purple)}\n.agent-name{font-weight:600;font-size:16px}\n.agent-id{color:var(--text-dim);font-family:var(--font-mono);font-size:12px}\n.agent-caps{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}\n.cap-tag{background:var(--surface-hover);border:1px solid var(--border);border-radius:4px;padding:2px 8px;font-size:12px;color:var(--accent)}\n.agent-metrics{margin-top:12px;font-size:12px;color:var(--text-dim)}\n.job-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:20px;margin-bottom:16px}\n.job-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}\n.job-title{font-weight:600;font-size:15px}\n.job-id{font-family:var(--font-mono);font-size:12px;color:var(--text-dim)}\n.progress-bar{background:var(--surface-hover);border-radius:4px;height:6px;margin:8px 0 16px;overflow:hidden}\n.progress-fill{background:var(--accent);height:100%;border-radius:4px;transition:width .3s ease}\n.progress-label{font-size:12px;color:var(--text-dim);margin-bottom:4px}\n.kanban{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}\n.kanban-lane{min-height:60px}\n.lane-title{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:1px;margin-bottom:8px;padding-bottom:4px;border-bottom:2px solid var(--border)}\n.lane-title.dispatched{color:var(--yellow);border-color:var(--yellow)}\n.lane-title.overdue{color:var(--red);border-color:var(--red)}\n.lane-title.resolved{color:var(--green);border-color:var(--green)}\n.task-card{background:var(--surface-hover);border:1px solid var(--border);border-radius:6px;padding:10px 12px;margin-bottom:8px;font-size:13px}\n.task-trace{font-family:var(--font-mono);font-size:11px;color:var(--accent);margin-bottom:4px}\n.task-desc{color:var(--text);margin-bottom:4px}\n.task-meta{font-size:11px;color:var(--text-dim)}\n.terminal-section{max-width:640px}\n.terminal-section h2{font-size:16px;margin-bottom:16px;color:var(--accent);font-family:var(--font-mono)}\n.form-group{margin-bottom:16px}\n.form-group label{display:block;font-size:13px;color:var(--text-dim);margin-bottom:6px}\n.form-group input,.form-group textarea{width:100%;background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:10px 14px;color:var(--text);font-size:14px;font-family:var(--font-mono);outline:none;transition:border-color .2s}\n.form-group input:focus,.form-group textarea:focus{border-color:var(--accent)}\n.form-group textarea{min-height:120px;resize:vertical}\n.btn-group{display:flex;gap:12px;margin-top:20px}\n.btn{padding:10px 24px;border:none;border-radius:6px;font-size:14px;font-weight:600;cursor:pointer;transition:opacity .2s}\n.btn:hover{opacity:.85}\n.btn:disabled{opacity:.5;cursor:not-allowed}\n.btn-primary{background:var(--accent);color:var(--bg)}\n.btn-danger{background:var(--red);color:#fff}\n.toast{position:fixed;bottom:24px;right:24px;padding:12px 20px;border-radius:8px;font-size:14px;z-index:1000;animation:slide-in .3s ease}\n.toast.success{background:var(--green);color:#fff}\n.toast.error{background:var(--red);color:#fff}\n@keyframes slide-in{from{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}\n.empty{color:var(--text-dim);text-align:center;padding:40px 0;font-size:14px}\n.fleet-summary{display:flex;gap:16px;margin-bottom:20px}\n.summary-item{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 20px;text-align:center}\n.summary-value{font-size:24px;font-weight:700;font-family:var(--font-mono)}\n.summary-label{font-size:11px;color:var(--text-dim);text-transform:uppercase;letter-spacing:1px;margin-top:2px}\n</style>\n</head>\n<body>\n<header>\n <h1>HumanClaw</h1>\n <p class=\"subtitle\">Async Physical Node Orchestration Framework</p>\n</header>\n<nav>\n <button class=\"tab active\" data-panel=\"fleet\">Carbon Compute Pool</button>\n <button class=\"tab\" data-panel=\"pipeline\">Task Pipeline</button>\n <button class=\"tab\" data-panel=\"terminal\">I/O Terminal</button>\n</nav>\n<main>\n <section id=\"fleet\" class=\"panel active\"></section>\n <section id=\"pipeline\" class=\"panel\"></section>\n <section id=\"terminal\" class=\"panel\"></section>\n</main>\n<script>\nconst API='/api/v1';\nfunction esc(s){const d=document.createElement('div');d.textContent=s;return d.innerHTML}\n\n// ─── Fleet ──────────────────────────────────────────────────\nasync function loadFleet(el){\n el.innerHTML='<div class=\"empty\">Loading...</div>';\n try{\n const r=await fetch(API+'/nodes/status');\n const d=await r.json();\n let h='<div class=\"fleet-summary\">';\n h+='<div class=\"summary-item\"><div class=\"summary-value\">'+d.total+'</div><div class=\"summary-label\">Total</div></div>';\n h+='<div class=\"summary-item\"><div class=\"summary-value\" style=\"color:var(--green)\">'+d.idle+'</div><div class=\"summary-label\">Idle</div></div>';\n h+='<div class=\"summary-item\"><div class=\"summary-value\" style=\"color:var(--yellow)\">'+d.busy+'</div><div class=\"summary-label\">Busy</div></div>';\n h+='<div class=\"summary-item\"><div class=\"summary-value\" style=\"color:var(--red)\">'+d.offline+'</div><div class=\"summary-label\">Offline</div></div>';\n h+='<div class=\"summary-item\"><div class=\"summary-value\" style=\"color:var(--purple)\">'+d.oom+'</div><div class=\"summary-label\">OOM</div></div>';\n h+='</div>';\n if(!d.agents.length){el.innerHTML=h+'<div class=\"empty\">No physical nodes registered. Use CLI: humanclaw agent add</div>';return}\n h+='<div class=\"fleet-grid\">';\n for(const a of d.agents){\n h+='<div class=\"agent-card\"><div class=\"agent-header\"><span class=\"status-dot '+a.status+'\"></span><span class=\"agent-name\">'+esc(a.name)+'</span></div>';\n h+='<div class=\"agent-id\">'+a.agent_id+'</div><div class=\"agent-caps\">';\n for(const c of a.capabilities)h+='<span class=\"cap-tag\">'+esc(c)+'</span>';\n h+='</div><div class=\"agent-metrics\">Active tasks: '+a.active_task_count;\n if(a.avg_delivery_hours!==null)h+=' | Avg delivery: '+a.avg_delivery_hours+'h';\n h+='</div></div>';\n }\n h+='</div>';\n el.innerHTML=h;\n }catch{el.innerHTML='<div class=\"empty\">Failed to load fleet data</div>'}\n}\n\n// ─── Pipeline ───────────────────────────────────────────────\nfunction taskCard(t){\n return '<div class=\"task-card\"><div class=\"task-trace\">'+t.trace_id+'</div><div class=\"task-desc\">'+esc(t.todo_description)+'</div><div class=\"task-meta\">Assignee: '+t.assignee_id+' | Deadline: '+new Date(t.deadline).toLocaleString()+'</div></div>';\n}\nasync function loadPipeline(el){\n el.innerHTML='<div class=\"empty\">Loading...</div>';\n try{\n const r=await fetch(API+'/jobs/active');\n const d=await r.json();\n if(!d.jobs.length){el.innerHTML='<div class=\"empty\">No active jobs. Create one via the API or CLI.</div>';return}\n let h='';\n for(const j of d.jobs){\n const res=j.tasks.filter(t=>t.status==='RESOLVED').length;\n const tot=j.tasks.length;\n const pct=tot?Math.round(res/tot*100):0;\n const dispatched=j.tasks.filter(t=>t.status==='DISPATCHED'||t.status==='PENDING');\n const overdue=j.tasks.filter(t=>t.status==='OVERDUE');\n const done=j.tasks.filter(t=>t.status==='RESOLVED');\n h+='<div class=\"job-card\"><div class=\"job-header\"><span class=\"job-title\">'+esc(j.original_prompt)+'</span><span class=\"job-id\">'+j.job_id+'</span></div>';\n h+='<div class=\"progress-label\">'+res+'/'+tot+' completed ('+pct+'%)</div>';\n h+='<div class=\"progress-bar\"><div class=\"progress-fill\" style=\"width:'+pct+'%\"></div></div>';\n h+='<div class=\"kanban\"><div class=\"kanban-lane\"><div class=\"lane-title dispatched\">Dispatched ('+dispatched.length+')</div>'+dispatched.map(taskCard).join('')+'</div>';\n h+='<div class=\"kanban-lane\"><div class=\"lane-title overdue\">Overdue ('+overdue.length+')</div>'+overdue.map(taskCard).join('')+'</div>';\n h+='<div class=\"kanban-lane\"><div class=\"lane-title resolved\">Resolved ('+done.length+')</div>'+done.map(taskCard).join('')+'</div></div></div>';\n }\n el.innerHTML=h;\n }catch{el.innerHTML='<div class=\"empty\">Failed to load pipeline data</div>'}\n}\n\n// ─── Terminal ───────────────────────────────────────────────\nfunction showToast(msg,type){\n const old=document.querySelector('.toast');if(old)old.remove();\n const t=document.createElement('div');t.className='toast '+type;t.textContent=msg;document.body.appendChild(t);\n setTimeout(()=>t.remove(),3000);\n}\nfunction loadTerminal(el){\n el.innerHTML='<div class=\"terminal-section\"><h2>&gt; I/O Resolution Terminal</h2>'\n +'<div class=\"form-group\"><label for=\"trace-id\">Trace ID</label><input type=\"text\" id=\"trace-id\" placeholder=\"e.g. TK-9527\"/></div>'\n +'<div class=\"form-group\"><label for=\"result-text\">Delivery Payload (text)</label><textarea id=\"result-text\" placeholder=\"Paste the worker\\\\'s deliverable, summary, or code here...\"></textarea></div>'\n +'<div class=\"btn-group\"><button class=\"btn btn-primary\" id=\"btn-submit\">Submit &amp; Resume</button><button class=\"btn btn-danger\" id=\"btn-reject\">Reject &amp; Retry</button></div></div>';\n document.getElementById('btn-submit').addEventListener('click',async()=>{\n const tid=document.getElementById('trace-id').value.trim();\n const txt=document.getElementById('result-text').value.trim();\n if(!tid){showToast('Trace ID is required','error');return}\n if(!txt){showToast('Delivery payload is required','error');return}\n try{\n const r=await fetch(API+'/tasks/resume',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({trace_id:tid,result_data:{text:txt}})});\n const d=await r.json();\n if(!r.ok){showToast(d.error||'Failed','error');return}\n showToast(d.job_complete?'Task resolved! Job complete.':'Task '+tid+' resolved.','success');\n document.getElementById('trace-id').value='';document.getElementById('result-text').value='';\n }catch{showToast('Network error','error')}\n });\n document.getElementById('btn-reject').addEventListener('click',async()=>{\n const tid=document.getElementById('trace-id').value.trim();\n if(!tid){showToast('Trace ID is required','error');return}\n try{\n const r=await fetch(API+'/tasks/reject',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({trace_id:tid})});\n const d=await r.json();\n if(!r.ok){showToast(d.error||'Failed','error');return}\n showToast('Task '+tid+' rejected and deadline extended.','success');\n document.getElementById('trace-id').value='';document.getElementById('result-text').value='';\n }catch{showToast('Network error','error')}\n });\n}\n\n// ─── Tabs ───────────────────────────────────────────────────\nconst tabs=document.querySelectorAll('.tab');\nconst panels=document.querySelectorAll('.panel');\nfunction load(id){\n const el=document.getElementById(id);\n if(id==='fleet')loadFleet(el);\n else if(id==='pipeline')loadPipeline(el);\n else if(id==='terminal')loadTerminal(el);\n}\ntabs.forEach(t=>t.addEventListener('click',()=>{\n tabs.forEach(x=>x.classList.remove('active'));\n panels.forEach(x=>x.classList.remove('active'));\n t.classList.add('active');\n const id=t.dataset.panel;\n document.getElementById(id).classList.add('active');\n load(id);\n}));\nload('fleet');\nsetInterval(()=>{\n const a=document.querySelector('.tab.active');\n if(a&&a.dataset.panel!=='terminal')load(a.dataset.panel);\n},10000);\n</script>\n</body>\n</html>`;\n}\n"],"mappings":"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","names":["db","db","Router","db","db","db","db","db","router","Router","Router","db","router","Router","Router","db","router","Router","db","db"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanclaw/humanclaw",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Async physical node orchestration framework - treating humans as distributed worker nodes",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -21,7 +21,7 @@
21
21
  "workflow"
22
22
  ],
23
23
  "bin": {
24
- "humanclaw": "./dist/index.js"
24
+ "humanclaw": "dist/index.js"
25
25
  },
26
26
  "main": "./dist/index.js",
27
27
  "types": "./dist/index.d.ts",