gipity 1.0.336 → 1.0.347
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 +3 -3
- package/dist/__tests__/claude-trust.test.d.ts +1 -0
- package/dist/__tests__/claude-trust.test.js +71 -0
- package/dist/__tests__/claude-trust.test.js.map +1 -0
- package/dist/__tests__/cli-cmd-job.test.d.ts +1 -0
- package/dist/__tests__/cli-cmd-job.test.js +204 -0
- package/dist/__tests__/cli-cmd-job.test.js.map +1 -0
- package/dist/__tests__/cli-smoke.test.js +7 -2
- package/dist/__tests__/cli-smoke.test.js.map +1 -1
- package/dist/__tests__/relay-machine-id.test.d.ts +1 -0
- package/dist/__tests__/relay-machine-id.test.js +41 -0
- package/dist/__tests__/relay-machine-id.test.js.map +1 -0
- package/dist/__tests__/relay-redact.test.d.ts +1 -0
- package/dist/__tests__/relay-redact.test.js +78 -0
- package/dist/__tests__/relay-redact.test.js.map +1 -0
- package/dist/__tests__/setup-skills-block.test.d.ts +1 -0
- package/dist/__tests__/setup-skills-block.test.js +65 -0
- package/dist/__tests__/setup-skills-block.test.js.map +1 -0
- package/dist/adopt-cwd.d.ts +3 -0
- package/dist/adopt-cwd.js +1 -0
- package/dist/adopt-cwd.js.map +1 -1
- package/dist/api.d.ts +6 -0
- package/dist/api.js +11 -0
- package/dist/api.js.map +1 -1
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +14 -0
- package/dist/auth.js.map +1 -1
- package/dist/commands/add.js +16 -5
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/claude.d.ts +14 -0
- package/dist/commands/claude.js +45 -1
- package/dist/commands/claude.js.map +1 -1
- package/dist/commands/credits.js +21 -0
- package/dist/commands/credits.js.map +1 -1
- package/dist/commands/init.js +71 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/job.d.ts +2 -0
- package/dist/commands/job.js +251 -0
- package/dist/commands/job.js.map +1 -0
- package/dist/commands/realtime.js +25 -1
- package/dist/commands/realtime.js.map +1 -1
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/dist/knowledge.d.ts +4 -4
- package/dist/knowledge.js +42 -19
- package/dist/knowledge.js.map +1 -1
- package/dist/project-setup.d.ts +5 -0
- package/dist/project-setup.js +9 -4
- package/dist/project-setup.js.map +1 -1
- package/dist/prompts.d.ts +6 -6
- package/dist/prompts.js +7 -6
- package/dist/prompts.js.map +1 -1
- package/dist/relay/daemon.js +30 -4
- package/dist/relay/daemon.js.map +1 -1
- package/dist/relay/machine-id.d.ts +2 -0
- package/dist/relay/machine-id.js +64 -0
- package/dist/relay/machine-id.js.map +1 -0
- package/dist/relay/onboarding.js +2 -1
- package/dist/relay/onboarding.js.map +1 -1
- package/dist/relay/redact.d.ts +34 -0
- package/dist/relay/redact.js +80 -0
- package/dist/relay/redact.js.map +1 -0
- package/dist/setup.d.ts +38 -0
- package/dist/setup.js +82 -11
- package/dist/setup.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Gipity CLI
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The full-stack platform tuned for AI agents.
|
|
4
4
|
|
|
5
|
-
[Gipity](https://gipity.ai) is the platform: hosting, databases, file storage, deployment, workflows, code execution, and monitoring. Agent-tuned from
|
|
5
|
+
[Gipity](https://gipity.ai) is the platform: hosting, databases, file storage, deployment, workflows, code execution, and monitoring. Agent-tuned from idea to deploy. Use standalone, or pair with Claude Code to give your local agent cloud superpowers. Any model, any infra, always your code.
|
|
6
6
|
|
|
7
7
|
This CLI connects [Claude Code](https://claude.ai/claude-code) to Gipity's cloud platform - databases, deployment, browser testing, image gen, and 50+ other capabilities your local agent doesn't have. It also syncs files so Claude Code and the Gipity web agent share the same project.
|
|
8
8
|
|
|
@@ -138,7 +138,7 @@ gipity sync down # Pull remote changes
|
|
|
138
138
|
| `gipity approval` | List, create, answer, or cancel pending approvals |
|
|
139
139
|
| `gipity workflow` | Manage and trigger automated workflows |
|
|
140
140
|
| `gipity file` | Browse remote files (ls, cat, tree) |
|
|
141
|
-
| `gipity
|
|
141
|
+
| `gipity add <template>` | Add a template (web-simple, 2d-game, 3d-world, web-fullstack, api) |
|
|
142
142
|
| `gipity test` | Run project tests in sandboxed containers |
|
|
143
143
|
| `gipity logs fn <name>` | View function execution logs |
|
|
144
144
|
| `gipity page-inspect <url>` | Inspect a URL: console errors, performance, failed resources |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* markFolderTrusted - pre-accepts Claude Code's per-directory workspace-trust
|
|
3
|
+
* dialog by writing `projects["<dir>"].hasTrustDialogAccepted` into
|
|
4
|
+
* ~/.claude.json. Verifies the write is additive (every other key preserved),
|
|
5
|
+
* idempotent, and never clobbers a malformed config.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { mkdtempSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { tmpdir } from 'os';
|
|
12
|
+
import { markFolderTrusted } from '../commands/claude.js';
|
|
13
|
+
const PROJECT = '/home/test/GipityProjects/project-001';
|
|
14
|
+
let home;
|
|
15
|
+
let origHome;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
home = mkdtempSync(`${tmpdir()}/gipity-trust-test-`);
|
|
18
|
+
origHome = process.env.HOME;
|
|
19
|
+
process.env.HOME = home; // os.homedir() honors $HOME on POSIX
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
if (origHome === undefined)
|
|
23
|
+
delete process.env.HOME;
|
|
24
|
+
else
|
|
25
|
+
process.env.HOME = origHome;
|
|
26
|
+
});
|
|
27
|
+
function claudeJson() { return join(home, '.claude.json'); }
|
|
28
|
+
function readCfg() { return JSON.parse(readFileSync(claudeJson(), 'utf-8')); }
|
|
29
|
+
describe('markFolderTrusted', () => {
|
|
30
|
+
it('adds the trust entry while preserving other top-level keys and projects', () => {
|
|
31
|
+
writeFileSync(claudeJson(), JSON.stringify({
|
|
32
|
+
numStartups: 42,
|
|
33
|
+
projects: { '/some/other/dir': { hasTrustDialogAccepted: true, foo: 1 } },
|
|
34
|
+
}));
|
|
35
|
+
markFolderTrusted(PROJECT);
|
|
36
|
+
const cfg = readCfg();
|
|
37
|
+
assert.equal(cfg.projects[PROJECT].hasTrustDialogAccepted, true);
|
|
38
|
+
assert.equal(cfg.numStartups, 42, 'unrelated top-level keys preserved');
|
|
39
|
+
assert.deepEqual(cfg.projects['/some/other/dir'], { hasTrustDialogAccepted: true, foo: 1 }, 'other projects untouched');
|
|
40
|
+
});
|
|
41
|
+
it('merges into an existing project entry without dropping its other fields', () => {
|
|
42
|
+
writeFileSync(claudeJson(), JSON.stringify({
|
|
43
|
+
projects: { [PROJECT]: { allowedTools: ['Bash'], history: [1, 2] } },
|
|
44
|
+
}));
|
|
45
|
+
markFolderTrusted(PROJECT);
|
|
46
|
+
const cfg = readCfg();
|
|
47
|
+
assert.equal(cfg.projects[PROJECT].hasTrustDialogAccepted, true);
|
|
48
|
+
assert.deepEqual(cfg.projects[PROJECT].allowedTools, ['Bash']);
|
|
49
|
+
assert.deepEqual(cfg.projects[PROJECT].history, [1, 2]);
|
|
50
|
+
});
|
|
51
|
+
it('is a no-op when the folder is already trusted', () => {
|
|
52
|
+
const original = JSON.stringify({
|
|
53
|
+
projects: { [PROJECT]: { hasTrustDialogAccepted: true } },
|
|
54
|
+
}, null, 2);
|
|
55
|
+
writeFileSync(claudeJson(), original);
|
|
56
|
+
markFolderTrusted(PROJECT);
|
|
57
|
+
assert.equal(readFileSync(claudeJson(), 'utf-8'), original, 'file untouched');
|
|
58
|
+
});
|
|
59
|
+
it('creates ~/.claude.json when it does not exist', () => {
|
|
60
|
+
assert.equal(existsSync(claudeJson()), false);
|
|
61
|
+
markFolderTrusted(PROJECT);
|
|
62
|
+
assert.equal(readCfg().projects[PROJECT].hasTrustDialogAccepted, true);
|
|
63
|
+
});
|
|
64
|
+
it('leaves a malformed config untouched and does not throw', () => {
|
|
65
|
+
const garbage = '{ this is not json';
|
|
66
|
+
writeFileSync(claudeJson(), garbage);
|
|
67
|
+
assert.doesNotThrow(() => markFolderTrusted(PROJECT));
|
|
68
|
+
assert.equal(readFileSync(claudeJson(), 'utf-8'), garbage, 'malformed file not clobbered');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=claude-trust.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-trust.test.js","sourceRoot":"","sources":["../../src/__tests__/claude-trust.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { test, before, after } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { runCliAsync } from './helpers/spawn-cli.js';
|
|
4
|
+
import { startMockServer } from './helpers/mock-server.js';
|
|
5
|
+
import { makeAuthedHome, makeProjectDir } from './helpers/test-home.js';
|
|
6
|
+
let mock;
|
|
7
|
+
let home;
|
|
8
|
+
before(async () => { mock = await startMockServer(); home = makeAuthedHome(); });
|
|
9
|
+
after(async () => { await mock.stop(); });
|
|
10
|
+
function fresh(args) {
|
|
11
|
+
const d = makeProjectDir({ apiBase: mock.apiBase });
|
|
12
|
+
return runCliAsync(['--api-base', mock.apiBase, ...args], { env: { HOME: home }, cwd: d });
|
|
13
|
+
}
|
|
14
|
+
test('gipity job list shows jobs with name + runtime + compute + version', async () => {
|
|
15
|
+
mock.reset();
|
|
16
|
+
mock.on('GET /projects/p_TestProj/jobs', { body: { data: [
|
|
17
|
+
{ name: 'align', runtime: 'python-3.11', compute: 'gpu-small', version: 2, on_complete: 'notify', description: 'Forced alignment' },
|
|
18
|
+
{ name: 'render', runtime: 'node-20', compute: 'cpu-large', version: 1, description: null },
|
|
19
|
+
] } });
|
|
20
|
+
const r = await fresh(['job', 'list']);
|
|
21
|
+
assert.equal(r.status, 0, r.stderr);
|
|
22
|
+
assert.match(r.stdout, /align/);
|
|
23
|
+
assert.match(r.stdout, /python-3\.11/);
|
|
24
|
+
assert.match(r.stdout, /gpu-small/);
|
|
25
|
+
assert.match(r.stdout, /v2/);
|
|
26
|
+
assert.match(r.stdout, /→ notify/);
|
|
27
|
+
assert.match(r.stdout, /render/);
|
|
28
|
+
assert.match(r.stdout, /cpu-large/);
|
|
29
|
+
assert.doesNotMatch(r.stdout, /undefined/);
|
|
30
|
+
});
|
|
31
|
+
test('gipity job submit <name> posts and prints run_guid + status', async () => {
|
|
32
|
+
mock.reset();
|
|
33
|
+
mock.on('POST /projects/p_TestProj/jobs/align/submit', { body: { data: { run_guid: 'jr_xx1234', status: 'queued', replayed: false } } });
|
|
34
|
+
const r = await fresh(['job', 'submit', 'align', '{"audio":"foo.wav"}']);
|
|
35
|
+
assert.equal(r.status, 0, r.stderr);
|
|
36
|
+
assert.match(r.stdout, /jr_xx1234/);
|
|
37
|
+
assert.match(r.stdout, /queued/);
|
|
38
|
+
assert.doesNotMatch(r.stdout, /undefined/);
|
|
39
|
+
});
|
|
40
|
+
test('gipity job submit with --idempotency-key shows replayed marker', async () => {
|
|
41
|
+
mock.reset();
|
|
42
|
+
mock.on('POST /projects/p_TestProj/jobs/align/submit', { body: { data: { run_guid: 'jr_xx1234', status: 'success', replayed: true } } });
|
|
43
|
+
const r = await fresh(['job', 'submit', 'align', '--idempotency-key', 'k1']);
|
|
44
|
+
assert.equal(r.status, 0, r.stderr);
|
|
45
|
+
assert.match(r.stdout, /jr_xx1234/);
|
|
46
|
+
assert.match(r.stdout, /replayed/);
|
|
47
|
+
});
|
|
48
|
+
test('gipity job status <guid> renders progress + status', async () => {
|
|
49
|
+
mock.reset();
|
|
50
|
+
mock.on('GET /projects/p_TestProj/jobs/runs/jr_xx1234', { body: { data: {
|
|
51
|
+
guid: 'jr_xx1234',
|
|
52
|
+
status: 'running',
|
|
53
|
+
progress_pct: 0.42,
|
|
54
|
+
progress_message: 'thinking',
|
|
55
|
+
duration_ms: null,
|
|
56
|
+
error: null,
|
|
57
|
+
output: null,
|
|
58
|
+
} } });
|
|
59
|
+
const r = await fresh(['job', 'status', 'jr_xx1234']);
|
|
60
|
+
assert.equal(r.status, 0, r.stderr);
|
|
61
|
+
assert.match(r.stdout, /running/);
|
|
62
|
+
assert.match(r.stdout, /42%/);
|
|
63
|
+
assert.match(r.stdout, /thinking/);
|
|
64
|
+
});
|
|
65
|
+
test('gipity job runs <name> lists per-run rows with status + duration + guid', async () => {
|
|
66
|
+
mock.reset();
|
|
67
|
+
mock.on('GET /projects/p_TestProj/jobs/align/runs', { body: { data: [
|
|
68
|
+
{ status: 'success', duration_ms: 1234, trigger_type: 'cli', guid: 'jr_a', created_at: '2026-05-01T10:00:00Z' },
|
|
69
|
+
{ status: 'failed', duration_ms: 200, trigger_type: 'cli', guid: 'jr_b', created_at: '2026-05-02T10:00:00Z', error: 'kaboom' },
|
|
70
|
+
] } });
|
|
71
|
+
const r = await fresh(['job', 'runs', 'align']);
|
|
72
|
+
assert.equal(r.status, 0, r.stderr);
|
|
73
|
+
assert.match(r.stdout, /success/);
|
|
74
|
+
assert.match(r.stdout, /1234ms/);
|
|
75
|
+
assert.match(r.stdout, /jr_a/);
|
|
76
|
+
assert.match(r.stdout, /failed/);
|
|
77
|
+
assert.match(r.stdout, /kaboom/);
|
|
78
|
+
});
|
|
79
|
+
test('gipity job cancel <guid> sends DELETE and prints cancelled', async () => {
|
|
80
|
+
mock.reset();
|
|
81
|
+
mock.on('DELETE /projects/p_TestProj/jobs/runs/jr_xx1234', { body: { data: { success: true, status: 'cancelled' } } });
|
|
82
|
+
const r = await fresh(['job', 'cancel', 'jr_xx1234']);
|
|
83
|
+
assert.equal(r.status, 0, r.stderr);
|
|
84
|
+
assert.match(r.stdout, /cancelled/);
|
|
85
|
+
});
|
|
86
|
+
test('gipity job logs <guid> --no-follow does a one-shot GET (no stream)', async () => {
|
|
87
|
+
mock.reset();
|
|
88
|
+
mock.on('GET /projects/p_TestProj/jobs/runs/jr_xx1234', { body: { data: {
|
|
89
|
+
guid: 'jr_xx1234',
|
|
90
|
+
status: 'success',
|
|
91
|
+
progress_pct: 1,
|
|
92
|
+
output: { result: 'ok' },
|
|
93
|
+
duration_ms: 500,
|
|
94
|
+
} } });
|
|
95
|
+
const r = await fresh(['job', 'logs', 'jr_xx1234', '--no-follow']);
|
|
96
|
+
assert.equal(r.status, 0, r.stderr);
|
|
97
|
+
assert.match(r.stdout, /success/);
|
|
98
|
+
assert.match(r.stdout, /result/);
|
|
99
|
+
});
|
|
100
|
+
test('gipity job run-local fails clearly when jobs/<name>/ does not exist', async () => {
|
|
101
|
+
// No mock interaction needed - this is a local-only path that exits before
|
|
102
|
+
// any HTTP / Docker call.
|
|
103
|
+
const r = await fresh(['job', 'run-local', 'definitely-not-a-job']);
|
|
104
|
+
assert.notEqual(r.status, 0);
|
|
105
|
+
assert.match(r.stderr, /not found/i);
|
|
106
|
+
});
|
|
107
|
+
test('gipity job run-local with a mocked docker binary builds the right docker run command', async () => {
|
|
108
|
+
// Install a fake `docker` on PATH that records its argv to a temp file and
|
|
109
|
+
// exits 0. Then run-local should: (1) pass `docker info` probe, (2) shell out
|
|
110
|
+
// with `docker run --rm --network bridge --memory 1g --cpus 1 ...`. We assert
|
|
111
|
+
// on the recorded argv to pin the contract.
|
|
112
|
+
const { mkdtempSync, writeFileSync, readFileSync, mkdirSync, chmodSync } = await import('node:fs');
|
|
113
|
+
const { join } = await import('node:path');
|
|
114
|
+
const { tmpdir } = await import('node:os');
|
|
115
|
+
const sandboxRoot = mkdtempSync(`${tmpdir()}/gipity-runlocal-test-`);
|
|
116
|
+
// Project dir with a jobs/hello/main.py handler
|
|
117
|
+
const projDir = join(sandboxRoot, 'proj');
|
|
118
|
+
mkdirSync(join(projDir, 'jobs', 'hello'), { recursive: true });
|
|
119
|
+
writeFileSync(join(projDir, 'jobs', 'hello', 'main.py'), '# @gipity:job runtime=python-3.11\nprint("ok")\n');
|
|
120
|
+
// Make it a Gipity-linked project so requireConfig doesn't bail out.
|
|
121
|
+
writeFileSync(join(projDir, '.gipity.json'), JSON.stringify({
|
|
122
|
+
projectGuid: 'p_TestProj',
|
|
123
|
+
projectSlug: 'proj',
|
|
124
|
+
accountSlug: 'me',
|
|
125
|
+
agentGuid: 'a_x',
|
|
126
|
+
apiBase: mock.apiBase,
|
|
127
|
+
ignore: [],
|
|
128
|
+
}));
|
|
129
|
+
// Fake docker shim - records argv to a file and exits 0.
|
|
130
|
+
const fakeBin = join(sandboxRoot, 'bin');
|
|
131
|
+
mkdirSync(fakeBin, { recursive: true });
|
|
132
|
+
const recordFile = join(sandboxRoot, 'docker-argv.txt');
|
|
133
|
+
const fakeDocker = `#!/usr/bin/env bash
|
|
134
|
+
echo "$@" >> "${recordFile}"
|
|
135
|
+
exit 0
|
|
136
|
+
`;
|
|
137
|
+
writeFileSync(join(fakeBin, 'docker'), fakeDocker);
|
|
138
|
+
chmodSync(join(fakeBin, 'docker'), 0o755);
|
|
139
|
+
const r = await runCliAsync(['--api-base', mock.apiBase, 'job', 'run-local', 'hello'], {
|
|
140
|
+
env: {
|
|
141
|
+
HOME: home,
|
|
142
|
+
PATH: `${fakeBin}:${process.env.PATH ?? ''}`,
|
|
143
|
+
},
|
|
144
|
+
cwd: projDir,
|
|
145
|
+
});
|
|
146
|
+
assert.equal(r.status, 0, r.stderr);
|
|
147
|
+
const recorded = readFileSync(recordFile, 'utf-8');
|
|
148
|
+
// Two invocations: docker info (probe) + docker run ...
|
|
149
|
+
const lines = recorded.trim().split('\n');
|
|
150
|
+
assert.ok(lines.length >= 2, `expected at least 2 docker invocations, got ${lines.length}: ${recorded}`);
|
|
151
|
+
assert.match(lines[0], /^info$/);
|
|
152
|
+
const runLine = lines.find(l => l.startsWith('run ')) ?? '';
|
|
153
|
+
assert.match(runLine, /--rm/);
|
|
154
|
+
assert.match(runLine, /--network bridge/);
|
|
155
|
+
assert.match(runLine, /--memory 1g/);
|
|
156
|
+
assert.match(runLine, /--cpus 1/);
|
|
157
|
+
assert.match(runLine, /--user sandbox/);
|
|
158
|
+
assert.match(runLine, /--workdir \/work/);
|
|
159
|
+
assert.match(runLine, /-v .*\/jobs\/hello:\/work/);
|
|
160
|
+
assert.match(runLine, /python3 \/work\/main\.py/);
|
|
161
|
+
});
|
|
162
|
+
test('gipity job run-local exits non-zero when docker is not on PATH', async () => {
|
|
163
|
+
const { mkdtempSync } = await import('node:fs');
|
|
164
|
+
const { tmpdir } = await import('node:os');
|
|
165
|
+
const emptyBin = mkdtempSync(`${tmpdir()}/gipity-nodocker-`);
|
|
166
|
+
const { writeFileSync, mkdirSync } = await import('node:fs');
|
|
167
|
+
const { join } = await import('node:path');
|
|
168
|
+
const projDir = mkdtempSync(`${tmpdir()}/gipity-nodocker-proj-`);
|
|
169
|
+
mkdirSync(join(projDir, 'jobs', 'hello'), { recursive: true });
|
|
170
|
+
writeFileSync(join(projDir, 'jobs', 'hello', 'main.py'), 'print("x")\n');
|
|
171
|
+
writeFileSync(join(projDir, '.gipity.json'), JSON.stringify({
|
|
172
|
+
projectGuid: 'p_TestProj', projectSlug: 'proj', accountSlug: 'me',
|
|
173
|
+
agentGuid: 'a_x', apiBase: mock.apiBase, ignore: [],
|
|
174
|
+
}));
|
|
175
|
+
const r = await runCliAsync(['--api-base', mock.apiBase, 'job', 'run-local', 'hello'], {
|
|
176
|
+
env: { HOME: home, PATH: emptyBin },
|
|
177
|
+
cwd: projDir,
|
|
178
|
+
});
|
|
179
|
+
assert.notEqual(r.status, 0);
|
|
180
|
+
assert.match(r.stderr, /docker daemon not reachable/i);
|
|
181
|
+
});
|
|
182
|
+
test('gipity job logs <guid> --follow parses SSE events and prints stdout/stderr chunks', async () => {
|
|
183
|
+
// Pre-built SSE blob (mock server writes the body as one chunk + closes;
|
|
184
|
+
// the CLI's reader still processes each `event:`/`data:` pair correctly).
|
|
185
|
+
mock.reset();
|
|
186
|
+
const sse = [
|
|
187
|
+
`event: status\ndata: ${JSON.stringify({ status: 'running', progress_pct: null, progress_message: null, attempt: 1 })}\n\n`,
|
|
188
|
+
`event: log\ndata: ${JSON.stringify({ type: 'stdout', chunk: 'hello stdout\n' })}\n\n`,
|
|
189
|
+
`event: log\ndata: ${JSON.stringify({ type: 'stderr', chunk: 'an error\n' })}\n\n`,
|
|
190
|
+
`event: status\ndata: ${JSON.stringify({ status: 'success', progress_pct: 1, progress_message: 'done', attempt: 1 })}\n\n`,
|
|
191
|
+
`event: output\ndata: ${JSON.stringify({ result: 'ok' })}\n\n`,
|
|
192
|
+
].join('');
|
|
193
|
+
mock.on('GET /projects/p_TestProj/jobs/runs/jr_xx1234/logs/stream', {
|
|
194
|
+
raw: sse,
|
|
195
|
+
contentType: 'text/event-stream',
|
|
196
|
+
});
|
|
197
|
+
const r = await fresh(['job', 'logs', 'jr_xx1234']);
|
|
198
|
+
assert.equal(r.status, 0, `expected 0 got ${r.status}; stderr=${r.stderr}`);
|
|
199
|
+
assert.match(r.stdout, /hello stdout/);
|
|
200
|
+
assert.match(r.stderr, /an error/);
|
|
201
|
+
assert.match(r.stderr, /running/);
|
|
202
|
+
assert.match(r.stderr, /success/);
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=cli-cmd-job.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-cmd-job.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-cmd-job.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,16 +7,21 @@ import { runCli } from './helpers/spawn-cli.js';
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const PKG_VERSION = JSON.parse(readFileSync(resolve(__dirname, '..', '..', 'package.json'), 'utf-8')).version;
|
|
9
9
|
describe('cli-smoke: --version and --help', () => {
|
|
10
|
-
it('--version prints the package version', () => {
|
|
10
|
+
it('--version prints the package version + auth status', () => {
|
|
11
11
|
const r = runCli(['--version']);
|
|
12
12
|
assert.equal(r.status, 0);
|
|
13
|
-
|
|
13
|
+
// Branded line: "Gipity v1.2.3"
|
|
14
|
+
assert.match(r.stdout, new RegExp(`Gipity\\s+v${PKG_VERSION.replace(/\./g, '\\.')}`));
|
|
15
|
+
// Auth status: logged-in, session expired, or never logged in.
|
|
16
|
+
assert.match(r.stdout, /Logged in as |Session expired for |Not logged in\. Run: gipity login/);
|
|
14
17
|
});
|
|
15
18
|
it('--help shows version banner near the top and grouped sections in order', () => {
|
|
16
19
|
const r = runCli(['--help']);
|
|
17
20
|
assert.equal(r.status, 0);
|
|
18
21
|
const out = r.stdout;
|
|
19
22
|
assert.match(out, new RegExp(`Gipity CLI\\s+v${PKG_VERSION.replace(/\./g, '\\.')}`));
|
|
23
|
+
// Cross-agent positioning line surfaces in top-level help.
|
|
24
|
+
assert.match(out, /no MCP server needed/);
|
|
20
25
|
const sections = ['Common:', 'Connect:', 'Project:', 'Files:', 'App building:', 'Utilities:', 'Agent:', 'Setup:'];
|
|
21
26
|
let lastIdx = -1;
|
|
22
27
|
for (const s of sections) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-smoke.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAE9G,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"cli-smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-smoke.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the relay machine-id fingerprint. The native-id paths
|
|
3
|
+
* (Linux/macOS/Windows) are environment-specific; these cover the public
|
|
4
|
+
* guarantees: a uniform 64-char hex output, determinism, and that the
|
|
5
|
+
* GIPITY_RELAY_MACHINE_ID override drives the value (the path hosted
|
|
6
|
+
* relay-host containers rely on).
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, afterEach } from 'node:test';
|
|
9
|
+
import assert from 'node:assert/strict';
|
|
10
|
+
import { getMachineId } from '../relay/machine-id.js';
|
|
11
|
+
const ORIG = process.env.GIPITY_RELAY_MACHINE_ID;
|
|
12
|
+
describe('getMachineId', () => {
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
if (ORIG === undefined)
|
|
15
|
+
delete process.env.GIPITY_RELAY_MACHINE_ID;
|
|
16
|
+
else
|
|
17
|
+
process.env.GIPITY_RELAY_MACHINE_ID = ORIG;
|
|
18
|
+
});
|
|
19
|
+
it('returns a uniform 64-char lowercase hex string', () => {
|
|
20
|
+
assert.match(getMachineId(), /^[0-9a-f]{64}$/);
|
|
21
|
+
});
|
|
22
|
+
it('is deterministic for a fixed override', () => {
|
|
23
|
+
process.env.GIPITY_RELAY_MACHINE_ID = 'relay-host:alice@example.com';
|
|
24
|
+
const a = getMachineId();
|
|
25
|
+
const b = getMachineId();
|
|
26
|
+
assert.equal(a, b);
|
|
27
|
+
assert.match(a, /^[0-9a-f]{64}$/);
|
|
28
|
+
});
|
|
29
|
+
it('different overrides produce different ids', () => {
|
|
30
|
+
process.env.GIPITY_RELAY_MACHINE_ID = 'relay-host:alice@example.com';
|
|
31
|
+
const alice = getMachineId();
|
|
32
|
+
process.env.GIPITY_RELAY_MACHINE_ID = 'relay-host:bob@example.com';
|
|
33
|
+
const bob = getMachineId();
|
|
34
|
+
assert.notEqual(alice, bob);
|
|
35
|
+
});
|
|
36
|
+
it('an empty override is ignored (falls through to a real id)', () => {
|
|
37
|
+
process.env.GIPITY_RELAY_MACHINE_ID = ' ';
|
|
38
|
+
assert.match(getMachineId(), /^[0-9a-f]{64}$/);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=relay-machine-id.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay-machine-id.test.js","sourceRoot":"","sources":["../../src/__tests__/relay-machine-id.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;AAEjD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;;YAC9D,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,8BAA8B,CAAC;QACrE,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,8BAA8B,CAAC;QACrE,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,4BAA4B,CAAC;QACnE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,KAAK,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the relay secret-redaction pass. No daemon, no network -
|
|
3
|
+
* just `normalizeSecrets` and `redactEntries`. Uses node's built-in runner.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { normalizeSecrets, redactEntries, REDACTION_MARKER } from '../relay/redact.js';
|
|
8
|
+
// A realistic-length fake credential and a short one (must NOT be treated
|
|
9
|
+
// as a secret - see MIN_SECRET_LEN guard).
|
|
10
|
+
const OAUTH = 'sk-ant-oat01-AAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
11
|
+
const API_KEY = 'sk-ant-api03-BBBBBBBBBBBBBBBBBBBBBBBBBBBB';
|
|
12
|
+
const SHORT = 'abc';
|
|
13
|
+
describe('normalizeSecrets', () => {
|
|
14
|
+
it('drops empty, nullish, and too-short values', () => {
|
|
15
|
+
assert.deepEqual(normalizeSecrets([undefined, null, '', SHORT]), []);
|
|
16
|
+
});
|
|
17
|
+
it('dedups and sorts longest-first', () => {
|
|
18
|
+
const longer = API_KEY + 'XXXX';
|
|
19
|
+
const out = normalizeSecrets([API_KEY, longer, API_KEY]);
|
|
20
|
+
assert.deepEqual(out, [longer, API_KEY]);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('redactEntries', () => {
|
|
24
|
+
it('scrubs a secret out of a tool_result content string', () => {
|
|
25
|
+
const entries = [
|
|
26
|
+
{ kind: 'tool_result', tool_use_id: 't1', content: `the token is ${OAUTH} ok` },
|
|
27
|
+
];
|
|
28
|
+
const [out] = redactEntries(entries, normalizeSecrets([OAUTH]));
|
|
29
|
+
assert.equal(out.content, `the token is ${REDACTION_MARKER} ok`);
|
|
30
|
+
});
|
|
31
|
+
it('scrubs a secret out of assistant text and nested blocks', () => {
|
|
32
|
+
const entries = [
|
|
33
|
+
{
|
|
34
|
+
kind: 'assistant',
|
|
35
|
+
text: `here it is: ${API_KEY}`,
|
|
36
|
+
blocks: [{ type: 'text', text: `again ${API_KEY}` }],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
const [out] = redactEntries(entries, normalizeSecrets([API_KEY]));
|
|
40
|
+
assert.equal(out.text, `here it is: ${REDACTION_MARKER}`);
|
|
41
|
+
assert.equal(out.blocks[0].text, `again ${REDACTION_MARKER}`);
|
|
42
|
+
});
|
|
43
|
+
it('handles either credential env value (oauth or api key)', () => {
|
|
44
|
+
const entries = [
|
|
45
|
+
{ kind: 'system', content: `oauth=${OAUTH} apikey=${API_KEY}` },
|
|
46
|
+
];
|
|
47
|
+
const [out] = redactEntries(entries, normalizeSecrets([OAUTH, API_KEY]));
|
|
48
|
+
assert.equal(out.content, `oauth=${REDACTION_MARKER} apikey=${REDACTION_MARKER}`);
|
|
49
|
+
});
|
|
50
|
+
it('leaves a clean entry untouched', () => {
|
|
51
|
+
const entries = [{ kind: 'prompt', prompt: 'build me a todo app' }];
|
|
52
|
+
const [out] = redactEntries(entries, normalizeSecrets([OAUTH]));
|
|
53
|
+
assert.equal(out.prompt, 'build me a todo app');
|
|
54
|
+
});
|
|
55
|
+
it('leaves clean content intact when there are no secrets', () => {
|
|
56
|
+
const entries = [{ kind: 'prompt', prompt: `mentions ${SHORT}` }];
|
|
57
|
+
const [out] = redactEntries(entries, normalizeSecrets([SHORT, '']));
|
|
58
|
+
assert.equal(out.prompt, `mentions ${SHORT}`);
|
|
59
|
+
});
|
|
60
|
+
it('redacts a JWT-shaped string even with no literal secrets', () => {
|
|
61
|
+
// Gipity access/refresh tokens are JWTs and rotate; the pattern pass
|
|
62
|
+
// catches them if the literal-secret list is momentarily stale.
|
|
63
|
+
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQyfQ.s1gnatur3_AbC-dEf';
|
|
64
|
+
const entries = [
|
|
65
|
+
{ kind: 'tool_result', tool_use_id: 't1', content: `"accessToken":"${jwt}"` },
|
|
66
|
+
];
|
|
67
|
+
const [out] = redactEntries(entries, []);
|
|
68
|
+
assert.equal(out.content, `"accessToken":"${REDACTION_MARKER}"`);
|
|
69
|
+
});
|
|
70
|
+
it('does not mutate the input entries', () => {
|
|
71
|
+
const entries = [
|
|
72
|
+
{ kind: 'tool_result', tool_use_id: 't1', content: OAUTH },
|
|
73
|
+
];
|
|
74
|
+
redactEntries(entries, normalizeSecrets([OAUTH]));
|
|
75
|
+
assert.equal(entries[0].content, OAUTH);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=relay-redact.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay-redact.test.js","sourceRoot":"","sources":["../../src/__tests__/relay-redact.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* applySkillsBlock - the managed CLAUDE.md / AGENTS.md integration block.
|
|
3
|
+
*
|
|
4
|
+
* The Gipity block is delimited by stable markers and fully managed: every
|
|
5
|
+
* run refreshes it to the current SKILLS_CONTENT while preserving the user's
|
|
6
|
+
* own content outside the markers. These cover the four input shapes plus
|
|
7
|
+
* idempotency - the property that makes per-session refresh safe.
|
|
8
|
+
*/
|
|
9
|
+
import { test } from 'node:test';
|
|
10
|
+
import assert from 'node:assert/strict';
|
|
11
|
+
import { applySkillsBlock, GIPITY_BLOCK_BEGIN, GIPITY_BLOCK_END, SKILLS_CONTENT } from '../setup.js';
|
|
12
|
+
function count(haystack, needle) {
|
|
13
|
+
return haystack.split(needle).length - 1;
|
|
14
|
+
}
|
|
15
|
+
test('no file: returns the managed block, marker-wrapped and newline-terminated', () => {
|
|
16
|
+
const out = applySkillsBlock(null);
|
|
17
|
+
assert.ok(out.includes(GIPITY_BLOCK_BEGIN), 'has begin marker');
|
|
18
|
+
assert.ok(out.includes(GIPITY_BLOCK_END), 'has end marker');
|
|
19
|
+
assert.ok(out.includes(SKILLS_CONTENT), 'has current skills content');
|
|
20
|
+
assert.ok(out.endsWith('\n'), 'ends with a newline');
|
|
21
|
+
});
|
|
22
|
+
test('marked block: content refreshed in place, surrounding text preserved', () => {
|
|
23
|
+
const stale = `${GIPITY_BLOCK_BEGIN}\n# Gipity Integration\n\nSTALE OLD TEXT\n${GIPITY_BLOCK_END}`;
|
|
24
|
+
const file = `# My Project\n\nMy own notes.\n\n${stale}\n\nNotes below the block.\n`;
|
|
25
|
+
const out = applySkillsBlock(file);
|
|
26
|
+
assert.ok(out.includes('My own notes.'), 'preserves content above the block');
|
|
27
|
+
assert.ok(out.includes('Notes below the block.'), 'preserves content below the block');
|
|
28
|
+
assert.ok(!out.includes('STALE OLD TEXT'), 'stale block content is replaced');
|
|
29
|
+
assert.ok(out.includes(SKILLS_CONTENT), 'has current skills content');
|
|
30
|
+
assert.equal(count(out, GIPITY_BLOCK_BEGIN), 1, 'exactly one block, no duplication');
|
|
31
|
+
});
|
|
32
|
+
test('legacy unmarked block: migrated to a marked block, stale text dropped', () => {
|
|
33
|
+
const file = '# Gipity Integration\n\nOLD UNMARKED CONTENT from a previous CLI version.\n';
|
|
34
|
+
const out = applySkillsBlock(file);
|
|
35
|
+
assert.ok(out.includes(GIPITY_BLOCK_BEGIN), 'now wrapped in markers');
|
|
36
|
+
assert.ok(!out.includes('OLD UNMARKED CONTENT'), 'legacy text dropped');
|
|
37
|
+
assert.ok(out.includes(SKILLS_CONTENT), 'has current skills content');
|
|
38
|
+
assert.equal(count(out, GIPITY_BLOCK_BEGIN), 1, 'exactly one block');
|
|
39
|
+
});
|
|
40
|
+
test('legacy unmarked block below user content: user content survives migration', () => {
|
|
41
|
+
const file = '# My Project\n\nImportant project notes.\n\n# Gipity Integration\n\nstale legacy text\n';
|
|
42
|
+
const out = applySkillsBlock(file);
|
|
43
|
+
assert.ok(out.includes('Important project notes.'), 'user content above is kept');
|
|
44
|
+
assert.ok(!out.includes('stale legacy text'), 'legacy block is replaced');
|
|
45
|
+
assert.equal(count(out, GIPITY_BLOCK_BEGIN), 1, 'exactly one block');
|
|
46
|
+
});
|
|
47
|
+
test('user file with no Gipity block: block appended, user content kept', () => {
|
|
48
|
+
const file = '# My Project\n\nJust my notes, no Gipity block.\n';
|
|
49
|
+
const out = applySkillsBlock(file);
|
|
50
|
+
assert.ok(out.startsWith('# My Project'), 'user content stays at the top');
|
|
51
|
+
assert.ok(out.includes('Just my notes, no Gipity block.'), 'user content kept');
|
|
52
|
+
assert.ok(out.includes(GIPITY_BLOCK_BEGIN), 'managed block appended');
|
|
53
|
+
});
|
|
54
|
+
test('idempotent: re-applying the result changes nothing', () => {
|
|
55
|
+
const inputs = [
|
|
56
|
+
null,
|
|
57
|
+
'# My Project\n\nNotes.\n',
|
|
58
|
+
'# Gipity Integration\n\nlegacy text\n',
|
|
59
|
+
];
|
|
60
|
+
for (const input of inputs) {
|
|
61
|
+
const once = applySkillsBlock(input);
|
|
62
|
+
assert.equal(applySkillsBlock(once), once, 'a second apply is a no-op');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=setup-skills-block.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-skills-block.test.js","sourceRoot":"","sources":["../../src/__tests__/setup-skills-block.test.ts"],"names":[],"mappings":"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"}
|
package/dist/adopt-cwd.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SUPPORTED_TOOLS } from './setup.js';
|
|
1
2
|
export interface ProjectData {
|
|
2
3
|
short_guid: string;
|
|
3
4
|
name: string;
|
|
@@ -56,6 +57,8 @@ export declare function adoptCurrentDir(opts: {
|
|
|
56
57
|
confirmDeletions: boolean;
|
|
57
58
|
/** Force a specific agent guid; skip the auto-lookup. */
|
|
58
59
|
agentOverride?: string;
|
|
60
|
+
/** Subset of AI-tool primers to write. Defaults to all. */
|
|
61
|
+
tools?: typeof SUPPORTED_TOOLS;
|
|
59
62
|
}): Promise<AdoptResult>;
|
|
60
63
|
/** Re-export so callers can unify on these constants for messaging. */
|
|
61
64
|
export declare const ADOPT_THRESHOLDS: {
|
package/dist/adopt-cwd.js
CHANGED