agentproc 0.3.0__tar.gz → 0.4.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentproc
3
- Version: 0.3.0
3
+ Version: 0.4.1
4
4
  Summary: AgentProc Protocol SDK + CLI — connect any Agent CLI to a messaging platform
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/jeffkit/agentproc
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentproc"
7
- version = "0.3.0"
7
+ version = "0.4.1"
8
8
  description = "AgentProc Protocol SDK + CLI — connect any Agent CLI to a messaging platform"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -227,6 +227,27 @@ def build_parser() -> argparse.ArgumentParser:
227
227
  def show_help() -> None:
228
228
  sys.stdout.write(f"""agentproc v{PKG_VERSION} (protocol {PROTOCOL_VERSION})
229
229
 
230
+ The fastest way in:
231
+ agentproc hub list # see what's available
232
+ agentproc hub run echo-agent -p "hello" # smoke test (no API key)
233
+ cd ~/projects/my-app && agentproc hub run claude-code -p "explain this"
234
+
235
+ The CLI fetches the profile from the GitHub hub on first use, caches it at
236
+ ~/.agentproc/cache/hub/<name>/ (24h TTL), and uses your current directory as
237
+ the agent's cwd. Set GITHUB_TOKEN to raise the rate limit (see `agentproc hub --help`).
238
+
239
+ Hub subcommands:
240
+ hub list List all profiles in the hub
241
+ hub show <name> Show a profile's README
242
+ hub run <name> [run-options] Fetch (if needed) and run a profile
243
+ hub install <name> Copy a profile to the current directory
244
+
245
+ Run `agentproc hub --help` for the full hub reference.
246
+
247
+ ───────────────────────────────────────────────────────────────────────────────
248
+
249
+ Advanced: run a local profile YAML directly (no hub fetch)
250
+
230
251
  Usage:
231
252
  agentproc --profile <path.yaml> --prompt "hello" [options]
232
253
 
@@ -240,7 +261,8 @@ Session:
240
261
  --from <user> Sender identifier
241
262
 
242
263
  Execution:
243
- --cwd <path> Override profile.cwd
264
+ --cwd <path> Override profile.cwd (relative paths resolve
265
+ against the profile.yaml's directory)
244
266
  --env KEY=VALUE Extra env var (repeatable)
245
267
  --timeout <secs> Override profile.timeout_secs
246
268
  --no-stream Set AGENT_STREAMING=0
@@ -263,9 +285,16 @@ Output semantics:
263
285
  The final session id is printed on stderr as: agentproc:session:<id>
264
286
 
265
287
  Examples:
266
- agentproc --profile hub/echo-agent/profile.yaml --prompt "hi"
267
- agentproc -p hub/claude-code/profile.yaml --prompt "hello" --verbose
268
- cat prompt.txt | agentproc -p prof.yaml --stdin
288
+ # Local profile (relative cwd resolves next to profile.yaml):
289
+ agentproc --profile ./hub/echo-agent/profile.yaml --prompt "hi"
290
+
291
+ # Local claude-code profile, claude runs against your project:
292
+ agentproc --profile ./hub/claude-code/profile.yaml \\
293
+ --prompt "explain this codebase" \\
294
+ --cwd /path/to/your/project
295
+
296
+ # Prompt from stdin:
297
+ cat prompt.txt | agentproc --profile prof.yaml --stdin
269
298
  """)
270
299
 
271
300
 
@@ -288,9 +317,46 @@ def _run_hub_subcommand(args: List[str]) -> int:
288
317
  sub = args[0]
289
318
  rest = args[1:]
290
319
 
320
+ # Any subcommand with --help/-h shows the hub help uniformly.
321
+ if "--help" in rest or "-h" in rest:
322
+ _show_hub_help()
323
+ return 0
324
+
291
325
  # Common flag
292
326
  refresh = "--refresh" in rest
