@1mancompany/onemancompany 0.7.19 → 0.7.20

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/frontend/app.js CHANGED
@@ -795,6 +795,9 @@ class AppController {
795
795
  // Create Product modal
796
796
  this._initCreateProductModal();
797
797
 
798
+ // Product selector feedback
799
+ this._initProductSelector();
800
+
798
801
  hrBtn?.addEventListener('click', () => {
799
802
  hrBtn.disabled = true;
800
803
  this.logEntry('CEO', '🔄 Triggering quarterly review...', 'ceo');
@@ -7262,6 +7265,20 @@ class AppController {
7262
7265
  }
7263
7266
 
7264
7267
  // ===== Product Selector =====
7268
+ _initProductSelector() {
7269
+ const sel = document.getElementById('ceo-product-select');
7270
+ if (!sel) return;
7271
+ sel.addEventListener('change', () => {
7272
+ if (sel.value) {
7273
+ sel.style.borderColor = 'var(--pixel-cyan)';
7274
+ sel.style.color = 'var(--pixel-white)';
7275
+ } else {
7276
+ sel.style.borderColor = '';
7277
+ sel.style.color = '';
7278
+ }
7279
+ });
7280
+ }
7281
+
7265
7282
  async _refreshProductSelector() {
7266
7283
  try {
7267
7284
  const data = await fetch('/api/products').then(r => r.json());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1mancompany/onemancompany",
3
- "version": "0.7.19",
3
+ "version": "0.7.20",
4
4
  "description": "The AI Operating System for One-Person Companies",
5
5
  "bin": {
6
6
  "onemancompany": "bin/cli.js"
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "onemancompany"
3
- version = "0.7.19"
3
+ version = "0.7.20"
4
4
  description = "A one-man company simulation with pixel art visualization and LangChain AI agents"
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
@@ -655,7 +655,7 @@ async def ceo_submit_task(
655
655
 
656
656
  @router.post("/api/task/{project_id}/followup")
657
657
  async def task_followup(project_id: str, body: dict) -> dict:
658
- """CEO adds follow-up instructions to an existing task, dispatched to EA with context."""
658
+ """CEO adds follow-up instructions to an existing task, dispatched to assignee (product owner or EA) with context."""
659
659
  from datetime import datetime as _dt
660
660
 
661
661
  from onemancompany.core.agent_loop import get_agent_loop
@@ -699,7 +699,23 @@ async def task_followup(project_id: str, body: dict) -> dict:
699
699
  for fname in deliverables:
700
700
  work_summary_lines.append(f" {fname}")
701
701
 
702
- # Build follow-up task for EA
702
+ # Determine assignee: product owner if product-linked, else EA
703
+ assignee_id = EA_ID
704
+ product_id = doc.get("product_id", "")
705
+ if product_id:
706
+ from onemancompany.core.product import find_slug_by_product_id, load_product
707
+ product_slug = find_slug_by_product_id(product_id)
708
+ if product_slug:
709
+ product = load_product(product_slug)
710
+ if product and product.get("owner_id"):
711
+ assignee_id = product["owner_id"]
712
+ logger.debug("[FOLLOWUP] Product-linked project {}, routing to owner {}",
713
+ project_id, assignee_id)
714
+ if assignee_id == EA_ID:
715
+ logger.debug("[FOLLOWUP] No product owner found for project {}, falling back to EA",
716
+ project_id)
717
+
718
+ # Build follow-up task for assignee
703
719
  context_parts = [
704
720
  f"CEO has added follow-up instructions to a completed task:\n",
705
721
  f"Original task: {original_task}\n",
@@ -721,11 +737,11 @@ async def task_followup(project_id: str, body: dict) -> dict:
721
737
  else:
722
738
  tree = TaskTree(project_id=project_id)
723
739
 
724
- ea_loop = get_agent_loop(EA_ID)
725
- if not ea_loop:
726
- raise HTTPException(status_code=503, detail="EA agent not available")
740
+ assignee_loop = get_agent_loop(assignee_id)
741
+ if not assignee_loop:
742
+ raise HTTPException(status_code=503, detail=f"Agent {assignee_id} not available")
727
743
 
728
- schedule_node_id = "" # will be set to the EA node to schedule
744
+ schedule_node_id = "" # will be set to the assignee node to schedule
729
745
 
730
746
  if tree.root_id:
731
747
  # Add a new subtree from CEO root — old subtree stays intact
@@ -741,39 +757,39 @@ async def task_followup(project_id: str, body: dict) -> dict:
741
757
  followup_node.node_type = NodeType.CEO_FOLLOWUP
742
758
  followup_node.status = TaskPhase.ACCEPTED.value
743
759
 
744
- # Create a new EA node under the followup node for execution
745
- ea_child = tree.add_child(
760
+ # Create execution node under the followup node
761
+ exec_child = tree.add_child(
746
762
  parent_id=followup_node.id,
747
- employee_id=EA_ID,
763
+ employee_id=assignee_id,
748
764
  description=followup_task,
749
765
  acceptance_criteria=[],
750
766
  )
751
- schedule_node_id = ea_child.id
767
+ schedule_node_id = exec_child.id
752
768
 
753
769
  # Keep CEO root in PROCESSING while new subtree runs
754
770
  if root and root.node_type == NodeType.CEO_PROMPT:
755
771
  root.status = TaskPhase.PROCESSING.value
756
772
  else:
757
- # No root yet — create CEO root + EA child
773
+ # No root yet — create CEO root + assignee child
758
774
  ceo_root = tree.create_root(employee_id=CEO_ID, description=instructions)
759
775
  ceo_root.node_type = NodeType.CEO_PROMPT
760
776
  ceo_root.set_status(TaskPhase.PROCESSING)
761
- ea_child = tree.add_child(
777
+ exec_child = tree.add_child(
762
778
  parent_id=ceo_root.id,
763
- employee_id=EA_ID,
779
+ employee_id=assignee_id,
764
780
  description=instructions,
765
781
  acceptance_criteria=[],
766
782
  )
767
- schedule_node_id = ea_child.id
783
+ schedule_node_id = exec_child.id
768
784
 
769
785
  _save_project_tree(pdir, tree)
770
786
 
771
- # Schedule the EA node for execution
787
+ # Schedule the assignee node for execution
772
788
  if schedule_node_id:
773
789
  tree_path = str(Path(pdir) / TASK_TREE_FILENAME)
774
790
  from onemancompany.core.agent_loop import employee_manager
775
- employee_manager.schedule_node(EA_ID, schedule_node_id, tree_path)
776
- employee_manager._schedule_next(EA_ID)
791
+ employee_manager.schedule_node(assignee_id, schedule_node_id, tree_path)
792
+ employee_manager._schedule_next(assignee_id)
777
793
 
778
794
  # Update project.yaml status back to in_progress
779
795
  doc["status"] = "in_progress"