@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.
- package/dist/cli-help.d.ts +18 -0
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +32 -1
- package/dist/cli-help.js.map +1 -1
- package/dist/fanout.d.ts +56 -0
- package/dist/fanout.d.ts.map +1 -0
- package/dist/fanout.js +119 -0
- package/dist/fanout.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/loop.d.ts +13 -0
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +72 -7
- package/dist/loop.js.map +1 -1
- package/dist/model-tier.d.ts +69 -0
- package/dist/model-tier.d.ts.map +1 -0
- package/dist/model-tier.js +101 -0
- package/dist/model-tier.js.map +1 -0
- package/dist/plan-tasks.d.ts +44 -0
- package/dist/plan-tasks.d.ts.map +1 -0
- package/dist/plan-tasks.js +167 -0
- package/dist/plan-tasks.js.map +1 -0
- package/dist/run-bin.d.ts.map +1 -1
- package/dist/run-bin.js +20 -0
- package/dist/run-bin.js.map +1 -1
- package/dist/runner.d.ts +18 -14
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +12 -23
- package/dist/runner.js.map +1 -1
- package/dist/stage-exec.d.ts +13 -0
- package/dist/stage-exec.d.ts.map +1 -1
- package/dist/stage-exec.js +32 -1
- package/dist/stage-exec.js.map +1 -1
- package/dist/stages.d.ts +18 -0
- package/dist/stages.d.ts.map +1 -1
- package/dist/stages.js +17 -0
- package/dist/stages.js.map +1 -1
- package/dist/worktree.d.ts +24 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +43 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +1 -1
- package/templates/plan.md +26 -4
- package/templates/subtask.md +32 -0
package/dist/stage-exec.js
CHANGED
|
@@ -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
|
-
|
|
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
|
: {}),
|
package/dist/stage-exec.js.map
CHANGED
|
@@ -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;
|
|
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
|
package/dist/stages.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
package/dist/stages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stages.js","sourceRoot":"","sources":["../src/stages.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/worktree.js
ADDED
|
@@ -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
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 (
|
|
93
|
-
`docs(plan):` or `chore(plan):` commit. Then print a one-line
|
|
94
|
-
task-key and the number of plan tasks authored. Do not implement;
|
|
95
|
-
reviews the plan next.
|
|
114
|
+
Commit ONLY the spec + plan + (if written) the task graph — this 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
|