293
- positional = [a for a in rest if not a.startswith("--")]
327
+
328
+ # Separate hub-level flags from runner-level flags and positional args.
329
+ # In the `hub run` context, `-p` means `--prompt` (the profile name is
330
+ # positional, not a path), so normalize it before handing off to argparse.
331
+ positional: List[str] = []
332
+ runner_args: List[str] = []
333
+ takes_value = {"--prompt", "-p", "--session", "--session-name", "--from",
334
+ "--cwd", "--env", "--timeout"}
335
+ boolean_flags = {"--no-stream", "--verbose", "--quiet", "--raw", "--stdin"}
336
+ i = 0
337
+ while i < len(rest):
338
+ a = rest[i]
339
+ if a in ("--refresh", "-h", "--help"):
340
+ i += 1
341
+ continue
342
+ if a in takes_value:
343
+ runner_args.append("--prompt" if a == "-p" else a)
344
+ if i + 1 < len(rest):
345
+ runner_args.append(rest[i + 1])
346
+ i += 2
347
+ else:
348
+ i += 1
349
+ continue
350
+ if a in boolean_flags:
351
+ runner_args.append(a)
352
+ i += 1
353
+ continue
354
+ if a.startswith("-"):
355
+ sys.stderr.write(f"error: unknown option: {a}\n\n")
356
+ _show_hub_help()
357
+ return 2
358
+ positional.append(a)
359
+ i += 1
294
360
 
295
361
  def _log(msg: str) -> None:
296
362
  sys.stderr.write(msg + "\n")
@@ -319,7 +385,14 @@ def _run_hub_subcommand(args: List[str]) -> int:
319
385
  if not positional:
320
386
  sys.stderr.write("error: hub install requires a profile name\n")
321
387
  return 2
322
- hub_mod.install_profile(positional[0], Path.cwd(), refresh=refresh, on_log=_log)
388
+ dest = hub_mod.install_profile(positional[0], Path.cwd(), refresh=refresh, on_log=_log)
389
+ # Tell the user exactly what they got and how to run it next.
390
+ rel_profile = os.path.relpath(str(dest / "profile.yaml"), str(Path.cwd()))
391
+ sys.stderr.write("\n")
392
+ sys.stderr.write(f"Next: edit {rel_profile} if you want, then run:\n")
393
+ sys.stderr.write(
394
+ f' agentproc --profile {rel_profile} --prompt "hi" --cwd <your-project>\n'
395
+ )
323
396
  return 0
324
397
 
325
398
  if sub == "run":
@@ -330,18 +403,20 @@ def _run_hub_subcommand(args: List[str]) -> int:
330
403
  cache_dir = hub_mod.fetch_profile(profile_name, refresh=refresh, on_log=_log)
331
404
  profile_path = str(cache_dir / "profile.yaml")
332
405
 
333
- # Re-parse remaining args (excluding the profile name) as runner options.
406
+ # Parse the runner-level flags we separated out above.
334
407
  parser = build_parser()
335
- # Drop the first positional (profile name) and --refresh from rest.
336
- runner_args = [a for i, a in enumerate(rest) if not (
337
- (not a.startswith("--") and i == 0) or a == "--refresh"
338
- )]
339
408
  opts = parser.parse_args(runner_args)
340
409
 
341
410
  if not opts.prompt and not opts.stdin:
342
411
  sys.stderr.write("error: hub run requires --prompt <text> or --stdin\n")
343
412
  return 2
344
413
 
414
+ # hub run uses the user's current directory as the agent's cwd when
415
+ # --cwd is not given. Matches the hub docs and the right default for
416
+ # AI-CLI profiles where the agent should operate on the user's project.
417
+ if not opts.cwd:
418
+ opts.cwd = str(Path.cwd())
419
+
345
420
  return _run_agent_with_profile(profile_path, opts)
346
421
 
347
422
  sys.stderr.write(f"error: unknown hub subcommand: {sub}\n\n")
@@ -385,6 +460,7 @@ Profiles are cached at ~/.agentproc/cache/hub/<name>/ (24h TTL).
385
460
 
