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.
Files changed (116) hide show
  1. package/dist/cli-client.d.ts +17 -0
  2. package/dist/cli-client.js +76 -0
  3. package/dist/cli-client.js.map +1 -0
  4. package/dist/cli-entry.d.ts +2 -0
  5. package/dist/cli-entry.js +22 -0
  6. package/dist/cli-entry.js.map +1 -0
  7. package/dist/codex-installer.d.ts +1 -1
  8. package/dist/codex-installer.js +7 -6
  9. package/dist/codex-installer.js.map +1 -1
  10. package/dist/command-rpc.js +0 -1
  11. package/dist/command-rpc.js.map +1 -1
  12. package/dist/create-ftown-session.d.ts +1 -6
  13. package/dist/create-ftown-session.js +3 -25
  14. package/dist/create-ftown-session.js.map +1 -1
  15. package/dist/cursor-hook-installer.d.ts +1 -1
  16. package/dist/cursor-hook-installer.js +6 -5
  17. package/dist/cursor-hook-installer.js.map +1 -1
  18. package/dist/ensure-ftown-path.js +1 -1
  19. package/dist/env-commands.d.ts +32 -0
  20. package/dist/env-commands.js +162 -0
  21. package/dist/env-commands.js.map +1 -0
  22. package/dist/ftown-cli.d.ts +2 -6
  23. package/dist/ftown-cli.js +25 -79
  24. package/dist/ftown-cli.js.map +1 -1
  25. package/dist/ftown-env-cli.d.ts +2 -31
  26. package/dist/ftown-env-cli.js +7 -176
  27. package/dist/ftown-env-cli.js.map +1 -1
  28. package/dist/ftown-home.d.ts +24 -10
  29. package/dist/ftown-home.js +19 -41
  30. package/dist/ftown-home.js.map +1 -1
  31. package/dist/ftown-sessions-cli.d.ts +1 -1
  32. package/dist/ftown-sessions-cli.js +6 -499
  33. package/dist/ftown-sessions-cli.js.map +1 -1
  34. package/dist/harness-cli.d.ts +1 -1
  35. package/dist/harness-cli.js +6 -626
  36. package/dist/harness-cli.js.map +1 -1
  37. package/dist/harness-commands.d.ts +2 -0
  38. package/dist/harness-commands.js +576 -0
  39. package/dist/harness-commands.js.map +1 -0
  40. package/dist/harness-installer.d.ts +1 -10
  41. package/dist/harness-installer.js +13 -166
  42. package/dist/harness-installer.js.map +1 -1
  43. package/dist/harness-registry.d.ts +1 -27
  44. package/dist/harness-registry.js +1 -20
  45. package/dist/harness-registry.js.map +1 -1
  46. package/dist/hook-installer.d.ts +1 -1
  47. package/dist/hook-installer.js +5 -4
  48. package/dist/hook-installer.js.map +1 -1
  49. package/dist/index.js +10 -108
  50. package/dist/index.js.map +1 -1
  51. package/dist/install-ftown-command-cli.d.ts +3 -3
  52. package/dist/install-ftown-command-cli.js +67 -22
  53. package/dist/install-ftown-command-cli.js.map +1 -1
  54. package/dist/install-ftown-skill.d.ts +6 -0
  55. package/dist/install-ftown-skill.js +111 -10
  56. package/dist/install-ftown-skill.js.map +1 -1
  57. package/dist/install-notify-script.d.ts +1 -1
  58. package/dist/install-notify-script.js +7 -6
  59. package/dist/install-notify-script.js.map +1 -1
  60. package/dist/mail-delivery.d.ts +1 -1
  61. package/dist/mail-delivery.js +3 -5
  62. package/dist/mail-delivery.js.map +1 -1
  63. package/dist/mcp/server.js +1 -1
  64. package/dist/mcp/server.js.map +1 -1
  65. package/dist/muse-plugin-installer.js +4 -0
  66. package/dist/muse-plugin-installer.js.map +1 -1
  67. package/dist/opencode-plugin-installer.d.ts +1 -2
  68. package/dist/opencode-plugin-installer.js +1 -2
  69. package/dist/opencode-plugin-installer.js.map +1 -1
  70. package/dist/provider-env-store.js +1 -1
  71. package/dist/provider-env-store.js.map +1 -1
  72. package/dist/retired-skill-assets.d.ts +3 -0
  73. package/dist/retired-skill-assets.js +11 -0
  74. package/dist/retired-skill-assets.js.map +1 -1
  75. package/dist/sessions-commands.d.ts +2 -0
  76. package/dist/sessions-commands.js +445 -0
  77. package/dist/sessions-commands.js.map +1 -0
  78. package/dist/setup-migrations.d.ts +6 -0
  79. package/dist/setup-migrations.js +28 -0
  80. package/dist/setup-migrations.js.map +1 -0
  81. package/dist/setup-state.d.ts +16 -0
  82. package/dist/setup-state.js +163 -0
  83. package/dist/setup-state.js.map +1 -0
  84. package/dist/setup.d.ts +25 -0
  85. package/dist/setup.js +120 -0
  86. package/dist/setup.js.map +1 -0
  87. package/dist/types.d.ts +1 -0
  88. package/dist/wire-types.js +1 -8
  89. package/dist/wire-types.js.map +1 -1
  90. package/package.json +2 -3
  91. package/pi-extension/API.md +4 -0
  92. package/pi-extension/ftown.js +1 -2
  93. package/skills/ftown/SKILL.md +71 -19
  94. package/skills/ftown/references/orchestrator.md +23 -99
  95. package/skills/ftown/references/sessions.md +37 -42
  96. package/dist/claude-trust.d.ts +0 -11
  97. package/dist/claude-trust.js +0 -47
  98. package/dist/claude-trust.js.map +0 -1
  99. package/dist/install-ftown-cli.d.ts +0 -3
  100. package/dist/install-ftown-cli.js +0 -29
  101. package/dist/install-ftown-cli.js.map +0 -1
  102. package/dist/install-ftown-env-cli.d.ts +0 -3
  103. package/dist/install-ftown-env-cli.js +0 -30
  104. package/dist/install-ftown-env-cli.js.map +0 -1
  105. package/dist/install-ftown-workflows-cli.d.ts +0 -3
  106. package/dist/install-ftown-workflows-cli.js +0 -33
  107. package/dist/install-ftown-workflows-cli.js.map +0 -1
  108. package/dist/workflow-runner-cli.d.ts +0 -2
  109. package/dist/workflow-runner-cli.js +0 -376
  110. package/dist/workflow-runner-cli.js.map +0 -1
  111. package/dist/workflow-runner.d.ts +0 -163
  112. package/dist/workflow-runner.js +0 -307
  113. package/dist/workflow-runner.js.map +0 -1
  114. package/skills/fticket/SKILL.md +0 -166
  115. package/skills/ftown/references/workflows.md +0 -470
  116. 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":"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"}
