ftown-bridge 0.19.39 → 0.19.41
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/cli-client.d.ts +17 -0
- package/dist/cli-client.js +76 -0
- package/dist/cli-client.js.map +1 -0
- package/dist/cli-entry.d.ts +2 -0
- package/dist/cli-entry.js +22 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/codex-installer.d.ts +1 -1
- package/dist/codex-installer.js +7 -6
- package/dist/codex-installer.js.map +1 -1
- package/dist/command-rpc.js +0 -1
- package/dist/command-rpc.js.map +1 -1
- package/dist/create-ftown-session.d.ts +1 -6
- package/dist/create-ftown-session.js +3 -25
- package/dist/create-ftown-session.js.map +1 -1
- package/dist/cursor-hook-installer.d.ts +1 -1
- package/dist/cursor-hook-installer.js +6 -5
- package/dist/cursor-hook-installer.js.map +1 -1
- package/dist/ensure-ftown-path.js +1 -1
- package/dist/env-commands.d.ts +32 -0
- package/dist/env-commands.js +162 -0
- package/dist/env-commands.js.map +1 -0
- package/dist/ftown-cli.d.ts +2 -6
- package/dist/ftown-cli.js +25 -79
- package/dist/ftown-cli.js.map +1 -1
- package/dist/ftown-env-cli.d.ts +2 -31
- package/dist/ftown-env-cli.js +7 -176
- package/dist/ftown-env-cli.js.map +1 -1
- package/dist/ftown-home.d.ts +24 -10
- package/dist/ftown-home.js +19 -41
- package/dist/ftown-home.js.map +1 -1
- package/dist/ftown-sessions-cli.d.ts +1 -1
- package/dist/ftown-sessions-cli.js +6 -499
- package/dist/ftown-sessions-cli.js.map +1 -1
- package/dist/harness-cli.d.ts +1 -1
- package/dist/harness-cli.js +6 -626
- package/dist/harness-cli.js.map +1 -1
- package/dist/harness-commands.d.ts +2 -0
- package/dist/harness-commands.js +576 -0
- package/dist/harness-commands.js.map +1 -0
- package/dist/harness-installer.d.ts +1 -10
- package/dist/harness-installer.js +13 -166
- package/dist/harness-installer.js.map +1 -1
- package/dist/harness-registry.d.ts +1 -27
- package/dist/harness-registry.js +1 -20
- package/dist/harness-registry.js.map +1 -1
- package/dist/hook-installer.d.ts +1 -1
- package/dist/hook-installer.js +5 -4
- package/dist/hook-installer.js.map +1 -1
- package/dist/index.js +10 -108
- package/dist/index.js.map +1 -1
- package/dist/install-ftown-command-cli.d.ts +3 -3
- package/dist/install-ftown-command-cli.js +67 -22
- package/dist/install-ftown-command-cli.js.map +1 -1
- package/dist/install-ftown-skill.d.ts +6 -0
- package/dist/install-ftown-skill.js +111 -10
- package/dist/install-ftown-skill.js.map +1 -1
- package/dist/install-notify-script.d.ts +1 -1
- package/dist/install-notify-script.js +7 -6
- package/dist/install-notify-script.js.map +1 -1
- package/dist/mail-delivery.d.ts +1 -1
- package/dist/mail-delivery.js +3 -5
- package/dist/mail-delivery.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/muse-plugin-installer.js +4 -0
- package/dist/muse-plugin-installer.js.map +1 -1
- package/dist/opencode-plugin-installer.d.ts +1 -2
- package/dist/opencode-plugin-installer.js +1 -2
- package/dist/opencode-plugin-installer.js.map +1 -1
- package/dist/provider-env-store.js +1 -1
- package/dist/provider-env-store.js.map +1 -1
- package/dist/retired-skill-assets.d.ts +3 -0
- package/dist/retired-skill-assets.js +11 -0
- package/dist/retired-skill-assets.js.map +1 -1
- package/dist/sessions-commands.d.ts +2 -0
- package/dist/sessions-commands.js +445 -0
- package/dist/sessions-commands.js.map +1 -0
- package/dist/setup-migrations.d.ts +6 -0
- package/dist/setup-migrations.js +28 -0
- package/dist/setup-migrations.js.map +1 -0
- package/dist/setup-state.d.ts +16 -0
- package/dist/setup-state.js +163 -0
- package/dist/setup-state.js.map +1 -0
- package/dist/setup.d.ts +25 -0
- package/dist/setup.js +120 -0
- package/dist/setup.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/wire-types.js +1 -8
- package/dist/wire-types.js.map +1 -1
- package/package.json +2 -3
- package/pi-extension/API.md +4 -0
- package/pi-extension/ftown.js +1 -2
- package/skills/ftown/SKILL.md +71 -19
- package/skills/ftown/references/orchestrator.md +23 -99
- package/skills/ftown/references/sessions.md +37 -42
- package/dist/claude-trust.d.ts +0 -11
- package/dist/claude-trust.js +0 -47
- package/dist/claude-trust.js.map +0 -1
- package/dist/install-ftown-cli.d.ts +0 -3
- package/dist/install-ftown-cli.js +0 -29
- package/dist/install-ftown-cli.js.map +0 -1
- package/dist/install-ftown-env-cli.d.ts +0 -3
- package/dist/install-ftown-env-cli.js +0 -30
- package/dist/install-ftown-env-cli.js.map +0 -1
- package/dist/install-ftown-workflows-cli.d.ts +0 -3
- package/dist/install-ftown-workflows-cli.js +0 -33
- package/dist/install-ftown-workflows-cli.js.map +0 -1
- package/dist/workflow-runner-cli.d.ts +0 -2
- package/dist/workflow-runner-cli.js +0 -376
- package/dist/workflow-runner-cli.js.map +0 -1
- package/dist/workflow-runner.d.ts +0 -163
- package/dist/workflow-runner.js +0 -307
- package/dist/workflow-runner.js.map +0 -1
- package/skills/fticket/SKILL.md +0 -166
- package/skills/ftown/references/workflows.md +0 -470
- package/skills/ftown/scripts/example.flow.mjs +0 -170
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { PROVIDER_AUTH_ENV, PROVIDER_FLAVORS, listProviderEnv, removeProviderToken, setProviderToken, } from './provider-env-store.js';
|
|
2
|
+
/** Mask all but the last 4 chars; tokens of length <=4 are fully masked. */
|
|
3
|
+
export function maskToken(value) {
|
|
4
|
+
if (value.length <= 4)
|
|
5
|
+
return '****';
|
|
6
|
+
return `****${value.slice(-4)}`;
|
|
7
|
+
}
|
|
8
|
+
/** Resolve a provider flavor to its source env-var KEY. Throws on unknown. */
|
|
9
|
+
export function resolveProviderSource(provider) {
|
|
10
|
+
const mapping = PROVIDER_AUTH_ENV[provider];
|
|
11
|
+
if (!mapping) {
|
|
12
|
+
throw new Error(`Unknown provider "${provider}" — use one of: ${PROVIDER_FLAVORS.join(', ')}`);
|
|
13
|
+
}
|
|
14
|
+
return mapping.source;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the token for `set` without exposing it on argv.
|
|
18
|
+
*
|
|
19
|
+
* When `positional` is a real value (defined and not the "-" stdin sentinel) it
|
|
20
|
+
* is used verbatim (trimmed) and `onArgvToken` is invoked so the caller can warn
|
|
21
|
+
* that an argv token leaks into `ps`/shell history. Otherwise the token is read
|
|
22
|
+
* from stdin via `readStdin` (piped, keeping it out of `ps` output and shell
|
|
23
|
+
* history). Throws a clear error when no non-empty token is found.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolveSetToken(positional, readStdin, onArgvToken) {
|
|
26
|
+
const fromArgv = positional !== undefined && positional !== '-';
|
|
27
|
+
if (fromArgv)
|
|
28
|
+
onArgvToken?.();
|
|
29
|
+
const raw = fromArgv ? positional : await readStdin();
|
|
30
|
+
const token = (raw ?? '').trim();
|
|
31
|
+
if (!token) {
|
|
32
|
+
throw new Error('No token provided — pass it as an argument or pipe it via stdin ' +
|
|
33
|
+
'(e.g. `printf %s "$TOKEN" | ftown env set <provider> -`)');
|
|
34
|
+
}
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
/** Read all of process.stdin to end, decoded as UTF-8 (trimming is the caller's job). */
|
|
38
|
+
async function readStdin() {
|
|
39
|
+
const chunks = [];
|
|
40
|
+
for await (const chunk of process.stdin) {
|
|
41
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
42
|
+
}
|
|
43
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Classify each flavor's token: stored in env.json wins over the process env;
|
|
47
|
+
* a flavor absent from BOTH is "missing" and listed under `blocked`.
|
|
48
|
+
*/
|
|
49
|
+
export function buildDoctorReport(store, processEnv) {
|
|
50
|
+
const flavors = PROVIDER_FLAVORS.map((flavor) => {
|
|
51
|
+
const source = PROVIDER_AUTH_ENV[flavor].source;
|
|
52
|
+
let status;
|
|
53
|
+
if (store[source])
|
|
54
|
+
status = 'env.json';
|
|
55
|
+
else if (processEnv[source])
|
|
56
|
+
status = 'process-env';
|
|
57
|
+
else
|
|
58
|
+
status = 'missing';
|
|
59
|
+
return { flavor, source, status };
|
|
60
|
+
});
|
|
61
|
+
const blocked = flavors.filter((f) => f.status === 'missing').map((f) => f.flavor);
|
|
62
|
+
return { flavors, blocked };
|
|
63
|
+
}
|
|
64
|
+
/** Positional args, skipping flags and the values of value-taking flags. */
|
|
65
|
+
function positionals(args, valueFlags) {
|
|
66
|
+
const out = [];
|
|
67
|
+
for (let i = 0; i < args.length; i++) {
|
|
68
|
+
const a = args[i];
|
|
69
|
+
if (a.startsWith('--')) {
|
|
70
|
+
if (valueFlags.includes(a))
|
|
71
|
+
i++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
out.push(a);
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
function usage() {
|
|
79
|
+
console.error(`Usage: ftown env <command> [options]
|
|
80
|
+
|
|
81
|
+
Commands:
|
|
82
|
+
set <provider> [token] Store a machine token for a provider
|
|
83
|
+
ls List configured provider tokens (masked)
|
|
84
|
+
rm <provider> Remove a stored provider token
|
|
85
|
+
doctor Report which providers are configured / blocked
|
|
86
|
+
|
|
87
|
+
Providers: ${PROVIDER_FLAVORS.join(' | ')}
|
|
88
|
+
|
|
89
|
+
Recommended (keeps the token out of \`ps\` and shell history): omit the token
|
|
90
|
+
positional and read it from stdin —
|
|
91
|
+
ftown env set zai then paste the token and press Ctrl-D
|
|
92
|
+
printf %s "$TOKEN" | ftown env set zai - pipe it (the "-" forces stdin)
|
|
93
|
+
|
|
94
|
+
Tokens live in ~/.ftown/env.json (mode 0o600). Values are always masked on output.`);
|
|
95
|
+
}
|
|
96
|
+
/** Dispatch a single command. Throws on bad input; main() maps that to exit 1. */
|
|
97
|
+
export async function run(argv) {
|
|
98
|
+
const cmd = argv[0];
|
|
99
|
+
const rest = argv.slice(1);
|
|
100
|
+
switch (cmd) {
|
|
101
|
+
case 'set': {
|
|
102
|
+
const positional = positionals(rest, []);
|
|
103
|
+
const provider = positional[0];
|
|
104
|
+
if (!provider) {
|
|
105
|
+
throw new Error('Usage: ftown env set <provider> [token] (omit the token to read it from stdin)');
|
|
106
|
+
}
|
|
107
|
+
const source = resolveProviderSource(provider);
|
|
108
|
+
const token = await resolveSetToken(positional[1], readStdin, () => console.error('ftown env: warning: the token was passed as an argument, which exposes it to ' +
|
|
109
|
+
'`ps` and shell history. Prefer stdin: `printf %s "$TOKEN" | ftown env set <provider> -`.'));
|
|
110
|
+
setProviderToken(source, token);
|
|
111
|
+
console.log(`set ${source} (${maskToken(token)}) for ${provider}`);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case 'ls': {
|
|
115
|
+
const store = listProviderEnv();
|
|
116
|
+
const keys = Object.keys(store);
|
|
117
|
+
if (keys.length === 0) {
|
|
118
|
+
console.log('(no provider tokens configured)');
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
for (const key of keys)
|
|
122
|
+
console.log(`${key} ${maskToken(store[key])}`);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'rm': {
|
|
126
|
+
const positional = positionals(rest, []);
|
|
127
|
+
const provider = positional[0];
|
|
128
|
+
if (!provider)
|
|
129
|
+
throw new Error('Usage: ftown env rm <provider>');
|
|
130
|
+
const source = resolveProviderSource(provider);
|
|
131
|
+
const existed = removeProviderToken(source);
|
|
132
|
+
console.log(existed ? `removed ${source} for ${provider}` : `${source} (${provider}) was not set`);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'doctor': {
|
|
136
|
+
const report = buildDoctorReport(listProviderEnv(), process.env);
|
|
137
|
+
for (const f of report.flavors) {
|
|
138
|
+
console.log(`${f.flavor.padEnd(9)} ${f.source.padEnd(20)} ${f.status}`);
|
|
139
|
+
}
|
|
140
|
+
console.log(`blocked: ${report.blocked.length ? report.blocked.join(', ') : '(none)'}`);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
default:
|
|
144
|
+
usage();
|
|
145
|
+
throw new Error(cmd ? `Unknown command "${cmd}"` : 'No command given');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export async function runEnv(argv) {
|
|
149
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
150
|
+
usage();
|
|
151
|
+
return argv.length ? 0 : 1;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await run(argv);
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.error(`ftown env: ${error instanceof Error ? error.message : String(error)}`);
|
|
159
|
+
return 1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=env-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-commands.js","sourceRoot":"","sources":["../src/env-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,mBAAmB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9E,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAA8B,EAC9B,SAAgC,EAChC,WAAwB;IAExB,MAAM,QAAQ,GAAG,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,GAAG,CAAC;IAChE,IAAI,QAAQ;QAAE,WAAW,EAAE,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,SAAS,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,kEAAkE;YAChE,0DAA0D,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yFAAyF;AACzF,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAeD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA6B,EAC7B,UAA8C;IAE9C,MAAM,OAAO,GAAwB,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACnE,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;QAChD,IAAI,MAAoB,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,CAAC;YAAE,MAAM,GAAG,UAAU,CAAC;aAClC,IAAI,UAAU,CAAC,MAAM,CAAC;YAAE,MAAM,GAAG,aAAa,CAAC;;YAC/C,MAAM,GAAG,SAAS,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACnF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,4EAA4E;AAC5E,SAAS,WAAW,CAAC,IAAc,EAAE,UAAoB;IACvD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,CAAC,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,KAAK;IACZ,OAAO,CAAC,KAAK,CAAC;;;;;;;;aAQH,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;mFAO0C,CAAC,CAAC;AACrF,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE3B,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAC;YACrG,CAAC;YACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CACjE,OAAO,CAAC,KAAK,CACX,+EAA+E;gBAC7E,0FAA0F,CAC7F,CACF,CAAC;YACF,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,KAAK,SAAS,CAAC,KAAK,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC;YACnE,MAAM;QACR,CAAC;QAED,KAAK,IAAI,CAAC,CAAC,CAAC;YACV,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;gBAC/C,MAAM;YACR,CAAC;YACD,KAAK,MAAM,GAAG,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;YACxE,MAAM;QACR,CAAC;QAED,KAAK,IAAI,CAAC,CAAC,CAAC;YACV,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,QAAQ,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,QAAQ,eAAe,CAAC,CAAC;YACnG,MAAM;QACR,CAAC;QAED,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,iBAAiB,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YACjE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1E,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxF,MAAM;QACR,CAAC;QAED;YACE,KAAK,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB,GAAG,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IACzC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAAC,KAAK,EAAE,CAAC;QAAC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAC3G,IAAI,CAAC;QAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IAClC,OAAO,KAAK,EAAE,CAAC;QAAC,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC;AACpH,CAAC"}
|
package/dist/ftown-cli.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
* Resolve a subcommand to its absolute sibling launcher path under `ftownDir`.
|
|
4
|
-
* Throws a clear Error (listing the valid subcommands) on undefined/unknown.
|
|
5
|
-
*/
|
|
6
|
-
export declare function resolveSubcommandTarget(sub: string | undefined, ftownDir: string): string;
|
|
7
|
-
/** Multi-line usage text listing every routed subcommand. */
|
|
2
|
+
export { isCliEntry } from './cli-entry.js';
|
|
8
3
|
export declare function usage(): string;
|
|
4
|
+
export declare function runFtown(argv: string[]): Promise<number>;
|
package/dist/ftown-cli.js
CHANGED
|
@@ -1,91 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* is forwarded verbatim to its dedicated launcher with stdio inherited, and the
|
|
9
|
-
* child's exit code is propagated unchanged.
|
|
10
|
-
*/
|
|
11
|
-
import { execFileSync } from 'node:child_process';
|
|
12
|
-
import { homedir } from 'node:os';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
import { pathToFileURL } from 'node:url';
|
|
15
|
-
const FTOWN_DIR = join(homedir(), '.ftown');
|
|
16
|
-
/** Subcommand -> sibling launcher path (relative to a given ftownDir). */
|
|
17
|
-
const SUBCOMMANDS = ['env', 'sessions', 'workflows', 'harness'];
|
|
18
|
-
function isSubcommand(sub) {
|
|
19
|
-
return SUBCOMMANDS.includes(sub);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Resolve a subcommand to its absolute sibling launcher path under `ftownDir`.
|
|
23
|
-
* Throws a clear Error (listing the valid subcommands) on undefined/unknown.
|
|
24
|
-
*/
|
|
25
|
-
export function resolveSubcommandTarget(sub, ftownDir) {
|
|
26
|
-
if (sub === undefined || !isSubcommand(sub)) {
|
|
27
|
-
const got = sub === undefined ? '(none)' : `"${sub}"`;
|
|
28
|
-
throw new Error(`Unknown subcommand ${got} — use one of: ${SUBCOMMANDS.join(', ')}`);
|
|
29
|
-
}
|
|
30
|
-
switch (sub) {
|
|
31
|
-
case 'env':
|
|
32
|
-
return join(ftownDir, 'ftown-env');
|
|
33
|
-
case 'sessions':
|
|
34
|
-
return join(ftownDir, 'ftown-sessions');
|
|
35
|
-
case 'workflows':
|
|
36
|
-
return join(ftownDir, 'ftown-workflows');
|
|
37
|
-
case 'harness':
|
|
38
|
-
return join(ftownDir, 'bin', 'ftown-harness');
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/** Multi-line usage text listing every routed subcommand. */
|
|
2
|
+
import { runSessions } from './sessions-commands.js';
|
|
3
|
+
import { runHarness } from './harness-commands.js';
|
|
4
|
+
import { runEnv } from './env-commands.js';
|
|
5
|
+
import { runSetup } from './setup.js';
|
|
6
|
+
import { executeCli, isCliEntry } from './cli-entry.js';
|
|
7
|
+
export { isCliEntry } from './cli-entry.js';
|
|
42
8
|
export function usage() {
|
|
43
|
-
return `Usage: ftown <
|
|
9
|
+
return `Usage: ftown <setup|sessions|harness|env> [args...]
|
|
44
10
|
|
|
45
11
|
Subcommands:
|
|
46
|
-
|
|
12
|
+
setup Install or upgrade local CLI, hooks, plugins and skill (--repair to recheck)
|
|
47
13
|
sessions List, create, read and drive ftown agent sessions
|
|
48
|
-
|
|
49
|
-
|
|
14
|
+
harness Inspect and drive the local ftown-bridge harness
|
|
15
|
+
env Manage per-provider machine tokens (~/.ftown/env.json)`;
|
|
50
16
|
}
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const rest = argv.slice(1);
|
|
55
|
-
if (sub === undefined || sub === '--help' || sub === '-h' || sub === 'help') {
|
|
17
|
+
export async function runFtown(argv) {
|
|
18
|
+
const [group, ...args] = argv;
|
|
19
|
+
if (!group || ['--help', '-h', 'help'].includes(group)) {
|
|
56
20
|
console.log(usage());
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
let target;
|
|
60
|
-
try {
|
|
61
|
-
target = resolveSubcommandTarget(sub, FTOWN_DIR);
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
65
|
-
console.error(`ftown: ${msg}`);
|
|
66
|
-
console.error(usage());
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
execFileSync(target, rest, { stdio: 'inherit' });
|
|
21
|
+
return 0;
|
|
71
22
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.error(`ftown ${sub}: ${msg}`);
|
|
82
|
-
process.exit(1);
|
|
23
|
+
switch (group) {
|
|
24
|
+
case 'sessions': return runSessions(args);
|
|
25
|
+
case 'harness': return runHarness(args);
|
|
26
|
+
case 'env': return runEnv(args);
|
|
27
|
+
case 'setup': return runSetup(args);
|
|
28
|
+
default:
|
|
29
|
+
console.error(`ftown: Unknown subcommand "${group}"`);
|
|
30
|
+
console.error(usage());
|
|
31
|
+
return 1;
|
|
83
32
|
}
|
|
84
33
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const entry = process.argv[1];
|
|
88
|
-
if (entry && import.meta.url === pathToFileURL(entry).href) {
|
|
89
|
-
main();
|
|
34
|
+
if (isCliEntry(import.meta.url, process.argv[1])) {
|
|
35
|
+
void executeCli(() => runFtown(process.argv.slice(2)));
|
|
90
36
|
}
|
|
91
37
|
//# sourceMappingURL=ftown-cli.js.map
|
package/dist/ftown-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ftown-cli.js","sourceRoot":"","sources":["../src/ftown-cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"ftown-cli.js","sourceRoot":"","sources":["../src/ftown-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,UAAU,KAAK;IACnB,OAAO;;;;;;oEAM2D,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc;IAC3C,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IAC3F,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,SAAS,CAAC,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC;YAAS,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,GAAG,CAAC,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAAC,OAAO,CAAC,CAAC;IACnG,CAAC;AACH,CAAC;AAED,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/ftown-env-cli.d.ts
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
/** Resolve a provider flavor to its source env-var KEY. Throws on unknown. */
|
|
5
|
-
export declare function resolveProviderSource(provider: string): string;
|
|
6
|
-
/**
|
|
7
|
-
* Resolve the token for `set` without exposing it on argv.
|
|
8
|
-
*
|
|
9
|
-
* When `positional` is a real value (defined and not the "-" stdin sentinel) it
|
|
10
|
-
* is used verbatim (trimmed) and `onArgvToken` is invoked so the caller can warn
|
|
11
|
-
* that an argv token leaks into `ps`/shell history. Otherwise the token is read
|
|
12
|
-
* from stdin via `readStdin` (piped, keeping it out of `ps` output and shell
|
|
13
|
-
* history). Throws a clear error when no non-empty token is found.
|
|
14
|
-
*/
|
|
15
|
-
export declare function resolveSetToken(positional: string | undefined, readStdin: () => Promise<string>, onArgvToken?: () => void): Promise<string>;
|
|
16
|
-
export type DoctorStatus = 'env.json' | 'process-env' | 'missing';
|
|
17
|
-
export interface DoctorFlavorEntry {
|
|
18
|
-
flavor: string;
|
|
19
|
-
source: string;
|
|
20
|
-
status: DoctorStatus;
|
|
21
|
-
}
|
|
22
|
-
export interface DoctorReport {
|
|
23
|
-
flavors: DoctorFlavorEntry[];
|
|
24
|
-
blocked: string[];
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Classify each flavor's token: stored in env.json wins over the process env;
|
|
28
|
-
* a flavor absent from BOTH is "missing" and listed under `blocked`.
|
|
29
|
-
*/
|
|
30
|
-
export declare function buildDoctorReport(store: Record<string, string>, processEnv: Record<string, string | undefined>): DoctorReport;
|
|
31
|
-
/** Dispatch a single command. Throws on bad input; main() maps that to exit 1. */
|
|
32
|
-
export declare function run(argv: string[]): Promise<void>;
|
|
2
|
+
export { isCliEntry } from './cli-entry.js';
|
|
3
|
+
export * from './env-commands.js';
|
package/dist/ftown-env-cli.js
CHANGED
|
@@ -1,179 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
import { pathToFileURL } from 'node:url';
|
|
11
|
-
import { PROVIDER_AUTH_ENV, PROVIDER_FLAVORS, listProviderEnv, removeProviderToken, setProviderToken, } from './provider-env-store.js';
|
|
12
|
-
/** Mask all but the last 4 chars; tokens of length <=4 are fully masked. */
|
|
13
|
-
export function maskToken(value) {
|
|
14
|
-
if (value.length <= 4)
|
|
15
|
-
return '****';
|
|
16
|
-
return `****${value.slice(-4)}`;
|
|
17
|
-
}
|
|
18
|
-
/** Resolve a provider flavor to its source env-var KEY. Throws on unknown. */
|
|
19
|
-
export function resolveProviderSource(provider) {
|
|
20
|
-
const mapping = PROVIDER_AUTH_ENV[provider];
|
|
21
|
-
if (!mapping) {
|
|
22
|
-
throw new Error(`Unknown provider "${provider}" — use one of: ${PROVIDER_FLAVORS.join(', ')}`);
|
|
23
|
-
}
|
|
24
|
-
return mapping.source;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Resolve the token for `set` without exposing it on argv.
|
|
28
|
-
*
|
|
29
|
-
* When `positional` is a real value (defined and not the "-" stdin sentinel) it
|
|
30
|
-
* is used verbatim (trimmed) and `onArgvToken` is invoked so the caller can warn
|
|
31
|
-
* that an argv token leaks into `ps`/shell history. Otherwise the token is read
|
|
32
|
-
* from stdin via `readStdin` (piped, keeping it out of `ps` output and shell
|
|
33
|
-
* history). Throws a clear error when no non-empty token is found.
|
|
34
|
-
*/
|
|
35
|
-
export async function resolveSetToken(positional, readStdin, onArgvToken) {
|
|
36
|
-
const fromArgv = positional !== undefined && positional !== '-';
|
|
37
|
-
if (fromArgv)
|
|
38
|
-
onArgvToken?.();
|
|
39
|
-
const raw = fromArgv ? positional : await readStdin();
|
|
40
|
-
const token = (raw ?? '').trim();
|
|
41
|
-
if (!token) {
|
|
42
|
-
throw new Error('No token provided — pass it as an argument or pipe it via stdin ' +
|
|
43
|
-
'(e.g. `printf %s "$TOKEN" | ftown env set <provider> -`)');
|
|
44
|
-
}
|
|
45
|
-
return token;
|
|
46
|
-
}
|
|
47
|
-
/** Read all of process.stdin to end, decoded as UTF-8 (trimming is the caller's job). */
|
|
48
|
-
async function readStdin() {
|
|
49
|
-
const chunks = [];
|
|
50
|
-
for await (const chunk of process.stdin) {
|
|
51
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
52
|
-
}
|
|
53
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Classify each flavor's token: stored in env.json wins over the process env;
|
|
57
|
-
* a flavor absent from BOTH is "missing" and listed under `blocked`.
|
|
58
|
-
*/
|
|
59
|
-
export function buildDoctorReport(store, processEnv) {
|
|
60
|
-
const flavors = PROVIDER_FLAVORS.map((flavor) => {
|
|
61
|
-
const source = PROVIDER_AUTH_ENV[flavor].source;
|
|
62
|
-
let status;
|
|
63
|
-
if (store[source])
|
|
64
|
-
status = 'env.json';
|
|
65
|
-
else if (processEnv[source])
|
|
66
|
-
status = 'process-env';
|
|
67
|
-
else
|
|
68
|
-
status = 'missing';
|
|
69
|
-
return { flavor, source, status };
|
|
70
|
-
});
|
|
71
|
-
const blocked = flavors.filter((f) => f.status === 'missing').map((f) => f.flavor);
|
|
72
|
-
return { flavors, blocked };
|
|
73
|
-
}
|
|
74
|
-
/** Positional args, skipping flags and the values of value-taking flags. */
|
|
75
|
-
function positionals(args, valueFlags) {
|
|
76
|
-
const out = [];
|
|
77
|
-
for (let i = 0; i < args.length; i++) {
|
|
78
|
-
const a = args[i];
|
|
79
|
-
if (a.startsWith('--')) {
|
|
80
|
-
if (valueFlags.includes(a))
|
|
81
|
-
i++;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
out.push(a);
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
88
|
-
function usage() {
|
|
89
|
-
console.error(`Usage: ftown env <command> [options]
|
|
90
|
-
|
|
91
|
-
Commands:
|
|
92
|
-
set <provider> [token] Store a machine token for a provider
|
|
93
|
-
ls List configured provider tokens (masked)
|
|
94
|
-
rm <provider> Remove a stored provider token
|
|
95
|
-
doctor Report which providers are configured / blocked
|
|
96
|
-
|
|
97
|
-
Providers: ${PROVIDER_FLAVORS.join(' | ')}
|
|
98
|
-
|
|
99
|
-
Recommended (keeps the token out of \`ps\` and shell history): omit the token
|
|
100
|
-
positional and read it from stdin —
|
|
101
|
-
ftown env set zai then paste the token and press Ctrl-D
|
|
102
|
-
printf %s "$TOKEN" | ftown env set zai - pipe it (the "-" forces stdin)
|
|
103
|
-
|
|
104
|
-
Tokens live in ~/.ftown/env.json (mode 0o600). Values are always masked on output.`);
|
|
105
|
-
}
|
|
106
|
-
/** Dispatch a single command. Throws on bad input; main() maps that to exit 1. */
|
|
107
|
-
export async function run(argv) {
|
|
108
|
-
const cmd = argv[0];
|
|
109
|
-
const rest = argv.slice(1);
|
|
110
|
-
switch (cmd) {
|
|
111
|
-
case 'set': {
|
|
112
|
-
const positional = positionals(rest, []);
|
|
113
|
-
const provider = positional[0];
|
|
114
|
-
if (!provider) {
|
|
115
|
-
throw new Error('Usage: ftown env set <provider> [token] (omit the token to read it from stdin)');
|
|
116
|
-
}
|
|
117
|
-
const source = resolveProviderSource(provider);
|
|
118
|
-
const token = await resolveSetToken(positional[1], readStdin, () => console.error('ftown-env: warning: the token was passed as an argument, which exposes it to ' +
|
|
119
|
-
'`ps` and shell history. Prefer stdin: `printf %s "$TOKEN" | ftown env set <provider> -`.'));
|
|
120
|
-
setProviderToken(source, token);
|
|
121
|
-
console.log(`set ${source} (${maskToken(token)}) for ${provider}`);
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
case 'ls': {
|
|
125
|
-
const store = listProviderEnv();
|
|
126
|
-
const keys = Object.keys(store);
|
|
127
|
-
if (keys.length === 0) {
|
|
128
|
-
console.log('(no provider tokens configured)');
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
for (const key of keys)
|
|
132
|
-
console.log(`${key} ${maskToken(store[key])}`);
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
case 'rm': {
|
|
136
|
-
const positional = positionals(rest, []);
|
|
137
|
-
const provider = positional[0];
|
|
138
|
-
if (!provider)
|
|
139
|
-
throw new Error('Usage: ftown env rm <provider>');
|
|
140
|
-
const source = resolveProviderSource(provider);
|
|
141
|
-
const existed = removeProviderToken(source);
|
|
142
|
-
console.log(existed ? `removed ${source} for ${provider}` : `${source} (${provider}) was not set`);
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
case 'doctor': {
|
|
146
|
-
const report = buildDoctorReport(listProviderEnv(), process.env);
|
|
147
|
-
for (const f of report.flavors) {
|
|
148
|
-
console.log(`${f.flavor.padEnd(9)} ${f.source.padEnd(20)} ${f.status}`);
|
|
149
|
-
}
|
|
150
|
-
console.log(`blocked: ${report.blocked.length ? report.blocked.join(', ') : '(none)'}`);
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
default:
|
|
154
|
-
usage();
|
|
155
|
-
throw new Error(cmd ? `Unknown command "${cmd}"` : 'No command given');
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
async function main() {
|
|
159
|
-
const argv = process.argv.slice(2);
|
|
160
|
-
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
161
|
-
usage();
|
|
162
|
-
process.exit(argv.length === 0 ? 1 : 0);
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
await run(argv);
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
169
|
-
console.error(`ftown-env: ${msg}`);
|
|
170
|
-
process.exit(1);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Only run as a script (installed CLI / `node dist/ftown-env-cli.js`), never on
|
|
174
|
-
// import — tests import the exported helpers without triggering the dispatcher.
|
|
175
|
-
const entry = process.argv[1];
|
|
176
|
-
if (entry && import.meta.url === pathToFileURL(entry).href) {
|
|
177
|
-
void main();
|
|
2
|
+
// Compatibility entrypoint; canonical dispatch and implementation are shared.
|
|
3
|
+
import { runFtown } from './ftown-cli.js';
|
|
4
|
+
import { executeCli, isCliEntry } from './cli-entry.js';
|
|
5
|
+
export { isCliEntry } from './cli-entry.js';
|
|
6
|
+
export * from './env-commands.js';
|
|
7
|
+
if (isCliEntry(import.meta.url, process.argv[1])) {
|
|
8
|
+
void executeCli(() => runFtown(['env', ...process.argv.slice(2)]));
|
|
178
9
|
}
|
|
179
10
|
//# sourceMappingURL=ftown-env-cli.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ftown-env-cli.js","sourceRoot":"","sources":["../src/ftown-env-cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"ftown-env-cli.js","sourceRoot":"","sources":["../src/ftown-env-cli.ts"],"names":[],"mappings":";AACA,8EAA8E;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
package/dist/ftown-home.d.ts
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default data dir is ~/.ftown/data (machine-stable, like the rest of ~/.ftown).
|
|
3
|
-
* Older bridges defaulted to ./data relative to the launch cwd — if that legacy
|
|
4
|
-
* dir holds sessions and the new default does not exist yet, migrate it once so
|
|
5
|
-
* an upgraded bridge still resurrects its sessions.
|
|
6
|
-
*/
|
|
1
|
+
/** Resolve the default without migrating data or touching global state. */
|
|
7
2
|
export declare function resolveDefaultDataDir(): string;
|
|
8
|
-
|
|
3
|
+
/** Explicit setup-only migration of the historical cwd-relative data directory. */
|
|
4
|
+
export declare function migrateLegacyDataDir(): void;
|
|
9
5
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* Resolve the ".ftown home" — the directory that holds THIS bridge instance's
|
|
7
|
+
* pointer and registry files: bridge.json,
|
|
8
|
+
* session-registry.json.
|
|
9
|
+
*
|
|
10
|
+
* Why this indirection exists:
|
|
11
|
+
* - The DEFAULT install keeps $HOME/.ftown. The harness CLIs
|
|
12
|
+
* (harness-cli.ts / ftown-sessions-cli.ts, and their
|
|
13
|
+
* deployed sibling copies) hardcode `join(homedir(), '.ftown', 'bridge.json')`
|
|
14
|
+
* to find the primary bridge, so the default MUST stay byte-for-byte at
|
|
15
|
+
* $HOME/.ftown or those CLIs break.
|
|
16
|
+
* - A NON-default `--data-dir` (a Solo test, Docker, or a second co-resident
|
|
17
|
+
* bridge) owns its OWN instance files under that dir. It must never write or
|
|
18
|
+
* delete the primary bridge's pointer/registry state under $HOME/.ftown — a
|
|
19
|
+
* co-resident primary bridge relies on those files.
|
|
20
|
+
*
|
|
21
|
+
* Semantics: if `dataDir` resolves to the default data dir, return
|
|
22
|
+
* `$HOME/.ftown`; otherwise the custom data dir is its own instance home.
|
|
23
|
+
*
|
|
24
|
+
* `defaultDataDir` can pass the already-resolved default. Resolution is read-only.
|
|
13
25
|
*/
|
|
26
|
+
export declare function resolveFtownHome(dataDir: string, defaultDataDir?: string): string;
|
|
27
|
+
/** Compatibility helper for tests; default resolution no longer caches HOME. */
|
|
14
28
|
export declare function resetFtownHomeForTests(): void;
|