takomi 2.1.2 → 2.1.3

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 (49) hide show
  1. package/.pi/README.md +124 -124
  2. package/.pi/agents/architect.md +15 -15
  3. package/.pi/agents/coder.md +14 -14
  4. package/.pi/agents/designer.md +17 -17
  5. package/.pi/agents/orchestrator.md +22 -22
  6. package/.pi/agents/reviewer.md +16 -16
  7. package/.pi/extensions/oauth-router/README.md +125 -125
  8. package/.pi/extensions/oauth-router/commands.ts +380 -380
  9. package/.pi/extensions/oauth-router/config.ts +200 -200
  10. package/.pi/extensions/oauth-router/index.ts +41 -41
  11. package/.pi/extensions/oauth-router/oauth-flow.ts +154 -154
  12. package/.pi/extensions/oauth-router/oauth-store.ts +121 -121
  13. package/.pi/extensions/oauth-router/package.json +14 -14
  14. package/.pi/extensions/oauth-router/policies.ts +27 -27
  15. package/.pi/extensions/oauth-router/provider.ts +492 -492
  16. package/.pi/extensions/oauth-router/scripts/vibe-verify.py +98 -98
  17. package/.pi/extensions/oauth-router/state.ts +174 -174
  18. package/.pi/extensions/oauth-router/types.ts +153 -153
  19. package/.pi/extensions/takomi-runtime/command-text.ts +130 -130
  20. package/.pi/extensions/takomi-runtime/commands.ts +179 -179
  21. package/.pi/extensions/takomi-runtime/context-panel.ts +282 -282
  22. package/.pi/extensions/takomi-runtime/index.ts +1288 -1288
  23. package/.pi/extensions/takomi-runtime/profile.ts +114 -114
  24. package/.pi/extensions/takomi-runtime/routing-policy.ts +105 -105
  25. package/.pi/extensions/takomi-runtime/shared.ts +492 -492
  26. package/.pi/extensions/takomi-runtime/subagent-controller.ts +364 -364
  27. package/.pi/extensions/takomi-runtime/subagent-render.ts +501 -501
  28. package/.pi/extensions/takomi-runtime/subagent-types.ts +83 -83
  29. package/.pi/extensions/takomi-runtime/ui.ts +133 -133
  30. package/.pi/extensions/takomi-subagents/agent-aliases.ts +18 -18
  31. package/.pi/extensions/takomi-subagents/agents.ts +113 -113
  32. package/.pi/extensions/takomi-subagents/delegation-plan.ts +95 -95
  33. package/.pi/extensions/takomi-subagents/dispatch-helpers.ts +26 -26
  34. package/.pi/extensions/takomi-subagents/dispatch.ts +215 -215
  35. package/.pi/extensions/takomi-subagents/index.ts +75 -75
  36. package/.pi/extensions/takomi-subagents/live-updates.ts +83 -83
  37. package/.pi/extensions/takomi-subagents/native-render.ts +174 -174
  38. package/.pi/extensions/takomi-subagents/tool-runner.ts +209 -209
  39. package/.pi/themes/takomi-noir.json +81 -81
  40. package/package.json +59 -59
  41. package/src/doctor.js +87 -84
  42. package/src/pi-harness.js +355 -351
  43. package/src/pi-installer.js +193 -171
  44. package/src/pi-takomi-core/index.ts +4 -4
  45. package/src/pi-takomi-core/orchestration.ts +402 -402
  46. package/src/pi-takomi-core/routing.ts +93 -93
  47. package/src/pi-takomi-core/types.ts +173 -173
  48. package/src/pi-takomi-core/workflows.ts +299 -299
  49. package/src/skills-installer.js +101 -101
