projectinator 0.3.0 → 0.4.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/README.md +30 -11
- package/bin/projectinator.mjs +56 -11
- package/dist/bakeoff.js +163 -0
- package/dist/bakeoff.js.map +1 -0
- package/dist/build-state.js +26 -0
- package/dist/build-state.js.map +1 -0
- package/dist/burndown.js +19 -0
- package/dist/burndown.js.map +1 -0
- package/dist/calibration.js +86 -0
- package/dist/calibration.js.map +1 -0
- package/dist/cli.js +289 -0
- package/dist/cli.js.map +1 -0
- package/dist/cost.js +35 -0
- package/dist/cost.js.map +1 -0
- package/dist/council.js +147 -0
- package/dist/council.js.map +1 -0
- package/dist/demo.js +93 -0
- package/dist/demo.js.map +1 -0
- package/dist/estimate.js +98 -0
- package/dist/estimate.js.map +1 -0
- package/dist/executor.js +118 -0
- package/dist/executor.js.map +1 -0
- package/dist/git.js +82 -0
- package/dist/git.js.map +1 -0
- package/dist/intake.js +98 -0
- package/dist/intake.js.map +1 -0
- package/dist/models.js +171 -0
- package/dist/models.js.map +1 -0
- package/dist/narrate.js +76 -0
- package/dist/narrate.js.map +1 -0
- package/dist/openrouter.js +112 -0
- package/dist/openrouter.js.map +1 -0
- package/dist/orchestrator.js +273 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pm.js +245 -0
- package/dist/pm.js.map +1 -0
- package/dist/preview.js +194 -0
- package/dist/preview.js.map +1 -0
- package/dist/registry-store.js +38 -0
- package/dist/registry-store.js.map +1 -0
- package/dist/registry.js +115 -0
- package/dist/registry.js.map +1 -0
- package/dist/research.js +98 -0
- package/dist/research.js.map +1 -0
- package/dist/retro.js +83 -0
- package/dist/retro.js.map +1 -0
- package/dist/roles.js +357 -0
- package/dist/roles.js.map +1 -0
- package/dist/router.js +95 -0
- package/dist/router.js.map +1 -0
- package/dist/run-bakeoff.js +68 -0
- package/dist/run-bakeoff.js.map +1 -0
- package/dist/run-build.js +193 -0
- package/dist/run-build.js.map +1 -0
- package/{src/run-dev.ts → dist/run-dev.js} +23 -39
- package/dist/run-dev.js.map +1 -0
- package/{src/run-pm.ts → dist/run-pm.js} +34 -46
- package/dist/run-pm.js.map +1 -0
- package/{src/run-research.ts → dist/run-research.js} +19 -30
- package/dist/run-research.js.map +1 -0
- package/{src/run-scout.ts → dist/run-scout.js} +17 -27
- package/dist/run-scout.js.map +1 -0
- package/dist/run-web.js +93 -0
- package/dist/run-web.js.map +1 -0
- package/dist/scout.js +81 -0
- package/dist/scout.js.map +1 -0
- package/dist/session-cost.js +15 -0
- package/dist/session-cost.js.map +1 -0
- package/dist/stack.js +34 -0
- package/dist/stack.js.map +1 -0
- package/dist/stuck.js +21 -0
- package/dist/stuck.js.map +1 -0
- package/dist/tui/App.js +1269 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/BakeOff.js +95 -0
- package/dist/tui/BakeOff.js.map +1 -0
- package/dist/tui/BoardEditor.js +183 -0
- package/dist/tui/BoardEditor.js.map +1 -0
- package/dist/tui/EditableBoard.js +140 -0
- package/dist/tui/EditableBoard.js.map +1 -0
- package/dist/tui/Frame.js +78 -0
- package/dist/tui/Frame.js.map +1 -0
- package/dist/tui/Intake.js +59 -0
- package/dist/tui/Intake.js.map +1 -0
- package/dist/tui/Kanban.js +75 -0
- package/dist/tui/Kanban.js.map +1 -0
- package/dist/tui/Settings.js +299 -0
- package/dist/tui/Settings.js.map +1 -0
- package/dist/tui/StackPick.js +44 -0
- package/dist/tui/StackPick.js.map +1 -0
- package/dist/tui/WebAccounts.js +131 -0
- package/dist/tui/WebAccounts.js.map +1 -0
- package/dist/tui/components.js +178 -0
- package/dist/tui/components.js.map +1 -0
- package/dist/tui/config.js +129 -0
- package/dist/tui/config.js.map +1 -0
- package/dist/tui/deploy.js +114 -0
- package/dist/tui/deploy.js.map +1 -0
- package/dist/tui/engine.js +710 -0
- package/dist/tui/engine.js.map +1 -0
- package/dist/tui/notify.js +47 -0
- package/dist/tui/notify.js.map +1 -0
- package/dist/tui/panels.js +42 -0
- package/dist/tui/panels.js.map +1 -0
- package/dist/tui/templates.js +106 -0
- package/dist/tui/templates.js.map +1 -0
- package/dist/tui/theme.js +42 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/validate.js +51 -0
- package/dist/tui/validate.js.map +1 -0
- package/{src/tui.tsx → dist/tui.js} +23 -33
- package/dist/tui.js.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/web/oauth-anthropic.js +179 -0
- package/dist/web/oauth-anthropic.js.map +1 -0
- package/dist/web/session.js +274 -0
- package/dist/web/session.js.map +1 -0
- package/package.json +5 -4
- package/src/bakeoff.ts +0 -214
- package/src/build-state.ts +0 -47
- package/src/burndown.ts +0 -35
- package/src/calibration.ts +0 -88
- package/src/cost.ts +0 -43
- package/src/council.ts +0 -175
- package/src/demo.ts +0 -106
- package/src/estimate.ts +0 -111
- package/src/executor.ts +0 -169
- package/src/git.ts +0 -72
- package/src/intake.ts +0 -125
- package/src/models.ts +0 -175
- package/src/narrate.ts +0 -87
- package/src/openrouter.ts +0 -119
- package/src/orchestrator.ts +0 -310
- package/src/pm.ts +0 -302
- package/src/preview.ts +0 -206
- package/src/registry-store.ts +0 -41
- package/src/registry.ts +0 -132
- package/src/research.ts +0 -123
- package/src/retro.ts +0 -99
- package/src/roles.ts +0 -401
- package/src/router.ts +0 -120
- package/src/run-bakeoff.ts +0 -77
- package/src/run-build.ts +0 -203
- package/src/run-web.ts +0 -87
- package/src/scout.ts +0 -121
- package/src/session-cost.ts +0 -17
- package/src/stack.ts +0 -46
- package/src/tui/App.tsx +0 -1760
- package/src/tui/BakeOff.tsx +0 -190
- package/src/tui/BoardEditor.tsx +0 -260
- package/src/tui/EditableBoard.tsx +0 -179
- package/src/tui/Frame.tsx +0 -142
- package/src/tui/Intake.tsx +0 -111
- package/src/tui/Kanban.tsx +0 -158
- package/src/tui/Settings.tsx +0 -513
- package/src/tui/StackPick.tsx +0 -79
- package/src/tui/WebAccounts.tsx +0 -197
- package/src/tui/components.tsx +0 -340
- package/src/tui/config.ts +0 -150
- package/src/tui/deploy.ts +0 -137
- package/src/tui/engine.ts +0 -749
- package/src/tui/notify.ts +0 -21
- package/src/tui/panels.tsx +0 -89
- package/src/tui/templates.ts +0 -119
- package/src/tui/theme.ts +0 -44
- package/src/tui/validate.ts +0 -53
- package/src/types.ts +0 -208
- package/src/web/oauth-anthropic.ts +0 -206
- package/src/web/session.ts +0 -299
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Anthropic OAuth (PKCE) — "connect with your Claude Pro/Max subscription".
|
|
2
|
+
//
|
|
3
|
+
// This reuses Claude Code's own OAuth client_id, so every call must be disguised
|
|
4
|
+
// as Claude Code to be accepted. As of Jan 2026 Anthropic enforces this
|
|
5
|
+
// server-side (consumer tokens are rejected outside Claude Code / claude.ai), and
|
|
6
|
+
// third-party use violates their Consumer ToS (account-ban risk). We build it
|
|
7
|
+
// because you asked for the connect-link UX and to test whether the token still
|
|
8
|
+
// works — treat any 401/403 on the test as "enforcement won, fall back".
|
|
9
|
+
//
|
|
10
|
+
// Flow: buildAuthorizeUrl() → user approves in browser → copies the code shown on
|
|
11
|
+
// the callback page → exchangeCode() → tokens stored → refresh() as needed.
|
|
12
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
13
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
17
|
+
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
18
|
+
const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
19
|
+
// The only redirect registered for this client's manual flow. The callback page
|
|
20
|
+
// on console.anthropic.com displays the code for you to copy.
|
|
21
|
+
const REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
|
|
22
|
+
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
23
|
+
// Claude Code's request signature — required or the token is rejected.
|
|
24
|
+
const CC_BETA = "oauth-2025-04-20,claude-code-20250219";
|
|
25
|
+
const CC_UA = "claude-cli/1.0.0 (external, cli)";
|
|
26
|
+
const CC_SYSTEM = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
27
|
+
function tokenPath() {
|
|
28
|
+
const dir = join(homedir(), ".projectinator", "web", "claude");
|
|
29
|
+
mkdirSync(dir, { recursive: true });
|
|
30
|
+
return join(dir, "oauth.json");
|
|
31
|
+
}
|
|
32
|
+
export function hasOAuth() {
|
|
33
|
+
return existsSync(tokenPath());
|
|
34
|
+
}
|
|
35
|
+
export function clearOAuth() {
|
|
36
|
+
try {
|
|
37
|
+
rmSync(tokenPath(), { force: true });
|
|
38
|
+
}
|
|
39
|
+
catch { /* non-fatal */ }
|
|
40
|
+
}
|
|
41
|
+
function saveTokens(t) {
|
|
42
|
+
const p = tokenPath();
|
|
43
|
+
writeFileSync(p, JSON.stringify(t, null, 2));
|
|
44
|
+
try {
|
|
45
|
+
chmodSync(p, 0o600);
|
|
46
|
+
}
|
|
47
|
+
catch { /* best effort */ }
|
|
48
|
+
}
|
|
49
|
+
function loadTokens() {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(readFileSync(tokenPath(), "utf8"));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ---- PKCE ----
|
|
58
|
+
function b64url(buf) {
|
|
59
|
+
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
60
|
+
}
|
|
61
|
+
/** Build the authorize URL + PKCE material. Param order matches Claude Code and
|
|
62
|
+
* scope spaces are %20-encoded (claude.ai rejects the '+' that URLSearchParams
|
|
63
|
+
* emits → "Invalid request format"). */
|
|
64
|
+
export function buildAuthorizeUrl() {
|
|
65
|
+
const verifier = b64url(randomBytes(32));
|
|
66
|
+
const challenge = b64url(createHash("sha256").update(verifier).digest());
|
|
67
|
+
const state = b64url(randomBytes(16));
|
|
68
|
+
const params = new URLSearchParams({
|
|
69
|
+
client_id: CLIENT_ID,
|
|
70
|
+
response_type: "code",
|
|
71
|
+
redirect_uri: REDIRECT_URI,
|
|
72
|
+
scope: SCOPES,
|
|
73
|
+
code_challenge_method: "S256",
|
|
74
|
+
state,
|
|
75
|
+
code_challenge: challenge,
|
|
76
|
+
});
|
|
77
|
+
return { url: `${AUTHORIZE_URL}?${params.toString().replace(/\+/g, "%20")}`, verifier, state };
|
|
78
|
+
}
|
|
79
|
+
/** Exchange the code copied from the callback page. It may arrive as "CODE#STATE". */
|
|
80
|
+
export async function exchangeCode(rawCode, pending) {
|
|
81
|
+
const [code, stateFromCode] = rawCode.trim().split("#");
|
|
82
|
+
const res = await fetch(TOKEN_URL, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: { "Content-Type": "application/json" },
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
grant_type: "authorization_code",
|
|
87
|
+
code,
|
|
88
|
+
state: stateFromCode ?? pending.state,
|
|
89
|
+
client_id: CLIENT_ID,
|
|
90
|
+
redirect_uri: REDIRECT_URI,
|
|
91
|
+
code_verifier: pending.verifier,
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
throw new Error(`Token exchange failed (${res.status}): ${(await res.text()).slice(0, 200)}`);
|
|
96
|
+
}
|
|
97
|
+
const j = (await res.json());
|
|
98
|
+
saveTokens({
|
|
99
|
+
access_token: j.access_token,
|
|
100
|
+
refresh_token: j.refresh_token,
|
|
101
|
+
expires_at: nowMs() + (j.expires_in ?? 3600) * 1000,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async function refresh(t) {
|
|
105
|
+
const res = await fetch(TOKEN_URL, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: { "Content-Type": "application/json" },
|
|
108
|
+
body: JSON.stringify({
|
|
109
|
+
grant_type: "refresh_token",
|
|
110
|
+
refresh_token: t.refresh_token,
|
|
111
|
+
client_id: CLIENT_ID,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
if (!res.ok) {
|
|
115
|
+
throw new Error(`Token refresh failed (${res.status}): ${(await res.text()).slice(0, 200)}`);
|
|
116
|
+
}
|
|
117
|
+
const j = (await res.json());
|
|
118
|
+
const next = {
|
|
119
|
+
access_token: j.access_token,
|
|
120
|
+
refresh_token: j.refresh_token ?? t.refresh_token,
|
|
121
|
+
expires_at: nowMs() + (j.expires_in ?? 3600) * 1000,
|
|
122
|
+
};
|
|
123
|
+
saveTokens(next);
|
|
124
|
+
return next;
|
|
125
|
+
}
|
|
126
|
+
async function validAccessToken() {
|
|
127
|
+
const t = loadTokens();
|
|
128
|
+
if (!t)
|
|
129
|
+
throw new Error("Not connected. Run the Claude OAuth connect flow first.");
|
|
130
|
+
if (nowMs() > t.expires_at - 60_000) {
|
|
131
|
+
return (await refresh(t)).access_token;
|
|
132
|
+
}
|
|
133
|
+
return t.access_token;
|
|
134
|
+
}
|
|
135
|
+
// nowMs isolated so the "no Date.now in workflow scripts" rule never bites here
|
|
136
|
+
// (this module runs in the app/CLI, not a workflow script).
|
|
137
|
+
function nowMs() {
|
|
138
|
+
return Date.now();
|
|
139
|
+
}
|
|
140
|
+
/** Call the Messages API with the OAuth token, disguised as Claude Code.
|
|
141
|
+
* Returns the assistant text. Tool-calling can be layered on later. */
|
|
142
|
+
export async function oauthComplete(messages, opts = {}) {
|
|
143
|
+
const token = await validAccessToken();
|
|
144
|
+
// Claude Code always leads the system prompt with its identity line; the token
|
|
145
|
+
// is rejected without it. Any extra system text is appended after.
|
|
146
|
+
const system = [
|
|
147
|
+
{ type: "text", text: CC_SYSTEM },
|
|
148
|
+
...(opts.system ? [{ type: "text", text: opts.system }] : []),
|
|
149
|
+
];
|
|
150
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: {
|
|
153
|
+
"Content-Type": "application/json",
|
|
154
|
+
"Authorization": `Bearer ${token}`,
|
|
155
|
+
"anthropic-version": "2023-06-01",
|
|
156
|
+
"anthropic-beta": CC_BETA,
|
|
157
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
158
|
+
"x-app": "cli",
|
|
159
|
+
"user-agent": CC_UA,
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify({
|
|
162
|
+
model: opts.model ?? "claude-sonnet-5",
|
|
163
|
+
max_tokens: opts.maxTokens ?? 1024,
|
|
164
|
+
system,
|
|
165
|
+
messages: messages.map((m) => ({ role: m.role, content: m.content })),
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
if (!res.ok) {
|
|
169
|
+
const body = (await res.text()).slice(0, 300);
|
|
170
|
+
throw new Error(`Messages API ${res.status}: ${body}\n(401/403 here = Jan-2026 enforcement rejecting a non-Claude-Code client)`);
|
|
171
|
+
}
|
|
172
|
+
const j = (await res.json());
|
|
173
|
+
return (j.content ?? []).filter((b) => b.type === "text").map((b) => b.text ?? "").join("").trim();
|
|
174
|
+
}
|
|
175
|
+
/** Quick connectivity/enforcement probe. Returns the reply or throws with the status. */
|
|
176
|
+
export async function oauthTest() {
|
|
177
|
+
return oauthComplete([{ role: "user", content: "Reply with exactly one word: hello" }], { maxTokens: 16 });
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=oauth-anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-anthropic.js","sourceRoot":"","sources":["../../src/web/oauth-anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
// EXPERIMENTAL web-login backend. Drives a provider's WEB UI (logged into your paid
|
|
2
|
+
// subscription) in a persistent Chromium profile to get ~free completions.
|
|
3
|
+
//
|
|
4
|
+
// Caveats you accepted: brittle (site DOM changes break selectors), against provider
|
|
5
|
+
// ToS (account-ban risk), TEXT ONLY (no tool-calling / no file tools), slow.
|
|
6
|
+
//
|
|
7
|
+
// Selectors live in PROVIDERS below — when a site changes, edit them there.
|
|
8
|
+
import { chromium } from "playwright";
|
|
9
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { createInterface } from "node:readline";
|
|
13
|
+
const PROVIDERS = {
|
|
14
|
+
claude: {
|
|
15
|
+
label: "Claude (claude.ai)",
|
|
16
|
+
newChatUrl: "https://claude.ai/new",
|
|
17
|
+
inputSelector: 'div[contenteditable="true"]',
|
|
18
|
+
assistantSelector: '[class*="claude"]',
|
|
19
|
+
stopSelector: '[data-is-streaming="true"]',
|
|
20
|
+
},
|
|
21
|
+
chatgpt: {
|
|
22
|
+
label: "ChatGPT (chatgpt.com)",
|
|
23
|
+
newChatUrl: "https://chatgpt.com/",
|
|
24
|
+
inputSelector: '#prompt-textarea, div[contenteditable="true"], textarea',
|
|
25
|
+
assistantSelector: '[data-message-author-role="assistant"]',
|
|
26
|
+
stopSelector: 'button[data-testid="stop-button"], button[aria-label*="Stop"]',
|
|
27
|
+
},
|
|
28
|
+
gemini: {
|
|
29
|
+
label: "Gemini (gemini.google.com)",
|
|
30
|
+
newChatUrl: "https://gemini.google.com/app",
|
|
31
|
+
inputSelector: 'rich-textarea div[contenteditable="true"], div[contenteditable="true"], textarea',
|
|
32
|
+
assistantSelector: "message-content, .model-response-text",
|
|
33
|
+
stopSelector: 'button[aria-label*="Stop"], button[aria-label*="stop"]',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
function profileDir(provider) {
|
|
37
|
+
const dir = join(homedir(), ".projectinator", "web", provider);
|
|
38
|
+
mkdirSync(dir, { recursive: true });
|
|
39
|
+
return dir;
|
|
40
|
+
}
|
|
41
|
+
function connectedMarker(provider) {
|
|
42
|
+
return join(profileDir(provider), ".connected");
|
|
43
|
+
}
|
|
44
|
+
/** Has this provider been logged in at least once (session saved)? */
|
|
45
|
+
export function isConnected(provider) {
|
|
46
|
+
return existsSync(connectedMarker(provider));
|
|
47
|
+
}
|
|
48
|
+
/** Which providers have a saved session. */
|
|
49
|
+
export function connectedProviders() {
|
|
50
|
+
return Object.keys(PROVIDERS).filter(isConnected);
|
|
51
|
+
}
|
|
52
|
+
function markConnected(provider) {
|
|
53
|
+
try {
|
|
54
|
+
writeFileSync(connectedMarker(provider), new Date().toISOString());
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
/* non-fatal */
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Log out: wipe the saved session (cookies + profile) for a provider. */
|
|
61
|
+
export function disconnect(provider) {
|
|
62
|
+
try {
|
|
63
|
+
rmSync(profileDir(provider), { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* non-fatal */
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Push the run window far off-screen so it drives the session without stealing
|
|
70
|
+
// focus or cluttering the desktop. Login windows stay on-screen (you interact).
|
|
71
|
+
const OFFSCREEN_ARGS = ["--window-position=-3200,-3200", "--window-size=1280,900"];
|
|
72
|
+
async function openContext(provider, opts) {
|
|
73
|
+
return chromium.launchPersistentContext(profileDir(provider), {
|
|
74
|
+
headless: opts.headless,
|
|
75
|
+
viewport: { width: 1280, height: 900 },
|
|
76
|
+
args: [
|
|
77
|
+
"--disable-blink-features=AutomationControlled",
|
|
78
|
+
...(opts.offscreen ? OFFSCREEN_ARGS : []),
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// One long-lived background browser per provider, reused across completions so
|
|
83
|
+
// nothing pops up per task. Launched on first webComplete, closed on app exit.
|
|
84
|
+
const runContexts = new Map();
|
|
85
|
+
async function runContext(provider) {
|
|
86
|
+
const existing = runContexts.get(provider);
|
|
87
|
+
if (existing)
|
|
88
|
+
return existing;
|
|
89
|
+
const ctx = await openContext(provider, { headless: false, offscreen: true });
|
|
90
|
+
ctx.on("close", () => {
|
|
91
|
+
if (runContexts.get(provider) === ctx)
|
|
92
|
+
runContexts.delete(provider);
|
|
93
|
+
});
|
|
94
|
+
runContexts.set(provider, ctx);
|
|
95
|
+
return ctx;
|
|
96
|
+
}
|
|
97
|
+
/** Close every background browser. Call on app exit. */
|
|
98
|
+
export async function closeWebSessions() {
|
|
99
|
+
const ctxs = [...runContexts.values()];
|
|
100
|
+
runContexts.clear();
|
|
101
|
+
await Promise.all(ctxs.map((c) => c.close().catch(() => { })));
|
|
102
|
+
}
|
|
103
|
+
/** Open a real browser window so you can log in once; the session is saved to disk. */
|
|
104
|
+
export async function webLogin(provider) {
|
|
105
|
+
const cfg = PROVIDERS[provider];
|
|
106
|
+
const ctx = await openContext(provider, { headless: false });
|
|
107
|
+
const page = ctx.pages()[0] ?? (await ctx.newPage());
|
|
108
|
+
// Non-fatal: even if the page is slow / behind a challenge, the window is open
|
|
109
|
+
// and you can log in (or navigate) manually.
|
|
110
|
+
try {
|
|
111
|
+
await page.goto(cfg.newChatUrl, { waitUntil: "commit", timeout: 60_000 });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
/* keep the window open regardless */
|
|
115
|
+
}
|
|
116
|
+
process.stdout.write(`\n A browser opened for ${cfg.label}.\n Log in there (wait for it to load), then press Enter here to save the session…`);
|
|
117
|
+
await new Promise((resolve) => {
|
|
118
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
119
|
+
rl.question("", () => {
|
|
120
|
+
rl.close();
|
|
121
|
+
resolve();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
await ctx.close();
|
|
125
|
+
markConnected(provider);
|
|
126
|
+
process.stdout.write(" Session saved.\n");
|
|
127
|
+
}
|
|
128
|
+
/** Non-interactive login for the TUI: open the login window and resolve once the
|
|
129
|
+
* caller signals done (e.g. user pressed a key in the app). Returns a handle to
|
|
130
|
+
* finish. The window shows the real site so you can log in. */
|
|
131
|
+
export async function webLoginBegin(provider) {
|
|
132
|
+
const cfg = PROVIDERS[provider];
|
|
133
|
+
const ctx = await openContext(provider, { headless: false });
|
|
134
|
+
const page = ctx.pages()[0] ?? (await ctx.newPage());
|
|
135
|
+
try {
|
|
136
|
+
await page.goto(cfg.newChatUrl, { waitUntil: "commit", timeout: 60_000 });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
/* keep the window open regardless */
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
finish: async () => {
|
|
143
|
+
await ctx.close();
|
|
144
|
+
markConnected(provider);
|
|
145
|
+
},
|
|
146
|
+
cancel: async () => {
|
|
147
|
+
await ctx.close();
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function lastAssistantText(page, cfg) {
|
|
152
|
+
const nodes = page.locator(cfg.assistantSelector);
|
|
153
|
+
const count = await nodes.count();
|
|
154
|
+
if (count === 0)
|
|
155
|
+
return "";
|
|
156
|
+
return (await nodes.nth(count - 1).innerText()).trim();
|
|
157
|
+
}
|
|
158
|
+
/** Send one prompt to the provider's web UI and return the reply text.
|
|
159
|
+
* Runs HEADED by default — claude.ai/chatgpt block headless browsers. Set
|
|
160
|
+
* opts.headless=true to try headless (often challenged). */
|
|
161
|
+
export async function webComplete(provider, prompt, opts = {}) {
|
|
162
|
+
const cfg = PROVIDERS[provider];
|
|
163
|
+
const timeoutMs = opts.timeoutMs ?? 90_000;
|
|
164
|
+
// Reuse the one background browser; open a fresh page (= fresh chat) per ask.
|
|
165
|
+
const ctx = await runContext(provider);
|
|
166
|
+
const page = await ctx.newPage();
|
|
167
|
+
try {
|
|
168
|
+
try {
|
|
169
|
+
await page.goto(cfg.newChatUrl, { waitUntil: "commit", timeout: 60_000 });
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
/* proceed — the input wait below is the real readiness check */
|
|
173
|
+
}
|
|
174
|
+
const input = page.locator(cfg.inputSelector).first();
|
|
175
|
+
try {
|
|
176
|
+
await input.waitFor({ state: "visible", timeout: 45_000 });
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
// Diagnose: dump what actually loaded so we can fix selectors / spot a challenge.
|
|
180
|
+
const shot = join(profileDir(provider), "debug.png");
|
|
181
|
+
try {
|
|
182
|
+
await page.screenshot({ path: shot, fullPage: false });
|
|
183
|
+
}
|
|
184
|
+
catch { /* ignore */ }
|
|
185
|
+
const url = page.url();
|
|
186
|
+
const title = await page.title().catch(() => "");
|
|
187
|
+
const body = (await page.locator("body").innerText().catch(() => "")).slice(0, 200).replace(/\s+/g, " ");
|
|
188
|
+
throw new Error(`Input never appeared.\n url: ${url}\n title: ${title}\n page text: "${body}…"\n screenshot: ${shot}\n (looks like a login/challenge page? → the session may not be carrying over, or the selector changed)`);
|
|
189
|
+
}
|
|
190
|
+
await input.click();
|
|
191
|
+
await input.fill(prompt);
|
|
192
|
+
await page.keyboard.press("Enter");
|
|
193
|
+
// Wait for a reply to appear, then for it to stop changing.
|
|
194
|
+
const deadline = Date.now() + timeoutMs;
|
|
195
|
+
let last = "";
|
|
196
|
+
let stable = 0;
|
|
197
|
+
while (Date.now() < deadline) {
|
|
198
|
+
try {
|
|
199
|
+
await page.waitForTimeout(700);
|
|
200
|
+
const text = await lastAssistantText(page, cfg);
|
|
201
|
+
const streaming = (await page.locator(cfg.stopSelector).count()) > 0;
|
|
202
|
+
if (text && text === last && !streaming) {
|
|
203
|
+
stable++;
|
|
204
|
+
if (stable >= 3)
|
|
205
|
+
return text; // ~2s unchanged and not streaming → done
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
stable = 0;
|
|
209
|
+
}
|
|
210
|
+
last = text;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
break; // page/context closed — return whatever we captured
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (last)
|
|
217
|
+
return last;
|
|
218
|
+
throw new Error("No response captured (selectors may be stale, or you're not logged in).");
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
await page.close().catch(() => { }); // keep the context alive for the next ask
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** Diagnostic: send a prompt, wait, then dump candidate selectors so we can find the
|
|
225
|
+
* right one for the assistant reply. Headed. */
|
|
226
|
+
export async function webDump(provider, prompt) {
|
|
227
|
+
const cfg = PROVIDERS[provider];
|
|
228
|
+
const ctx = await openContext(provider, { headless: false });
|
|
229
|
+
try {
|
|
230
|
+
const page = ctx.pages()[0] ?? (await ctx.newPage());
|
|
231
|
+
try {
|
|
232
|
+
await page.goto(cfg.newChatUrl, { waitUntil: "commit", timeout: 60_000 });
|
|
233
|
+
}
|
|
234
|
+
catch { /* ignore */ }
|
|
235
|
+
const input = page.locator(cfg.inputSelector).first();
|
|
236
|
+
await input.waitFor({ state: "visible", timeout: 45_000 });
|
|
237
|
+
await input.click();
|
|
238
|
+
await input.fill(prompt);
|
|
239
|
+
await page.keyboard.press("Enter");
|
|
240
|
+
console.log(" sent — waiting 18s for the reply to render…");
|
|
241
|
+
await page.waitForTimeout(18_000);
|
|
242
|
+
const report = await page.evaluate(() => {
|
|
243
|
+
const cands = [
|
|
244
|
+
// chatgpt
|
|
245
|
+
'[data-message-author-role="assistant"]', ".markdown",
|
|
246
|
+
// gemini
|
|
247
|
+
"message-content", ".model-response-text", "model-response",
|
|
248
|
+
// claude
|
|
249
|
+
'[class*="claude"]', ".font-claude-message", "[data-is-streaming]",
|
|
250
|
+
// generic
|
|
251
|
+
".prose", '[class*="message"]', "[data-testid]", "main div[tabindex]",
|
|
252
|
+
];
|
|
253
|
+
const out = [];
|
|
254
|
+
for (const sel of cands) {
|
|
255
|
+
const els = document.querySelectorAll(sel);
|
|
256
|
+
const last = els[els.length - 1];
|
|
257
|
+
out.push({ sel, count: els.length, lastText: (last?.innerText ?? "").slice(0, 100).replace(/\s+/g, " ") });
|
|
258
|
+
}
|
|
259
|
+
return { url: location.href, title: document.title, cands: out };
|
|
260
|
+
});
|
|
261
|
+
console.log("\n url:", report.url, "\n title:", report.title, "\n --- candidate selectors ---");
|
|
262
|
+
for (const c of report.cands)
|
|
263
|
+
console.log(` [${c.count}] ${c.sel}\n last: "${c.lastText}"`);
|
|
264
|
+
console.log("");
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
await ctx.close();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export function isWebProvider(s) {
|
|
271
|
+
return s === "chatgpt" || s === "claude" || s === "gemini";
|
|
272
|
+
}
|
|
273
|
+
export { PROVIDERS };
|
|
274
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/web/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projectinator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Your AI build team in the terminal — hand it an app idea, a PM model plans a Scrum backlog, and the best model per role designs, codes, and tests it into working files. Bring your own API key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -33,14 +33,15 @@
|
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
35
|
"bin",
|
|
36
|
-
"
|
|
36
|
+
"dist"
|
|
37
37
|
],
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=22.19.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"start": "tsx src/tui.tsx",
|
|
43
|
-
"
|
|
43
|
+
"compile": "tsc -p tsconfig.build.json",
|
|
44
|
+
"prepublishOnly": "rm -rf dist && npm run compile && npm run typecheck && npm test",
|
|
44
45
|
"demo": "tsx src/demo.ts",
|
|
45
46
|
"dev:task": "tsx src/run-dev.ts",
|
|
46
47
|
"pm": "tsx src/run-pm.ts",
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
"@types/node": "^22.10.0",
|
|
58
59
|
"@types/react": "^19.2.17",
|
|
59
60
|
"ink-testing-library": "^4.0.0",
|
|
61
|
+
"tsx": "4.23.1",
|
|
60
62
|
"typescript": "^5.7.2",
|
|
61
63
|
"vitest": "^2.1.8"
|
|
62
64
|
},
|
|
@@ -67,7 +69,6 @@
|
|
|
67
69
|
"ink-spinner": "5.0.0",
|
|
68
70
|
"playwright": "1.61.1",
|
|
69
71
|
"react": "19.2.7",
|
|
70
|
-
"tsx": "4.23.1",
|
|
71
72
|
"typebox": "1.3.7"
|
|
72
73
|
}
|
|
73
74
|
}
|