@phamvuhoang/otto-core 0.18.0 → 0.19.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.
Files changed (46) hide show
  1. package/dist/cli-help.d.ts +18 -0
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +32 -1
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/fanout.d.ts +56 -0
  6. package/dist/fanout.d.ts.map +1 -0
  7. package/dist/fanout.js +119 -0
  8. package/dist/fanout.js.map +1 -0
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +4 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/loop.d.ts +13 -0
  14. package/dist/loop.d.ts.map +1 -1
  15. package/dist/loop.js +72 -7
  16. package/dist/loop.js.map +1 -1
  17. package/dist/model-tier.d.ts +69 -0
  18. package/dist/model-tier.d.ts.map +1 -0
  19. package/dist/model-tier.js +101 -0
  20. package/dist/model-tier.js.map +1 -0
  21. package/dist/plan-tasks.d.ts +44 -0
  22. package/dist/plan-tasks.d.ts.map +1 -0
  23. package/dist/plan-tasks.js +167 -0
  24. package/dist/plan-tasks.js.map +1 -0
  25. package/dist/run-bin.d.ts.map +1 -1
  26. package/dist/run-bin.js +20 -0
  27. package/dist/run-bin.js.map +1 -1
  28. package/dist/runner.d.ts +18 -14
  29. package/dist/runner.d.ts.map +1 -1
  30. package/dist/runner.js +12 -23
  31. package/dist/runner.js.map +1 -1
  32. package/dist/stage-exec.d.ts +13 -0
  33. package/dist/stage-exec.d.ts.map +1 -1
  34. package/dist/stage-exec.js +32 -1
  35. package/dist/stage-exec.js.map +1 -1
  36. package/dist/stages.d.ts +18 -0
  37. package/dist/stages.d.ts.map +1 -1
  38. package/dist/stages.js +17 -0
  39. package/dist/stages.js.map +1 -1
  40. package/dist/worktree.d.ts +24 -0
  41. package/dist/worktree.d.ts.map +1 -0
  42. package/dist/worktree.js +43 -0
  43. package/dist/worktree.js.map +1 -0
  44. package/package.json +1 -1
  45. package/templates/plan.md +26 -4
  46. package/templates/subtask.md +32 -0
@@ -4,10 +4,18 @@ import { DEFAULT_AGENT } from "./agent-runtime.js";
4
4
  import { analyzeContext } from "./context-report.js";
5
5
  import { applyPromptReduction } from "./prompt-reduction.js";
6
6
  import { renderTemplate } from "./render.js";
7
+ import { resolveStageModel } from "./model-tier.js";
7
8
  import { DEFAULT_BACKOFF_MS, backoffFor, withRetries } from "./retry.js";
8
9
  import { getAgentRuntime, runStage, stageLogPath, } from "./runner.js";
9
10
  import { readSafetyPolicy, } from "./safety-policy.js";
10
11
  import { USE_COLOR, dim } from "./stream-render.js";
12
+ /** Fallback ladder when routing is requested without one — every tier resolves
13
+ * to the runtime default (issue #66 P11). The real ladder comes from run-bin. */
14
+ const EMPTY_LADDER = {
15
+ cheap: undefined,
16
+ mid: undefined,
17
+ strong: undefined,
18
+ };
11
19
  /** A policy violation found at a shell/@spill tag becomes a `blocked` trajectory
12
20
  * safety event — the command was denied and skipped, so Otto prevented it. */
