@contextq/cli 0.0.1 → 0.1.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 +48 -3
- package/dist/desktop-guide.d.ts +8 -0
- package/dist/desktop-guide.js +40 -0
- package/dist/desktop-guide.js.map +1 -0
- package/dist/detect.d.ts +42 -0
- package/dist/detect.js +70 -0
- package/dist/detect.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-config.d.ts +17 -0
- package/dist/mcp-config.js +79 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/platform-cred.d.ts +105 -0
- package/dist/platform-cred.js +210 -0
- package/dist/platform-cred.js.map +1 -0
- package/dist/prompt.d.ts +8 -0
- package/dist/prompt.js +53 -0
- package/dist/prompt.js.map +1 -0
- package/dist/session-hook.d.ts +95 -0
- package/dist/session-hook.js +217 -0
- package/dist/session-hook.js.map +1 -0
- package/dist/skills-sync.d.ts +62 -0
- package/dist/skills-sync.js +129 -0
- package/dist/skills-sync.js.map +1 -0
- package/dist/slug.d.ts +48 -0
- package/dist/slug.js +62 -0
- package/dist/slug.js.map +1 -0
- package/dist/tasks-init.d.ts +14 -0
- package/dist/tasks-init.js +51 -0
- package/dist/tasks-init.js.map +1 -0
- package/package.json +31 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-config.ts — idempotent .mcp.json merge.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors skills/contextq/scripts/install-hook.sh's wire_mcp(): never
|
|
5
|
+
* clobbers an existing .mcp.json, only ever sets/reads the "contextq" key
|
|
6
|
+
* under mcpServers, and defaults the key value to the ${CONTEXT_API_KEY}
|
|
7
|
+
* placeholder (safe default -- no secret on disk) unless --embed-key is
|
|
8
|
+
* passed. Claude Code expands ${VAR} from ITS OWN process environment, not
|
|
9
|
+
* from the credential file this installer writes -- same documented gap
|
|
10
|
+
* install-hook.sh warns about.
|
|
11
|
+
*/
|
|
12
|
+
export interface McpWireResult {
|
|
13
|
+
path: string;
|
|
14
|
+
action: 'created' | 'added' | 'skipped';
|
|
15
|
+
detail: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function wireMcpJson(root: string, apiUrl: string, embedKey: boolean, apiKey: string): McpWireResult;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-config.ts — idempotent .mcp.json merge.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors skills/contextq/scripts/install-hook.sh's wire_mcp(): never
|
|
5
|
+
* clobbers an existing .mcp.json, only ever sets/reads the "contextq" key
|
|
6
|
+
* under mcpServers, and defaults the key value to the ${CONTEXT_API_KEY}
|
|
7
|
+
* placeholder (safe default -- no secret on disk) unless --embed-key is
|
|
8
|
+
* passed. Claude Code expands ${VAR} from ITS OWN process environment, not
|
|
9
|
+
* from the credential file this installer writes -- same documented gap
|
|
10
|
+
* install-hook.sh warns about.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { execFileSync } from 'node:child_process';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
/**
|
|
16
|
+
* T474: whether `relPath` (relative to `root`) is covered by a gitignore rule.
|
|
17
|
+
* Returns null when this can't be determined (no git repo at `root`, or git
|
|
18
|
+
* itself is unavailable) -- callers must treat that as "unknown", not "safe".
|
|
19
|
+
*/
|
|
20
|
+
function isPathGitIgnored(root, relPath) {
|
|
21
|
+
try {
|
|
22
|
+
execFileSync('git', ['check-ignore', '-q', '--', relPath], { cwd: root, stdio: 'ignore' });
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const status = err.status;
|
|
27
|
+
if (status === 1)
|
|
28
|
+
return false;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function wireMcpJson(root, apiUrl, embedKey, apiKey) {
|
|
33
|
+
const path = join(root, '.mcp.json');
|
|
34
|
+
const existed = existsSync(path);
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
let doc = {};
|
|
37
|
+
if (existed) {
|
|
38
|
+
const raw = readFileSync(path, 'utf-8');
|
|
39
|
+
try {
|
|
40
|
+
doc = raw.trim() === '' ? {} : JSON.parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
throw new Error(`.mcp.json exists but is not valid JSON (${err.message}) -- refusing to touch it`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
doc.mcpServers ??= {};
|
|
47
|
+
if (doc.mcpServers.contextq) {
|
|
48
|
+
return { path, action: 'skipped', detail: 'contextq server entry already present' };
|
|
49
|
+
}
|
|
50
|
+
// T474: --embed-key is about to write the raw secret to disk -- refuse when
|
|
51
|
+
// .mcp.json would land in a commit, since that turns a local convenience
|
|
52
|
+
// flag into a leaked-credential incident the moment someone runs `git add .`.
|
|
53
|
+
if (embedKey) {
|
|
54
|
+
const ignored = isPathGitIgnored(root, '.mcp.json');
|
|
55
|
+
if (ignored === false) {
|
|
56
|
+
throw new Error('.mcp.json is not covered by .gitignore in this repo -- refusing to write the raw API key into a ' +
|
|
57
|
+
'file git would track. Add ".mcp.json" to .gitignore first, or re-run without --embed-key to use ' +
|
|
58
|
+
'the safer ${CONTEXT_API_KEY} placeholder instead.');
|
|
59
|
+
}
|
|
60
|
+
if (ignored === null) {
|
|
61
|
+
console.log('[warn] could not verify .mcp.json is gitignored (no git repo detected at this path) -- writing the raw key anyway.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
doc.mcpServers.contextq = {
|
|
65
|
+
command: 'npx',
|
|
66
|
+
args: ['-y', '@contextq/mcp'],
|
|
67
|
+
env: {
|
|
68
|
+
CONTEXT_API_URL: apiUrl,
|
|
69
|
+
CONTEXT_API_KEY: embedKey ? apiKey : '${CONTEXT_API_KEY}',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
writeFileSync(path, `${JSON.stringify(doc, null, 2)}\n`);
|
|
73
|
+
return {
|
|
74
|
+
path,
|
|
75
|
+
action: existed ? 'added' : 'created',
|
|
76
|
+
detail: `contextq server wired (key=${embedKey ? 'embedded literal' : '${CONTEXT_API_KEY} placeholder'})`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../src/mcp-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform-cred.ts — read/write the contextq platform credential file.
|
|
3
|
+
*
|
|
4
|
+
* Same path + mode as the existing T144 web installer (src/routes/installer.ts)
|
|
5
|
+
* and the same path the contextq skill's bash scripts (contextq-api.sh,
|
|
6
|
+
* install-hook.sh, contextq-boot.sh) and Bun cred-resolve.ts already read:
|
|
7
|
+
*
|
|
8
|
+
* macOS: ~/Library/Application Support/contextq/credentials
|
|
9
|
+
* Windows: %APPDATA%/contextq/credentials
|
|
10
|
+
* Linux: $XDG_CONFIG_HOME/contextq/credentials (default ~/.config)
|
|
11
|
+
*
|
|
12
|
+
* The existing readers disagree on which key names they check: install.sh
|
|
13
|
+
* (T144) writes CTQ_API_KEY/CTQ_API_URL (read by cred-resolve.ts's Bun path),
|
|
14
|
+
* while every bash script (contextq-api.sh, install-hook.sh, contextq-boot.sh)
|
|
15
|
+
* only ever reads CONTEXT_API_KEY/CONTEXT_API_URL from this same file. Rather
|
|
16
|
+
* than picking a side, this installer writes BOTH pairs so the credential it
|
|
17
|
+
* writes is visible to every existing reader regardless of that pre-existing
|
|
18
|
+
* inconsistency.
|
|
19
|
+
*
|
|
20
|
+
* Never logs or prints the key value.
|
|
21
|
+
*
|
|
22
|
+
* T676: writeCreds() itself remains an unconditional overwrite -- callers
|
|
23
|
+
* decide when that's appropriate. The safety layer lives in the helpers
|
|
24
|
+
* below (credsFileExists/credsEqual/backupCredsFile), which index.ts's
|
|
25
|
+
* runInit() composes into: no write on an ambient env var alone when a
|
|
26
|
+
* credential file already exists, a timestamped backup before any write
|
|
27
|
+
* that would actually change an existing file, and a no-op when the new
|
|
28
|
+
* value is identical to what's already on disk.
|
|
29
|
+
*/
|
|
30
|
+
export interface Creds {
|
|
31
|
+
apiKey: string;
|
|
32
|
+
apiUrl: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* T676: test-only override so cli/ tests can point every read/write at a
|
|
36
|
+
* throwaway temp dir instead of the real machine-wide credential path.
|
|
37
|
+
* Checked first, ahead of every OS-specific branch below. Production never
|
|
38
|
+
* sets this -- there is no code path that sets it outside a test.
|
|
39
|
+
*/
|
|
40
|
+
export declare function platformCredDir(): string;
|
|
41
|
+
export declare function platformCredFile(): string;
|
|
42
|
+
/** Does a credential file already exist on disk (real or overridden dir)? */
|
|
43
|
+
export declare function credsFileExists(): boolean;
|
|
44
|
+
/** Same apiKey AND same apiUrl -- the "nothing would actually change" case. */
|
|
45
|
+
export declare function credsEqual(a: Creds, b: Creds): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Copy whatever credential file is currently on disk to a timestamped
|
|
48
|
+
* sibling (mode 600, same directory) BEFORE it gets overwritten. Returns
|
|
49
|
+
* the backup path, or null when there was no existing file to back up.
|
|
50
|
+
* Never throws on missing source -- callers gate this on credsFileExists().
|
|
51
|
+
*/
|
|
52
|
+
export declare function backupCredsFile(): string | null;
|
|
53
|
+
/** Read whatever is already on disk. Both apiKey/apiUrl are '' when absent. */
|
|
54
|
+
export declare function readExistingCreds(): Creds;
|
|
55
|
+
/**
|
|
56
|
+
* Write the credential file at mode 0600 (dir at 0700). Overwrites whatever
|
|
57
|
+
* was there before — callers decide when that's appropriate (explicit --key,
|
|
58
|
+
* or no existing credential at all).
|
|
59
|
+
*/
|
|
60
|
+
export declare function writeCreds(creds: Creds): string;
|
|
61
|
+
export declare const KEY_RE: RegExp;
|
|
62
|
+
export interface CredentialDecisionInput {
|
|
63
|
+
/** `--key` flag value, if the caller passed one. */
|
|
64
|
+
explicitKey?: string;
|
|
65
|
+
/** Name of whichever ambient env var supplied a key, or null when neither is set. */
|
|
66
|
+
ambientVarName: 'CONTEXT_API_KEY' | 'CTQ_API_KEY' | null;
|
|
67
|
+
/** The ambient env var's value; '' when ambientVarName is null. */
|
|
68
|
+
ambientKey: string;
|
|
69
|
+
apiUrl: string;
|
|
70
|
+
}
|
|
71
|
+
export interface CredentialDecision {
|
|
72
|
+
apiKey: string;
|
|
73
|
+
credLine: string;
|
|
74
|
+
/**
|
|
75
|
+
* null only when the caller must fall through to an interactive prompt:
|
|
76
|
+
* no --key, no ambient env var, and no existing file to fall back to.
|
|
77
|
+
*/
|
|
78
|
+
action: 'created' | 'rotated' | 'skipped' | null;
|
|
79
|
+
backupPath: string | null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* T676: the non-interactive half of `contextq init`'s credential
|
|
83
|
+
* resolution. Fixes the real incident this task is named for -- a demo run
|
|
84
|
+
* with only an AMBIENT env var set (direnv-exported CONTEXT_API_KEY from
|
|
85
|
+
* some repo's .env.local) used to be treated exactly like an explicit
|
|
86
|
+
* --key, silently overwriting a pre-existing machine-wide credential file
|
|
87
|
+
* with no backup. Branches, matching T676's required behavior 1-4:
|
|
88
|
+
*
|
|
89
|
+
* 1. no --key, ambient env only, file exists -> file untouched, used as-is,
|
|
90
|
+
* "skipped" naming the ignored env var
|
|
91
|
+
* 2. --key given, file exists with a different key or url -> back up the
|
|
92
|
+
* existing file (mode 600, timestamped) THEN write, "rotated"
|
|
93
|
+
* 3. --key given, file exists with the identical key AND url -> no write,
|
|
94
|
+
* "skipped (unchanged)"
|
|
95
|
+
* 4. no existing file at all -> unchanged prior behavior, "created"
|
|
96
|
+
* (works from either --key or an ambient env var, since there is
|
|
97
|
+
* nothing to protect)
|
|
98
|
+
*
|
|
99
|
+
* The one case this function does not resolve on its own is "no --key, no
|
|
100
|
+
* ambient env var, no existing file" -- action comes back null and the
|
|
101
|
+
* caller must prompt interactively, then call this function again with the
|
|
102
|
+
* typed value as `explicitKey` to get a consistent created/rotated/skipped
|
|
103
|
+
* decision (falls into branch 4 in practice, since there is no file yet).
|
|
104
|
+
*/
|
|
105
|
+
export declare function decideCredentialWrite(input: CredentialDecisionInput): CredentialDecision;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* platform-cred.ts — read/write the contextq platform credential file.
|
|
3
|
+
*
|
|
4
|
+
* Same path + mode as the existing T144 web installer (src/routes/installer.ts)
|
|
5
|
+
* and the same path the contextq skill's bash scripts (contextq-api.sh,
|
|
6
|
+
* install-hook.sh, contextq-boot.sh) and Bun cred-resolve.ts already read:
|
|
7
|
+
*
|
|
8
|
+
* macOS: ~/Library/Application Support/contextq/credentials
|
|
9
|
+
* Windows: %APPDATA%/contextq/credentials
|
|
10
|
+
* Linux: $XDG_CONFIG_HOME/contextq/credentials (default ~/.config)
|
|
11
|
+
*
|
|
12
|
+
* The existing readers disagree on which key names they check: install.sh
|
|
13
|
+
* (T144) writes CTQ_API_KEY/CTQ_API_URL (read by cred-resolve.ts's Bun path),
|
|
14
|
+
* while every bash script (contextq-api.sh, install-hook.sh, contextq-boot.sh)
|
|
15
|
+
* only ever reads CONTEXT_API_KEY/CONTEXT_API_URL from this same file. Rather
|
|
16
|
+
* than picking a side, this installer writes BOTH pairs so the credential it
|
|
17
|
+
* writes is visible to every existing reader regardless of that pre-existing
|
|
18
|
+
* inconsistency.
|
|
19
|
+
*
|
|
20
|
+
* Never logs or prints the key value.
|
|
21
|
+
*
|
|
22
|
+
* T676: writeCreds() itself remains an unconditional overwrite -- callers
|
|
23
|
+
* decide when that's appropriate. The safety layer lives in the helpers
|
|
24
|
+
* below (credsFileExists/credsEqual/backupCredsFile), which index.ts's
|
|
25
|
+
* runInit() composes into: no write on an ambient env var alone when a
|
|
26
|
+
* credential file already exists, a timestamped backup before any write
|
|
27
|
+
* that would actually change an existing file, and a no-op when the new
|
|
28
|
+
* value is identical to what's already on disk.
|
|
29
|
+
*/
|
|
30
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
31
|
+
import { homedir } from 'node:os';
|
|
32
|
+
import { join } from 'node:path';
|
|
33
|
+
/**
|
|
34
|
+
* T676: test-only override so cli/ tests can point every read/write at a
|
|
35
|
+
* throwaway temp dir instead of the real machine-wide credential path.
|
|
36
|
+
* Checked first, ahead of every OS-specific branch below. Production never
|
|
37
|
+
* sets this -- there is no code path that sets it outside a test.
|
|
38
|
+
*/
|
|
39
|
+
export function platformCredDir() {
|
|
40
|
+
const override = process.env.CTQ_CRED_DIR || process.env.CONTEXTQ_CRED_DIR;
|
|
41
|
+
if (override)
|
|
42
|
+
return override;
|
|
43
|
+
const candidates = CRED_DIR_NAMES.map(platformCredDirFor);
|
|
44
|
+
return candidates.find((dir) => existsSync(join(dir, 'credentials'))) ?? candidates[0];
|
|
45
|
+
}
|
|
46
|
+
const CRED_DIR_NAMES = ['contextq', 'ctq-brain'];
|
|
47
|
+
function platformCredDirFor(dirName) {
|
|
48
|
+
const home = homedir();
|
|
49
|
+
if (process.platform === 'darwin') {
|
|
50
|
+
return join(home, 'Library', 'Application Support', dirName);
|
|
51
|
+
}
|
|
52
|
+
if (process.platform === 'win32') {
|
|
53
|
+
const appData = process.env.APPDATA ?? join(home, 'AppData', 'Roaming');
|
|
54
|
+
return join(appData, dirName);
|
|
55
|
+
}
|
|
56
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? join(home, '.config');
|
|
57
|
+
return join(xdg, dirName);
|
|
58
|
+
}
|
|
59
|
+
export function platformCredFile() {
|
|
60
|
+
return join(platformCredDir(), 'credentials');
|
|
61
|
+
}
|
|
62
|
+
/** Does a credential file already exist on disk (real or overridden dir)? */
|
|
63
|
+
export function credsFileExists() {
|
|
64
|
+
return existsSync(platformCredFile());
|
|
65
|
+
}
|
|
66
|
+
/** Same apiKey AND same apiUrl -- the "nothing would actually change" case. */
|
|
67
|
+
export function credsEqual(a, b) {
|
|
68
|
+
return a.apiKey === b.apiKey && a.apiUrl === b.apiUrl;
|
|
69
|
+
}
|
|
70
|
+
function utcTimestamp() {
|
|
71
|
+
const d = new Date();
|
|
72
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
73
|
+
return (`${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}` +
|
|
74
|
+
`T${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}Z`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Copy whatever credential file is currently on disk to a timestamped
|
|
78
|
+
* sibling (mode 600, same directory) BEFORE it gets overwritten. Returns
|
|
79
|
+
* the backup path, or null when there was no existing file to back up.
|
|
80
|
+
* Never throws on missing source -- callers gate this on credsFileExists().
|
|
81
|
+
*/
|
|
82
|
+
export function backupCredsFile() {
|
|
83
|
+
const file = platformCredFile();
|
|
84
|
+
if (!existsSync(file))
|
|
85
|
+
return null;
|
|
86
|
+
const dir = platformCredDir();
|
|
87
|
+
const backupPath = join(dir, `credentials.bak-${utcTimestamp()}`);
|
|
88
|
+
copyFileSync(file, backupPath);
|
|
89
|
+
chmodSync(backupPath, 0o600);
|
|
90
|
+
return backupPath;
|
|
91
|
+
}
|
|
92
|
+
function readEnvVal(key, filePath) {
|
|
93
|
+
if (!existsSync(filePath))
|
|
94
|
+
return '';
|
|
95
|
+
try {
|
|
96
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
97
|
+
for (const line of content.split('\n')) {
|
|
98
|
+
if (line.startsWith(`${key}=`))
|
|
99
|
+
return line.slice(key.length + 1).trim();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// never throw on a read error — treat as "no credential found"
|
|
104
|
+
}
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
/** Read whatever is already on disk. Both apiKey/apiUrl are '' when absent. */
|
|
108
|
+
export function readExistingCreds() {
|
|
109
|
+
const file = platformCredFile();
|
|
110
|
+
const apiKey = readEnvVal('CTQ_API_KEY', file) || readEnvVal('CONTEXT_API_KEY', file);
|
|
111
|
+
const apiUrl = readEnvVal('CTQ_API_URL', file) || readEnvVal('CONTEXT_API_URL', file);
|
|
112
|
+
return { apiKey, apiUrl };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Write the credential file at mode 0600 (dir at 0700). Overwrites whatever
|
|
116
|
+
* was there before — callers decide when that's appropriate (explicit --key,
|
|
117
|
+
* or no existing credential at all).
|
|
118
|
+
*/
|
|
119
|
+
export function writeCreds(creds) {
|
|
120
|
+
const dir = platformCredDir();
|
|
121
|
+
const file = platformCredFile();
|
|
122
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
123
|
+
chmodSync(dir, 0o700);
|
|
124
|
+
const body = `CTQ_API_KEY=${creds.apiKey}\n` +
|
|
125
|
+
`CTQ_API_URL=${creds.apiUrl}\n` +
|
|
126
|
+
`CONTEXT_API_KEY=${creds.apiKey}\n` +
|
|
127
|
+
`CONTEXT_API_URL=${creds.apiUrl}\n`;
|
|
128
|
+
writeFileSync(file, body, { mode: 0o600 });
|
|
129
|
+
chmodSync(file, 0o600);
|
|
130
|
+
return file;
|
|
131
|
+
}
|
|
132
|
+
export const KEY_RE = /^sk_live_[0-9a-f]{40}$/;
|
|
133
|
+
const LABEL_CREATED = '[create]';
|
|
134
|
+
const LABEL_ROTATED = '[rotate]';
|
|
135
|
+
const LABEL_SKIPPED = '[skip] ';
|
|
136
|
+
/**
|
|
137
|
+
* T676: the non-interactive half of `contextq init`'s credential
|
|
138
|
+
* resolution. Fixes the real incident this task is named for -- a demo run
|
|
139
|
+
* with only an AMBIENT env var set (direnv-exported CONTEXT_API_KEY from
|
|
140
|
+
* some repo's .env.local) used to be treated exactly like an explicit
|
|
141
|
+
* --key, silently overwriting a pre-existing machine-wide credential file
|
|
142
|
+
* with no backup. Branches, matching T676's required behavior 1-4:
|
|
143
|
+
*
|
|
144
|
+
* 1. no --key, ambient env only, file exists -> file untouched, used as-is,
|
|
145
|
+
* "skipped" naming the ignored env var
|
|
146
|
+
* 2. --key given, file exists with a different key or url -> back up the
|
|
147
|
+
* existing file (mode 600, timestamped) THEN write, "rotated"
|
|
148
|
+
* 3. --key given, file exists with the identical key AND url -> no write,
|
|
149
|
+
* "skipped (unchanged)"
|
|
150
|
+
* 4. no existing file at all -> unchanged prior behavior, "created"
|
|
151
|
+
* (works from either --key or an ambient env var, since there is
|
|
152
|
+
* nothing to protect)
|
|
153
|
+
*
|
|
154
|
+
* The one case this function does not resolve on its own is "no --key, no
|
|
155
|
+
* ambient env var, no existing file" -- action comes back null and the
|
|
156
|
+
* caller must prompt interactively, then call this function again with the
|
|
157
|
+
* typed value as `explicitKey` to get a consistent created/rotated/skipped
|
|
158
|
+
* decision (falls into branch 4 in practice, since there is no file yet).
|
|
159
|
+
*/
|
|
160
|
+
export function decideCredentialWrite(input) {
|
|
161
|
+
const existing = readExistingCreds();
|
|
162
|
+
const fileExists = credsFileExists();
|
|
163
|
+
const writeSafely = (newCreds) => {
|
|
164
|
+
if (!fileExists) {
|
|
165
|
+
writeCreds(newCreds);
|
|
166
|
+
return { action: 'created', backupPath: null };
|
|
167
|
+
}
|
|
168
|
+
if (credsEqual(existing, newCreds)) {
|
|
169
|
+
return { action: 'skipped', backupPath: null };
|
|
170
|
+
}
|
|
171
|
+
const backupPath = backupCredsFile();
|
|
172
|
+
writeCreds(newCreds);
|
|
173
|
+
return { action: 'rotated', backupPath };
|
|
174
|
+
};
|
|
175
|
+
if (input.explicitKey) {
|
|
176
|
+
if (!KEY_RE.test(input.explicitKey)) {
|
|
177
|
+
throw new Error('the provided API key does not look valid (expected sk_live_<40 hex chars>)');
|
|
178
|
+
}
|
|
179
|
+
const apiKey = input.explicitKey;
|
|
180
|
+
const result = writeSafely({ apiKey, apiUrl: input.apiUrl });
|
|
181
|
+
const credLine = result.action === 'skipped'
|
|
182
|
+
? `${LABEL_SKIPPED} credentials (unchanged)`
|
|
183
|
+
: result.action === 'rotated'
|
|
184
|
+
? `${LABEL_ROTATED} credentials (${platformCredFile()}; previous saved to ${result.backupPath})`
|
|
185
|
+
: `${LABEL_CREATED} credentials (${platformCredFile()}, mode 600)`;
|
|
186
|
+
return { apiKey, credLine, action: result.action, backupPath: result.backupPath };
|
|
187
|
+
}
|
|
188
|
+
if (fileExists && existing.apiKey) {
|
|
189
|
+
// Branch 1: an ambient env var, if any, is deliberately never even
|
|
190
|
+
// validated here -- it is not going to be used, so a garbage value must
|
|
191
|
+
// not throw.
|
|
192
|
+
const credLine = input.ambientVarName
|
|
193
|
+
? `${LABEL_SKIPPED} credentials (already configured at ${platformCredFile()}; env ${input.ambientVarName} ignored, pass --key to rotate)`
|
|
194
|
+
: `${LABEL_SKIPPED} credentials (already configured at ${platformCredFile()}; pass --key to rotate)`;
|
|
195
|
+
return { apiKey: existing.apiKey, credLine, action: 'skipped', backupPath: null };
|
|
196
|
+
}
|
|
197
|
+
if (input.ambientKey) {
|
|
198
|
+
if (!KEY_RE.test(input.ambientKey)) {
|
|
199
|
+
throw new Error('the provided API key does not look valid (expected sk_live_<40 hex chars>)');
|
|
200
|
+
}
|
|
201
|
+
const apiKey = input.ambientKey;
|
|
202
|
+
const result = writeSafely({ apiKey, apiUrl: input.apiUrl });
|
|
203
|
+
const credLine = result.action === 'rotated'
|
|
204
|
+
? `${LABEL_ROTATED} credentials (${platformCredFile()}; previous saved to ${result.backupPath})`
|
|
205
|
+
: `${LABEL_CREATED} credentials (${platformCredFile()}, mode 600)`;
|
|
206
|
+
return { apiKey, credLine, action: result.action, backupPath: result.backupPath };
|
|
207
|
+
}
|
|
208
|
+
return { apiKey: '', credLine: '', action: null, backupPath: null };
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=platform-cred.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-cred.js","sourceRoot":"","sources":["../src/platform-cred.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC;;;;;GAKG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC3E,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC1D,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,WAAW,CAAU,CAAC;AAE1D,SAAS,kBAAkB,CAAC,OAAe;IACzC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,eAAe,EAAE,EAAE,aAAa,CAAC,CAAC;AAChD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,gBAAgB,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,CAAQ,EAAE,CAAQ;IAC3C,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,CACL,GAAG,CAAC,CAAC,cAAc,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE;QACxE,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,GAAG,CAC9E,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,YAAY,EAAE,EAAE,CAAC,CAAC;IAClE,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/B,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC7B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAE,QAAgB;IAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3E,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;IACjE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,UAAU,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,UAAU,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACtF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAEtB,MAAM,IAAI,GACR,eAAe,KAAK,CAAC,MAAM,IAAI;QAC/B,eAAe,KAAK,CAAC,MAAM,IAAI;QAC/B,mBAAmB,KAAK,CAAC,MAAM,IAAI;QACnC,mBAAmB,KAAK,CAAC,MAAM,IAAI,CAAC;IAEtC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,wBAAwB,CAAC;AAE/C,MAAM,aAAa,GAAG,UAAU,CAAC;AACjC,MAAM,aAAa,GAAG,UAAU,CAAC;AACjC,MAAM,aAAa,GAAG,SAAS,CAAC;AAuBhC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA8B;IAClE,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC;IAErC,MAAM,WAAW,GAAG,CAClB,QAAe,EAC2D,EAAE;QAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,UAAU,CAAC,QAAQ,CAAC,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QACjD,CAAC;QACD,IAAI,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;YACnC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QACjD,CAAC;QACD,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC;QACrC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;IAC3C,CAAC,CAAC;IAEF,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;QACjC,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,MAAM,QAAQ,GACZ,MAAM,CAAC,MAAM,KAAK,SAAS;YACzB,CAAC,CAAC,GAAG,aAAa,0BAA0B;YAC5C,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS;gBAC3B,CAAC,CAAC,GAAG,aAAa,iBAAiB,gBAAgB,EAAE,uBAAuB,MAAM,CAAC,UAAU,GAAG;gBAChG,CAAC,CAAC,GAAG,aAAa,iBAAiB,gBAAgB,EAAE,aAAa,CAAC;QACzE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IACpF,CAAC;IAED,IAAI,UAAU,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QAClC,mEAAmE;QACnE,wEAAwE;QACxE,aAAa;QACb,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc;YACnC,CAAC,CAAC,GAAG,aAAa,uCAAuC,gBAAgB,EAAE,SAAS,KAAK,CAAC,cAAc,iCAAiC;YACzI,CAAC,CAAC,GAAG,aAAa,uCAAuC,gBAAgB,EAAE,yBAAyB,CAAC;QACvG,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IACpF,CAAC;IAED,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC;QAChC,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,MAAM,QAAQ,GACZ,MAAM,CAAC,MAAM,KAAK,SAAS;YACzB,CAAC,CAAC,GAAG,aAAa,iBAAiB,gBAAgB,EAAE,uBAAuB,MAAM,CAAC,UAAU,GAAG;YAChG,CAAC,CAAC,GAAG,aAAa,iBAAiB,gBAAgB,EAAE,aAAa,CAAC;QACvE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IACpF,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACtE,CAAC"}
|
package/dist/prompt.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt.ts — masked stdin prompt for the API key, no extra dependency.
|
|
3
|
+
*
|
|
4
|
+
* Returns '' immediately when stdin is not a TTY (non-interactive/CI run) --
|
|
5
|
+
* callers must treat that as "no key available" and fail with a clear
|
|
6
|
+
* message rather than hang waiting for input that will never arrive.
|
|
7
|
+
*/
|
|
8
|
+
export declare function promptHidden(question: string): Promise<string>;
|
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt.ts — masked stdin prompt for the API key, no extra dependency.
|
|
3
|
+
*
|
|
4
|
+
* Returns '' immediately when stdin is not a TTY (non-interactive/CI run) --
|
|
5
|
+
* callers must treat that as "no key available" and fail with a clear
|
|
6
|
+
* message rather than hang waiting for input that will never arrive.
|
|
7
|
+
*/
|
|
8
|
+
const CTRL_C = String.fromCharCode(3);
|
|
9
|
+
const CTRL_D = String.fromCharCode(4);
|
|
10
|
+
const DEL = String.fromCharCode(127);
|
|
11
|
+
export async function promptHidden(question) {
|
|
12
|
+
if (!process.stdin.isTTY)
|
|
13
|
+
return '';
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const stdin = process.stdin;
|
|
16
|
+
const stdout = process.stdout;
|
|
17
|
+
stdout.write(question);
|
|
18
|
+
let input = '';
|
|
19
|
+
const onData = (chunk) => {
|
|
20
|
+
const char = chunk.toString('utf8');
|
|
21
|
+
switch (char) {
|
|
22
|
+
case '\n':
|
|
23
|
+
case '\r':
|
|
24
|
+
case CTRL_D:
|
|
25
|
+
stdin.setRawMode?.(false);
|
|
26
|
+
stdin.pause();
|
|
27
|
+
stdin.removeListener('data', onData);
|
|
28
|
+
stdout.write('\n');
|
|
29
|
+
resolve(input.trim());
|
|
30
|
+
break;
|
|
31
|
+
case CTRL_C:
|
|
32
|
+
stdout.write('\n');
|
|
33
|
+
process.exit(130);
|
|
34
|
+
break;
|
|
35
|
+
case DEL:
|
|
36
|
+
case '\b':
|
|
37
|
+
if (input.length > 0) {
|
|
38
|
+
input = input.slice(0, -1);
|
|
39
|
+
stdout.write('\b \b');
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
input += char;
|
|
44
|
+
stdout.write('*');
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
stdin.setRawMode?.(true);
|
|
48
|
+
stdin.resume();
|
|
49
|
+
stdin.setEncoding('utf8');
|
|
50
|
+
stdin.on('data', onData);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEvB,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,CAAC,KAAa,EAAQ,EAAE;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACpC,QAAQ,IAAI,EAAE,CAAC;gBACb,KAAK,IAAI,CAAC;gBACV,KAAK,IAAI,CAAC;gBACV,KAAK,MAAM;oBACT,KAAK,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;oBAC1B,KAAK,CAAC,KAAK,EAAE,CAAC;oBACd,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBACrC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACnB,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBACtB,MAAM;gBACR,KAAK,MAAM;oBACT,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAClB,MAAM;gBACR,KAAK,GAAG,CAAC;gBACT,KAAK,IAAI;oBACP,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACrB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;wBAC3B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACxB,CAAC;oBACD,MAAM;gBACR;oBACE,KAAK,IAAI,IAAI,CAAC;oBACd,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-hook.ts — idempotent SessionStart boot-hook merge, for BOTH
|
|
3
|
+
* Claude Code and Codex CLI (T665).
|
|
4
|
+
*
|
|
5
|
+
* Targets <root>/.claude/settings.local.json for Claude Code, NOT
|
|
6
|
+
* settings.json -- mirroring skills/contextq/scripts/install-hook.sh's own
|
|
7
|
+
* explicit rule: the baked hook command embeds an absolute $HOME/... path,
|
|
8
|
+
* which is per-machine and MUST stay in a gitignored file, never a
|
|
9
|
+
* shared/global settings file (see install-hook.sh header comment).
|
|
10
|
+
*
|
|
11
|
+
* Codex's own convention treats project-level `.codex/config.toml` /
|
|
12
|
+
* `.codex/hooks.json` as "trusted-repo settings" meant to be COMMITTED and
|
|
13
|
+
* shared across a team (verified against developers.openai.com/codex docs,
|
|
14
|
+
* 2026-08-20: "Project `.codex/config.toml` -> trusted-repo Codex settings
|
|
15
|
+
* such as sandbox, MCP, hooks, model, or reasoning defaults") -- there is no
|
|
16
|
+
* Codex-native equivalent of Claude's settings.json/settings.local.json
|
|
17
|
+
* split. Since the command we write embeds the SAME per-machine absolute
|
|
18
|
+
* path either way, wireCodexSessionHook() deliberately breaks from that
|
|
19
|
+
* convention and gitignores `.codex/hooks.json` itself (see
|
|
20
|
+
* ensureGitignored below) rather than let a per-machine path get committed
|
|
21
|
+
* and silently break for every teammate whose contextq skill lives
|
|
22
|
+
* somewhere else (or isn't installed at all).
|
|
23
|
+
*
|
|
24
|
+
* This installer POINTS AT the contextq skill's boot script when it is
|
|
25
|
+
* already installed globally at ~/.claude/skills/contextq -- it never
|
|
26
|
+
* copies/vendors the skill tree into the target project (out of this
|
|
27
|
+
* installer's declared write-scope: .mcp.json, .claude/settings*.json,
|
|
28
|
+
* .codex/hooks.json, .contextq/, and the credential file only).
|
|
29
|
+
*
|
|
30
|
+
* ONE shared code path for both harnesses (T665 requirement), in two
|
|
31
|
+
* layers:
|
|
32
|
+
* - buildBootCommand() is the single command-string builder both writers
|
|
33
|
+
* call -- same env vars, same shellQuote()-based escaping, same target
|
|
34
|
+
* script.
|
|
35
|
+
* - mergeSessionStartHook() is the single read-merge-idempotent-write
|
|
36
|
+
* implementation both writers call. Claude's `.claude/settings.local.json`
|
|
37
|
+
* and Codex's `.codex/hooks.json` use the IDENTICAL JSON shape for a
|
|
38
|
+
* SessionStart entry -- { hooks: { SessionStart: [ { hooks: [ { type:
|
|
39
|
+
* 'command', command } ] } ] } } (verified against Codex's `hooks.json`
|
|
40
|
+
* schema at developers.openai.com/codex/hooks, 2026-08-20) -- so there is
|
|
41
|
+
* exactly one implementation of "does this file already have our hook,
|
|
42
|
+
* and if not, append it", parameterized by which file path to merge
|
|
43
|
+
* into. The two exported writers (wireSessionHook, wireCodexSessionHook)
|
|
44
|
+
* are thin wrappers supplying only the path + an optional top-level
|
|
45
|
+
* default field Codex's schema additionally supports ("description").
|
|
46
|
+
*/
|
|
47
|
+
export interface HookWireResult {
|
|
48
|
+
path: string;
|
|
49
|
+
action: 'wired' | 'skipped';
|
|
50
|
+
detail: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* T656: POSIX single-quote wrap, safe for any input including shell
|
|
54
|
+
* metacharacters, unbalanced quotes, backticks, `$()`, `;`, etc. This is the
|
|
55
|
+
* defense-in-depth layer: slug.ts's validateSlug()/sanitizeSlugFallback()
|
|
56
|
+
* already constrain --agent/--workspace to a safe charset before they reach
|
|
57
|
+
* here, but this function must make the written command safe on its own,
|
|
58
|
+
* because a future caller of wireSessionHook()/wireCodexSessionHook() might
|
|
59
|
+
* bypass that validation (it takes plain strings, not a branded/validated
|
|
60
|
+
* type) -- every value substituted into the command string, including
|
|
61
|
+
* bootScript itself, goes through this.
|
|
62
|
+
*
|
|
63
|
+
* Standard technique: wrap in single quotes (nothing is interpolated inside
|
|
64
|
+
* single quotes in POSIX sh/bash), and for each embedded single quote,
|
|
65
|
+
* close the quote, emit an escaped literal quote, then reopen: ' -> '\''.
|
|
66
|
+
*/
|
|
67
|
+
export declare function shellQuote(value: string): string;
|
|
68
|
+
export declare function ctqBrainBootScript(): string;
|
|
69
|
+
/**
|
|
70
|
+
* buildBootCommand — the ONE harness-agnostic command builder (T665). Both
|
|
71
|
+
* wireSessionHook (Claude) and wireCodexSessionHook (Codex) call this to
|
|
72
|
+
* produce the exact same shell command string. Codex's SessionStart stdin
|
|
73
|
+
* contract and its `hookSpecificOutput.additionalContext` output shape are
|
|
74
|
+
* verified (2026-08-20, developers.openai.com/codex/hooks) to match Claude's
|
|
75
|
+
* field-for-field (session_id, transcript_path, cwd, hook_event_name on
|
|
76
|
+
* stdin; the same hookSpecificOutput.additionalContext JSON, or plain text,
|
|
77
|
+
* on stdout) -- so contextq-boot.sh's existing --hook output needs no
|
|
78
|
+
* per-harness branching, and this builder needs none either.
|
|
79
|
+
*/
|
|
80
|
+
export declare function buildBootCommand(agentSlug: string, workspace: string, bootScript: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* `bootScriptOverride` exists purely for tests: production callers (index.ts)
|
|
83
|
+
* always call this with 3 args and get ctqBrainBootScript(), which points at
|
|
84
|
+
* a real, per-machine, possibly-absent path under $HOME -- tests need to
|
|
85
|
+
* exercise the "wired" branch deterministically without depending on the
|
|
86
|
+
* host actually having contextq installed.
|
|
87
|
+
*/
|
|
88
|
+
export declare function wireSessionHook(root: string, agentSlug: string, workspace: string, bootScriptOverride?: string): HookWireResult;
|
|
89
|
+
/**
|
|
90
|
+
* wireCodexSessionHook — the Codex writer (T665). Same command, same merge
|
|
91
|
+
* core as wireSessionHook above; only the target path, the top-level
|
|
92
|
+
* "description" default, and the gitignore step differ. `bootScriptOverride`
|
|
93
|
+
* exists for the same test-determinism reason as wireSessionHook's.
|
|
94
|
+
*/
|
|
95
|
+
export declare function wireCodexSessionHook(root: string, agentSlug: string, workspace: string, bootScriptOverride?: string): HookWireResult;
|