@@ -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
- * `ftown` — top-level dispatcher that routes subcommands to the sibling
4
- * launchers installed by ftown-bridge under ~/.ftown.
5
- *
6
- * Installed to ~/.ftown/ftown by ftown-bridge. Imports ONLY node builtins, so
7
- * no extra sibling copy is needed alongside the compiled CLI. Each subcommand
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 <env|sessions|workflows|harness> [args...]
9
+ return `Usage: ftown <setup|sessions|harness|env> [args...]
44
10
 
45
11
  Subcommands:
46
- env Manage per-provider machine tokens (~/.ftown/env.json)
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
- workflows Run deterministic, resumable multi-session workflows
49
- harness Inspect and drive the local ftown-bridge harness`;
14
+ harness Inspect and drive the local ftown-bridge harness
15
+ env Manage per-provider machine tokens (~/.ftown/env.json)`;
50
16
  }
51
- function main() {
52
- const argv = process.argv.slice(2);
53
- const sub = argv[0];
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
- process.exit(0);
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
- catch (err) {
73
- const e = err;
74
- if (typeof e.status === 'number')
75
- process.exit(e.status);
76
- if (e.code === 'ENOENT') {
77
- console.error(`ftown ${sub}: not installed (restart the bridge)`);
78
- process.exit(1);
79
- }
80
- const msg = err instanceof Error ? err.message : String(err);
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
- // Only run as a script (installed CLI / `node dist/ftown-cli.js`), never on
86
- // import — tests import the exported helpers without triggering the dispatcher.
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
@@ -1 +1 @@
1
- {"version":3,"file":"ftown-cli.js","sourceRoot":"","sources":["../src/ftown-cli.ts"],"names":[],"mappings":"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"}
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"}
@@ -1,32 +1,3 @@
1
1
  #!/usr/bin/env node
2
- /** Mask all but the last 4 chars; tokens of length <=4 are fully masked. */
3
- export declare function maskToken(value: string): string;
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';
@@ -1,179 +1,10 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * `ftown env` — manage per-provider machine tokens in ~/.ftown/env.json.
4
- *
5
- * Installed to ~/.ftown/ftown-env by ftown-bridge (alongside a sibling copy of
6
- * provider-env-store.js). Imports ONLY ./provider-env-store.js (plus node
7
- * builtins) so a single sibling copy makes the installed CLI self-sufficient.
8
- * Every token value is masked before it touches stdout — raw secrets never print.
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":"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"}
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"}
@@ -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
- export declare function resolveFtownHome(dataDir: string, defaultDataDir?: string): string;
3
+ /** Explicit setup-only migration of the historical cwd-relative data directory. */
4
+ export declare function migrateLegacyDataDir(): void;
9
5
  /**
10
- * Test-only: clear the memoized default data dir so a $HOME override in a later
11
- * test is honored instead of a value cached from an earlier one. Never call this
12
- * in production — index.ts always passes an explicit `defaultDataDir`.
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;