13
21
  function violationToSafetyEvent(v) {
@@ -50,12 +58,35 @@ export async function executeStage(opts) {
50
58
  const { originalChars, reducedChars, cacheHits } = reduced.stats;
51
59
  process.stderr.write(`${dim(`prompt reduce ${originalChars} -> ${reducedChars} chars | cache hits ${cacheHits}`)}\n`);
52
60
  }
53
- const result = await runStage(stage, prompt, workspaceDir, iteration, spillHostDir, stageLog, { signal, runtime, sink: opts.sink });
61
+ // Route the model for this stage (issue #66 P11): a pin wins, else the
62
+ // declared tier through the ladder when routing is on, else runtime default.
63
+ const model = resolveStageModel({
64
+ runtimeId: opts.agentId ?? DEFAULT_AGENT,
65
+ stage,
66
+ routing: opts.modelRouting === true,
67
+ ladder: opts.tierLadder ?? EMPTY_LADDER,
68
+ assessment: opts.riskAssessment,
69
+ escalations: opts.escalations,
70
+ });
71
+ const result = await runStage(stage, prompt, workspaceDir, iteration, spillHostDir, stageLog, {
72
+ signal,
73
+ runtime,
74
+ sink: opts.sink,
75
+ modelSpec: model.spec,
76
+ sandboxWriteRoots: opts.sandboxWriteRoots,
77
+ });
54
78
  // Attribute the *final* prompt's window footprint by category (issue #62
55
79
  // P7). `prompt` is post-reduction, so the breakdown reflects what was sent.
56
80
  return {
57
81
  ...result,
58
82
  contextBreakdown: analyzeContext(prompt),
83
+ ...(model.tier
84
+ ? {
85
+ routedTier: model.tier,
86
+ routedModel: model.spec,
87
+ modelSource: model.source,
88
+ }
89
+ : {}),
59
90
  ...(violations.length > 0
60
91
  ? { safetyEvents: violations.map(violationToSafetyEvent) }
61
92
  : {}),
@@ -1 +1 @@
1
- {"version":3,"file":"stage-exec.js","sourceRoot":"","sources":["../src/stage-exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,aAAa,EAAuB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,YAAY,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAqBpD;+EAC+E;AAC/E,SAAS,sBAAsB,CAAC,CAAkB;IAChD,OAAO;QACL,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAyB;IAEzB,MAAM,EACJ,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,SAAS,EACT,UAAU,EACV,SAAS,GAAG,KAAK,EACjB,MAAM,GACP,GAAG,IAAI,CAAC;IACT,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC;IAC1C,MAAM,QAAQ,GAAG,SAAS,OAAO,CAAC,GAAG,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC5E,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5E,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,IAAI,aAAa,CAAC,CAAC;IAC/D,6EAA6E;IAC7E,+EAA+E;IAC/E,+EAA+E;IAC/E,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAE9C,OAAO,WAAW,CAChB,KAAK,IAAI,EAAE;QACT,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,UAAU,GAAsB,EAAE,CAAC;QACzC,IAAI,MAAM,GAAG,cAAc,CACzB,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,EAC7C,IAAI,EACJ;YACE,GAAG,EAAE,YAAY;YACjB,YAAY;YACZ,YAAY;YACZ,MAAM;YACN,iBAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;SAC7C,CACF,CAAC;QACF,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAC7C,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YACxB,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,iBAAiB,aAAa,OAAO,YAAY,uBAAuB,SAAS,EAAE,CAAC,IAAI,CAChG,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,KAAK,EACL,MAAM,EACN,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CACrC,CAAC;QACF,yEAAyE;QACzE,4EAA4E;QAC5E,OAAO;YACL,GAAG,MAAM;YACT,gBAAgB,EAAE,cAAc,CAAC,MAAM,CAAC;YACxC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;gBACvB,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE;gBAC1D,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC,EACD;QACE,GAAG,EAAE,UAAU;QACf,SAAS,EAAE,kBAAkB;QAC7B,SAAS,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;YAC1B,MAAM,IAAI,GAAG,UAAU,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,MAAM,GAAG,mBAAmB,OAAO,OAAO,UAAU,UAAU,IAAI,KAAK,CAAC;YAC9E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,GAAI,GAAa,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,CACnF,CAAC;YACF,IAAI,CAAC;gBACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,yDAAyD;YAC3D,CAAC;QACH,CAAC;KACF,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"stage-exec.js","sourceRoot":"","sources":["../src/stage-exec.ts"],"names":[],"mappings":"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"}
package/dist/stages.d.ts CHANGED
@@ -1,53 +1,71 @@
1
+ import type { ModelTier } from "./model-tier.js";
1
2
  export type Stage = {
2
3
  name: string;
3
4
  template: string;
4
5
  permissionMode?: string;
6
+ /** Difficulty tier for model routing (issue #66 P11). Absent ⇒ runtime default model. */
7
+ tier?: ModelTier;
5
8
  };
6
9
  export declare const STAGES: {
7
10
  plan: {
8
11
  name: string;
9
12
  template: string;
10
13
  permissionMode: string;
14
+ tier: "strong";
11
15
  };
12
16
  implementer: {
13
17
  name: string;
14
18
  template: string;
15
19
  permissionMode: string;
20
+ tier: "mid";
16
21
  };
17
22
  ghafkImplementer: {
18
23
  name: string;
19
24
  template: string;
20
25
  permissionMode: string;
26
+ tier: "mid";
21
27
  };
22
28
  ghafkIssueImplementer: {
23
29
  name: string;
24
30
  template: string;
25
31
  permissionMode: string;
32
+ tier: "mid";
26
33
  };
27
34
  linearImplementer: {
28
35
  name: string;
29
36
  template: string;
30
37
  permissionMode: string;
38
+ tier: "mid";
31
39
  };
32
40
  linearIssueImplementer: {
33
41
  name: string;
34
42
  template: string;
35
43
  permissionMode: string;
44
+ tier: "mid";
36
45
  };
37
46
  verifier: {
38
47
  name: string;
39
48
  template: string;
40
49
  permissionMode: string;
50
+ tier: "strong";
41
51
  };
42
52
  applyReviewImplementer: {
43
53
  name: string;
44
54
  template: string;
45
55
  permissionMode: string;
56
+ tier: "strong";
46
57
  };
47
58
  reviewer: {
48
59
  name: string;
49
60
  template: string;
50
61
  permissionMode: string;
62
+ tier: "strong";
63
+ };
64
+ subImplementer: {
65
+ name: string;
66
+ template: string;
67
+ permissionMode: string;
68
+ tier: "mid";
51
69
  };
52
70
  };
53
71
  //# sourceMappingURL=stages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stages.d.ts","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAOF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDlB,CAAC"}
1
+ {"version":3,"file":"stages.d.ts","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAAC;AAOF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiElB,CAAC"}
package/dist/stages.js CHANGED
@@ -10,46 +10,63 @@ export const STAGES = {
10
10
  name: "plan",
11
11
  template: "plan.md",
12
12
  permissionMode: "bypassPermissions",
13
+ tier: "strong",
13
14
  },
14
15
  implementer: {
15
16
  name: "implementer",
16
17
  template: "afk.md",
17
18
  permissionMode: "bypassPermissions",
19
+ tier: "mid",
18
20
  },
19
21
  ghafkImplementer: {
20
22
  name: "ghafk-implementer",
21
23
  template: "ghafk.md",
22
24
  permissionMode: "bypassPermissions",
25
+ tier: "mid",
23
26
  },
24
27
  ghafkIssueImplementer: {
25
28
  name: "ghafk-issue-implementer",
26
29
  template: "ghafk-issue.md",
27
30
  permissionMode: "bypassPermissions",
31
+ tier: "mid",
28
32
  },
29
33
  linearImplementer: {
30
34
  name: "linear-implementer",
31
35
  template: "linearafk.md",
32
36
  permissionMode: "bypassPermissions",
37
+ tier: "mid",
33
38
  },
34
39
  linearIssueImplementer: {
35
40
  name: "linear-issue-implementer",
36
41
  template: "linearafk-issue.md",
37
42
  permissionMode: "bypassPermissions",
43
+ tier: "mid",
38
44
  },
39
45
  verifier: {
40
46
  name: "verifier",
41
47
  template: "verify.md",
42
48
  permissionMode: "bypassPermissions",
49
+ tier: "strong",
43
50
  },
44
51
  applyReviewImplementer: {
45
52
  name: "apply-review-implementer",
46
53
  template: "apply-review.md",
47
54
  permissionMode: "bypassPermissions",
55
+ tier: "strong",
48
56
  },
49
57
  reviewer: {
50
58
  name: "reviewer",
51
59
  template: "review.md",
52
60
  permissionMode: "bypassPermissions",
61
+ tier: "strong",
62
+ },
63
+ // One fanned-out plan task, run in an isolated worktree with bounded context
64
+ // (issue #66 P11). Mechanical-to-moderate per-task work → mid tier.
65
+ subImplementer: {
66
+ name: "sub-implementer",
67
+ template: "subtask.md",
68
+ permissionMode: "bypassPermissions",
69
+ tier: "mid",
53
70
  },
54
71
  };
55
72
  //# sourceMappingURL=stages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stages.js","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAMA,gFAAgF;AAChF,8EAA8E;AAC9E,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,yEAAyE;IACzE,4EAA4E;IAC5E,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,mBAAmB;KACpB;IACjB,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,QAAQ;QAClB,cAAc,EAAE,mBAAmB;KACpB;IACjB,gBAAgB,EAAE;QAChB,IAAI,EAAE,mBAAmB;QACzB,QAAQ,EAAE,UAAU;QACpB,cAAc,EAAE,mBAAmB;KACpB;IACjB,qBAAqB,EAAE;QACrB,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE,gBAAgB;QAC1B,cAAc,EAAE,mBAAmB;KACpB;IACjB,iBAAiB,EAAE;QACjB,IAAI,EAAE,oBAAoB;QAC1B,QAAQ,EAAE,cAAc;QACxB,cAAc,EAAE,mBAAmB;KACpB;IACjB,sBAAsB,EAAE;QACtB,IAAI,EAAE,0BAA0B;QAChC,QAAQ,EAAE,oBAAoB;QAC9B,cAAc,EAAE,mBAAmB;KACpB;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,mBAAmB;KACpB;IACjB,sBAAsB,EAAE;QACtB,IAAI,EAAE,0BAA0B;QAChC,QAAQ,EAAE,iBAAiB;QAC3B,cAAc,EAAE,mBAAmB;KACpB;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,mBAAmB;KACpB;CAClB,CAAC"}
1
+ {"version":3,"file":"stages.js","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"AAUA,gFAAgF;AAChF,8EAA8E;AAC9E,iFAAiF;AACjF,kFAAkF;AAClF,gFAAgF;AAChF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,yEAAyE;IACzE,4EAA4E;IAC5E,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,QAAQ;KACC;IACjB,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,QAAQ;QAClB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;IACjB,gBAAgB,EAAE;QAChB,IAAI,EAAE,mBAAmB;QACzB,QAAQ,EAAE,UAAU;QACpB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;IACjB,qBAAqB,EAAE;QACrB,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE,gBAAgB;QAC1B,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;IACjB,iBAAiB,EAAE;QACjB,IAAI,EAAE,oBAAoB;QAC1B,QAAQ,EAAE,cAAc;QACxB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;IACjB,sBAAsB,EAAE;QACtB,IAAI,EAAE,0BAA0B;QAChC,QAAQ,EAAE,oBAAoB;QAC9B,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,QAAQ;KACC;IACjB,sBAAsB,EAAE;QACtB,IAAI,EAAE,0BAA0B;QAChC,QAAQ,EAAE,iBAAiB;QAC3B,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,QAAQ;KACC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,WAAW;QACrB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,QAAQ;KACC;IACjB,6EAA6E;IAC7E,oEAAoE;IACpE,cAAc,EAAE;QACd,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,YAAY;QACtB,cAAc,EAAE,mBAAmB;QACnC,IAAI,EAAE,KAAK;KACI;CAClB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Git-worktree isolation for sub-agent fan-out (issue #66 P11). Each parallel
3
+ * sub-agent runs in its own worktree under `.otto-tmp/wt/<id>` — a separate
4
+ * working directory sharing the repo's object store, so the agents never clobber
5
+ * each other's files. The dir is inside the workspace, so the native OS sandbox
6
+ * still confines writes. `.otto-tmp/` is already gitignored.
7
+ */
8
+ /**
9
+ * Create an isolated worktree at HEAD under `.otto-tmp/wt/<id>`. `--detach` so
10
+ * the sub-agent commits onto a detached HEAD without creating or moving a branch.
11
+ * `cleanup()` removes the worktree (and its dir); it is idempotent and safe to
12
+ * call from a `finally`.
13
+ */
14
+ export declare function createWorktree(workspaceDir: string, id: string): {
15
+ dir: string;
16
+ cleanup: () => void;
17
+ };
18
+ /**
19
+ * Prune leftover worktrees from a crashed prior run: remove the `.otto-tmp/wt`
20
+ * tree wholesale, then GC git's worktree registry so the stale entries don't
21
+ * linger. Call once before a fan-out round.
22
+ */
23
+ export declare function reapWorktrees(workspaceDir: string): void;
24
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,MAAM,GACT;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAetC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAGxD"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Git-worktree isolation for sub-agent fan-out (issue #66 P11). Each parallel
3
+ * sub-agent runs in its own worktree under `.otto-tmp/wt/<id>` — a separate
4
+ * working directory sharing the repo's object store, so the agents never clobber
5
+ * each other's files. The dir is inside the workspace, so the native OS sandbox
6
+ * still confines writes. `.otto-tmp/` is already gitignored.
7
+ */
8
+ import { rmSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { git } from "./git.js";
11
+ /**
12
+ * Create an isolated worktree at HEAD under `.otto-tmp/wt/<id>`. `--detach` so
13
+ * the sub-agent commits onto a detached HEAD without creating or moving a branch.
14
+ * `cleanup()` removes the worktree (and its dir); it is idempotent and safe to
15
+ * call from a `finally`.
16
+ */
17
+ export function createWorktree(workspaceDir, id) {
18
+ const rel = join(".otto-tmp", "wt", id);
19
+ const dir = join(workspaceDir, rel);
20
+ // Remove any stale worktree at this path first (a crashed prior run), then add.
21
+ git(["worktree", "remove", "--force", dir], workspaceDir);
22
+ rmSync(dir, { recursive: true, force: true });
23
+ git(["worktree", "add", "--detach", dir, "HEAD"], workspaceDir);
24
+ let cleaned = false;
25
+ const cleanup = () => {
26
+ if (cleaned)
27
+ return;
28
+ cleaned = true;
29
+ git(["worktree", "remove", "--force", dir], workspaceDir);
30
+ rmSync(dir, { recursive: true, force: true });
31
+ };
32
+ return { dir, cleanup };
33
+ }
34
+ /**
35
+ * Prune leftover worktrees from a crashed prior run: remove the `.otto-tmp/wt`
36
+ * tree wholesale, then GC git's worktree registry so the stale entries don't
37
+ * linger. Call once before a fan-out round.
38
+ */
39
+ export function reapWorktrees(workspaceDir) {
40
+ rmSync(join(workspaceDir, ".otto-tmp", "wt"), { recursive: true, force: true });
41
+ git(["worktree", "prune"], workspaceDir);
42
+ }
43
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,YAAoB,EACpB,EAAU;IAEV,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACpC,gFAAgF;IAChF,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;IAChE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;QAC1D,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,YAAoB;IAChD,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;AAC3C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phamvuhoang/otto-core",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Claude Code AFK orchestration: iteration loop, native-sandbox runner, template renderer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/templates/plan.md CHANGED
@@ -87,9 +87,31 @@ Use the `Write` tool. An ordered checklist of **bite-sized, testable tasks**, on
87
87
  Keep tasks ordered so each is gated on the prior; name the test file that pins
88
88
  each task.
89
89
 
90
+ ## 4b. WRITE THE TASK GRAPH (optional) — `.otto/tasks/<task-key>/tasks.json`
91
+
92
+ Use the `Write` tool to also emit a machine-readable task graph so Otto can fan
93
+ independent tasks out to isolated sub-agents (issue #66 P11). Shape:
94
+
95
+ ```json
96
+ {
97
+ "version": 1,
98
+ "tasks": [
99
+ { "id": "t1", "title": "<short>", "fileScope": ["path/you/expect/to/touch"], "dependsOn": [], "parallelSafe": true },
100
+ { "id": "t2", "title": "<short>", "fileScope": ["other/path"], "dependsOn": ["t1"], "parallelSafe": false }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ Rules: `id` unique; `dependsOn` lists earlier task ids that must land first;
106
+ `fileScope` lists the files the task is expected to edit; set `parallelSafe`
107
+ **true only when** the task shares no files and no ordering with its siblings —
108
+ **be conservative and default to `false` when unsure**. This file is OPTIONAL:
109
+ if the work does not decompose into cleanly independent tasks, omit it and the
110
+ run proceeds sequentially. A malformed file is ignored (fan-out simply disabled).
111
+
90
112
  ## 5. COMMIT
91
113
 
92
- Commit ONLY the spec + plan (and this is the whole runno code). Use a
93
- `docs(plan):` or `chore(plan):` commit. Then print a one-line summary of the
94
- task-key and the number of plan tasks authored. Do not implement; the human
95
- reviews the plan next.
114
+ Commit ONLY the spec + plan + (if written) the task graphthis is the whole
115
+ run, no code. Use a `docs(plan):` or `chore(plan):` commit. Then print a one-line
116
+ summary of the task-key and the number of plan tasks authored. Do not implement;
117
+ the human reviews the plan next.
@@ -0,0 +1,32 @@
1
+ {{ RESUME }}
2
+
3
+ <learnings>
4
+
5
+ !?`cat ./.otto/LEARNINGS.md|||_No learnings recorded yet._`
6
+
7
+ </learnings>
8
+
9
+ <task>
10
+
11
+ You are implementing **one** task in an isolated worktree, as part of a parallel
12
+ fan-out (issue #66 P11). Do the whole task and nothing else.
13
+
14
+ **Task:** {{ TASK_TITLE }}
15
+
16
+ **Files you are expected to touch (your scope — do not edit files outside it):**
17
+
18
+ ```
19
+ {{ TASK_SCOPE }}
20
+ ```
21
+
22
+ Stay strictly within that file scope: a sibling sub-agent owns every other file
23
+ in parallel, so editing outside your scope will collide at merge time. If the
24
+ task genuinely cannot be done without touching a file outside the scope, do as
25
+ much as you safely can within scope and note the gap in your commit message.
26
+
27
+ Write the failing test first where it applies, implement, run the relevant
28
+ feedback loop, and make a single focused commit for this task. Do not push.
29
+
30
+ </task>
31
+
32
+ @include:prompt.md