dlab-cli 0.1.3__tar.gz → 0.2.0__tar.gz
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.
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/PKG-INFO +3 -1
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/cli.py +71 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/docker.py +2 -1
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/js/parallel-agents.ts +6 -1
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/local.py +2 -1
- dlab_cli-0.2.0/dlab/opencode_logparser.py +625 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/timeline.py +91 -157
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/app.py +7 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/log_watcher.py +18 -23
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/models.py +26 -6
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/agent_list.py +14 -6
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/artifacts_pane.py +24 -3
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/log_view.py +119 -17
- dlab_cli-0.2.0/dlab/viewer/__init__.py +7 -0
- dlab_cli-0.2.0/dlab/viewer/html/__init__.py +0 -0
- dlab_cli-0.2.0/dlab/viewer/html/viewer.html +498 -0
- dlab_cli-0.2.0/dlab/viewer/layout.py +121 -0
- dlab_cli-0.2.0/dlab/viewer/server.py +408 -0
- dlab_cli-0.2.0/dlab/viewer/session_data.py +890 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/PKG-INFO +3 -1
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/SOURCES.txt +10 -1
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/requires.txt +2 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/pyproject.toml +4 -1
- dlab_cli-0.2.0/tests/test_opencode_logparser.py +724 -0
- dlab_cli-0.2.0/tests/test_viewer.py +806 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/LICENSE +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/README.md +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/__init__.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/config.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/create_dpack.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/create_dpack_wizard.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/create_parallel_agent_wizard.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/data/__init__.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/data/models.json +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/js/__init__.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/model_fallback.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/parallel_tool.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/session.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/__init__.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/__init__.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/search_popup.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab/tui/widgets/status_bar.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/dependency_links.txt +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/entry_points.txt +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/dlab_cli.egg-info/top_level.txt +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/setup.cfg +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_cli.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_config.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_create_dpack.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_create_dpack_wizard.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_create_parallel_agent_wizard.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_docker.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_generate_dpack_integration.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_integration.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_model_fallback.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_parallel_tool.py +0 -0
- {dlab_cli-0.1.3 → dlab_cli-0.2.0}/tests/test_session.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dlab-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A harness for agentic data science — run coding agents with domain skills, parallel subagents, and frozen Docker environments
|
|
5
5
|
Author: DecisionAI
|
|
6
6
|
License: Apache-2.0
|
|
@@ -18,6 +18,8 @@ Requires-Dist: pyyaml>=6.0
|
|
|
18
18
|
Requires-Dist: textual>=2.0
|
|
19
19
|
Requires-Dist: modal>=0.70
|
|
20
20
|
Requires-Dist: dhub-cli>=0.10
|
|
21
|
+
Requires-Dist: fastapi>=0.100
|
|
22
|
+
Requires-Dist: uvicorn[standard]>=0.20
|
|
21
23
|
Provides-Extra: dev
|
|
22
24
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
23
25
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
@@ -273,6 +273,34 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
273
273
|
help="Path to session work directory (default: cwd if it has _opencode_logs)",
|
|
274
274
|
)
|
|
275
275
|
|
|
276
|
+
# View subcommand (browser-based session viewer)
|
|
277
|
+
view_parser = subparsers.add_parser(
|
|
278
|
+
"view",
|
|
279
|
+
help="Open browser-based session viewer with DAG visualization",
|
|
280
|
+
)
|
|
281
|
+
view_parser.add_argument(
|
|
282
|
+
"work_dir",
|
|
283
|
+
metavar="WORK_DIR",
|
|
284
|
+
help="Path to session work directory",
|
|
285
|
+
)
|
|
286
|
+
view_parser.add_argument(
|
|
287
|
+
"--port",
|
|
288
|
+
type=int,
|
|
289
|
+
default=0,
|
|
290
|
+
help="Port for the viewer server (default: auto-select)",
|
|
291
|
+
)
|
|
292
|
+
view_parser.add_argument(
|
|
293
|
+
"--no-open",
|
|
294
|
+
action="store_true",
|
|
295
|
+
help="Start server without opening browser",
|
|
296
|
+
)
|
|
297
|
+
view_parser.add_argument(
|
|
298
|
+
"--export",
|
|
299
|
+
metavar="FILE",
|
|
300
|
+
default=None,
|
|
301
|
+
help="Export self-contained HTML file instead of starting server",
|
|
302
|
+
)
|
|
303
|
+
|
|
276
304
|
# Create decision-pack subcommand
|
|
277
305
|
create_dpack_parser = subparsers.add_parser(
|
|
278
306
|
"create-dpack",
|
|
@@ -897,6 +925,47 @@ def cmd_create_parallel_agent(args: argparse.Namespace) -> int:
|
|
|
897
925
|
return 0
|
|
898
926
|
|
|
899
927
|
|
|
928
|
+
def cmd_view(args: argparse.Namespace) -> int:
|
|
929
|
+
"""
|
|
930
|
+
Handle view mode - browser-based session viewer with DAG visualization.
|
|
931
|
+
|
|
932
|
+
Parameters
|
|
933
|
+
----------
|
|
934
|
+
args : argparse.Namespace
|
|
935
|
+
Parsed command-line arguments.
|
|
936
|
+
|
|
937
|
+
Returns
|
|
938
|
+
-------
|
|
939
|
+
int
|
|
940
|
+
Exit code (0 for success, non-zero for failure).
|
|
941
|
+
"""
|
|
942
|
+
work_dir: Path = Path(args.work_dir).resolve()
|
|
943
|
+
|
|
944
|
+
if not work_dir.exists():
|
|
945
|
+
print(f"Error: Work directory not found: {work_dir}", file=sys.stderr)
|
|
946
|
+
return 1
|
|
947
|
+
|
|
948
|
+
logs_dir: Path = work_dir / "_opencode_logs"
|
|
949
|
+
if not logs_dir.exists():
|
|
950
|
+
print(f"Error: No logs directory found: {logs_dir}", file=sys.stderr)
|
|
951
|
+
print("Make sure this is a valid dlab session directory.", file=sys.stderr)
|
|
952
|
+
return 1
|
|
953
|
+
|
|
954
|
+
# Export mode — no server dependencies needed
|
|
955
|
+
if args.export:
|
|
956
|
+
from dlab.viewer.server import export_viewer
|
|
957
|
+
output_path: Path = Path(args.export)
|
|
958
|
+
return export_viewer(work_dir, output_path)
|
|
959
|
+
|
|
960
|
+
from dlab.viewer import run_viewer
|
|
961
|
+
|
|
962
|
+
return run_viewer(
|
|
963
|
+
work_dir,
|
|
964
|
+
port=args.port,
|
|
965
|
+
open_browser=not args.no_open,
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
|
|
900
969
|
def cmd_timeline(args: argparse.Namespace) -> int:
|
|
901
970
|
"""
|
|
902
971
|
Handle timeline mode - display execution timeline for a session.
|
|
@@ -1066,6 +1135,8 @@ def main() -> None:
|
|
|
1066
1135
|
exit_code = cmd_create_dpack(args)
|
|
1067
1136
|
elif args.command == "timeline":
|
|
1068
1137
|
exit_code = cmd_timeline(args)
|
|
1138
|
+
elif args.command == "view":
|
|
1139
|
+
exit_code = cmd_view(args)
|
|
1069
1140
|
elif args.dpack or args.data or args.prompt or args.prompt_file or args.continue_dir:
|
|
1070
1141
|
exit_code = cmd_run(args)
|
|
1071
1142
|
else:
|
|
@@ -527,7 +527,8 @@ def build_runner_script(
|
|
|
527
527
|
return f'''#!/bin/bash
|
|
528
528
|
set -o pipefail
|
|
529
529
|
prompt=$(cat {prompt_file})
|
|
530
|
-
|
|
530
|
+
echo "$prompt" | python3 -c "import json,sys; print(json.dumps({{'type':'dlab_start','timestamp':int(__import__('time').time()*1000),'model':'{model}','agent':'{log_prefix}','prompt':sys.stdin.read().strip()}}))" > /_opencode_logs/{log_prefix}.log
|
|
531
|
+
opencode run --format json --log-level DEBUG --model "{model}" "$prompt" 2>&1 | tee -a /_opencode_logs/{log_prefix}.log
|
|
531
532
|
'''
|
|
532
533
|
|
|
533
534
|
|
|
@@ -269,9 +269,11 @@ CRITICAL OUTPUT RULES:
|
|
|
269
269
|
`
|
|
270
270
|
const fullPrompt = subagentContext + args.prompts[i] + "\n\n" + (config.subagent_suffix_prompt || "")
|
|
271
271
|
|
|
272
|
-
// Spawn - log file starts with JSON directly (no header)
|
|
273
272
|
const logFile = join(logsDir, `instance-${i + 1}.log`)
|
|
274
273
|
|
|
274
|
+
// Write dlab_start event as first line (model, agent, prompt)
|
|
275
|
+
writeFileSync(logFile, JSON.stringify({type: "dlab_start", timestamp: Date.now(), model, agent: args.agent, prompt: fullPrompt}) + "\n")
|
|
276
|
+
|
|
275
277
|
const proc = Bun.spawn(["opencode", "run", "--format", "json", "--log-level", "DEBUG", "--model", model, fullPrompt], {
|
|
276
278
|
cwd: instanceDir,
|
|
277
279
|
stdout: "pipe",
|
|
@@ -355,6 +357,9 @@ RULES:
|
|
|
355
357
|
|
|
356
358
|
const consLogFile = join(logsDir, "consolidator.log")
|
|
357
359
|
|
|
360
|
+
// Write dlab_start event as first line
|
|
361
|
+
writeFileSync(consLogFile, JSON.stringify({type: "dlab_start", timestamp: Date.now(), model: consolidatorModel, agent: "consolidator", prompt: consolidatorPrompt}) + "\n")
|
|
362
|
+
|
|
358
363
|
const consProc = Bun.spawn(["opencode", "run", "--format", "json", "--log-level", "DEBUG", "--model", consolidatorModel, consolidatorPrompt], {
|
|
359
364
|
cwd: runDir,
|
|
360
365
|
stdout: "pipe",
|
|
@@ -251,7 +251,8 @@ def run_opencode_local(
|
|
|
251
251
|
runner_script: str = f'''#!/bin/bash
|
|
252
252
|
set -o pipefail
|
|
253
253
|
prompt=$(cat "{prompt_file}")
|
|
254
|
-
|
|
254
|
+
echo "$prompt" | python3 -c "import json,sys; print(json.dumps({{'type':'dlab_start','timestamp':int(__import__('time').time()*1000),'model':'{model}','agent':'{log_prefix}','prompt':sys.stdin.read().strip()}}))" > "{log_path}"
|
|
255
|
+
opencode run --format json --log-level DEBUG --model "{model}" "$prompt" 2>&1 | tee -a "{log_path}"
|
|
255
256
|
'''
|
|
256
257
|
runner_file: Path = work_path / ".run_opencode.sh"
|
|
257
258
|
runner_file.write_text(runner_script)
|