386
461
  def _run_agent_with_profile(profile_path: str, opts) -> int:
387
462
  """Shared runner logic for both --profile path and hub run path."""
463
+ profile_dir = str(Path(profile_path).resolve().parent)
388
464
  try:
389
465
  yaml_text = Path(profile_path).resolve().read_text(encoding="utf-8")
390
466
  profile_raw = parse_yaml(yaml_text)
@@ -426,6 +502,7 @@ def _run_agent_with_profile(profile_path: str, opts) -> int:
426
502
  from_user=opts.from_user,
427
503
  streaming=streaming,
428
504
  cwd=opts.cwd,
505
+ profile_dir=profile_dir,
429
506
  extra_env=extra_env,
430
507
  timeout_secs=opts.timeout,
431
508
  ),
@@ -446,6 +523,7 @@ def _run_agent_with_profile(profile_path: str, opts) -> int:
446
523
  from_user=opts.from_user,
447
524
  streaming=streaming,
448
525
  cwd=opts.cwd,
526
+ profile_dir=profile_dir,
449
527
  extra_env=extra_env,
450
528
  timeout_secs=opts.timeout,
451
529
  on_partial=lambda t: verbose and sys.stderr.write(
@@ -478,26 +556,48 @@ def main(argv: Optional[List[str]] = None) -> int:
478
556
  if argv is None:
479
557
  argv = sys.argv[1:]
480
558
 
481
- # `agentproc hub <subcommand>` — defer to hub dispatcher.
482
- if argv and argv[0] == "hub":
483
- return _run_hub_subcommand(argv[1:])
484
-
485
- parser = build_parser()
486
- opts = parser.parse_args(argv)
487
-
488
- if opts.help:
489
- show_help()
490
- return 0
491
- if opts.version:
492
- show_version()
493
- return 0
559
+ try:
560
+ # `agentproc hub <subcommand>` defer to hub dispatcher.
561
+ if argv and argv[0] == "hub":
562
+ return _run_hub_subcommand(argv[1:])
494
563
 
495
- if not opts.profile:
496
- sys.stderr.write("error: --profile is required\n\n")
497
- show_help()
498
- return 2
564
+ parser = build_parser()
565
+ opts = parser.parse_args(argv)
566
+
567
+ if opts.help:
568
+ show_help()
569
+ return 0
570
+ if opts.version:
571
+ show_version()
572
+ return 0
573
+
574
+ if not opts.profile:
575
+ sys.stderr.write("error: --profile is required\n\n")
576
+ show_help()
577
+ return 2
499
578
 
500
- return _run_agent_with_profile(opts.profile, opts)
579
+ return _run_agent_with_profile(opts.profile, opts)
580
+ except KeyboardInterrupt:
581
+ return 130
582
+ except Exception as e:
583
+ # Friendly handling for known hub errors: print the message + hint,
584
+ # never a raw stack trace.
585
+ from .hub import HubError
586
+ if isinstance(e, HubError):
587
+ sys.stderr.write(f"error: {e}\n")
588
+ if e.hint:
589
+ sys.stderr.write(f"\n{e.hint}\n")
590
+ return 1
591
+ # Network errors that slipped through unwrapped.
592
+ msg = str(e)
593
+ if any(s in msg for s in ("fetch failed", "ENOTFOUND", "ECONNREFUSED", "ECONNRESET", "urlopen error")):
594
+ sys.stderr.write(f"error: network error talking to GitHub: {msg}\n")
595
+ sys.stderr.write("\nThis is usually transient. Re-run the command, or run against a local checkout:\n")
596
+ sys.stderr.write(' agentproc --profile ./hub/<name>/profile.yaml --prompt "hi"\n')
597
+ return 1
598
+ # Everything else: surface the message without dumping a traceback.
599
+ sys.stderr.write(f"error: {msg}\n")
600
+ return 1
501
601
 
502
602
 
503
603
  if __name__ == "__main__":