zob-harness 0.9.2 → 0.11.0
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/.pi/capabilities/zob-public-runtime-capabilities.json +49 -1
- package/.pi/extensions/zob-harness/index.ts +5 -1
- package/.pi/extensions/zob-harness/src/core/constants.ts +7 -4
- package/.pi/extensions/zob-harness/src/domains/context/context-discovery.ts +83 -22
- package/.pi/extensions/zob-harness/src/domains/goal/goal-todos/formatting.ts +5 -2
- package/.pi/extensions/zob-harness/src/domains/plan/plan-todos.ts +661 -0
- package/.pi/extensions/zob-harness/src/runtime/commands/plans.ts +93 -0
- package/.pi/extensions/zob-harness/src/runtime/commands.ts +3 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-activity.ts +289 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-feed.ts +27 -0
- package/.pi/extensions/zob-harness/src/runtime/delegation-monitor.ts +8 -0
- package/.pi/extensions/zob-harness/src/runtime/events.ts +56 -3
- package/.pi/extensions/zob-harness/src/runtime/plan-capture.ts +203 -11
- package/.pi/extensions/zob-harness/src/runtime/plan-launch.ts +166 -0
- package/.pi/extensions/zob-harness/src/runtime/state.ts +2 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-context.ts +3 -3
- package/.pi/extensions/zob-harness/src/runtime/tools-delegation/helpers.ts +31 -1
- package/.pi/extensions/zob-harness/src/runtime/tools-delegation/register.ts +3 -0
- package/.pi/extensions/zob-harness/src/runtime/tools-plan.ts +70 -0
- package/.pi/extensions/zob-harness/src/runtime/widget.ts +14 -4
- package/.pi/extensions/zob-harness/src/runtime/zobHarness.ts +3 -0
- package/.pi/skills/zob-coms-v2-live/SKILL.md +5 -2
- package/.pi/skills/zob-context-discovery/SKILL.md +1 -1
- package/.pi/skills/zob-goal-todo-tree/SKILL.md +11 -10
- package/.pi/skills/zob-harness/SKILL.md +5 -2
- package/.pi/skills/zob-tool-router/SKILL.md +5 -1
- package/.pi/skills/zob-zagent-creator/SKILL.md +22 -6
- package/AGENTS.md +3 -1
- package/package.json +1 -1
- package/scripts/context-discovery/shared.mjs +48 -14
- package/scripts/context-discovery/smoke.mjs +38 -5
|
@@ -321,6 +321,25 @@
|
|
|
321
321
|
],
|
|
322
322
|
"noShipNotes": "Imports chain report TODOs into goal state; no source edits."
|
|
323
323
|
},
|
|
324
|
+
{
|
|
325
|
+
"name": "zob_plan_launch",
|
|
326
|
+
"family": "plan",
|
|
327
|
+
"modes": [
|
|
328
|
+
"plan",
|
|
329
|
+
"implement",
|
|
330
|
+
"factory",
|
|
331
|
+
"orchestrator"
|
|
332
|
+
],
|
|
333
|
+
"skillRefs": [
|
|
334
|
+
".pi/skills/zob-harness/SKILL.md",
|
|
335
|
+
".pi/skills/zob-goal-todo-tree/SKILL.md"
|
|
336
|
+
],
|
|
337
|
+
"docRefs": [
|
|
338
|
+
".pi/extensions/zob-harness/src/AGENTS.md",
|
|
339
|
+
"AGENTS.md"
|
|
340
|
+
],
|
|
341
|
+
"noShipNotes": "Launches a saved plan TODO sidecar into runtime goal/TODO metadata; does not edit source files and must not recreate TODOs from prose. Blocks on active-goal/relaunch conflicts unless explicitly gated."
|
|
342
|
+
},
|
|
324
343
|
{
|
|
325
344
|
"name": "create_goal",
|
|
326
345
|
"family": "goal",
|
|
@@ -1029,7 +1048,7 @@
|
|
|
1029
1048
|
"README.md",
|
|
1030
1049
|
"scripts/README.md"
|
|
1031
1050
|
],
|
|
1032
|
-
"noShipNotes": "Bounded repo-local context discovery only; for exploratory/natural-language repo discovery start with zob_context_search/ColGREP when installed/ready; if the native tool is unavailable but bash is available, use compact npm run --silent zob:context:query before rg/grep; otherwise use grep/find/read fallback. Never auto-install ColGREP, run installer/network/package-manager commands, broad-grep .pi without pruning .pi/sessions and .pi/agent-sessions, read forbidden/secret/session/vendor/build paths, persist raw secret/session bodies, inject stale/global/unbounded prompt context, or treat broad search hits as exact proof without grep/read/file-ref verification. Oracle/no-ship review must check freshness, citation coverage, and forbidden-source violations."
|
|
1051
|
+
"noShipNotes": "Bounded repo-local context discovery only; for exploratory/natural-language repo discovery start with zob_context_search/ColGREP when installed/ready and reuse it at context pivot points (new subsystem/domain, ambiguous file area, fallback_status suggesting narrower paths, repeated low-signal grep/find, unfamiliar code before edits, or unknown validation/test failure); if the native tool is unavailable but bash is available, use compact npm run --silent zob:context:query before rg/grep; otherwise use grep/find/read fallback. Never auto-install ColGREP, run installer/network/package-manager commands, broad-grep .pi without pruning .pi/sessions and .pi/agent-sessions, read forbidden/secret/session/vendor/build paths, persist raw secret/session bodies, inject stale/global/unbounded prompt context, or treat broad search hits as exact proof without grep/read/file-ref verification; grep/read remain the exact-proof path after semantic discovery and when exact identifiers/paths are already known. Oracle/no-ship review must check freshness, citation coverage, and forbidden-source violations."
|
|
1033
1052
|
},
|
|
1034
1053
|
{
|
|
1035
1054
|
"name": "zob_context_readiness",
|
|
@@ -1850,6 +1869,35 @@
|
|
|
1850
1869
|
"AGENTS.md"
|
|
1851
1870
|
],
|
|
1852
1871
|
"noShipNotes": "Lists specialist agents only."
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
"name": "plan",
|
|
1875
|
+
"family": "plan",
|
|
1876
|
+
"modes": [
|
|
1877
|
+
"all"
|
|
1878
|
+
],
|
|
1879
|
+
"skillRefs": [
|
|
1880
|
+
".pi/skills/zob-harness/SKILL.md",
|
|
1881
|
+
".pi/skills/zob-goal-todo-tree/SKILL.md"
|
|
1882
|
+
],
|
|
1883
|
+
"docRefs": [
|
|
1884
|
+
"AGENTS.md"
|
|
1885
|
+
],
|
|
1886
|
+
"noShipNotes": "Inspects or launches saved plan TODO sidecars; launch mutates runtime goal/TODO metadata only."
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
"name": "plans",
|
|
1890
|
+
"family": "plan",
|
|
1891
|
+
"modes": [
|
|
1892
|
+
"all"
|
|
1893
|
+
],
|
|
1894
|
+
"skillRefs": [
|
|
1895
|
+
".pi/skills/zob-harness/SKILL.md"
|
|
1896
|
+
],
|
|
1897
|
+
"docRefs": [
|
|
1898
|
+
"AGENTS.md"
|
|
1899
|
+
],
|
|
1900
|
+
"noShipNotes": "Lists captured plan artifacts and launchability metadata only."
|
|
1853
1901
|
}
|
|
1854
1902
|
]
|
|
1855
1903
|
}
|
|
@@ -43,8 +43,12 @@ export { DEFAULT_GOAL_ACTIVATION_MODE, clearRuntimeGoalContinuationState, clearR
|
|
|
43
43
|
export type { GoalActivationMode, RuntimeGoal, RuntimeGoalStatus, RuntimeGoalOracleStatus, RuntimeGoalOracleVerdict } from "./src/runtime/goal-runtime.js";
|
|
44
44
|
export { extractModeIntent, looksLikeCompletePlanResponse, stripModeIntentMarkup, validateModeIntent } from "./src/runtime/mode-intent.js";
|
|
45
45
|
export type { ZobModeIntent, ZobModeIntentConfidence, ZobModeIntentRisk, ZobModeIntentValidation } from "./src/runtime/mode-intent.js";
|
|
46
|
-
export { capturePlanArtifact, extractPlanTitle, shouldCapturePlanResponse } from "./src/runtime/plan-capture.js";
|
|
46
|
+
export { capturePlanArtifact, extractPlanTitle, listCapturedPlanEntries, shouldCapturePlanResponse, updateCapturedPlanEntry } from "./src/runtime/plan-capture.js";
|
|
47
47
|
export type { PlanCaptureInput, PlanCaptureResult, PlanIndexEntry } from "./src/runtime/plan-capture.js";
|
|
48
|
+
export { launchCapturedPlan, previewCapturedPlanLaunch, resolveCapturedPlanForLaunch } from "./src/runtime/plan-launch.js";
|
|
49
|
+
export type { PlanLaunchInput, PlanLaunchResult, PlanLaunchSelector } from "./src/runtime/plan-launch.js";
|
|
50
|
+
export { PLAN_TODOS_BLOCK_END, PLAN_TODOS_BLOCK_START, PLAN_TODOS_CANONICAL_SCHEMA, PLAN_TODOS_DISPLAY_CARD_END, PLAN_TODOS_DISPLAY_CARD_START, PLAN_TODOS_INPUT_SCHEMA, PLAN_TODOS_SIDECAR_SCHEMA, buildPlanTodoSidecar, canonicalManifestHash, compileMarkdownPlanTodoManifest, extractAndNormalizePlanTodoManifest, extractPlanTodosJson, formatPlanTodoManifestDisplayCard, formatPlanTodoManifestTree, normalizePlanTodoManifest, planTodoSidecarRelativePath, readPlanTodoSidecar, redactPlanTodosBlockForDisplay, validatePlanTodoSidecar, writePlanTodoSidecar } from "./src/domains/plan/plan-todos.js";
|
|
51
|
+
export type { PlanLaunchStatus, PlanTodoCanonicalItem, PlanTodoCanonicalManifest, PlanTodoDisplayCardOptions, PlanTodoDisplayRedactionResult, PlanTodoManifestQuality, PlanTodoManifestResult, PlanTodoManifestSource, PlanTodoSidecar } from "./src/domains/plan/plan-todos.js";
|
|
48
52
|
export { ZOB_COMPACTION_CONTINUITY_CONTRACT, ZOB_TOOL_ROUTING_CONTRACT } from "./src/core/constants.js";
|
|
49
53
|
export { ZOB_COMPACTION_DETAILS_SCHEMA, ZOB_COMPACTION_ENTRY_TYPE, ZOB_COMPACTION_HARD_CAP_TOKENS, ZOB_COMPACTION_LEDGER_SCHEMA, ZOB_COMPACTION_SUMMARY_SCHEMA, ZOB_COMPACTION_TARGET_TOKENS, buildDeterministicZobCompactionResult, buildDeterministicZobCompactionSummary, buildZobCompactionDetails, buildZobCompactionInstructions, buildZobCompactionLedgerEntry, buildZobCompactionStateCapsule, withZobCompactionDetails, zobCompactionBodyFreeViolations } from "./src/runtime/compaction-policy.js";
|
|
50
54
|
export type { ZobCompactionDetails, ZobCompactionFileRefsInput, ZobCompactionInstructionInput, ZobCompactionLedgerEntry, ZobCompactionStateCapsule } from "./src/runtime/compaction-policy.js";
|
|
@@ -63,17 +63,18 @@ export const ZOB_COMPUTE_READ_TOOLS = ["zob_compute_preview", "zob_compute_resol
|
|
|
63
63
|
export const ZOB_COMPUTE_REPORT_TOOLS = ["zob_compute_write_profile_reports"] as const;
|
|
64
64
|
export const ZOB_PROJECT_DNA_READ_TOOLS = ["zob_project_dna_readiness", "zob_project_dna_plan_workflow", "zob_project_dna_query", "zob_project_dna_federated_query"] as const;
|
|
65
65
|
export const ZOB_PROJECT_DNA_PROPOSAL_TOOLS = ["zob_project_dna_writeback_proposal"] as const;
|
|
66
|
+
export const ZOB_PLAN_LAUNCH_TOOLS = ["zob_plan_launch"] as const;
|
|
66
67
|
export const ZOB_RUNTIME_GOAL_TOOLS = ["get_goal", "get_goal_todos", "add_goal_todo", "add_goal_todos", "update_goal_todo", "resolve_goal_todo", "complete_goal_todo", "block_goal_todo", "split_goal_todo", "validate_goal_todo_claim", "accept_goal_todo_claim", "reject_goal_todo_claim", "import_factory_todos", "import_orchestration_todos", "import_chain_todos", "create_goal", "resume_goal", "propose_goal_completion", "record_goal_oracle", "update_goal"] as const;
|
|
67
68
|
export const ZOB_AUTONOMOUS_READ_TOOLS = ["zob_autonomous_validate_run", "zob_autonomous_validate_smoke"] as const;
|
|
68
69
|
export const ZOB_AUTONOMOUS_FACTORY_TOOLS = ["zob_autonomous_dry_run", "zob_autonomous_readonly_smoke"] as const;
|
|
69
70
|
|
|
70
71
|
export const MODE_TOOLS: Record<ModeName, string[]> = {
|
|
71
72
|
explore: ["read", "grep", "find", "ls", "bash", "delegate_agent", "delegate_task", "zob_coms_list", "zob_coms_get", "zob_coms_await", "zpeer_ask", "zob_goal_room_list", "zob_workspace_claims_list", "zob_worker_pool_status", "zob_merge_queue_list", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_AUTONOMOUS_READ_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS],
|
|
72
|
-
plan: ["read", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "chain_run", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
73
|
-
implement: ["read", "bash", "edit", "write", "grep", "find", "ls", "delegate_agent", "delegate_task", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
73
|
+
plan: ["read", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "chain_run", ...ZOB_PLAN_LAUNCH_TOOLS, ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
74
|
+
implement: ["read", "bash", "edit", "write", "grep", "find", "ls", "delegate_agent", "delegate_task", ...ZOB_PLAN_LAUNCH_TOOLS, ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
74
75
|
oracle: ["read", "grep", "find", "ls", "bash", "delegate_agent", "delegate_task", "zob_coms_list", "zob_coms_get", "zob_coms_await", "zpeer_ask", "zob_goal_room_list", "zob_workspace_claims_list", "zob_worker_pool_status", "zob_merge_queue_list", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_AUTONOMOUS_READ_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS],
|
|
75
|
-
orchestrator: ["read", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "chain_run", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS],
|
|
76
|
-
factory: ["read", "bash", "edit", "write", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "factory_run", "factory_quarantine_review", "factory_quarantine_activate", "factory_quarantine_verify_activation", "chain_run", ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_AUTONOMOUS_READ_TOOLS, ...ZOB_AUTONOMOUS_FACTORY_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
76
|
+
orchestrator: ["read", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "chain_run", ...ZOB_PLAN_LAUNCH_TOOLS, ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS],
|
|
77
|
+
factory: ["read", "bash", "edit", "write", "grep", "find", "ls", "delegate_agent", "delegate_task", "orchestrate_run", "factory_run", "factory_quarantine_review", "factory_quarantine_activate", "factory_quarantine_verify_activation", "chain_run", ...ZOB_PLAN_LAUNCH_TOOLS, ...ZOB_RUNTIME_GOAL_TOOLS, ...ZOB_DELEGATION_READ_TOOLS, ...ZOB_ZCOMMIT_TOOLS, ...ZOB_ZAGENT_TOOLS, ...ZOB_AUTONOMOUS_READ_TOOLS, ...ZOB_AUTONOMOUS_FACTORY_TOOLS, ...ZOB_COMS_TOOLS, ...ZOB_GOAL_ROOM_TOOLS, ...ZOB_GOVERNED_REQUEST_TOOLS, ...ZOB_WORKSPACE_CLAIM_TOOLS, ...ZOB_WORKER_POOL_TOOLS, ...ZOB_MERGE_QUEUE_TOOLS, ...ZOB_MISSION_CONTROL_READ_TOOLS, ...ZOB_MISSION_CONTROL_PROPOSAL_TOOLS, ...ZOB_CONTEXT_READ_TOOLS, ...ZOB_CONTEXT_PROPOSAL_TOOLS, ...ZOB_COMPUTE_READ_TOOLS, ...ZOB_COMPUTE_REPORT_TOOLS, ...ZOB_PROJECT_DNA_READ_TOOLS, ...ZOB_PROJECT_DNA_PROPOSAL_TOOLS],
|
|
77
78
|
// Vanilla is handled specially by applyMode: all currently available Pi tools are enabled.
|
|
78
79
|
vanilla: [],
|
|
79
80
|
};
|
|
@@ -88,6 +89,8 @@ export const MODE_PROMPTS: Record<ModeName, string> = {
|
|
|
88
89
|
- No edits, no commits, no broad test runs.
|
|
89
90
|
- For non-trivial or tool-ambiguous plans, apply the ZOB tool-routing contract and state which families are in/out before detailed steps.
|
|
90
91
|
- Produce scope table, likely files, TDD sequence, validation ladder, atomic commit plan, risks, and stop conditions.
|
|
92
|
+
- For complete implementation plans, include exactly one machine-readable TODO manifest block at the end: <!-- ZOB_PLAN_TODOS_START --> + fenced JSON schema zob.plan-todos.v1 + <!-- ZOB_PLAN_TODOS_END -->; keep it simple (objective, todos, key, title, done_when, checks, children) so zob_plan_launch can launch without the LLM recreating TODOs from prose.
|
|
93
|
+
- Treat launchability as part of plan quality: if the explicit TODO block is omitted, capture falls back to deterministic Markdown list parsing and may record fallback warnings or needs_manifest; do not rely on prose-only plans when you can emit the block.
|
|
91
94
|
- Consume prior explore outputs before re-reading. Avoid duplicate discovery.
|
|
92
95
|
- Single-plan rule: if the immediately previous assistant response already provided a complete plan for the same request, do not restate it; summarize that the plan is already provided and offer to refine, save, or implement it.
|
|
93
96
|
- If auto-mode switched to plan after a short handoff, produce the deferred plan once and do not request plan mode again.`,
|
|
@@ -14,6 +14,7 @@ export interface ContextDiscoveryConfig {
|
|
|
14
14
|
maxResults: number;
|
|
15
15
|
maxContextLines: number;
|
|
16
16
|
maxFileBytes: number;
|
|
17
|
+
colgrepTimeoutMs: number;
|
|
17
18
|
};
|
|
18
19
|
promptInjection: {
|
|
19
20
|
enabled: boolean;
|
|
@@ -48,11 +49,14 @@ const DEFAULT_CONFIG: ContextDiscoveryConfig = {
|
|
|
48
49
|
fallbackProvider: "grep",
|
|
49
50
|
includePaths: [".pi/extensions", ".pi/skills", ".pi/capabilities", "scripts", "docs", "README.md", "AGENTS.md"],
|
|
50
51
|
excludePaths: [".env", "**/.env", ".env.*", "**/*secret*", "**/*key*", "*.pem", ".pi/sessions", ".pi/agent-sessions", "node_modules", "dist", "build"],
|
|
51
|
-
limits: { maxResults: 6, maxContextLines: 1, maxFileBytes: 1024 * 1024 },
|
|
52
|
+
limits: { maxResults: 6, maxContextLines: 1, maxFileBytes: 1024 * 1024, colgrepTimeoutMs: 8_000 },
|
|
52
53
|
promptInjection: { enabled: true, includeInstallHint: true },
|
|
53
54
|
loadedFrom: "defaults",
|
|
54
55
|
};
|
|
55
56
|
const TEXT_EXTENSIONS = new Set(["", ".cjs", ".css", ".js", ".json", ".md", ".mjs", ".sh", ".ts", ".tsx", ".txt", ".yaml", ".yml"]);
|
|
57
|
+
const COLGREP_DEFAULT_TIMEOUT_MS = 8_000;
|
|
58
|
+
const COLGREP_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
59
|
+
const FALLBACK_CANDIDATE_BUDGET = 500;
|
|
56
60
|
|
|
57
61
|
function clampInteger(value: unknown, fallback: number, min: number, max: number): number {
|
|
58
62
|
const numberValue = typeof value === "number" ? value : Number(value);
|
|
@@ -64,6 +68,35 @@ function shellQuote(value: string): string {
|
|
|
64
68
|
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
function escapeRegExpLiteral(value: string): string {
|
|
72
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function extractFallbackSearchTerms(query: string): string[] {
|
|
76
|
+
const rawTerms = query.toLowerCase().match(/[\p{L}\p{N}_-]+/gu) ?? [];
|
|
77
|
+
const usefulTerms = rawTerms.filter((term) => term.length >= 3 || /\d/u.test(term) || term.includes("_") || term.includes("-"));
|
|
78
|
+
return [...new Set(usefulTerms)].sort((left, right) => right.length - left.length || left.localeCompare(right)).slice(0, 12);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function fallbackLineScore(lineLower: string, queryLower: string, terms: string[]): number {
|
|
82
|
+
let score = queryLower.length > 0 && lineLower.includes(queryLower) ? 100 : 0;
|
|
83
|
+
for (const term of terms) {
|
|
84
|
+
if (lineLower.includes(term)) score += Math.min(10, term.length);
|
|
85
|
+
}
|
|
86
|
+
return score;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getColgrepTimeoutMs(config: ContextDiscoveryConfig): number {
|
|
90
|
+
return clampInteger(process.env.ZOB_CONTEXT_COLGREP_TIMEOUT_MS ?? config.limits.colgrepTimeoutMs, COLGREP_DEFAULT_TIMEOUT_MS, 500, 30_000);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function buildFallbackVerificationCommand(query: string, roots: string[], searchTerms: string[], mode: ContextSearchMode, pattern?: string): string {
|
|
94
|
+
const rootArgs = roots.map(shellQuote).join(" ") || ".";
|
|
95
|
+
if (mode === "regex") return `grep -R -n -E ${shellQuote(pattern ?? query)} ${rootArgs}`;
|
|
96
|
+
const grepPattern = searchTerms.length > 0 ? searchTerms.slice(0, 10).map(escapeRegExpLiteral).join("|") : escapeRegExpLiteral(query);
|
|
97
|
+
return `grep -R -n -E ${shellQuote(grepPattern)} ${rootArgs}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
67
100
|
function globToRegExp(pattern: string): RegExp {
|
|
68
101
|
const escaped = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/gu, "\\$&")).join(".*");
|
|
69
102
|
return new RegExp(`^${escaped}$`, "iu");
|
|
@@ -144,10 +177,10 @@ export function buildActiveSearchBackendPromptSnippet(repoRoot: string): string
|
|
|
144
177
|
const detection = detectColgrep(repoRoot);
|
|
145
178
|
const scope = `${config.loadedFrom}; roots=${config.includePaths.slice(0, 6).join(",")}; excludes=${config.excludePaths.length}`;
|
|
146
179
|
if (detection.ready) {
|
|
147
|
-
return `\n\nZOB ACTIVE SEARCH BACKEND\n- active search backend: colgrep\n- prompt injection: enabled by ${scope}; bounded per turn from current repo config, not a global/stale context pack.\n- For exploratory, natural-language, or "where is this mechanism?" repo discovery, start with zob_context_search/ColGREP before grep/find.\n- If zob_context_search is not listed in your available tools but bash is available, run npm run --silent zob:context:query -- --query "<natural language query>" --max-results 6 --max-context-lines 1 before rg/grep; the wrapper returns compact refs by default.\n- Do not conclude the native tool is unavailable and immediately use broad rg/grep; use the wrapper above as the ColGREP path.\n-
|
|
180
|
+
return `\n\nZOB ACTIVE SEARCH BACKEND\n- active search backend: colgrep\n- prompt injection: enabled by ${scope}; bounded per turn from current repo config, not a global/stale context pack.\n- For exploratory, natural-language, or "where is this mechanism?" repo discovery, start with zob_context_search/ColGREP before grep/find.\n- If zob_context_search is not listed in your available tools but bash is available, run npm run --silent zob:context:query -- --query "<natural language query>" --max-results 6 --max-context-lines 1 before rg/grep; the wrapper returns compact refs by default.\n- Do not conclude the native tool is unavailable and immediately use broad rg/grep; use the wrapper above as the ColGREP path.\n- Reuse zob_context_search/ColGREP at context pivot points: new subsystem/domain, ambiguous or broad file area, fallback_status suggesting narrower paths, repeated low-signal grep/find, unfamiliar code before edits, or unknown validation/test failure.\n- Use grep/read after semantic discovery for exact proof, known identifiers, final citations, and line refs; use grep/read directly when exact identifiers or paths are already known.\n- Never run broad grep/find over .pi unless .pi/sessions and .pi/agent-sessions are explicitly excluded/pruned.\n- Search output must stay bounded and avoid forbidden paths/secrets.`;
|
|
148
181
|
}
|
|
149
182
|
const installHint = config.promptInjection.includeInstallHint ? `\n- Optional ColGREP setup hint: ${detection.guidance}` : "";
|
|
150
|
-
return `\n\nZOB ACTIVE SEARCH BACKEND\n- active search backend: grep fallback\n- prompt injection: enabled by ${scope}; bounded per turn from current repo config, not a global/stale context pack.\n- Prefer zob_context_search when listed; if not listed and bash is available, npm run --silent zob:context:query -- --query "<query>" still gives the same bounded compact fallback path.${installHint}\n- Missing ColGREP is not a blocker; do not auto-install it.\n-
|
|
183
|
+
return `\n\nZOB ACTIVE SEARCH BACKEND\n- active search backend: grep fallback\n- prompt injection: enabled by ${scope}; bounded per turn from current repo config, not a global/stale context pack.\n- Prefer zob_context_search when listed; if not listed and bash is available, npm run --silent zob:context:query -- --query "<query>" still gives the same bounded compact fallback path.${installHint}\n- Reuse the active context path at pivots such as new subsystem/domain, ambiguous file area, fallback_status suggesting narrower paths, repeated low-signal grep/find, unfamiliar code before edits, or unknown validation/test failure.\n- Missing ColGREP is not a blocker; do not auto-install it.\n- Use grep/read for exact proof and when exact identifiers or paths are already known; never run broad grep/find over .pi unless .pi/sessions and .pi/agent-sessions are explicitly excluded/pruned.`;
|
|
151
184
|
}
|
|
152
185
|
|
|
153
186
|
function safeSearchRoots(repoRoot: string, config: ContextDiscoveryConfig, requestedPaths?: string[]): { roots: string[]; rejected: string[] } {
|
|
@@ -211,12 +244,9 @@ function extractJsonResults(repoRoot: string, stdout: string, config: ContextDis
|
|
|
211
244
|
}
|
|
212
245
|
}
|
|
213
246
|
|
|
214
|
-
const COLGREP_TIMEOUT_MS = 30_000;
|
|
215
|
-
const COLGREP_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
216
|
-
|
|
217
247
|
type ColgrepRunResult = { ok: boolean; results: NormalizedContextResult[]; error?: string };
|
|
218
248
|
|
|
219
|
-
async function runColgrep(repoRoot: string, query: string, roots: string[], config: ContextDiscoveryConfig, maxResults: number, maxContextLines: number): Promise<ColgrepRunResult> {
|
|
249
|
+
async function runColgrep(repoRoot: string, query: string, roots: string[], config: ContextDiscoveryConfig, maxResults: number, maxContextLines: number, timeoutMs: number): Promise<ColgrepRunResult> {
|
|
220
250
|
const args = ["--json", "-k", String(maxResults), "-n", String(maxContextLines), query, ...roots];
|
|
221
251
|
return await new Promise<ColgrepRunResult>((resolve) => {
|
|
222
252
|
let stdout = "";
|
|
@@ -231,8 +261,8 @@ async function runColgrep(repoRoot: string, query: string, roots: string[], conf
|
|
|
231
261
|
};
|
|
232
262
|
const timer = setTimeout(() => {
|
|
233
263
|
child.kill("SIGTERM");
|
|
234
|
-
finish({ ok: false, results: [], error: `
|
|
235
|
-
},
|
|
264
|
+
finish({ ok: false, results: [], error: `ColGREP exceeded ${String(timeoutMs)}ms; bounded grep fallback used. Retry with narrower paths for semantic ranking.` });
|
|
265
|
+
}, timeoutMs);
|
|
236
266
|
child.stdout.setEncoding("utf8");
|
|
237
267
|
child.stderr.setEncoding("utf8");
|
|
238
268
|
child.stdout.on("data", (chunk: string) => {
|
|
@@ -254,40 +284,62 @@ async function runColgrep(repoRoot: string, query: string, roots: string[], conf
|
|
|
254
284
|
});
|
|
255
285
|
}
|
|
256
286
|
|
|
257
|
-
function fallbackSearch(repoRoot: string, params: Required<Pick<ContextSearchParams, "query" | "mode">> & Pick<ContextSearchParams, "pattern" | "paths">, config: ContextDiscoveryConfig, maxResults: number, maxContextLines: number): { results: NormalizedContextResult[]; rejectedPaths: string[]; roots: string[] } {
|
|
287
|
+
function fallbackSearch(repoRoot: string, params: Required<Pick<ContextSearchParams, "query" | "mode">> & Pick<ContextSearchParams, "pattern" | "paths">, config: ContextDiscoveryConfig, maxResults: number, maxContextLines: number): { results: NormalizedContextResult[]; rejectedPaths: string[]; roots: string[]; searchTerms: string[] } {
|
|
258
288
|
const { roots, rejected } = safeSearchRoots(repoRoot, config, params.paths);
|
|
259
289
|
const files: string[] = [];
|
|
260
290
|
for (const root of roots) collectFiles(repoRoot, root, config, files);
|
|
261
291
|
const needle = params.mode === "regex" ? params.pattern ?? params.query : params.query;
|
|
292
|
+
const queryLower = params.query.toLowerCase();
|
|
293
|
+
const searchTerms = params.mode === "regex" ? [] : extractFallbackSearchTerms(params.query);
|
|
262
294
|
let regex: RegExp | undefined;
|
|
263
295
|
if (params.mode === "regex") {
|
|
264
296
|
try { regex = new RegExp(needle, "iu"); } catch { regex = undefined; }
|
|
265
297
|
}
|
|
266
298
|
const results: NormalizedContextResult[] = [];
|
|
299
|
+
const rankedResults: NormalizedContextResult[] = [];
|
|
300
|
+
const pushRankedResult = (result: NormalizedContextResult): void => {
|
|
301
|
+
rankedResults.push(result);
|
|
302
|
+
if (rankedResults.length > FALLBACK_CANDIDATE_BUDGET) {
|
|
303
|
+
rankedResults.sort((left, right) => (right.score ?? 0) - (left.score ?? 0) || left.ref.localeCompare(right.ref));
|
|
304
|
+
rankedResults.length = FALLBACK_CANDIDATE_BUDGET;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
267
307
|
for (const path of [...new Set(files)].sort()) {
|
|
268
|
-
if (results.length >= maxResults) break;
|
|
308
|
+
if ((params.mode === "files" || params.mode === "regex") && results.length >= maxResults) break;
|
|
269
309
|
if (params.mode === "files") {
|
|
270
|
-
if (!path.toLowerCase().includes(
|
|
310
|
+
if (!path.toLowerCase().includes(queryLower)) continue;
|
|
271
311
|
results.push({ path, ref: path, preview: path });
|
|
272
312
|
continue;
|
|
273
313
|
}
|
|
274
314
|
const lines = readFileSync(join(repoRoot, path), "utf8").split(/\r?\n/u);
|
|
275
315
|
for (let index = 0; index < lines.length; index += 1) {
|
|
276
|
-
const
|
|
316
|
+
const lineText = lines[index];
|
|
317
|
+
const score = regex ? undefined : fallbackLineScore(lineText.toLowerCase(), queryLower, searchTerms);
|
|
318
|
+
const matched = regex ? regex.test(lineText) : (score ?? 0) > 0;
|
|
277
319
|
if (!matched) continue;
|
|
278
320
|
const start = Math.max(0, index - maxContextLines);
|
|
279
321
|
const end = Math.min(lines.length, index + maxContextLines + 1);
|
|
280
|
-
|
|
322
|
+
const result = {
|
|
281
323
|
path,
|
|
282
324
|
line: index + 1,
|
|
283
325
|
ref: `${path}:${index + 1}`,
|
|
284
|
-
preview:
|
|
326
|
+
preview: lineText.trim().slice(0, 240),
|
|
285
327
|
context: lines.slice(start, end).map((text, offset) => ({ line: start + offset + 1, text: text.slice(0, 240) })),
|
|
286
|
-
|
|
287
|
-
|
|
328
|
+
score,
|
|
329
|
+
} satisfies NormalizedContextResult;
|
|
330
|
+
if (regex) {
|
|
331
|
+
results.push(result);
|
|
332
|
+
if (results.length >= maxResults) break;
|
|
333
|
+
} else {
|
|
334
|
+
pushRankedResult(result);
|
|
335
|
+
}
|
|
288
336
|
}
|
|
289
337
|
}
|
|
290
|
-
|
|
338
|
+
if (params.mode !== "files" && params.mode !== "regex") {
|
|
339
|
+
rankedResults.sort((left, right) => (right.score ?? 0) - (left.score ?? 0) || left.ref.localeCompare(right.ref));
|
|
340
|
+
results.push(...rankedResults.slice(0, maxResults));
|
|
341
|
+
}
|
|
342
|
+
return { results, rejectedPaths: rejected, roots, searchTerms };
|
|
291
343
|
}
|
|
292
344
|
|
|
293
345
|
export async function runContextSearch(repoRoot: string, input: ContextSearchParams): Promise<Record<string, unknown>> {
|
|
@@ -296,14 +348,16 @@ export async function runContextSearch(repoRoot: string, input: ContextSearchPar
|
|
|
296
348
|
const mode = input.mode ?? "auto";
|
|
297
349
|
const maxResults = clampInteger(input.max_results, config.limits.maxResults, 1, 50);
|
|
298
350
|
const maxContextLines = clampInteger(input.max_context_lines, config.limits.maxContextLines, 0, 5);
|
|
351
|
+
const colgrepTimeoutMs = getColgrepTimeoutMs(config);
|
|
299
352
|
const detection = detectColgrep(repoRoot);
|
|
300
353
|
const { roots, rejected } = safeSearchRoots(repoRoot, config, input.paths);
|
|
301
354
|
let provider = detection.ready ? "colgrep" : "grep-fallback";
|
|
302
355
|
let fallback = !detection.ready;
|
|
303
356
|
let fallbackReason = detection.ready ? undefined : detection.guidance;
|
|
357
|
+
let fallbackSearchTerms: string[] = [];
|
|
304
358
|
let results: NormalizedContextResult[] = [];
|
|
305
359
|
if (detection.ready && mode !== "regex" && mode !== "files") {
|
|
306
|
-
const colgrep = await runColgrep(repoRoot, query, roots, config, maxResults, maxContextLines);
|
|
360
|
+
const colgrep = await runColgrep(repoRoot, query, roots, config, maxResults, maxContextLines, colgrepTimeoutMs);
|
|
307
361
|
if (colgrep.ok) results = colgrep.results;
|
|
308
362
|
else {
|
|
309
363
|
provider = "grep-fallback";
|
|
@@ -316,8 +370,14 @@ export async function runContextSearch(repoRoot: string, input: ContextSearchPar
|
|
|
316
370
|
fallbackReason = `${mode} mode uses exact grep/find fallback for deterministic results.`;
|
|
317
371
|
}
|
|
318
372
|
if (fallback || results.length === 0) {
|
|
373
|
+
if (!fallback) {
|
|
374
|
+
provider = "grep-fallback";
|
|
375
|
+
fallback = true;
|
|
376
|
+
fallbackReason = "ColGREP returned no compact refs; tokenized grep fallback used.";
|
|
377
|
+
}
|
|
319
378
|
const fallbackResult = fallbackSearch(repoRoot, { query, mode, pattern: input.pattern, paths: input.paths }, config, maxResults, maxContextLines);
|
|
320
379
|
results = fallbackResult.results;
|
|
380
|
+
fallbackSearchTerms = fallbackResult.searchTerms;
|
|
321
381
|
}
|
|
322
382
|
const refs = results.map((item) => item.ref);
|
|
323
383
|
return {
|
|
@@ -334,10 +394,11 @@ export async function runContextSearch(repoRoot: string, input: ContextSearchPar
|
|
|
334
394
|
results,
|
|
335
395
|
searchedRoots: roots,
|
|
336
396
|
rejectedPaths: rejected,
|
|
337
|
-
limits: { maxResults, maxContextLines },
|
|
397
|
+
limits: { maxResults, maxContextLines, colgrepTimeoutMs },
|
|
398
|
+
fallbackSearchTerms,
|
|
338
399
|
recommendedVerification: refs.length > 0
|
|
339
|
-
? [`read ${results[0]?.path ?? roots[0] ?? "."}`, "
|
|
340
|
-
: [
|
|
400
|
+
? [`read ${results[0]?.path ?? roots[0] ?? "."}`, "Then grep exact identifiers/strings for proof; rerun zob_context_search at context pivots or when fallback_status suggests narrower paths."]
|
|
401
|
+
: [buildFallbackVerificationCommand(query, roots, fallbackSearchTerms, mode, input.pattern), "If low-signal or ambiguous, rerun zob_context_search with narrower paths/query, then read exact files."],
|
|
341
402
|
safety: { repoRelativeOnly: true, forbiddenPathsExcluded: config.excludePaths, rawPromptOrConversationPersisted: false, autoInstall: false },
|
|
342
403
|
};
|
|
343
404
|
}
|
|
@@ -19,8 +19,11 @@ export function summarizeGoalTodos(todoState: GoalTodoState, goalId?: string): G
|
|
|
19
19
|
const validationFailed = nodes.filter((node) => node.validation?.status === "failed" || node.validation?.status === "blocked" || node.validation?.status === "warn").length;
|
|
20
20
|
const needsUser = nodes.filter((node) => node.status === "needs_user").length;
|
|
21
21
|
const needsOracle = nodes.filter((node) => node.status === "needs_oracle").length;
|
|
22
|
-
const
|
|
23
|
-
const
|
|
22
|
+
const hasOpenChildren = (node: GoalTodoNode): boolean => nodes.some((candidate) => candidate.parentId === node.id && OPEN_REQUIRED_STATUSES.has(candidate.status));
|
|
23
|
+
const agentCandidates = nodes.filter((node) => node.owner === "agent" && (node.status === "ready" || node.status === "planned" || node.status === "in_progress"));
|
|
24
|
+
const nextAgent = agentCandidates.find((node) => !hasOpenChildren(node)) ?? agentCandidates[0];
|
|
25
|
+
const userCandidates = nodes.filter((node) => ACTIONABLE_STATUSES.has(node.status) && (node.owner === "user" || node.status === "needs_user"));
|
|
26
|
+
const nextUser = userCandidates.find((node) => !hasOpenChildren(node)) ?? userCandidates[0];
|
|
24
27
|
return {
|
|
25
28
|
goalId,
|
|
26
29
|
total: nodes.length,
|