@pome-sh/cli 0.4.0 → 0.5.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 +27 -2
- package/dist/build-info.json +3 -3
- package/dist/src/cli/docs-topics.js +45 -14
- package/dist/src/cli/install.d.ts +4 -41
- package/dist/src/cli/install.js +31 -412
- package/dist/src/cli/main.js +12 -29
- package/dist/src/cli/register.d.ts +0 -22
- package/dist/src/cli/register.js +1 -31
- package/dist/src/doctor/checks.js +1 -1
- package/package.json +1 -2
- package/dist/src/cli/agent-sdk.d.ts +0 -32
- package/dist/src/cli/agent-sdk.js +0 -105
- package/dist/src/cli/embedded-wiring.d.ts +0 -47
- package/dist/src/cli/embedded-wiring.js +0 -443
- package/dist/src/cli/skills.d.ts +0 -8
- package/dist/src/cli/skills.js +0 -141
- package/skills/pome-setup/SKILL.md +0 -150
- package/skills/pome-test/SKILL.md +0 -137
package/dist/src/cli/main.js
CHANGED
|
@@ -18,7 +18,6 @@ import { runDocsCommand } from "./docs.js";
|
|
|
18
18
|
import { runCompileSeeds } from "./compile-seeds.js";
|
|
19
19
|
import { runScenariosCommand } from "./scenarios.js";
|
|
20
20
|
import { runEvalCommand } from "./eval.js";
|
|
21
|
-
import { runSkillsInstall } from "./skills.js";
|
|
22
21
|
import { copyAnnounceLine, ensureDefaultTask, runYoursFrameLines, trialsPinFallbackLine, } from "./default-task.js";
|
|
23
22
|
import { findTwin, runnableScenarios, } from "./scenarios-catalog.js";
|
|
24
23
|
import { friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, } from "./session.js";
|
|
@@ -141,19 +140,16 @@ export function createProgram() {
|
|
|
141
140
|
});
|
|
142
141
|
program
|
|
143
142
|
.command("install")
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
// F-893 — the Gen-1 agent-driven wiring is retired; this is a redirect to
|
|
144
|
+
// the Gen-2 path. allowUnknownOption + allowExcessArguments keep old
|
|
145
|
+
// invocations (`pome install --interactive`, `--api-url …`) landing on the
|
|
146
|
+
// redirect instead of erroring on a now-removed flag or stray operand.
|
|
147
|
+
.allowUnknownOption()
|
|
148
|
+
.allowExcessArguments()
|
|
149
|
+
.description("Retired (F-893). Prints the Gen-2 wiring path: `claude mcp add … pome` + `npx skills add pome-sh/digital-twins`, then the pome-intake / REST-launch preflight.")
|
|
150
|
+
.action(async () => {
|
|
151
151
|
const { runInstall } = await import("./install.js");
|
|
152
|
-
|
|
153
|
-
apiUrl: opts.apiUrl,
|
|
154
|
-
dashboardUrl: opts.dashboardUrl,
|
|
155
|
-
interactive: opts.interactive,
|
|
156
|
-
});
|
|
152
|
+
runInstall();
|
|
157
153
|
});
|
|
158
154
|
program
|
|
159
155
|
.command("login")
|
|
@@ -211,22 +207,9 @@ export function createProgram() {
|
|
|
211
207
|
if (code !== 0)
|
|
212
208
|
process.exitCode = code;
|
|
213
209
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
skills
|
|
218
|
-
.command("install")
|
|
219
|
-
.description("Install /pome-setup and /pome-test into ~/.claude/skills/ (symlinked to this pome install by default)")
|
|
220
|
-
.option("--copy", "Copy each skill instead of symlinking (CI, Windows without symlink permission)", false)
|
|
221
|
-
.option("--force", "Overwrite an existing install of the same skill", false)
|
|
222
|
-
.option("--dest <dir>", "Install into <dir> instead of ~/.claude/skills/ (testing and advanced users)")
|
|
223
|
-
.action(async (opts) => {
|
|
224
|
-
await runSkillsInstall({
|
|
225
|
-
copy: opts.copy,
|
|
226
|
-
force: opts.force,
|
|
227
|
-
dest: opts.dest,
|
|
228
|
-
});
|
|
229
|
-
});
|
|
210
|
+
// F-893 — `pome skills` / `pome skills install` retired. It only symlinked
|
|
211
|
+
// the two Gen-1 tombstone skills into ~/.claude/skills/; the Gen-2 coach set
|
|
212
|
+
// installs via `npx skills add pome-sh/digital-twins`.
|
|
230
213
|
const register = program
|
|
231
214
|
.command("register")
|
|
232
215
|
.description("Register a cloud entity (agent, ...) and link this project to it");
|
|
@@ -11,26 +11,4 @@ interface RegisterAgentOptions extends InteractiveSeams {
|
|
|
11
11
|
/** Normalize a `--twins github,slack` comma list to a validated twin array. */
|
|
12
12
|
export declare function normalizeRegisterTwins(raw: string | undefined): string[] | undefined;
|
|
13
13
|
export declare function runRegisterAgent(opts: RegisterAgentOptions): Promise<void>;
|
|
14
|
-
export interface EnsureAgentRegisteredOptions extends InteractiveSeams {
|
|
15
|
-
apiBaseUrl: string;
|
|
16
|
-
/** Where to look for the manifest. Defaults to process.cwd(). */
|
|
17
|
-
cwd?: string;
|
|
18
|
-
/** Test seam — forwarded to resolveCredentials. */
|
|
19
|
-
credentialsPath?: string;
|
|
20
|
-
}
|
|
21
|
-
export type EnsureAgentRegisteredResult = {
|
|
22
|
-
status: "registered";
|
|
23
|
-
agentId: string;
|
|
24
|
-
agentSlug: string;
|
|
25
|
-
} | {
|
|
26
|
-
status: "already-registered";
|
|
27
|
-
agentId: string;
|
|
28
|
-
agentSlug?: string;
|
|
29
|
-
} | {
|
|
30
|
-
status: "no-config";
|
|
31
|
-
};
|
|
32
|
-
/** Idempotent registration for `pome install`: a repo already linked under the
|
|
33
|
-
* caller's team keeps its id (no network, no duplicate); a fresh repo registers
|
|
34
|
-
* under the manifest name (or the config directory's basename). */
|
|
35
|
-
export declare function ensureAgentRegistered(opts: EnsureAgentRegisteredOptions): Promise<EnsureAgentRegisteredResult>;
|
|
36
14
|
export { friendlyHostedError };
|
package/dist/src/cli/register.js
CHANGED
|
@@ -19,7 +19,7 @@ import { postAgentResolver, resolveSeams, } from "./agent-resolver.js";
|
|
|
19
19
|
import { resolveCredentials } from "./credentials.js";
|
|
20
20
|
import { suggestFramework } from "./frameworks.js";
|
|
21
21
|
import { ensurePomeGitignored, readLinkCache, resolveCachedAgentId, writeLinkCache, } from "./link-cache.js";
|
|
22
|
-
import {
|
|
22
|
+
import { readRequiredManifest, writeManifest, } from "./project-config.js";
|
|
23
23
|
import { friendlyHostedError } from "./session.js";
|
|
24
24
|
const SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
|
|
25
25
|
/** Normalize a `--twins github,slack` comma list to a validated twin array. */
|
|
@@ -160,36 +160,6 @@ export async function runRegisterAgent(opts) {
|
|
|
160
160
|
console.error("Enabled services: not reported by this pome cloud (older control plane) — twin scoping may not have taken effect.");
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
/** Idempotent registration for `pome install`: a repo already linked under the
|
|
164
|
-
* caller's team keeps its id (no network, no duplicate); a fresh repo registers
|
|
165
|
-
* under the manifest name (or the config directory's basename). */
|
|
166
|
-
export async function ensureAgentRegistered(opts) {
|
|
167
|
-
const manifestRead = await readManifest(opts.cwd ?? process.cwd());
|
|
168
|
-
if (!manifestRead)
|
|
169
|
-
return { status: "no-config" };
|
|
170
|
-
const projectDir = dirname(manifestRead.path);
|
|
171
|
-
const creds = await resolveCredentials({
|
|
172
|
-
apiBaseUrl: opts.apiBaseUrl,
|
|
173
|
-
credentialsPath: opts.credentialsPath,
|
|
174
|
-
});
|
|
175
|
-
const cachedId = resolveCachedAgentId(await readLinkCache(projectDir), creds.teamId);
|
|
176
|
-
if (cachedId) {
|
|
177
|
-
return {
|
|
178
|
-
status: "already-registered",
|
|
179
|
-
agentId: cachedId,
|
|
180
|
-
agentSlug: manifestRead.manifest.agent.slug,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
const name = manifestRead.manifest.agent.name ?? basename(projectDir);
|
|
184
|
-
const agent = await createAndPersistAgent({
|
|
185
|
-
creds,
|
|
186
|
-
name,
|
|
187
|
-
manifestRead,
|
|
188
|
-
projectDir,
|
|
189
|
-
seams: resolveSeams(opts),
|
|
190
|
-
});
|
|
191
|
-
return { status: "registered", agentId: agent.id, agentSlug: agent.slug };
|
|
192
|
-
}
|
|
193
163
|
function stripControlCharacters(value) {
|
|
194
164
|
return value.replace(/[\u0000-\u001f\u007f]/g, "");
|
|
195
165
|
}
|
|
@@ -164,7 +164,7 @@ async function checkRouting(configDir) {
|
|
|
164
164
|
cause: `no POME_*_REST_URL / POME_*_MCP_URL read and no @pome-sh adapter found in the ${scan.filesScanned} source file(s) under ${relative(process.cwd(), configDir) || "."} — the agent has no path to the twin.`,
|
|
165
165
|
fix: [
|
|
166
166
|
'wire the adapter: import { withPome } from "@pome-sh/adapter-claude-sdk"; call withPome() at startup;',
|
|
167
|
-
"read the twin base URL from POME_GITHUB_REST_URL (injected by the runner) — or
|
|
167
|
+
"read the twin base URL from POME_GITHUB_REST_URL (injected by the runner) — or let your own coding agent wire it with the Gen-2 skills (`npx skills add pome-sh/digital-twins`).",
|
|
168
168
|
].join("\n"),
|
|
169
169
|
};
|
|
170
170
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pome-sh/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Digital-twin testing for AI agents — run tasks against resettable local or hosted twins and record tool-call traces for evaluation on pome.sh.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"dist",
|
|
35
35
|
"examples",
|
|
36
36
|
"scenarios",
|
|
37
|
-
"skills",
|
|
38
37
|
"LICENSE",
|
|
39
38
|
"package.json",
|
|
40
39
|
"README.md"
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/** Pinned driver version — bump deliberately, in lockstep with a re-test
|
|
2
|
-
* against the oldest Claude Code binary we expect on user machines. */
|
|
3
|
-
export declare const AGENT_SDK_VERSION = "0.3.202";
|
|
4
|
-
/**
|
|
5
|
-
* True when the machine has credentials the Claude Code binary can
|
|
6
|
-
* authenticate with on its own: a stored `/login` session (keychain or
|
|
7
|
-
* `$CLAUDE_CONFIG_DIR/.credentials.json`) or an explicit env credential.
|
|
8
|
-
* Mirrors the SDK's own resolution; pome never reads the secret values.
|
|
9
|
-
*/
|
|
10
|
-
export declare function detectClaudeLogin(env?: Record<string, string | undefined>, home?: string, platform?: NodeJS.Platform): boolean;
|
|
11
|
-
/** Directory the pinned SDK driver is provisioned into. */
|
|
12
|
-
export declare function agentSdkDir(home?: string): string;
|
|
13
|
-
export declare function isAgentSdkProvisioned(dir?: string): boolean;
|
|
14
|
-
/** Minimal structural view of the SDK's query() — the driver is loaded at
|
|
15
|
-
* runtime, so pome compiles against this shape, not the SDK's types. */
|
|
16
|
-
export type AgentSdkQueryFn = (args: {
|
|
17
|
-
prompt: string;
|
|
18
|
-
options: Record<string, unknown>;
|
|
19
|
-
}) => AsyncIterable<Record<string, unknown>>;
|
|
20
|
-
export interface AgentSdkModule {
|
|
21
|
-
query: AgentSdkQueryFn;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Install the pinned driver into `dir` using whichever package manager is
|
|
25
|
-
* on PATH. `--omit=optional` skips the ~244 MB platform runtime — the
|
|
26
|
-
* session runs on the user's own `claude` binary instead.
|
|
27
|
-
* Returns null (with a printed reason) when no package manager is found
|
|
28
|
-
* or the install fails; callers fall back to the interactive session.
|
|
29
|
-
*/
|
|
30
|
-
export declare function provisionAgentSdk(dir?: string): Promise<boolean>;
|
|
31
|
-
/** Import the provisioned driver. Returns null when not provisioned. */
|
|
32
|
-
export declare function loadAgentSdk(dir?: string): Promise<AgentSdkModule | null>;
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// FDRS-661 — Claude Agent SDK access for the embedded (headless) wiring
|
|
3
|
-
// session: detect whether the user's own credentials exist, and lazily
|
|
4
|
-
// provision the SDK driver into ~/.pome/agent-sdk/<version>.
|
|
5
|
-
//
|
|
6
|
-
// The SDK is deliberately NOT a dependency of @pome-sh/cli: its per-platform
|
|
7
|
-
// optionalDependency bundles the Claude Code runtime (~244 MB unpacked),
|
|
8
|
-
// which would sink `npx @pome-sh/cli demo` cold-start. Instead we install the
|
|
9
|
-
// driver package alone (--omit=optional, a few MB) on first use, and point
|
|
10
|
-
// it at the user's already-installed `claude` binary via
|
|
11
|
-
// `pathToClaudeCodeExecutable` — verified against SDK 0.3.202 driving
|
|
12
|
-
// Claude Code 2.1.201.
|
|
13
|
-
import { spawnSync } from "node:child_process";
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
15
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
16
|
-
import { homedir } from "node:os";
|
|
17
|
-
import { join } from "node:path";
|
|
18
|
-
import { pathToFileURL } from "node:url";
|
|
19
|
-
/** Pinned driver version — bump deliberately, in lockstep with a re-test
|
|
20
|
-
* against the oldest Claude Code binary we expect on user machines. */
|
|
21
|
-
export const AGENT_SDK_VERSION = "0.3.202";
|
|
22
|
-
/** macOS keychain service Claude Code stores its `/login` credential under.
|
|
23
|
-
* Existence-only probe (no `-w`): the secret is never read or printed. */
|
|
24
|
-
const CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
25
|
-
/**
|
|
26
|
-
* True when the machine has credentials the Claude Code binary can
|
|
27
|
-
* authenticate with on its own: a stored `/login` session (keychain or
|
|
28
|
-
* `$CLAUDE_CONFIG_DIR/.credentials.json`) or an explicit env credential.
|
|
29
|
-
* Mirrors the SDK's own resolution; pome never reads the secret values.
|
|
30
|
-
*/
|
|
31
|
-
export function detectClaudeLogin(env = process.env, home = homedir(), platform = process.platform) {
|
|
32
|
-
if (env.ANTHROPIC_API_KEY || env.CLAUDE_CODE_OAUTH_TOKEN || env.ANTHROPIC_AUTH_TOKEN) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
const configDir = env.CLAUDE_CONFIG_DIR || join(home, ".claude");
|
|
36
|
-
try {
|
|
37
|
-
if (existsSync(join(configDir, ".credentials.json")))
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
/* unreadable — treat as absent */
|
|
42
|
-
}
|
|
43
|
-
if (platform === "darwin") {
|
|
44
|
-
try {
|
|
45
|
-
const res = spawnSync("security", ["find-generic-password", "-s", CLAUDE_KEYCHAIN_SERVICE], { stdio: "ignore", timeout: 5000 });
|
|
46
|
-
if (res.status === 0)
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
/* lookup failed — treat as absent */
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
/** Directory the pinned SDK driver is provisioned into. */
|
|
56
|
-
export function agentSdkDir(home = homedir()) {
|
|
57
|
-
return join(home, ".pome", "agent-sdk", AGENT_SDK_VERSION);
|
|
58
|
-
}
|
|
59
|
-
function sdkEntryPath(dir) {
|
|
60
|
-
return join(dir, "node_modules", "@anthropic-ai", "claude-agent-sdk", "sdk.mjs");
|
|
61
|
-
}
|
|
62
|
-
export function isAgentSdkProvisioned(dir = agentSdkDir()) {
|
|
63
|
-
return existsSync(sdkEntryPath(dir));
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Install the pinned driver into `dir` using whichever package manager is
|
|
67
|
-
* on PATH. `--omit=optional` skips the ~244 MB platform runtime — the
|
|
68
|
-
* session runs on the user's own `claude` binary instead.
|
|
69
|
-
* Returns null (with a printed reason) when no package manager is found
|
|
70
|
-
* or the install fails; callers fall back to the interactive session.
|
|
71
|
-
*/
|
|
72
|
-
export async function provisionAgentSdk(dir = agentSdkDir()) {
|
|
73
|
-
await mkdir(dir, { recursive: true });
|
|
74
|
-
const manifest = join(dir, "package.json");
|
|
75
|
-
if (!existsSync(manifest)) {
|
|
76
|
-
await writeFile(manifest, JSON.stringify({ name: "pome-agent-sdk", private: true }, null, 2));
|
|
77
|
-
}
|
|
78
|
-
const spec = `@anthropic-ai/claude-agent-sdk@${AGENT_SDK_VERSION}`;
|
|
79
|
-
const attempts = [
|
|
80
|
-
["npm", ["install", "--omit=optional", "--no-audit", "--no-fund", spec]],
|
|
81
|
-
["bun", ["add", "--omit=optional", spec]],
|
|
82
|
-
];
|
|
83
|
-
for (const [bin, args] of attempts) {
|
|
84
|
-
const probe = spawnSync(bin, ["--version"], { stdio: "ignore", timeout: 10_000 });
|
|
85
|
-
if (probe.error || probe.status !== 0)
|
|
86
|
-
continue;
|
|
87
|
-
console.error(`downloading the Claude Agent SDK driver (${spec}, a few MB, one-time) …`);
|
|
88
|
-
const res = spawnSync(bin, args, { cwd: dir, stdio: "ignore", timeout: 300_000 });
|
|
89
|
-
if (res.status === 0 && isAgentSdkProvisioned(dir))
|
|
90
|
-
return true;
|
|
91
|
-
console.error(`(${bin} install of ${spec} failed)`);
|
|
92
|
-
}
|
|
93
|
-
console.error("couldn't provision the Claude Agent SDK driver (is npm or bun on PATH?).");
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
/** Import the provisioned driver. Returns null when not provisioned. */
|
|
97
|
-
export async function loadAgentSdk(dir = agentSdkDir()) {
|
|
98
|
-
const entry = sdkEntryPath(dir);
|
|
99
|
-
if (!existsSync(entry))
|
|
100
|
-
return null;
|
|
101
|
-
const mod = (await import(pathToFileURL(entry).href));
|
|
102
|
-
if (typeof mod.query !== "function")
|
|
103
|
-
return null;
|
|
104
|
-
return { query: mod.query };
|
|
105
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { AgentSdkQueryFn } from "./agent-sdk.js";
|
|
2
|
-
/** Tools the staging session may use. Everything else — Bash above all —
|
|
3
|
-
* is refused: package installs and verification are pome's job, after
|
|
4
|
-
* the diff is approved. NOTE: never mirror these into `allowedTools`;
|
|
5
|
-
* bare allowedTools entries auto-approve before canUseTool is consulted. */
|
|
6
|
-
export declare const STAGING_TOOLS: readonly ["Read", "Edit", "Write", "Glob", "Grep"];
|
|
7
|
-
/** First message of the headless session. The pome-setup skill (injected
|
|
8
|
-
* into the shadow's .claude/skills) carries the wiring knowledge; this
|
|
9
|
-
* adapts its interactive contract to staging: edits land automatically,
|
|
10
|
-
* the human approves ONE combined diff in pome's terminal afterwards. */
|
|
11
|
-
export declare const EMBEDDED_KICKOFF_PROMPT: string;
|
|
12
|
-
export type EmbeddedWiringOutcome = {
|
|
13
|
-
kind: "applied";
|
|
14
|
-
files: number;
|
|
15
|
-
packageJsonChanged: boolean;
|
|
16
|
-
} | {
|
|
17
|
-
kind: "declined";
|
|
18
|
-
} | {
|
|
19
|
-
kind: "no-diff";
|
|
20
|
-
reason: string;
|
|
21
|
-
} | {
|
|
22
|
-
kind: "session-error";
|
|
23
|
-
reason: string;
|
|
24
|
-
};
|
|
25
|
-
export interface EmbeddedWiringOptions {
|
|
26
|
-
/** The real repo root the approved diff is applied to. */
|
|
27
|
-
cwd: string;
|
|
28
|
-
/** The user's Claude Code binary — passed as pathToClaudeCodeExecutable. */
|
|
29
|
-
claudePath: string;
|
|
30
|
-
/** Packaged pome-setup skill directory (contains SKILL.md). */
|
|
31
|
-
skillSourceDir: string;
|
|
32
|
-
/** The provisioned SDK's query(). Injected — the test seam. */
|
|
33
|
-
query: AgentSdkQueryFn;
|
|
34
|
-
/** [y/N] prompt. */
|
|
35
|
-
confirm: (question: string) => Promise<boolean>;
|
|
36
|
-
/** Line sink, default console.error. */
|
|
37
|
-
log?: (line: string) => void;
|
|
38
|
-
}
|
|
39
|
-
export declare function runEmbeddedWiring(options: EmbeddedWiringOptions): Promise<EmbeddedWiringOutcome>;
|
|
40
|
-
/** Path-confining permission gate. Exported for direct unit tests. */
|
|
41
|
-
export declare function buildStagingCanUseTool(shadowRoot: string, log: (line: string) => void): (toolName: string, input: Record<string, unknown>) => Promise<{
|
|
42
|
-
behavior: "allow";
|
|
43
|
-
updatedInput: Record<string, unknown>;
|
|
44
|
-
} | {
|
|
45
|
-
behavior: "deny";
|
|
46
|
-
message: string;
|
|
47
|
-
}>;
|