preclaim 0.1.0 → 0.2.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/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lock.js +1 -1
- package/dist/commands/lock.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +10 -19
- package/dist/commands/login.js.map +1 -1
- package/dist/hooks/heartbeat-daemon.js +11 -0
- package/dist/hooks/heartbeat-daemon.js.map +1 -1
- package/dist/hooks/post-tool-use.js +4 -2
- package/dist/hooks/post-tool-use.js.map +1 -1
- package/dist/hooks/pre-tool-use.js +6 -2
- package/dist/hooks/pre-tool-use.js.map +1 -1
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +10 -5
- package/dist/lib/auth.js.map +1 -1
- package/package.json +6 -3
- package/.turbo/turbo-build.log +0 -4
- package/src/commands/check.ts +0 -28
- package/src/commands/config.ts +0 -43
- package/src/commands/init.ts +0 -109
- package/src/commands/install-hooks.ts +0 -72
- package/src/commands/lock.ts +0 -30
- package/src/commands/login.ts +0 -120
- package/src/commands/status.ts +0 -15
- package/src/commands/unlock.ts +0 -25
- package/src/commands/whoami.ts +0 -15
- package/src/hooks/heartbeat-daemon.ts +0 -49
- package/src/hooks/post-tool-use.ts +0 -44
- package/src/hooks/pre-tool-use.ts +0 -110
- package/src/hooks/session-start.ts +0 -87
- package/src/hooks/stop.ts +0 -43
- package/src/index.ts +0 -74
- package/src/lib/auth.ts +0 -17
- package/src/lib/client-factory.ts +0 -26
- package/src/lib/hook-io.ts +0 -37
- package/src/lib/output.ts +0 -20
- package/tsconfig.json +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,iBAkF/E"}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { writeFile, readFile } from 'node:fs/promises';
|
|
2
2
|
import { join, basename } from 'node:path';
|
|
3
|
-
import { defaultConfig, loadCredentials,
|
|
3
|
+
import { defaultConfig, loadCredentials, saveCredentials } from '@preclaim/core';
|
|
4
4
|
import { loginCommand } from './login.js';
|
|
5
5
|
const DEFAULT_BACKEND = 'https://preclaim.dev';
|
|
6
6
|
export async function initCommand(opts) {
|
|
@@ -41,11 +41,6 @@ export async function initCommand(opts) {
|
|
|
41
41
|
const projectName = dirName;
|
|
42
42
|
console.log(`Setting up Preclaim for "${projectName}"...`);
|
|
43
43
|
// Call onboard API
|
|
44
|
-
const client = new PreclaimClient({
|
|
45
|
-
baseUrl: backend,
|
|
46
|
-
accessToken: creds.accessToken,
|
|
47
|
-
timeoutMs: 10000,
|
|
48
|
-
});
|
|
49
44
|
const res = await fetch(`${backend}/api/v1/onboard`, {
|
|
50
45
|
method: 'POST',
|
|
51
46
|
headers: {
|
|
@@ -72,12 +67,7 @@ export async function initCommand(opts) {
|
|
|
72
67
|
// Update credentials with org_id
|
|
73
68
|
if (creds.user.orgId !== data.org_id) {
|
|
74
69
|
creds.user.orgId = data.org_id;
|
|
75
|
-
|
|
76
|
-
const { writeFile: wf, mkdir } = await import('node:fs/promises');
|
|
77
|
-
const { dirname } = await import('node:path');
|
|
78
|
-
const credPath = getCredentialsPath();
|
|
79
|
-
await mkdir(dirname(credPath), { recursive: true });
|
|
80
|
-
await wf(credPath, JSON.stringify(creds, null, 2) + '\n', { mode: 0o600 });
|
|
70
|
+
await saveCredentials(creds);
|
|
81
71
|
}
|
|
82
72
|
// Write config
|
|
83
73
|
const config = defaultConfig(data.project_id, backend);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/lock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveContext } from '../lib/client-factory.js';
|
|
2
2
|
export async function lockCommand(filePath, opts) {
|
|
3
|
-
const { client, config
|
|
3
|
+
const { client, config } = await resolveContext();
|
|
4
4
|
const sessionId = opts.session ?? `manual_${crypto.randomUUID().slice(0, 8)}`;
|
|
5
5
|
const ttl = opts.ttl ? parseInt(opts.ttl, 10) : config.ttl;
|
|
6
6
|
const result = await client.claimFile({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/commands/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,IAAwC;IAC1F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/commands/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,IAAwC;IAC1F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAE3D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC;QACpC,UAAU,EAAE,MAAM,CAAC,SAAS;QAC5B,SAAS,EAAE,QAAQ;QACnB,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,mBAAmB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAK,CAAC;IAE1B,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,WAAW,QAAQ,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,UAAW,CAAC,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACnG,CAAC;SAAM,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CAAC,aAAa,QAAQ,yBAAyB,IAAI,CAAC,MAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACpG,OAAO,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,MAAO,CAAC,WAAW,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;QACxF,OAAO,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,MAAO,CAAC,UAAU,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,kBAqBjC"}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
|
-
import {
|
|
3
|
-
import { dirname } from 'node:path';
|
|
4
|
-
import { getCredentialsPath } from '@preclaim/core';
|
|
5
|
-
const SUPABASE_URL = 'https://aawbukcvngdffueowjsa.supabase.co';
|
|
6
|
-
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFhd2J1a2N2bmdkZmZ1ZW93anNhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzM3NjI2NTcsImV4cCI6MjA4OTMzODY1N30.pwAyjgnbdoZmmJdsG2jF0nbvT4hueb8UZvstsdYhFFs';
|
|
2
|
+
import { getSupabaseConfig, saveCredentials } from '@preclaim/core';
|
|
7
3
|
export async function loginCommand() {
|
|
4
|
+
const supabaseConfig = getSupabaseConfig();
|
|
8
5
|
const server = createServer();
|
|
9
6
|
const port = await new Promise((resolve) => {
|
|
10
7
|
server.listen(0, () => {
|
|
@@ -12,21 +9,19 @@ export async function loginCommand() {
|
|
|
12
9
|
});
|
|
13
10
|
});
|
|
14
11
|
const redirectTo = `http://localhost:${port}/callback`;
|
|
15
|
-
const oauthUrl = `${
|
|
12
|
+
const oauthUrl = `${supabaseConfig.url}/auth/v1/authorize?provider=github&redirect_to=${encodeURIComponent(redirectTo)}`;
|
|
16
13
|
console.log('Opening browser for GitHub authentication...');
|
|
17
14
|
console.log(`If browser doesn't open, visit:\n${oauthUrl}\n`);
|
|
18
15
|
const { exec } = await import('node:child_process');
|
|
19
16
|
const openCmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
20
17
|
exec(`${openCmd} "${oauthUrl}"`);
|
|
21
|
-
await handleAuthCallback(server);
|
|
18
|
+
await handleAuthCallback(server, supabaseConfig);
|
|
22
19
|
}
|
|
23
|
-
function handleAuthCallback(server) {
|
|
20
|
+
function handleAuthCallback(server, supabase) {
|
|
24
21
|
return new Promise((resolve, reject) => {
|
|
25
22
|
server.on('request', async (req, res) => {
|
|
26
23
|
const url = new URL(req.url, `http://localhost`);
|
|
27
24
|
if (url.pathname === '/callback') {
|
|
28
|
-
// Supabase implicit flow: tokens come in hash fragment.
|
|
29
|
-
// Serve a page that extracts them and POSTs to /token.
|
|
30
25
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
31
26
|
res.end(`<!DOCTYPE html><html><body>
|
|
32
27
|
<h1>Logging in to Preclaim...</h1>
|
|
@@ -57,19 +52,16 @@ if (access_token) {
|
|
|
57
52
|
try {
|
|
58
53
|
const { access_token, refresh_token, expires_in } = JSON.parse(body);
|
|
59
54
|
// Get user info
|
|
60
|
-
const userRes = await fetch(`${
|
|
55
|
+
const userRes = await fetch(`${supabase.url}/auth/v1/user`, {
|
|
61
56
|
headers: {
|
|
62
57
|
'Authorization': `Bearer ${access_token}`,
|
|
63
|
-
'apikey':
|
|
58
|
+
'apikey': supabase.anonKey,
|
|
64
59
|
},
|
|
65
60
|
});
|
|
66
61
|
if (!userRes.ok)
|
|
67
62
|
throw new Error(`Failed to get user info: ${userRes.status}`);
|
|
68
63
|
const user = await userRes.json();
|
|
69
|
-
|
|
70
|
-
const credPath = getCredentialsPath();
|
|
71
|
-
await mkdir(dirname(credPath), { recursive: true });
|
|
72
|
-
await writeFile(credPath, JSON.stringify({
|
|
64
|
+
await saveCredentials({
|
|
73
65
|
accessToken: access_token,
|
|
74
66
|
refreshToken: refresh_token,
|
|
75
67
|
expiresAt: new Date(Date.now() + parseInt(expires_in) * 1000).toISOString(),
|
|
@@ -78,7 +70,7 @@ if (access_token) {
|
|
|
78
70
|
email: user.email ?? '',
|
|
79
71
|
orgId: '',
|
|
80
72
|
},
|
|
81
|
-
}
|
|
73
|
+
});
|
|
82
74
|
res.writeHead(200);
|
|
83
75
|
res.end('ok');
|
|
84
76
|
console.log(`Logged in as ${user.email ?? user.id}`);
|
|
@@ -98,8 +90,7 @@ if (access_token) {
|
|
|
98
90
|
});
|
|
99
91
|
setTimeout(() => {
|
|
100
92
|
console.error('Login timed out.');
|
|
101
|
-
server.close();
|
|
102
|
-
process.exit(1);
|
|
93
|
+
server.close(() => process.exit(1));
|
|
103
94
|
}, 120_000);
|
|
104
95
|
});
|
|
105
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,16 @@ const INTERVAL_MS = 60_000;
|
|
|
17
17
|
const MAX_FAILURES = 5;
|
|
18
18
|
let failures = 0;
|
|
19
19
|
async function heartbeat() {
|
|
20
|
+
// Check if access token has likely expired (JWT default: 1 hour)
|
|
21
|
+
// If daemon has been running > 55 min, count it as a failure
|
|
22
|
+
const uptimeMs = Date.now() - startTime;
|
|
23
|
+
if (uptimeMs > 55 * 60 * 1000) {
|
|
24
|
+
failures++;
|
|
25
|
+
if (failures >= MAX_FAILURES) {
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
20
30
|
const result = await client.heartbeat({ session_id: sessionId });
|
|
21
31
|
if (result.error) {
|
|
22
32
|
failures++;
|
|
@@ -28,6 +38,7 @@ async function heartbeat() {
|
|
|
28
38
|
failures = 0;
|
|
29
39
|
}
|
|
30
40
|
}
|
|
41
|
+
const startTime = Date.now();
|
|
31
42
|
// Run immediately, then every 60s
|
|
32
43
|
heartbeat();
|
|
33
44
|
const interval = setInterval(heartbeat, INTERVAL_MS);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat-daemon.js","sourceRoot":"","sources":["../../src/hooks/heartbeat-daemon.ts"],"names":[],"mappings":";AACA,yDAAyD;AACzD,6CAA6C;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AAClD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAC7C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;AAEtD,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;IAChC,OAAO,EAAE,OAAO;IAChB,WAAW;IACX,SAAS,EAAE,IAAI;CAChB,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,MAAM,CAAC;AAC3B,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,SAAU,EAAE,CAAC,CAAC;IAElE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,QAAQ,EAAE,CAAC;QACX,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,CAAC,CAAC;IACf,CAAC;AACH,CAAC;AAED,kCAAkC;AAClC,SAAS,EAAE,CAAC;AACZ,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAErD,qBAAqB;AACrB,SAAS,QAAQ;IACf,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"heartbeat-daemon.js","sourceRoot":"","sources":["../../src/hooks/heartbeat-daemon.ts"],"names":[],"mappings":";AACA,yDAAyD;AACzD,6CAA6C;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AAClD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAC7C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;AAEtD,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;IAChC,OAAO,EAAE,OAAO;IAChB,WAAW;IACX,SAAS,EAAE,IAAI;CAChB,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,MAAM,CAAC;AAC3B,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB,KAAK,UAAU,SAAS;IACtB,iEAAiE;IACjE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,IAAI,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QAC9B,QAAQ,EAAE,CAAC;QACX,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,SAAU,EAAE,CAAC,CAAC;IAElE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,QAAQ,EAAE,CAAC;QACX,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,CAAC,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7B,kCAAkC;AAClC,SAAS,EAAE,CAAC;AACZ,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAErD,qBAAqB;AACrB,SAAS,QAAQ;IACf,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -12,8 +12,10 @@ async function main() {
|
|
|
12
12
|
const command = input.tool_input?.command;
|
|
13
13
|
if (!command)
|
|
14
14
|
return;
|
|
15
|
-
// Detect git commit (not amend, not
|
|
16
|
-
const isCommit = /\bgit\s+commit\b/.test(command)
|
|
15
|
+
// Detect git commit (not amend, not --help)
|
|
16
|
+
const isCommit = /\bgit\s+commit\b/.test(command)
|
|
17
|
+
&& !/--help/.test(command)
|
|
18
|
+
&& !/--amend/.test(command);
|
|
17
19
|
if (!isCommit)
|
|
18
20
|
return;
|
|
19
21
|
const found = await findConfig();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-tool-use.js","sourceRoot":"","sources":["../../src/hooks/post-tool-use.ts"],"names":[],"mappings":";AACA,sCAAsC;AACtC,6DAA6D;AAE7D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QAEpC,6BAA6B;QAC7B,IAAI,KAAK,CAAC,SAAS,KAAK,MAAM;YAAE,OAAO;QAEvC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,OAA6B,CAAC;QAChE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,
|
|
1
|
+
{"version":3,"file":"post-tool-use.js","sourceRoot":"","sources":["../../src/hooks/post-tool-use.ts"],"names":[],"mappings":";AACA,sCAAsC;AACtC,6DAA6D;AAE7D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QAEpC,6BAA6B;QAC7B,IAAI,KAAK,CAAC,SAAS,KAAK,MAAM;YAAE,OAAO;QAEvC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,OAA6B,CAAC;QAChE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;eAC5C,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;eACvB,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEtB,MAAM,KAAK,GAAG,MAAM,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;YAChC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;YAC7B,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QAEH,qCAAqC;QACrC,MAAM,MAAM,CAAC,YAAY,CAAC;YACxB,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS;YAClC,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// PreToolUse hook — the gatekeeper
|
|
3
3
|
// Intercepts Edit/Write/MultiEdit tool calls, claims file locks
|
|
4
|
+
import { resolve, relative, dirname } from 'node:path';
|
|
4
5
|
import { PreclaimClient, findConfig, loadCredentials } from '@preclaim/core';
|
|
5
6
|
import { readHookInput, writeHookOutput } from '../lib/hook-io.js';
|
|
6
7
|
import { minimatch } from 'minimatch';
|
|
@@ -22,8 +23,11 @@ async function main() {
|
|
|
22
23
|
if (!found) {
|
|
23
24
|
return; // No config = allow (not a preclaim project)
|
|
24
25
|
}
|
|
25
|
-
//
|
|
26
|
-
|
|
26
|
+
// Normalize path: always relative to project root
|
|
27
|
+
// /Users/paul/project/src/file.ts en src/file.ts worden dezelfde lock
|
|
28
|
+
const projectRoot = dirname(found.configPath);
|
|
29
|
+
const absolutePath = resolve(projectRoot, filePath);
|
|
30
|
+
const relativePath = relative(projectRoot, absolutePath);
|
|
27
31
|
if (found.config.ignore.some(pattern => minimatch(relativePath, pattern))) {
|
|
28
32
|
return; // Ignored file = allow
|
|
29
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-tool-use.js","sourceRoot":"","sources":["../../src/hooks/pre-tool-use.ts"],"names":[],"mappings":";AACA,mCAAmC;AACnC,gEAAgE;AAEhE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;AAE5D,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QAEpC,oCAAoC;QACpC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,oBAAoB;QAC9B,CAAC;QAED,oCAAoC;QACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,SAA+B,CAAC;QACnE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,uBAAuB;QACjC,CAAC;QAED,cAAc;QACd,MAAM,KAAK,GAAG,MAAM,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,6CAA6C;QACvD,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"pre-tool-use.js","sourceRoot":"","sources":["../../src/hooks/pre-tool-use.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE/F,wBAAsB,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAmBhE"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { loadCredentials } from '@preclaim/core';
|
|
1
|
+
import { loadCredentials, refreshCredentials } from '@preclaim/core';
|
|
2
2
|
export async function requireAuth() {
|
|
3
3
|
const creds = await loadCredentials();
|
|
4
4
|
if (!creds) {
|
|
5
5
|
console.error('Not logged in. Run `preclaim login` first.');
|
|
6
6
|
process.exit(1);
|
|
7
7
|
}
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// 60s marge voor clock skew
|
|
9
|
+
const expiresAt = new Date(creds.expiresAt).getTime();
|
|
10
|
+
if (Date.now() >= expiresAt - 60_000) {
|
|
11
|
+
const refreshed = await refreshCredentials();
|
|
12
|
+
if (!refreshed) {
|
|
13
|
+
console.error('Session expired. Run `preclaim login` to re-authenticate.');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
return refreshed;
|
|
12
17
|
}
|
|
13
18
|
return creds;
|
|
14
19
|
}
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA4B,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAA4B,MAAM,gBAAgB,CAAC;AAE/F,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,4BAA4B;IAC5B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;IACtD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;YAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "preclaim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "AI File Coordination Layer — predictive file locking for AI coding agents",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"bin": {
|
|
6
|
-
"preclaim": "
|
|
7
|
+
"preclaim": "dist/index.js"
|
|
7
8
|
},
|
|
8
|
-
"
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
9
12
|
"scripts": {
|
|
10
13
|
"build": "tsc",
|
|
11
14
|
"dev": "tsc --watch",
|
package/.turbo/turbo-build.log
DELETED
package/src/commands/check.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { resolveContext } from '../lib/client-factory.js';
|
|
2
|
-
|
|
3
|
-
export async function checkCommand(filePaths: string[]) {
|
|
4
|
-
if (filePaths.length === 0) {
|
|
5
|
-
console.error('Specify one or more file paths to check.');
|
|
6
|
-
process.exit(1);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { client, config } = await resolveContext();
|
|
10
|
-
|
|
11
|
-
const result = await client.batchCheck({
|
|
12
|
-
project_id: config.projectId,
|
|
13
|
-
file_paths: filePaths,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
if (result.error) {
|
|
17
|
-
console.error(`Failed to check: ${result.error}`);
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
for (const [path, lock] of Object.entries(result.data!.locks)) {
|
|
22
|
-
if (lock) {
|
|
23
|
-
console.log(`LOCKED ${path} (session: ${lock.session_id.slice(0, 8)}… expires: ${new Date(lock.expires_at).toLocaleTimeString()})`);
|
|
24
|
-
} else {
|
|
25
|
-
console.log(`FREE ${path}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/commands/config.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { findConfig, type PreclaimConfig } from '@preclaim/core';
|
|
3
|
-
|
|
4
|
-
export async function configCommand(opts: { get?: string; set?: string }) {
|
|
5
|
-
const found = await findConfig();
|
|
6
|
-
if (!found) {
|
|
7
|
-
console.error('No .preclaim.json found. Run `preclaim init` first.');
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
if (opts.get) {
|
|
12
|
-
const value = found.config[opts.get as keyof PreclaimConfig];
|
|
13
|
-
console.log(JSON.stringify(value, null, 2));
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (opts.set) {
|
|
18
|
-
const [key, ...rest] = opts.set.split('=');
|
|
19
|
-
const value = rest.join('=');
|
|
20
|
-
|
|
21
|
-
if (!key || !value) {
|
|
22
|
-
console.error('Usage: preclaim config --set key=value');
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const raw = await readFile(found.configPath, 'utf-8');
|
|
27
|
-
const config = JSON.parse(raw) as Record<string, unknown>;
|
|
28
|
-
|
|
29
|
-
// Try to parse as JSON, fallback to string
|
|
30
|
-
try {
|
|
31
|
-
config[key] = JSON.parse(value);
|
|
32
|
-
} catch {
|
|
33
|
-
config[key] = value;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
await writeFile(found.configPath, JSON.stringify(config, null, 2) + '\n');
|
|
37
|
-
console.log(`Set ${key} = ${JSON.stringify(config[key])}`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// No flags — show full config
|
|
42
|
-
console.log(JSON.stringify(found.config, null, 2));
|
|
43
|
-
}
|
package/src/commands/init.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { writeFile, readFile } from 'node:fs/promises';
|
|
2
|
-
import { join, basename } from 'node:path';
|
|
3
|
-
import { defaultConfig, loadCredentials, PreclaimClient } from '@preclaim/core';
|
|
4
|
-
import { loginCommand } from './login.js';
|
|
5
|
-
|
|
6
|
-
const DEFAULT_BACKEND = 'https://preclaim.dev';
|
|
7
|
-
|
|
8
|
-
export async function initCommand(opts: { backend?: string; projectId?: string }) {
|
|
9
|
-
const configPath = join(process.cwd(), '.preclaim.json');
|
|
10
|
-
|
|
11
|
-
// Check if already exists
|
|
12
|
-
try {
|
|
13
|
-
await readFile(configPath, 'utf-8');
|
|
14
|
-
console.log('.preclaim.json already exists. Use `preclaim config` to modify.');
|
|
15
|
-
return;
|
|
16
|
-
} catch {
|
|
17
|
-
// File doesn't exist, proceed
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const backend = opts.backend ?? DEFAULT_BACKEND;
|
|
21
|
-
|
|
22
|
-
// If project ID provided directly, skip onboarding
|
|
23
|
-
if (opts.projectId) {
|
|
24
|
-
const config = defaultConfig(opts.projectId, backend);
|
|
25
|
-
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
26
|
-
console.log(`Created .preclaim.json (project: ${opts.projectId})`);
|
|
27
|
-
printNextSteps();
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check if logged in, if not: login first
|
|
32
|
-
let creds = await loadCredentials();
|
|
33
|
-
if (!creds) {
|
|
34
|
-
console.log('Not logged in. Starting authentication...\n');
|
|
35
|
-
await loginCommand();
|
|
36
|
-
creds = await loadCredentials();
|
|
37
|
-
if (!creds) {
|
|
38
|
-
console.error('Login failed. Please try again.');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
console.log('');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Derive project name from directory
|
|
45
|
-
const dirName = basename(process.cwd());
|
|
46
|
-
const projectSlug = dirName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
|
|
47
|
-
const projectName = dirName;
|
|
48
|
-
|
|
49
|
-
console.log(`Setting up Preclaim for "${projectName}"...`);
|
|
50
|
-
|
|
51
|
-
// Call onboard API
|
|
52
|
-
const client = new PreclaimClient({
|
|
53
|
-
baseUrl: backend,
|
|
54
|
-
accessToken: creds.accessToken,
|
|
55
|
-
timeoutMs: 10000,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const res = await fetch(`${backend}/api/v1/onboard`, {
|
|
59
|
-
method: 'POST',
|
|
60
|
-
headers: {
|
|
61
|
-
'Content-Type': 'application/json',
|
|
62
|
-
'Authorization': `Bearer ${creds.accessToken}`,
|
|
63
|
-
},
|
|
64
|
-
body: JSON.stringify({
|
|
65
|
-
project_name: projectName,
|
|
66
|
-
project_slug: projectSlug,
|
|
67
|
-
}),
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (!res.ok) {
|
|
71
|
-
const body = await res.text();
|
|
72
|
-
console.error(`Failed to create project: ${body}`);
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const { data } = await res.json() as { data: { project_id: string; org_id: string; already_existed: boolean } };
|
|
77
|
-
|
|
78
|
-
if (data.already_existed) {
|
|
79
|
-
console.log(`Project "${projectName}" already exists, using existing project.`);
|
|
80
|
-
} else {
|
|
81
|
-
console.log(`Project "${projectName}" created.`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Update credentials with org_id
|
|
85
|
-
if (creds.user.orgId !== data.org_id) {
|
|
86
|
-
creds.user.orgId = data.org_id;
|
|
87
|
-
const { getCredentialsPath } = await import('@preclaim/core');
|
|
88
|
-
const { writeFile: wf, mkdir } = await import('node:fs/promises');
|
|
89
|
-
const { dirname } = await import('node:path');
|
|
90
|
-
const credPath = getCredentialsPath();
|
|
91
|
-
await mkdir(dirname(credPath), { recursive: true });
|
|
92
|
-
await wf(credPath, JSON.stringify(creds, null, 2) + '\n', { mode: 0o600 });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Write config
|
|
96
|
-
const config = defaultConfig(data.project_id, backend);
|
|
97
|
-
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
98
|
-
|
|
99
|
-
console.log(`\nCreated .preclaim.json`);
|
|
100
|
-
printNextSteps();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function printNextSteps() {
|
|
104
|
-
console.log('');
|
|
105
|
-
console.log('Next steps:');
|
|
106
|
-
console.log(' 1. preclaim install-hooks');
|
|
107
|
-
console.log(' 2. Commit .preclaim.json to your repo');
|
|
108
|
-
console.log(' 3. Open multiple Claude Code terminals — locks are automatic');
|
|
109
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
-
import { join, dirname } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
|
|
7
|
-
interface ClaudeSettings {
|
|
8
|
-
hooks?: Record<string, Array<{
|
|
9
|
-
matcher: string;
|
|
10
|
-
hooks: Array<{
|
|
11
|
-
type: string;
|
|
12
|
-
command: string;
|
|
13
|
-
}>;
|
|
14
|
-
}>>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function installHooksCommand() {
|
|
18
|
-
const hooksDir = join(__dirname, '..', 'hooks');
|
|
19
|
-
const settingsDir = join(process.cwd(), '.claude');
|
|
20
|
-
const settingsPath = join(settingsDir, 'settings.json');
|
|
21
|
-
|
|
22
|
-
// Read existing settings or create new
|
|
23
|
-
let settings: ClaudeSettings = {};
|
|
24
|
-
try {
|
|
25
|
-
const raw = await readFile(settingsPath, 'utf-8');
|
|
26
|
-
settings = JSON.parse(raw);
|
|
27
|
-
} catch {
|
|
28
|
-
// File doesn't exist
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
settings.hooks = {
|
|
32
|
-
PreToolUse: [{
|
|
33
|
-
matcher: '',
|
|
34
|
-
hooks: [{
|
|
35
|
-
type: 'command',
|
|
36
|
-
command: `node ${join(hooksDir, 'pre-tool-use.js')}`,
|
|
37
|
-
}],
|
|
38
|
-
}],
|
|
39
|
-
PostToolUse: [{
|
|
40
|
-
matcher: '',
|
|
41
|
-
hooks: [{
|
|
42
|
-
type: 'command',
|
|
43
|
-
command: `node ${join(hooksDir, 'post-tool-use.js')}`,
|
|
44
|
-
}],
|
|
45
|
-
}],
|
|
46
|
-
Stop: [{
|
|
47
|
-
matcher: '',
|
|
48
|
-
hooks: [{
|
|
49
|
-
type: 'command',
|
|
50
|
-
command: `node ${join(hooksDir, 'stop.js')}`,
|
|
51
|
-
}],
|
|
52
|
-
}],
|
|
53
|
-
SessionStart: [{
|
|
54
|
-
matcher: '',
|
|
55
|
-
hooks: [{
|
|
56
|
-
type: 'command',
|
|
57
|
-
command: `node ${join(hooksDir, 'session-start.js')}`,
|
|
58
|
-
}],
|
|
59
|
-
}],
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
await mkdir(settingsDir, { recursive: true });
|
|
63
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
64
|
-
|
|
65
|
-
console.log('Claude Code hooks installed in .claude/settings.json');
|
|
66
|
-
console.log('');
|
|
67
|
-
console.log('Hooks configured:');
|
|
68
|
-
console.log(' - PreToolUse: file lock gatekeeper');
|
|
69
|
-
console.log(' - PostToolUse: commit detection → release locks');
|
|
70
|
-
console.log(' - Stop: session cleanup');
|
|
71
|
-
console.log(' - SessionStart: session registration + heartbeat');
|
|
72
|
-
}
|
package/src/commands/lock.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { resolveContext } from '../lib/client-factory.js';
|
|
2
|
-
|
|
3
|
-
export async function lockCommand(filePath: string, opts: { session?: string; ttl?: string }) {
|
|
4
|
-
const { client, config, credentials } = await resolveContext();
|
|
5
|
-
const sessionId = opts.session ?? `manual_${crypto.randomUUID().slice(0, 8)}`;
|
|
6
|
-
const ttl = opts.ttl ? parseInt(opts.ttl, 10) : config.ttl;
|
|
7
|
-
|
|
8
|
-
const result = await client.claimFile({
|
|
9
|
-
project_id: config.projectId,
|
|
10
|
-
file_path: filePath,
|
|
11
|
-
session_id: sessionId,
|
|
12
|
-
ttl_minutes: ttl,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
if (result.error) {
|
|
16
|
-
console.error(`Failed to lock: ${result.error}`);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const data = result.data!;
|
|
21
|
-
|
|
22
|
-
if (data.status === 'acquired' || data.status === 'already_held') {
|
|
23
|
-
console.log(`Locked: ${filePath} (expires: ${new Date(data.expires_at!).toLocaleTimeString()})`);
|
|
24
|
-
} else if (data.status === 'conflict') {
|
|
25
|
-
console.error(`Conflict: ${filePath} is locked by session ${data.holder!.session_id.slice(0, 8)}…`);
|
|
26
|
-
console.error(` Acquired: ${new Date(data.holder!.acquired_at).toLocaleTimeString()}`);
|
|
27
|
-
console.error(` Expires: ${new Date(data.holder!.expires_at).toLocaleTimeString()}`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
}
|