@@ -1,171 +1,193 @@
1
- import fs from 'fs-extra';
2
- import os from 'os';
3
- import path from 'path';
4
- import crypto from 'crypto';
5
- import pc from 'picocolors';
6
- import { PATHS } from './utils.js';
7
- import { getPiGlobalTargets } from './pi-harness.js';
8
-
9
- const HOME = os.homedir();
10
- const TAKOMI_HOME = path.join(HOME, '.takomi');
11
- export const PI_MANIFEST_PATH = path.join(TAKOMI_HOME, 'pi-manifest.json');
12
-
13
- function sha256(value) {
14
- return crypto.createHash('sha256').update(value).digest('hex');
15
- }
16
-
17
- async function hashPath(targetPath) {
18
- if (!await fs.pathExists(targetPath)) return null;
19
- const stat = await fs.stat(targetPath);
20
- if (stat.isFile()) {
21
- const buf = await fs.readFile(targetPath);
22
- return sha256(buf);
23
- }
24
-
25
- const entries = [];
26
- async function walk(dir, prefix = '') {
27
- const names = (await fs.readdir(dir)).sort();
28
- for (const name of names) {
29
- const full = path.join(dir, name);
30
- const rel = path.join(prefix, name).replace(/\\/g, '/');
31
- const st = await fs.stat(full);
32
- if (st.isDirectory()) {
33
- entries.push(`dir:${rel}`);
34
- await walk(full, rel);
35
- } else {
36
- const buf = await fs.readFile(full);
37
- entries.push(`file:${rel}:${sha256(buf)}`);
38
- }
39
- }
40
- }
41
- await walk(targetPath);
42
- return sha256(entries.join('\n'));
43
- }
44
-
45
- async function pathIsSameSymlink(dest, src) {
46
- try {
47
- const stat = await fs.lstat(dest);
48
- if (!stat.isSymbolicLink()) return false;
49
- const target = await fs.readlink(dest);
50
- const resolvedTarget = path.resolve(path.dirname(dest), target);
51
- return path.resolve(src) === resolvedTarget;
52
- } catch {
53
- return false;
54
- }
55
- }
56
-
57
- async function prepareOwnedTarget(src, dest) {
58
- if (await pathIsSameSymlink(dest, src)) return 'symlink';
59
- if (!await fs.pathExists(dest)) return 'copy';
60
- const stat = await fs.lstat(dest);
61
- if (stat.isSymbolicLink()) {
62
- await fs.remove(dest);
63
- return 'copy';
64
- }
65
- return 'copy';
66
- }
67
-
68
- async function copyOwnedDirectory(src, dest) {
69
- await fs.ensureDir(path.dirname(dest));
70
- const mode = await prepareOwnedTarget(src, dest);
71
- if (mode === 'symlink') return hashPath(src);
72
- await fs.copy(src, dest, { overwrite: true });
73
- return hashPath(dest);
74
- }
75
-
76
- async function copyOwnedFile(src, dest) {
77
- await fs.ensureDir(path.dirname(dest));
78
- const mode = await prepareOwnedTarget(src, dest);
79
- if (mode === 'symlink') return hashPath(src);
80
- await fs.copy(src, dest, { overwrite: true });
81
- return hashPath(dest);
82
- }
83
-
84
- export async function readPiInstallManifest() {
85
- try {
86
- if (await fs.pathExists(PI_MANIFEST_PATH)) return await fs.readJson(PI_MANIFEST_PATH);
87
- } catch {}
88
- return null;
89
- }
90
-
91
- export async function writePiInstallManifest(manifest) {
92
- await fs.ensureDir(TAKOMI_HOME);
93
- await fs.writeJson(PI_MANIFEST_PATH, manifest, { spaces: 2 });
94
- }
95
-
96
- export async function installPiHarnessAssets(version = 'unknown') {
97
- const srcRoot = PATHS.pi;
98
- const targets = getPiGlobalTargets();
99
-
100
- const copied = {};
101
-
102
- const readmeSrc = path.join(srcRoot, 'README.md');
103
- if (await fs.pathExists(readmeSrc)) {
104
- copied.readme = await copyOwnedFile(readmeSrc, path.join(targets.root, 'README.md'));
105
- }
106
-
107
- const extensionNames = ['takomi-runtime', 'takomi-subagents', 'oauth-router'];
108
- for (const name of extensionNames) {
109
- const src = path.join(srcRoot, 'extensions', name);
110
- if (await fs.pathExists(src)) {
111
- copied[`extension:${name}`] = await copyOwnedDirectory(src, path.join(targets.extensions, name));
112
- }
113
- }
114
-
115
- const owned = {
116
- prompts: { src: path.join(srcRoot, 'prompts'), dest: targets.prompts, type: 'dir' },
117
- agents: { src: path.join(srcRoot, 'agents'), dest: targets.agents, type: 'dir' },
118
- themes: { src: path.join(srcRoot, 'themes'), dest: targets.themes, type: 'dir' },
119
- };
120
-
121
- for (const [key, entry] of Object.entries(owned)) {
122
- if (!await fs.pathExists(entry.src)) continue;
123
- copied[key] = entry.type === 'dir'
124
- ? await copyOwnedDirectory(entry.src, entry.dest)
125
- : await copyOwnedFile(entry.src, entry.dest);
126
- }
127
-
128
- const manifest = {
129
- takomiVersion: version,
130
- installedAt: new Date().toISOString(),
131
- targetRoot: targets.root,
132
- owned: copied,
133
- preserved: {
134
- settings: targets.settings,
135
- routingPolicy: targets.routingPolicy,
136
- userStateDir: targets.takomi,
137
- },
138
- };
139
-
140
- await writePiInstallManifest(manifest);
141
- return { targets, manifest };
142
- }
143
-
144
- export async function syncPiHarnessAssets(version = 'unknown') {
145
- return installPiHarnessAssets(version);
146
- }
147
-
148
- export async function validatePiHarnessInstall() {
149
- const targets = getPiGlobalTargets();
150
- return {
151
- runtime: await fs.pathExists(path.join(targets.extensions, 'takomi-runtime')),
152
- subagents: await fs.pathExists(path.join(targets.extensions, 'takomi-subagents')),
153
- oauthRouter: await fs.pathExists(path.join(targets.extensions, 'oauth-router')),
154
- prompts: await fs.pathExists(targets.prompts),
155
- agents: await fs.pathExists(targets.agents),
156
- themes: await fs.pathExists(targets.themes),
157
- readme: await fs.pathExists(path.join(targets.root, 'README.md')),
158
- settingsPreserved: !await fs.pathExists(path.join(PATHS.pi, 'settings.json')) || true,
159
- };
160
- }
161
-
162
- export function printPiInstallSummary(result, validation) {
163
- console.log(pc.green('\n✔ Installed Takomi Pi harness assets'));
164
- console.log(pc.white(` Root: ${result.targets.root}`));
165
- console.log(pc.white(` Manifest: ${PI_MANIFEST_PATH}`));
166
- console.log(pc.white(` Extensions: ${validation.runtime && validation.subagents && validation.oauthRouter ? 'ok' : 'check needed'}`));
167
- console.log(pc.white(` Prompts: ${validation.prompts ? 'ok' : 'missing'}`));
168
- console.log(pc.white(` Agents: ${validation.agents ? 'ok' : 'missing'}`));
169
- console.log(pc.white(` Themes: ${validation.themes ? 'ok' : 'missing'}`));
170
- console.log(pc.dim('\nPreserved user-owned config: settings.json, takomi/model-routing.md, runtime session state.'));
171
- }
1
+ import fs from 'fs-extra';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import crypto from 'crypto';
5
+ import pc from 'picocolors';
6
+ import { PATHS } from './utils.js';
7
+ import { getPiGlobalTargets } from './pi-harness.js';
8
+
9
+ const HOME = os.homedir();
10
+ const TAKOMI_HOME = path.join(HOME, '.takomi');
11
+ export const PI_MANIFEST_PATH = path.join(TAKOMI_HOME, 'pi-manifest.json');
12
+
13
+ function sha256(value) {
14
+ return crypto.createHash('sha256').update(value).digest('hex');
15
+ }
16
+
17
+ async function hashPath(targetPath) {
18
+ if (!await fs.pathExists(targetPath)) return null;
19
+ const stat = await fs.stat(targetPath);
20
+ if (stat.isFile()) {
21
+ const buf = await fs.readFile(targetPath);
22
+ return sha256(buf);
23
+ }
24
+
25
+ const entries = [];
26
+ async function walk(dir, prefix = '') {
27
+ const names = (await fs.readdir(dir)).sort();
28
+ for (const name of names) {
29
+ const full = path.join(dir, name);
30
+ const rel = path.join(prefix, name).replace(/\\/g, '/');
31
+ const st = await fs.stat(full);
32
+ if (st.isDirectory()) {
33
+ entries.push(`dir:${rel}`);
34
+ await walk(full, rel);
35
+ } else {
36
+ const buf = await fs.readFile(full);
37
+ entries.push(`file:${rel}:${sha256(buf)}`);
38
+ }
39
+ }
40
+ }
41
+ await walk(targetPath);
42
+ return sha256(entries.join('\n'));
43
+ }
44
+
45
+ async function pathIsSameSymlink(dest, src) {
46
+ try {
47
+ const stat = await fs.lstat(dest);
48
+ if (!stat.isSymbolicLink()) return false;
49
+ const target = await fs.readlink(dest);
50
+ const resolvedTarget = path.resolve(path.dirname(dest), target);
51
+ return path.resolve(src) === resolvedTarget;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ async function prepareOwnedTarget(src, dest) {
58
+ if (await pathIsSameSymlink(dest, src)) return 'symlink';
59
+ if (!await fs.pathExists(dest)) return 'copy';
60
+ const stat = await fs.lstat(dest);
61
+ if (stat.isSymbolicLink()) {
62
+ await fs.remove(dest);
63
+ return 'copy';
64
+ }
65
+ return 'copy';
66
+ }
67
+
68
+ async function copyOwnedDirectory(src, dest) {
69
+ await fs.ensureDir(path.dirname(dest));
70
+ const mode = await prepareOwnedTarget(src, dest);
71
+ if (mode === 'symlink') return hashPath(src);
72
+ await fs.copy(src, dest, { overwrite: true });
73
+ return hashPath(dest);
74
+ }
75
+
76
+ async function copyOwnedFile(src, dest) {
77
+ await fs.ensureDir(path.dirname(dest));
78
+ const mode = await prepareOwnedTarget(src, dest);
79
+ if (mode === 'symlink') return hashPath(src);
80
+ await fs.copy(src, dest, { overwrite: true });
81
+ return hashPath(dest);
82
+ }
83
+
84
+ export async function readPiInstallManifest() {
85
+ try {
86
+ if (await fs.pathExists(PI_MANIFEST_PATH)) return await fs.readJson(PI_MANIFEST_PATH);
87
+ } catch {}
88
+ return null;
89
+ }
90
+
91
+ export async function writePiInstallManifest(manifest) {
92
+ await fs.ensureDir(TAKOMI_HOME);
93
+ await fs.writeJson(PI_MANIFEST_PATH, manifest, { spaces: 2 });
94
+ }
95
+
96
+ export async function installPiHarnessAssets(version = 'unknown') {
97
+ const srcRoot = PATHS.pi;
98
+ const targets = getPiGlobalTargets();
99
+
100
+ const copied = {};
101
+
102
+ const readmeSrc = path.join(srcRoot, 'README.md');
103
+ if (await fs.pathExists(readmeSrc)) {
104
+ copied.readme = await copyOwnedFile(readmeSrc, path.join(targets.root, 'README.md'));
105
+ }
106
+
107
+ const extensionNames = ['takomi-runtime', 'takomi-subagents', 'oauth-router'];
108
+ for (const name of extensionNames) {
109
+ const src = path.join(srcRoot, 'extensions', name);
110
+ if (await fs.pathExists(src)) {
111
+ copied[`extension:${name}`] = await copyOwnedDirectory(src, path.join(targets.extensions, name));
112
+ }
113
+ }
114
+
115
+ // Pi loads extensions from ~/.pi/agent/extensions. The runtime imports the
116
+ // shared Takomi core via ../../../src/pi-takomi-core, which resolves to
117
+ // ~/.pi/src/pi-takomi-core from an installed extension path.
118
+ const coreSrc = path.join(PATHS.root, 'src', 'pi-takomi-core');
119
+ const coreDest = path.join(path.dirname(targets.root), 'src', 'pi-takomi-core');
120
+ if (await fs.pathExists(coreSrc)) {
121
+ copied['core:pi-takomi-core'] = await copyOwnedDirectory(coreSrc, coreDest);
122
+ }
123
+
124
+ // Keep Pi extension module resolution self-contained for clean machines.
125
+ // Extension files import pi-subagents internals, so place the package where
126
+ // Node can resolve it while loading ~/.pi/agent/extensions/*.
127
+ const piSubagentsSrc = path.join(PATHS.root, 'node_modules', 'pi-subagents');
128
+ const piSubagentsDest = path.join(targets.root, 'node_modules', 'pi-subagents');
129
+ if (await fs.pathExists(piSubagentsSrc)) {
130
+ copied['node_module:pi-subagents'] = await copyOwnedDirectory(piSubagentsSrc, piSubagentsDest);
131
+ }
132
+
133
+ const owned = {
134
+ prompts: { src: path.join(srcRoot, 'prompts'), dest: targets.prompts, type: 'dir' },
135
+ agents: { src: path.join(srcRoot, 'agents'), dest: targets.agents, type: 'dir' },
136
+ themes: { src: path.join(srcRoot, 'themes'), dest: targets.themes, type: 'dir' },
137
+ };
138
+
139
+ for (const [key, entry] of Object.entries(owned)) {
140
+ if (!await fs.pathExists(entry.src)) continue;
141
+ copied[key] = entry.type === 'dir'
142
+ ? await copyOwnedDirectory(entry.src, entry.dest)
143
+ : await copyOwnedFile(entry.src, entry.dest);
144
+ }
145
+
146
+ const manifest = {
147
+ takomiVersion: version,
148
+ installedAt: new Date().toISOString(),
149
+ targetRoot: targets.root,
150
+ owned: copied,
151
+ preserved: {
152
+ settings: targets.settings,
153
+ routingPolicy: targets.routingPolicy,
154
+ userStateDir: targets.takomi,
155
+ },
156
+ };
157
+
158
+ await writePiInstallManifest(manifest);
159
+ return { targets, manifest };
160
+ }
161
+
162
+ export async function syncPiHarnessAssets(version = 'unknown') {
163
+ return installPiHarnessAssets(version);
164
+ }
165
+
166
+ export async function validatePiHarnessInstall() {
167
+ const targets = getPiGlobalTargets();
168
+ return {
169
+ runtime: await fs.pathExists(path.join(targets.extensions, 'takomi-runtime')),
170
+ subagents: await fs.pathExists(path.join(targets.extensions, 'takomi-subagents')),
171
+ oauthRouter: await fs.pathExists(path.join(targets.extensions, 'oauth-router')),
172
+ prompts: await fs.pathExists(targets.prompts),
173
+ agents: await fs.pathExists(targets.agents),
174
+ themes: await fs.pathExists(targets.themes),
175
+ readme: await fs.pathExists(path.join(targets.root, 'README.md')),
176
+ core: await fs.pathExists(path.join(path.dirname(targets.root), 'src', 'pi-takomi-core')),
177
+ piSubagentsModule: await fs.pathExists(path.join(targets.root, 'node_modules', 'pi-subagents')),
178
+ settingsPreserved: !await fs.pathExists(path.join(PATHS.pi, 'settings.json')) || true,
179
+ };
180
+ }
181
+
182
+ export function printPiInstallSummary(result, validation) {
183
+ console.log(pc.green('\n✔ Installed Takomi Pi harness assets'));
184
+ console.log(pc.white(` Root: ${result.targets.root}`));
185
+ console.log(pc.white(` Manifest: ${PI_MANIFEST_PATH}`));
186
+ console.log(pc.white(` Extensions: ${validation.runtime && validation.subagents && validation.oauthRouter ? 'ok' : 'check needed'}`));
187
+ console.log(pc.white(` Prompts: ${validation.prompts ? 'ok' : 'missing'}`));
188
+ console.log(pc.white(` Agents: ${validation.agents ? 'ok' : 'missing'}`));
189
+ console.log(pc.white(` Themes: ${validation.themes ? 'ok' : 'missing'}`));
190
+ console.log(pc.white(` Core: ${validation.core ? 'ok' : 'missing'}`));
191
+ console.log(pc.white(` Subagents: ${validation.piSubagentsModule ? 'ok' : 'missing module'}`));
192
+ console.log(pc.dim('\nPreserved user-owned config: settings.json, takomi/model-routing.md, runtime session state.'));
193
+ }
@@ -1,4 +1,4 @@
1
- export * from "./types";
2
- export * from "./workflows";
3
- export * from "./routing";
4
- export * from "./orchestration";
1
+ export * from "./types";
2
+ export * from "./workflows";
3
+ export * from "./routing";
4
+ export * from "./orchestration";