@furkankoykiran/contextify-cli 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/dist/batcher.d.ts +36 -0
- package/dist/batcher.d.ts.map +1 -0
- package/dist/batcher.js +94 -0
- package/dist/batcher.js.map +1 -0
- package/dist/commands/hooks.d.ts +32 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +253 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +49 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-hooks.d.ts +42 -0
- package/dist/commands/install-hooks.d.ts.map +1 -0
- package/dist/commands/install-hooks.js +162 -0
- package/dist/commands/install-hooks.js.map +1 -0
- package/dist/commands/install.d.ts +53 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +129 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +36 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/prompt.d.ts +17 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +141 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/ship.d.ts +6 -0
- package/dist/commands/ship.d.ts.map +1 -0
- package/dist/commands/ship.js +20 -0
- package/dist/commands/ship.js.map +1 -0
- package/dist/commands/wrap.d.ts +10 -0
- package/dist/commands/wrap.d.ts.map +1 -0
- package/dist/commands/wrap.js +83 -0
- package/dist/commands/wrap.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +84 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +34 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +68 -0
- package/dist/credentials.js.map +1 -0
- package/dist/identity.d.ts +42 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +201 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +0 -0
- package/dist/index.js.map +1 -0
- package/dist/shipper.d.ts +49 -0
- package/dist/shipper.d.ts.map +1 -0
- package/dist/shipper.js +110 -0
- package/dist/shipper.js.map +1 -0
- package/dist/transcript.d.ts +52 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +216 -0
- package/dist/transcript.js.map +1 -0
- package/package.json +69 -0
- package/src/hooks/session-end.sh +5 -0
- package/src/hooks/session-start.sh +5 -0
- package/src/hooks/stop.sh +5 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `contextify wrap -- <cmd> [args...]`
|
|
3
|
+
*
|
|
4
|
+
* Spawns the child command, mirrors its stdout/stderr to the user's
|
|
5
|
+
* terminal in real time, and ships batched copies to the Contextify server.
|
|
6
|
+
*
|
|
7
|
+
* Trade-off: we use `child_process.spawn` with piped stdio so we avoid
|
|
8
|
+
* a native dep (`node-pty`). Line-based commands (git, pnpm, scripts)
|
|
9
|
+
* work fine. Full-screen TUI apps lose true TTY semantics — that's a
|
|
10
|
+
* documented limitation, swappable for `node-pty` later if needed.
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from 'node:child_process';
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
14
|
+
import { Batcher } from '../batcher.js';
|
|
15
|
+
import { resolveConfig } from '../config.js';
|
|
16
|
+
import { shipBatch } from '../shipper.js';
|
|
17
|
+
const DEFAULT_MAX_BYTES = 64 * 1024;
|
|
18
|
+
const DEFAULT_MAX_IDLE_MS = 5_000;
|
|
19
|
+
export async function runWrap(opts) {
|
|
20
|
+
if (opts.argv.length === 0) {
|
|
21
|
+
process.stderr.write('error: contextify wrap -- <cmd> [args...]\n');
|
|
22
|
+
return 2;
|
|
23
|
+
}
|
|
24
|
+
let config;
|
|
25
|
+
try {
|
|
26
|
+
config = await resolveConfig(opts.cwd, opts.env);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
process.stderr.write(`contextify: ${err.message}\n`);
|
|
30
|
+
return 2;
|
|
31
|
+
}
|
|
32
|
+
const sessionId = randomUUID();
|
|
33
|
+
const ship = async (payload) => {
|
|
34
|
+
const batch = {
|
|
35
|
+
projectId: config.projectId,
|
|
36
|
+
projectName: config.projectName,
|
|
37
|
+
sessionId,
|
|
38
|
+
payload,
|
|
39
|
+
};
|
|
40
|
+
await shipBatch(batch, {
|
|
41
|
+
serverUrl: config.serverUrl,
|
|
42
|
+
cwd: opts.cwd,
|
|
43
|
+
forceSpool: opts.forceSpool,
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
const batcher = new Batcher({
|
|
47
|
+
maxBytes: opts.maxBytes ?? DEFAULT_MAX_BYTES,
|
|
48
|
+
maxIdleMs: opts.maxIdleMs ?? DEFAULT_MAX_IDLE_MS,
|
|
49
|
+
flush: ship,
|
|
50
|
+
});
|
|
51
|
+
batcher.start();
|
|
52
|
+
const [cmd, ...rest] = opts.argv;
|
|
53
|
+
const child = spawn(cmd, rest, {
|
|
54
|
+
cwd: opts.cwd,
|
|
55
|
+
env: opts.env ?? process.env,
|
|
56
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
57
|
+
});
|
|
58
|
+
child.stdout.on('data', (chunk) => {
|
|
59
|
+
process.stdout.write(chunk);
|
|
60
|
+
batcher.append(chunk.toString('utf8'));
|
|
61
|
+
});
|
|
62
|
+
child.stderr.on('data', (chunk) => {
|
|
63
|
+
process.stderr.write(chunk);
|
|
64
|
+
batcher.append(chunk.toString('utf8'));
|
|
65
|
+
});
|
|
66
|
+
const exitCode = await new Promise((resolve) => {
|
|
67
|
+
child.on('close', (code, signal) => {
|
|
68
|
+
if (typeof code === 'number')
|
|
69
|
+
resolve(code);
|
|
70
|
+
else if (signal)
|
|
71
|
+
resolve(128);
|
|
72
|
+
else
|
|
73
|
+
resolve(0);
|
|
74
|
+
});
|
|
75
|
+
child.on('error', (err) => {
|
|
76
|
+
process.stderr.write(`contextify: ${err.message}\n`);
|
|
77
|
+
resolve(127);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
await batcher.close();
|
|
81
|
+
return exitCode;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=wrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../src/commands/wrap.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const CONFIG_FILENAME = ".contextify.json";
|
|
2
|
+
export declare const DEFAULT_SERVER_URL = "http://localhost:3000";
|
|
3
|
+
export interface CliConfig {
|
|
4
|
+
readonly projectId: string;
|
|
5
|
+
readonly projectName?: string;
|
|
6
|
+
readonly serverUrl: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedConfig extends CliConfig {
|
|
9
|
+
readonly configPath: string | null;
|
|
10
|
+
readonly source: 'file' | 'env' | 'mixed' | 'none';
|
|
11
|
+
}
|
|
12
|
+
export declare function configPath(cwd: string): string;
|
|
13
|
+
export declare function readConfig(cwd: string): Promise<CliConfig | null>;
|
|
14
|
+
export declare function writeConfig(cwd: string, config: CliConfig): Promise<string>;
|
|
15
|
+
export declare function resolveConfig(cwd: string, env?: NodeJS.ProcessEnv): Promise<ResolvedConfig>;
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAClD,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;CACpD;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAiBvE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAOjF;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,cAAc,CAAC,CA2CzB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-local CLI configuration.
|
|
3
|
+
*
|
|
4
|
+
* `.contextify.json` lives in the user's cwd (the project root) and stores the
|
|
5
|
+
* `projectId`, optional display name, and server URL. Environment variables
|
|
6
|
+
* (`CONTEXTIFY_SERVER_URL`, `CONTEXTIFY_PROJECT_ID`) override the file so CI can
|
|
7
|
+
* inject credentials without rewriting the file on disk.
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { join, resolve } from 'node:path';
|
|
12
|
+
export const CONFIG_FILENAME = '.contextify.json';
|
|
13
|
+
export const DEFAULT_SERVER_URL = 'http://localhost:3000';
|
|
14
|
+
const SLUG_RE = /^[a-zA-Z0-9_-]+$/;
|
|
15
|
+
export function configPath(cwd) {
|
|
16
|
+
return join(resolve(cwd), CONFIG_FILENAME);
|
|
17
|
+
}
|
|
18
|
+
export async function readConfig(cwd) {
|
|
19
|
+
const path = configPath(cwd);
|
|
20
|
+
if (!existsSync(path))
|
|
21
|
+
return null;
|
|
22
|
+
const text = await readFile(path, 'utf8');
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(text);
|
|
25
|
+
if (!parsed.projectId || !SLUG_RE.test(parsed.projectId)) {
|
|
26
|
+
throw new Error(`${path}: projectId is missing or invalid`);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
projectId: parsed.projectId,
|
|
30
|
+
projectName: parsed.projectName,
|
|
31
|
+
serverUrl: parsed.serverUrl ?? DEFAULT_SERVER_URL,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw new Error(`${path}: ${err.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function writeConfig(cwd, config) {
|
|
39
|
+
if (!SLUG_RE.test(config.projectId)) {
|
|
40
|
+
throw new Error('projectId must match [a-zA-Z0-9_-]+');
|
|
41
|
+
}
|
|
42
|
+
const path = configPath(cwd);
|
|
43
|
+
await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
44
|
+
return path;
|
|
45
|
+
}
|
|
46
|
+
export async function resolveConfig(cwd, env = process.env) {
|
|
47
|
+
const fromFile = await readConfig(cwd);
|
|
48
|
+
const envProjectId = env.CONTEXTIFY_PROJECT_ID;
|
|
49
|
+
const envServerUrl = env.CONTEXTIFY_SERVER_URL;
|
|
50
|
+
if (envProjectId && envServerUrl) {
|
|
51
|
+
if (!SLUG_RE.test(envProjectId)) {
|
|
52
|
+
throw new Error('CONTEXTIFY_PROJECT_ID must match [a-zA-Z0-9_-]+');
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
projectId: envProjectId,
|
|
56
|
+
projectName: fromFile?.projectName,
|
|
57
|
+
serverUrl: envServerUrl,
|
|
58
|
+
configPath: fromFile ? configPath(cwd) : null,
|
|
59
|
+
source: fromFile ? 'mixed' : 'env',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (fromFile) {
|
|
63
|
+
return {
|
|
64
|
+
...fromFile,
|
|
65
|
+
projectId: envProjectId ?? fromFile.projectId,
|
|
66
|
+
serverUrl: envServerUrl ?? fromFile.serverUrl,
|
|
67
|
+
configPath: configPath(cwd),
|
|
68
|
+
source: envProjectId || envServerUrl ? 'mixed' : 'file',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (envProjectId) {
|
|
72
|
+
if (!SLUG_RE.test(envProjectId)) {
|
|
73
|
+
throw new Error('CONTEXTIFY_PROJECT_ID must match [a-zA-Z0-9_-]+');
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
projectId: envProjectId,
|
|
77
|
+
serverUrl: envServerUrl ?? DEFAULT_SERVER_URL,
|
|
78
|
+
configPath: null,
|
|
79
|
+
source: 'env',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
throw new Error('no contextify config found — run `contextify init <projectId>` or set CONTEXTIFY_PROJECT_ID');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface CredentialsFile {
|
|
2
|
+
/**
|
|
3
|
+
* The full `ctx_live_<prefix>_<secret>` string as issued by the
|
|
4
|
+
* dashboard. We never split it — the server parses the prefix
|
|
5
|
+
* itself from the bearer header.
|
|
6
|
+
*/
|
|
7
|
+
readonly apiKey: string;
|
|
8
|
+
/** Optional label for the key — informational only. */
|
|
9
|
+
readonly name?: string;
|
|
10
|
+
/** When this credentials file was written. */
|
|
11
|
+
readonly savedAt?: string;
|
|
12
|
+
/** Server URL this key was issued for. Lets users keep distinct keys per env. */
|
|
13
|
+
readonly serverUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedCredentials {
|
|
16
|
+
readonly apiKey: string;
|
|
17
|
+
readonly source: 'env' | 'file';
|
|
18
|
+
/** Present only when the source is the on-disk credentials file. */
|
|
19
|
+
readonly serverUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function credentialsPath(home?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the API key for outbound requests. Returns null if neither
|
|
24
|
+
* env nor file has one — callers should ship without an Authorization
|
|
25
|
+
* header in that case (server permits this in dev fallback mode).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveApiKey(env?: NodeJS.ProcessEnv): ResolvedCredentials | null;
|
|
28
|
+
/**
|
|
29
|
+
* Write a credentials file with secure permissions. Used by
|
|
30
|
+
* `contextify login --key <key>` (added later) and by integration
|
|
31
|
+
* tests. The file is chmod 600 — only the user can read.
|
|
32
|
+
*/
|
|
33
|
+
export declare function saveCredentials(file: CredentialsFile, home?: string): string;
|
|
34
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IAChC,oEAAoE;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,mBAAmB,GAAG,IAAI,CAkB9F;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CAevF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API key resolution for the CLI.
|
|
3
|
+
*
|
|
4
|
+
* 1. CONTEXTIFY_API_KEY env var wins (hosted/prod via systemd/launchd)
|
|
5
|
+
* 2. ~/.contextify/credentials.json on disk (per-user, persistent)
|
|
6
|
+
* 3. nothing — request goes unauthenticated, server returns 401
|
|
7
|
+
* (there is no legacy fallback)
|
|
8
|
+
*
|
|
9
|
+
* The credentials file is intentionally NOT inside the project repo —
|
|
10
|
+
* bearer keys must never be committable.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
const CRED_FILENAME = 'credentials.json';
|
|
16
|
+
const CRED_DIR_NAME = '.contextify';
|
|
17
|
+
export function credentialsPath(home = homedir()) {
|
|
18
|
+
return join(home, CRED_DIR_NAME, CRED_FILENAME);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the API key for outbound requests. Returns null if neither
|
|
22
|
+
* env nor file has one — callers should ship without an Authorization
|
|
23
|
+
* header in that case (server permits this in dev fallback mode).
|
|
24
|
+
*/
|
|
25
|
+
export function resolveApiKey(env = process.env) {
|
|
26
|
+
const fromEnv = env.CONTEXTIFY_API_KEY?.trim();
|
|
27
|
+
if (fromEnv) {
|
|
28
|
+
return { apiKey: fromEnv, source: 'env' };
|
|
29
|
+
}
|
|
30
|
+
const path = credentialsPath();
|
|
31
|
+
if (!existsSync(path))
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
const raw = readFileSync(path, 'utf8');
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
if (parsed?.apiKey && parsed.apiKey.startsWith('ctx_live_')) {
|
|
37
|
+
return { apiKey: parsed.apiKey, source: 'file', serverUrl: parsed.serverUrl };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Don't crash on a malformed credentials file — fall through to
|
|
42
|
+
// unauthenticated. The user can re-run `contextify login` to fix it.
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Write a credentials file with secure permissions. Used by
|
|
48
|
+
* `contextify login --key <key>` (added later) and by integration
|
|
49
|
+
* tests. The file is chmod 600 — only the user can read.
|
|
50
|
+
*/
|
|
51
|
+
export function saveCredentials(file, home = homedir()) {
|
|
52
|
+
const path = credentialsPath(home);
|
|
53
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
54
|
+
const payload = {
|
|
55
|
+
...file,
|
|
56
|
+
savedAt: new Date().toISOString(),
|
|
57
|
+
};
|
|
58
|
+
writeFileSync(path, JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
59
|
+
// Re-chmod in case writeFile didn't honor `mode` (e.g. existing file).
|
|
60
|
+
try {
|
|
61
|
+
chmodSync(path, 0o600);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// best-effort
|
|
65
|
+
}
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,aAAa,GAAG,kBAAkB,CAAC;AACzC,MAAM,aAAa,GAAG,aAAa,CAAC;AAwBpC,MAAM,UAAU,eAAe,CAAC,OAAe,OAAO,EAAE;IACtD,OAAO,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC5C,CAAC;IACD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;QAClD,IAAI,MAAM,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;QAChF,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,qEAAqE;IACvE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAqB,EAAE,OAAe,OAAO,EAAE;IAC7E,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACnC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAoB;QAC/B,GAAG,IAAI;QACP,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAClC,CAAC;IACF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,uEAAuE;IACvE,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type IdentitySource = 'env' | 'config' | 'git-remote' | 'folder';
|
|
2
|
+
export interface ResolvedIdentity {
|
|
3
|
+
readonly projectId: string;
|
|
4
|
+
readonly projectName: string;
|
|
5
|
+
readonly source: IdentitySource;
|
|
6
|
+
/** The directory that owns the identity — for git/config sources, the repo or config root. */
|
|
7
|
+
readonly anchor: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ResolveOptions {
|
|
10
|
+
readonly cwd: string;
|
|
11
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
12
|
+
/** Override for tests: `git remote get-url <name>`. */
|
|
13
|
+
readonly gitRemoteUrl?: (anchor: string, remoteName: string) => Promise<string | null>;
|
|
14
|
+
/** Override for tests: `git rev-parse --show-toplevel`. */
|
|
15
|
+
readonly gitToplevel?: (anchor: string) => Promise<string | null>;
|
|
16
|
+
/** Remote name to consult. Defaults to 'origin'. */
|
|
17
|
+
readonly remoteName?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Walks up from `start` looking for `.contextify.json`. Returns the
|
|
21
|
+
* directory that contains it, or null.
|
|
22
|
+
*/
|
|
23
|
+
export declare function findConfigAncestor(start: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Normalize a remote URL into a comparison-stable string.
|
|
26
|
+
*
|
|
27
|
+
* Examples (all → 'github.com/furkankoykiran/contextify'):
|
|
28
|
+
* - 'https://github.com/furkankoykiran/contextify.git'
|
|
29
|
+
* - 'git@github.com:FurkanKoykiran/contextify/'
|
|
30
|
+
* - 'ssh://git@github.com/furkankoykiran/contextify.git'
|
|
31
|
+
* - 'http://gitlab.example.com:8080/group/sub/repo.git' → 'gitlab.example.com/group/sub/repo'
|
|
32
|
+
*/
|
|
33
|
+
export declare function normalizeGitRemote(raw: string): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Convert any string into a safe lowercase slug that matches SLUG_RE.
|
|
36
|
+
* Used for `projectId` prefixes and falls back to 'project' if the
|
|
37
|
+
* derived string is empty.
|
|
38
|
+
*/
|
|
39
|
+
export declare function slugify(raw: string): string;
|
|
40
|
+
export declare function hash12(input: string): string;
|
|
41
|
+
export declare function resolveIdentity(opts: ResolveOptions): Promise<ResolvedIdentity>;
|
|
42
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,uDAAuD;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvF,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClE,oDAAoD;IACpD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyB7D;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM3C;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAiGD,wBAAsB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmBrF"}
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project identity resolver.
|
|
3
|
+
*
|
|
4
|
+
* Determines a deterministic, cross-environment `projectId` from the
|
|
5
|
+
* caller's working directory. Resolution stack — first hit wins:
|
|
6
|
+
*
|
|
7
|
+
* 1. CONTEXTIFY_PROJECT_ID env var (operator override)
|
|
8
|
+
* 2. .contextify.json#projectId (committed config)
|
|
9
|
+
* 3. git remote signature (origin → slug + hash12)
|
|
10
|
+
* 4. folder-realpath fallback (machine-local)
|
|
11
|
+
*
|
|
12
|
+
* See docs/DESIGN-claude-code-hooks.md §2 for the full rationale.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { execFile } from 'node:child_process';
|
|
16
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
17
|
+
import { basename, dirname, join, parse as parsePath, resolve } from 'node:path';
|
|
18
|
+
import { promisify } from 'node:util';
|
|
19
|
+
import { CONFIG_FILENAME, readConfig } from './config.js';
|
|
20
|
+
const execFileAsync = promisify(execFile);
|
|
21
|
+
const SLUG_RE = /^[a-zA-Z0-9_-]+$/;
|
|
22
|
+
const HASH_LEN = 12;
|
|
23
|
+
/**
|
|
24
|
+
* Walks up from `start` looking for `.contextify.json`. Returns the
|
|
25
|
+
* directory that contains it, or null.
|
|
26
|
+
*/
|
|
27
|
+
export function findConfigAncestor(start) {
|
|
28
|
+
let dir = resolve(start);
|
|
29
|
+
const root = parsePath(dir).root;
|
|
30
|
+
// Bounded by `dir === root` plus the parent-equality stop — never infinite.
|
|
31
|
+
for (;;) {
|
|
32
|
+
if (existsSync(join(dir, CONFIG_FILENAME)))
|
|
33
|
+
return dir;
|
|
34
|
+
if (dir === root)
|
|
35
|
+
return null;
|
|
36
|
+
const parent = dirname(dir);
|
|
37
|
+
if (parent === dir)
|
|
38
|
+
return null;
|
|
39
|
+
dir = parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Normalize a remote URL into a comparison-stable string.
|
|
44
|
+
*
|
|
45
|
+
* Examples (all → 'github.com/furkankoykiran/contextify'):
|
|
46
|
+
* - 'https://github.com/furkankoykiran/contextify.git'
|
|
47
|
+
* - 'git@github.com:FurkanKoykiran/contextify/'
|
|
48
|
+
* - 'ssh://git@github.com/furkankoykiran/contextify.git'
|
|
49
|
+
* - 'http://gitlab.example.com:8080/group/sub/repo.git' → 'gitlab.example.com/group/sub/repo'
|
|
50
|
+
*/
|
|
51
|
+
export function normalizeGitRemote(raw) {
|
|
52
|
+
let s = raw.trim().toLowerCase();
|
|
53
|
+
if (!s)
|
|
54
|
+
return null;
|
|
55
|
+
// ssh form: git@host:path
|
|
56
|
+
const sshMatch = /^git@([^:]+):(.+)$/.exec(s);
|
|
57
|
+
if (sshMatch) {
|
|
58
|
+
s = `${sshMatch[1]}/${sshMatch[2]}`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// strip scheme
|
|
62
|
+
s = s.replace(/^[a-z][a-z0-9+.-]*:\/\//, '');
|
|
63
|
+
// strip user@ (e.g. ssh://git@host/path)
|
|
64
|
+
s = s.replace(/^[^/@]+@/, '');
|
|
65
|
+
// strip :port if present right after host
|
|
66
|
+
s = s.replace(/^([^/]+):\d+/, '$1');
|
|
67
|
+
}
|
|
68
|
+
// strip trailing slash(es) first, then trailing .git
|
|
69
|
+
s = s.replace(/\/+$/, '');
|
|
70
|
+
s = s.replace(/\.git$/, '');
|
|
71
|
+
// a trailing slash can be left if the .git was the only trailing token
|
|
72
|
+
s = s.replace(/\/+$/, '');
|
|
73
|
+
// collapse double slashes
|
|
74
|
+
s = s.replace(/\/{2,}/g, '/');
|
|
75
|
+
if (!s.includes('/'))
|
|
76
|
+
return null;
|
|
77
|
+
return s;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert any string into a safe lowercase slug that matches SLUG_RE.
|
|
81
|
+
* Used for `projectId` prefixes and falls back to 'project' if the
|
|
82
|
+
* derived string is empty.
|
|
83
|
+
*/
|
|
84
|
+
export function slugify(raw) {
|
|
85
|
+
const cleaned = raw
|
|
86
|
+
.toLowerCase()
|
|
87
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
88
|
+
.replace(/^-+|-+$/g, '');
|
|
89
|
+
return cleaned.length === 0 ? 'project' : cleaned.slice(0, 64);
|
|
90
|
+
}
|
|
91
|
+
export function hash12(input) {
|
|
92
|
+
return createHash('sha256').update(input).digest('hex').slice(0, HASH_LEN);
|
|
93
|
+
}
|
|
94
|
+
/** Default `git remote get-url <name>` runner. Returns null if git is absent or the remote is missing. */
|
|
95
|
+
async function defaultGitRemoteUrl(anchor, remoteName) {
|
|
96
|
+
try {
|
|
97
|
+
const { stdout } = await execFileAsync('git', ['remote', 'get-url', remoteName], {
|
|
98
|
+
cwd: anchor,
|
|
99
|
+
timeout: 5_000,
|
|
100
|
+
});
|
|
101
|
+
const out = stdout.trim();
|
|
102
|
+
return out.length === 0 ? null : out;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Default `git rev-parse --show-toplevel` runner. Returns null if not in a git repo. */
|
|
109
|
+
async function defaultGitToplevel(anchor) {
|
|
110
|
+
try {
|
|
111
|
+
const { stdout } = await execFileAsync('git', ['rev-parse', '--show-toplevel'], {
|
|
112
|
+
cwd: anchor,
|
|
113
|
+
timeout: 5_000,
|
|
114
|
+
});
|
|
115
|
+
const out = stdout.trim();
|
|
116
|
+
return out.length === 0 ? null : out;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function envIdentity(env, cwd) {
|
|
123
|
+
const pid = env.CONTEXTIFY_PROJECT_ID;
|
|
124
|
+
if (!pid)
|
|
125
|
+
return null;
|
|
126
|
+
if (!SLUG_RE.test(pid)) {
|
|
127
|
+
throw new Error('CONTEXTIFY_PROJECT_ID must match [a-zA-Z0-9_-]+');
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
projectId: pid,
|
|
131
|
+
projectName: env.CONTEXTIFY_PROJECT_NAME || pid,
|
|
132
|
+
source: 'env',
|
|
133
|
+
anchor: cwd,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function configIdentity(cwd) {
|
|
137
|
+
const anchor = findConfigAncestor(cwd);
|
|
138
|
+
if (!anchor)
|
|
139
|
+
return null;
|
|
140
|
+
const cfg = await readConfig(anchor);
|
|
141
|
+
if (!cfg)
|
|
142
|
+
return null;
|
|
143
|
+
return {
|
|
144
|
+
projectId: cfg.projectId,
|
|
145
|
+
projectName: cfg.projectName ?? cfg.projectId,
|
|
146
|
+
source: 'config',
|
|
147
|
+
anchor,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async function gitIdentity(cwd, remoteName, remoteUrl, toplevel) {
|
|
151
|
+
const top = await toplevel(cwd);
|
|
152
|
+
if (!top)
|
|
153
|
+
return null;
|
|
154
|
+
const url = await remoteUrl(top, remoteName);
|
|
155
|
+
if (!url)
|
|
156
|
+
return null;
|
|
157
|
+
const normalized = normalizeGitRemote(url);
|
|
158
|
+
if (!normalized)
|
|
159
|
+
return null;
|
|
160
|
+
const slug = slugify(normalized.split('/').pop() ?? 'project');
|
|
161
|
+
const projectId = `${slug}-${hash12(normalized)}`;
|
|
162
|
+
return {
|
|
163
|
+
projectId,
|
|
164
|
+
projectName: slug,
|
|
165
|
+
source: 'git-remote',
|
|
166
|
+
anchor: top,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function folderIdentity(cwd) {
|
|
170
|
+
// Real path so symlink hops collapse to one identity.
|
|
171
|
+
let realCwd;
|
|
172
|
+
try {
|
|
173
|
+
realCwd = realpathSync(cwd);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
realCwd = resolve(cwd);
|
|
177
|
+
}
|
|
178
|
+
const slug = slugify(basename(realCwd));
|
|
179
|
+
const projectId = `${slug}-${hash12(realCwd)}`;
|
|
180
|
+
return {
|
|
181
|
+
projectId,
|
|
182
|
+
projectName: slug,
|
|
183
|
+
source: 'folder',
|
|
184
|
+
anchor: realCwd,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export async function resolveIdentity(opts) {
|
|
188
|
+
const env = opts.env ?? process.env;
|
|
189
|
+
const remoteName = opts.remoteName ?? 'origin';
|
|
190
|
+
const fromEnv = envIdentity(env, opts.cwd);
|
|
191
|
+
if (fromEnv)
|
|
192
|
+
return fromEnv;
|
|
193
|
+
const fromConfig = await configIdentity(opts.cwd);
|
|
194
|
+
if (fromConfig)
|
|
195
|
+
return fromConfig;
|
|
196
|
+
const fromGit = await gitIdentity(opts.cwd, remoteName, opts.gitRemoteUrl ?? defaultGitRemoteUrl, opts.gitToplevel ?? defaultGitToplevel);
|
|
197
|
+
if (fromGit)
|
|
198
|
+
return fromGit;
|
|
199
|
+
return folderIdentity(opts.cwd);
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare const VERSION = "0.4.0";
|
|
3
|
+
export interface CliEntry {
|
|
4
|
+
readonly argv: readonly string[];
|
|
5
|
+
readonly cwd?: string;
|
|
6
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
7
|
+
}
|
|
8
|
+
export declare function main(entry: CliEntry): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAoBA,eAAO,MAAM,OAAO,UAAU,CAAC;AAsD/B,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAClC;AAED,wBAAsB,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CA0C3D"}
|
package/dist/index.js
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|