@staff0rd/assist 0.207.0 → 0.208.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,6 +56,7 @@ After installation, the `assist` command will be available globally. You can als
56
56
  - `/screenshot` - Capture a screenshot of a running application window
57
57
  - `/raven` - Query and manage RavenDB connections and collections
58
58
  - `/seq` - Query Seq logs from a URL or filter expression
59
+ - `/sql` - Query a MSSQL database via assist sql
59
60
  - `/verify` - Run all verification commands in parallel
60
61
  - `/transcript-format` - Format meeting transcripts from VTT files
61
62
  - `/transcript-summarise` - Summarise transcripts missing summaries
@@ -175,6 +176,14 @@ After installation, the `assist` command will be available globally. You can als
175
176
  - `assist seq query <filter> -n <count>` - Fetch a specific number of events (default 50)
176
177
  - `assist seq query <filter> --from <date>` - Start of query window (UTC date or relative e.g. 5m, 1h, 2d)
177
178
  - `assist seq query <filter> --to <date>` - End of query window (UTC date or relative e.g. 5m, 1h, 2d)
179
+ - `assist sql auth add` - Add a new MSSQL connection (prompts for name, server, port, user, password, database)
180
+ - `assist sql auth list` - List configured SQL connections
181
+ - `assist sql auth remove <name>` - Remove a configured connection
182
+ - `assist sql set-connection <name>` - Set the default SQL connection
183
+ - `assist sql query "<sql>" [connection]` - Execute a read-only SQL statement and print results in table format (rejects INSERT/UPDATE/DELETE/DROP/CREATE/ALTER/TRUNCATE/MERGE/GRANT/REVOKE/EXEC)
184
+ - `assist sql mutate "<sql>" [connection]` - Execute a mutating SQL statement (not yet implemented)
185
+ - `assist sql tables [connection]` - List tables in the connected database (via INFORMATION_SCHEMA.TABLES)
186
+ - `assist sql columns <table> [connection]` - List columns for a table (use `schema.table` for non-default schema; via INFORMATION_SCHEMA.COLUMNS)
178
187
  - `assist screenshot <process>` - Capture a screenshot of a running application window (e.g. `assist screenshot notepad`). Output directory is configurable via `screenshot.outputDir` (default `./screenshots`)
179
188
  - `assist mermaid export [file.md]` - Render each fenced mermaid block to `<stem>-<index>.svg` via [Kroki](https://kroki.io). With no file, scans `*.md` in the current directory (non-recursive). Use `--out <dir>` to override the output directory. Use `--index <n>` to render only the nth mermaid block (1-based; requires a file argument). Endpoint is configurable via `mermaid.krokiUrl` (default `https://kroki.io`).
180
189
  - `assist prompts` - Show top 10 denied tool calls by frequency with count and repo breakdown
package/allowed.cli-reads CHANGED
@@ -41,6 +41,10 @@ assist roam show-claude-code-icon
41
41
  assist screenshot
42
42
  assist seq auth list
43
43
  assist seq query
44
+ assist sql auth list
45
+ assist sql columns
46
+ assist sql query
47
+ assist sql tables
44
48
  assist status-line
45
49
  assist verify
46
50
  assist voice
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: Query a MSSQL database via assist sql
3
+ ---
4
+
5
+ The user wants to query a MSSQL database. Use the `assist sql` CLI commands below.
6
+
7
+ ## Connection management
8
+
9
+ - `assist sql auth add` — interactively add a named connection (name, server, port, user, password, database)
10
+ - `assist sql auth list` — list configured connections
11
+ - `assist sql auth remove <name>` — remove a connection
12
+ - `assist sql set-connection <name>` — set the default connection
13
+
14
+ ## Schema introspection
15
+
16
+ - `assist sql tables [connection]` — list tables in the database
17
+ - `assist sql columns <table> [connection]` — list columns for a table (use `schema.table` for a non-default schema)
18
+
19
+ ## Querying
20
+
21
+ - `assist sql query "<sql>" [connection]` — execute a read-only SQL statement and print results in table format. Rejects mutating statements (INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE, MERGE, GRANT, REVOKE, EXEC)
22
+ - `assist sql mutate "<sql>" [connection]` — execute a mutating SQL statement (not yet implemented; will throw)
23
+
24
+ ## Workflow
25
+
26
+ 1. If no connections are configured, tell the user to run `assist sql auth add`. Do NOT attempt to add connections yourself.
27
+ 2. If the user doesn't specify a connection, omit it to use the default.
28
+ 3. Prefer `tables` and `columns` for schema discovery before crafting queries.
29
+ 4. Quote SQL strings carefully — wrap the statement in double quotes and escape inner double quotes if needed.
30
+ 5. Use `query` for SELECTs only. If the user asks for a mutation, tell them `assist sql mutate` is not yet implemented rather than working around the guard.
31
+ 6. Display query results to the user. If the output is large, summarise key rows and highlight anything notable.
32
+ 7. If the user asks follow-up questions, refine the query and re-run.
@@ -1,5 +1,4 @@
1
1
  {
2
- "autoUpdatesChannel": "stable",
3
2
  "statusLine": {
4
3
  "type": "command",
5
4
  "command": "assist status-line"
@@ -56,6 +55,7 @@
56
55
  "SlashCommand(/jira)",
57
56
  "Skill(seq)",
58
57
  "SlashCommand(/seq)",
58
+ "SlashCommand(/sql)",
59
59
  "Skill(inspect)",
60
60
  "SlashCommand(/inspect)",
61
61
  "Skill(prompts)",
@@ -41,6 +41,10 @@ assist roam show-claude-code-icon
41
41
  assist screenshot
42
42
  assist seq auth list
43
43
  assist seq query
44
+ assist sql auth list
45
+ assist sql columns
46
+ assist sql query
47
+ assist sql tables
44
48
  assist status-line
45
49
  assist verify
46
50
  assist voice
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.207.0",
9
+ version: "0.208.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -48,6 +48,7 @@ var package_default = {
48
48
  entities: "^7.0.1",
49
49
  "is-wsl": "^3.1.0",
50
50
  minimatch: "^10.1.1",
51
+ mssql: "^12.5.0",
51
52
  "node-notifier": "^10.0.1",
52
53
  "node-pty": "^1.1.0",
53
54
  semver: "^7.7.3",
@@ -69,6 +70,7 @@ var package_default = {
69
70
  "@semantic-release/git": "^10.0.1",
70
71
  "@types/better-sqlite3": "^7.6.13",
71
72
  "@types/blessed": "^0.1.27",
73
+ "@types/mssql": "^12.3.0",
72
74
  "@types/node": "^24.10.1",
73
75
  "@types/node-notifier": "^8.0.5",
74
76
  "@types/react": "^19.2.14",
@@ -1787,6 +1789,19 @@ var assistConfigSchema = z3.strictObject({
1787
1789
  ).default([]),
1788
1790
  defaultConnection: z3.string().optional()
1789
1791
  }).optional(),
1792
+ sql: z3.strictObject({
1793
+ connections: z3.array(
1794
+ z3.strictObject({
1795
+ name: z3.string(),
1796
+ server: z3.string(),
1797
+ port: z3.number(),
1798
+ user: z3.string(),
1799
+ password: z3.string(),
1800
+ database: z3.string()
1801
+ })
1802
+ ).default([]),
1803
+ defaultConnection: z3.string().optional()
1804
+ }).optional(),
1790
1805
  screenshot: z3.strictObject({
1791
1806
  outputDir: z3.string().default("./screenshots")
1792
1807
  }).default({ outputDir: "./screenshots" }),
@@ -11452,14 +11467,19 @@ function setDefaultConnection(name) {
11452
11467
  saveGlobalConfig(raw);
11453
11468
  }
11454
11469
 
11455
- // src/commands/seq/promptConnection.ts
11470
+ // src/shared/assertUniqueName.ts
11456
11471
  import chalk127 from "chalk";
11457
- async function promptConnection2(existingNames) {
11458
- const name = await promptInput("name", "Connection name:", "default");
11472
+ function assertUniqueName(existingNames, name) {
11459
11473
  if (existingNames.includes(name)) {
11460
11474
  console.error(chalk127.red(`Connection "${name}" already exists.`));
11461
11475
  process.exit(1);
11462
11476
  }
11477
+ }
11478
+
11479
+ // src/commands/seq/promptConnection.ts
11480
+ async function promptConnection2(existingNames) {
11481
+ const name = await promptInput("name", "Connection name:", "default");
11482
+ assertUniqueName(existingNames, name);
11463
11483
  const url = await promptInput("url", "Seq URL:", "http://localhost:5341");
11464
11484
  const apiToken = await promptPassword("apiToken", "API token:");
11465
11485
  return { name, url, apiToken };
@@ -11503,8 +11523,8 @@ function filterToSql(filter) {
11503
11523
  // src/commands/seq/fetchSeqData.ts
11504
11524
  async function fetchSeqData(conn, filter, count, from, to) {
11505
11525
  const sqlFilter = filterToSql(filter);
11506
- const sql = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count}`;
11507
- const params = new URLSearchParams({ q: sql });
11526
+ const sql2 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count}`;
11527
+ const params = new URLSearchParams({ q: sql2 });
11508
11528
  if (from) params.set("fromDateUtc", from);
11509
11529
  if (to) params.set("toDateUtc", to);
11510
11530
  const response = await fetchSeq(conn, "/api/data", params);
@@ -11638,25 +11658,37 @@ function rejectTimestampFilter(filter) {
11638
11658
  }
11639
11659
  }
11640
11660
 
11641
- // src/commands/seq/resolveConnection.ts
11661
+ // src/shared/resolveNamedConnection.ts
11642
11662
  import chalk131 from "chalk";
11643
- function resolveConnection2(name) {
11644
- const connections = loadConnections2();
11663
+ function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
11645
11664
  if (connections.length === 0) {
11646
11665
  console.error(
11647
- chalk131.red("No Seq connections configured. Run 'assist seq auth' first.")
11666
+ chalk131.red(
11667
+ `No ${kind} connections configured. Run '${authCommand}' first.`
11668
+ )
11648
11669
  );
11649
11670
  process.exit(1);
11650
11671
  }
11651
- const target = name ?? getDefaultConnection() ?? connections[0].name;
11672
+ const target = requested ?? defaultName ?? connections[0].name;
11652
11673
  const connection = connections.find((c) => c.name === target);
11653
11674
  if (!connection) {
11654
- console.error(chalk131.red(`Seq connection "${target}" not found.`));
11675
+ console.error(chalk131.red(`${kind} connection "${target}" not found.`));
11655
11676
  process.exit(1);
11656
11677
  }
11657
11678
  return connection;
11658
11679
  }
11659
11680
 
11681
+ // src/commands/seq/resolveConnection.ts
11682
+ function resolveConnection2(name) {
11683
+ return resolveNamedConnection(
11684
+ loadConnections2(),
11685
+ name,
11686
+ getDefaultConnection(),
11687
+ "Seq",
11688
+ "assist seq auth"
11689
+ );
11690
+ }
11691
+
11660
11692
  // src/commands/seq/seqQuery.ts
11661
11693
  async function seqQuery(filter, options2) {
11662
11694
  rejectTimestampFilter(filter);
@@ -11691,16 +11723,25 @@ ${events.length} events`));
11691
11723
  }
11692
11724
  }
11693
11725
 
11694
- // src/commands/seq/seqSetConnection.ts
11726
+ // src/shared/setNamedDefaultConnection.ts
11695
11727
  import chalk133 from "chalk";
11696
- function seqSetConnection(name) {
11697
- const connections = loadConnections2();
11728
+ function setNamedDefaultConnection(connections, name, setDefault, kind) {
11698
11729
  if (!connections.find((c) => c.name === name)) {
11699
11730
  console.error(chalk133.red(`Connection "${name}" not found.`));
11700
11731
  process.exit(1);
11701
11732
  }
11702
- setDefaultConnection(name);
11703
- console.log(`Default Seq connection set to "${name}".`);
11733
+ setDefault(name);
11734
+ console.log(`Default ${kind} connection set to "${name}".`);
11735
+ }
11736
+
11737
+ // src/commands/seq/seqSetConnection.ts
11738
+ function seqSetConnection(name) {
11739
+ setNamedDefaultConnection(
11740
+ loadConnections2(),
11741
+ name,
11742
+ setDefaultConnection,
11743
+ "Seq"
11744
+ );
11704
11745
  }
11705
11746
 
11706
11747
  // src/commands/registerSeq.ts
@@ -11720,6 +11761,257 @@ function registerSeq(program2) {
11720
11761
  ).option("--json", "Output raw JSON").action((filter, options2) => seqQuery(filter, options2));
11721
11762
  }
11722
11763
 
11764
+ // src/commands/sql/sqlAuth.ts
11765
+ import chalk135 from "chalk";
11766
+
11767
+ // src/commands/sql/loadConnections.ts
11768
+ function loadConnections3() {
11769
+ const raw = loadGlobalConfigRaw();
11770
+ const sql2 = raw.sql;
11771
+ return sql2?.connections ?? [];
11772
+ }
11773
+ function saveConnections3(connections) {
11774
+ const raw = loadGlobalConfigRaw();
11775
+ const sql2 = raw.sql ?? {};
11776
+ sql2.connections = connections;
11777
+ raw.sql = sql2;
11778
+ saveGlobalConfig(raw);
11779
+ }
11780
+ function getDefaultConnection2() {
11781
+ const raw = loadGlobalConfigRaw();
11782
+ const sql2 = raw.sql;
11783
+ return sql2?.defaultConnection;
11784
+ }
11785
+ function setDefaultConnection2(name) {
11786
+ const raw = loadGlobalConfigRaw();
11787
+ const sql2 = raw.sql ?? {};
11788
+ sql2.defaultConnection = name;
11789
+ raw.sql = sql2;
11790
+ saveGlobalConfig(raw);
11791
+ }
11792
+
11793
+ // src/commands/sql/promptConnection.ts
11794
+ import chalk134 from "chalk";
11795
+ async function promptConnection3(existingNames) {
11796
+ const name = await promptInput("name", "Connection name:", "default");
11797
+ assertUniqueName(existingNames, name);
11798
+ const server = await promptInput("server", "Server:", "localhost");
11799
+ const portStr = await promptInput("port", "Port:", "1433");
11800
+ const port = Number.parseInt(portStr, 10);
11801
+ if (!Number.isFinite(port)) {
11802
+ console.error(chalk134.red(`Invalid port "${portStr}".`));
11803
+ process.exit(1);
11804
+ }
11805
+ const user = await promptInput("user", "User:");
11806
+ const password = await promptPassword("password", "Password:");
11807
+ const database = await promptInput("database", "Database:");
11808
+ return { name, server, port, user, password, database };
11809
+ }
11810
+
11811
+ // src/commands/sql/sqlAuth.ts
11812
+ var sqlAuth = createConnectionAuth({
11813
+ load: loadConnections3,
11814
+ save: saveConnections3,
11815
+ format: (c) => `${chalk135.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
11816
+ promptNew: promptConnection3,
11817
+ onFirst: (c) => setDefaultConnection2(c.name)
11818
+ });
11819
+
11820
+ // src/commands/sql/printTable.ts
11821
+ import chalk136 from "chalk";
11822
+ function formatCell(value) {
11823
+ if (value === null || value === void 0) return "";
11824
+ if (value instanceof Date) return value.toISOString();
11825
+ if (typeof value === "object") return JSON.stringify(value);
11826
+ return String(value);
11827
+ }
11828
+ function printTable(rows) {
11829
+ if (rows.length === 0) {
11830
+ console.log(chalk136.yellow("(no rows)"));
11831
+ return;
11832
+ }
11833
+ const columns = Object.keys(rows[0]);
11834
+ const widths = columns.map(
11835
+ (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
11836
+ );
11837
+ const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
11838
+ console.log(chalk136.dim(header));
11839
+ console.log(chalk136.dim("-".repeat(header.length)));
11840
+ for (const row of rows) {
11841
+ const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
11842
+ console.log(line);
11843
+ }
11844
+ console.log(chalk136.dim(`
11845
+ ${rows.length} row${rows.length === 1 ? "" : "s"}`));
11846
+ }
11847
+
11848
+ // src/commands/sql/resolveConnection.ts
11849
+ function resolveConnection3(name) {
11850
+ return resolveNamedConnection(
11851
+ loadConnections3(),
11852
+ name,
11853
+ getDefaultConnection2(),
11854
+ "SQL",
11855
+ "assist sql auth add"
11856
+ );
11857
+ }
11858
+
11859
+ // src/commands/sql/sqlConnect.ts
11860
+ import sql from "mssql";
11861
+ async function sqlConnect(conn) {
11862
+ return await sql.connect({
11863
+ server: conn.server,
11864
+ port: conn.port,
11865
+ user: conn.user,
11866
+ password: conn.password,
11867
+ database: conn.database,
11868
+ options: {
11869
+ encrypt: false,
11870
+ trustServerCertificate: true
11871
+ }
11872
+ });
11873
+ }
11874
+
11875
+ // src/commands/sql/sqlColumns.ts
11876
+ async function sqlColumns(table, connectionName) {
11877
+ const conn = resolveConnection3(connectionName);
11878
+ const pool = await sqlConnect(conn);
11879
+ try {
11880
+ const parts = table.split(".");
11881
+ const schema = parts.length > 1 ? parts[0] : void 0;
11882
+ const name = parts.length > 1 ? parts[1] : parts[0];
11883
+ const request = pool.request().input("table", name);
11884
+ let where = "TABLE_NAME = @table";
11885
+ if (schema) {
11886
+ request.input("schema", schema);
11887
+ where += " AND TABLE_SCHEMA = @schema";
11888
+ }
11889
+ const result = await request.query(
11890
+ `SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION,
11891
+ DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE, COLUMN_DEFAULT
11892
+ FROM INFORMATION_SCHEMA.COLUMNS
11893
+ WHERE ${where}
11894
+ ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION`
11895
+ );
11896
+ const rows = result.recordset ?? [];
11897
+ printTable(rows);
11898
+ } finally {
11899
+ await pool.close();
11900
+ }
11901
+ }
11902
+
11903
+ // src/commands/sql/sqlMutate.ts
11904
+ async function sqlMutate(_query, _connectionName) {
11905
+ throw new Error("assist sql mutate is not yet implemented");
11906
+ }
11907
+
11908
+ // src/commands/sql/sqlQuery.ts
11909
+ import chalk137 from "chalk";
11910
+
11911
+ // src/commands/sql/isMutation.ts
11912
+ var MUTATION_KEYWORDS = [
11913
+ "INSERT",
11914
+ "UPDATE",
11915
+ "DELETE",
11916
+ "DROP",
11917
+ "CREATE",
11918
+ "ALTER",
11919
+ "TRUNCATE",
11920
+ "MERGE",
11921
+ "GRANT",
11922
+ "REVOKE",
11923
+ "EXEC",
11924
+ "EXECUTE"
11925
+ ];
11926
+ var MUTATION_PATTERN = new RegExp(
11927
+ `\\b(${MUTATION_KEYWORDS.join("|")})\\b`,
11928
+ "i"
11929
+ );
11930
+ function stripComments(sql2) {
11931
+ return sql2.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
11932
+ }
11933
+ function isMutation(sql2) {
11934
+ const stripped = stripComments(sql2);
11935
+ if (MUTATION_PATTERN.test(stripped)) return true;
11936
+ return /\bSELECT\b[\s\S]+\bINTO\s+\w/i.test(stripped);
11937
+ }
11938
+
11939
+ // src/commands/sql/sqlQuery.ts
11940
+ async function sqlQuery(query, connectionName) {
11941
+ if (isMutation(query)) {
11942
+ console.error(
11943
+ chalk137.red(
11944
+ "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
11945
+ )
11946
+ );
11947
+ process.exit(1);
11948
+ }
11949
+ const conn = resolveConnection3(connectionName);
11950
+ const pool = await sqlConnect(conn);
11951
+ try {
11952
+ const result = await pool.request().query(query);
11953
+ const rows = result.recordset ?? [];
11954
+ if (result.recordset) {
11955
+ printTable(rows);
11956
+ } else {
11957
+ console.log(
11958
+ chalk137.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
11959
+ );
11960
+ }
11961
+ } finally {
11962
+ await pool.close();
11963
+ }
11964
+ }
11965
+
11966
+ // src/commands/sql/sqlSetConnection.ts
11967
+ function sqlSetConnection(name) {
11968
+ setNamedDefaultConnection(
11969
+ loadConnections3(),
11970
+ name,
11971
+ setDefaultConnection2,
11972
+ "SQL"
11973
+ );
11974
+ }
11975
+
11976
+ // src/commands/sql/sqlTables.ts
11977
+ async function sqlTables(connectionName) {
11978
+ const conn = resolveConnection3(connectionName);
11979
+ const pool = await sqlConnect(conn);
11980
+ try {
11981
+ const result = await pool.request().query(
11982
+ `SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE
11983
+ FROM INFORMATION_SCHEMA.TABLES
11984
+ ORDER BY TABLE_SCHEMA, TABLE_NAME`
11985
+ );
11986
+ const rows = result.recordset ?? [];
11987
+ printTable(rows);
11988
+ } finally {
11989
+ await pool.close();
11990
+ }
11991
+ }
11992
+
11993
+ // src/commands/registerSql.ts
11994
+ function registerSql(program2) {
11995
+ const cmd = program2.command("sql").description("MSSQL query utilities");
11996
+ const auth2 = cmd.command("auth").description("Configure a SQL connection");
11997
+ auth2.command("add").description("Add a new connection").action(() => sqlAuth.add());
11998
+ auth2.command("list").description("List configured connections").action(() => sqlAuth.list());
11999
+ auth2.command("remove <name>").description("Remove a configured connection").action((name) => sqlAuth.remove(name));
12000
+ cmd.command("set-connection <name>").description("Set the default SQL connection").action((name) => sqlSetConnection(name));
12001
+ cmd.command("query <sql> [connection]").description("Execute a read-only SQL query (rejects mutating statements)").action(
12002
+ (query, connection) => sqlQuery(query, connection)
12003
+ );
12004
+ cmd.command("mutate <sql> [connection]").description("Execute a mutating SQL statement (not yet implemented)").action(
12005
+ (query, connection) => sqlMutate(query, connection)
12006
+ );
12007
+ cmd.command("tables [connection]").description("List tables in the connected database").action((connection) => sqlTables(connection));
12008
+ cmd.command("columns <table> [connection]").description(
12009
+ "List columns for a table (use schema.table for non-default schema)"
12010
+ ).action(
12011
+ (table, connection) => sqlColumns(table, connection)
12012
+ );
12013
+ }
12014
+
11723
12015
  // src/commands/transcript/shared.ts
11724
12016
  import { existsSync as existsSync32, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
11725
12017
  import { basename as basename8, join as join34, relative as relative2 } from "path";
@@ -12241,14 +12533,14 @@ import {
12241
12533
  import { dirname as dirname22, join as join38 } from "path";
12242
12534
 
12243
12535
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
12244
- import chalk134 from "chalk";
12536
+ import chalk138 from "chalk";
12245
12537
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
12246
12538
  function validateStagedContent(filename, content) {
12247
12539
  const firstLine = content.split("\n")[0];
12248
12540
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
12249
12541
  if (!match) {
12250
12542
  console.error(
12251
- chalk134.red(
12543
+ chalk138.red(
12252
12544
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
12253
12545
  )
12254
12546
  );
@@ -12257,7 +12549,7 @@ function validateStagedContent(filename, content) {
12257
12549
  const contentAfterLink = content.slice(firstLine.length).trim();
12258
12550
  if (!contentAfterLink) {
12259
12551
  console.error(
12260
- chalk134.red(
12552
+ chalk138.red(
12261
12553
  `Staged file ${filename} has no summary content after the transcript link.`
12262
12554
  )
12263
12555
  );
@@ -12653,7 +12945,7 @@ function registerVoice(program2) {
12653
12945
 
12654
12946
  // src/commands/roam/auth.ts
12655
12947
  import { randomBytes } from "crypto";
12656
- import chalk135 from "chalk";
12948
+ import chalk139 from "chalk";
12657
12949
 
12658
12950
  // src/lib/openBrowser.ts
12659
12951
  import { execSync as execSync37 } from "child_process";
@@ -12828,13 +13120,13 @@ async function auth() {
12828
13120
  saveGlobalConfig(config);
12829
13121
  const state = randomBytes(16).toString("hex");
12830
13122
  console.log(
12831
- chalk135.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
13123
+ chalk139.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
12832
13124
  );
12833
- console.log(chalk135.white("http://localhost:14523/callback\n"));
12834
- console.log(chalk135.blue("Opening browser for authorization..."));
12835
- console.log(chalk135.dim("Waiting for authorization callback..."));
13125
+ console.log(chalk139.white("http://localhost:14523/callback\n"));
13126
+ console.log(chalk139.blue("Opening browser for authorization..."));
13127
+ console.log(chalk139.dim("Waiting for authorization callback..."));
12836
13128
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
12837
- console.log(chalk135.dim("Exchanging code for tokens..."));
13129
+ console.log(chalk139.dim("Exchanging code for tokens..."));
12838
13130
  const tokens = await exchangeToken({
12839
13131
  code,
12840
13132
  clientId,
@@ -12850,7 +13142,7 @@ async function auth() {
12850
13142
  };
12851
13143
  saveGlobalConfig(config);
12852
13144
  console.log(
12853
- chalk135.green("Roam credentials and tokens saved to ~/.assist.yml")
13145
+ chalk139.green("Roam credentials and tokens saved to ~/.assist.yml")
12854
13146
  );
12855
13147
  }
12856
13148
 
@@ -13158,7 +13450,9 @@ Run \`assist run ${name} $ARGUMENTS 2>&1\`.
13158
13450
  function add3() {
13159
13451
  const { name, command, args, cwd } = requireParsedArgs();
13160
13452
  saveNewRunConfig(name, command, args, cwd);
13161
- createCommandFile(name);
13453
+ if (!name.startsWith("verify:")) {
13454
+ createCommandFile(name);
13455
+ }
13162
13456
  console.log(
13163
13457
  `Added run configuration: ${name} -> ${formatDisplay(command, args)}`
13164
13458
  );
@@ -13261,7 +13555,7 @@ import { execSync as execSync39 } from "child_process";
13261
13555
  import { existsSync as existsSync43, mkdirSync as mkdirSync16, unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
13262
13556
  import { tmpdir as tmpdir7 } from "os";
13263
13557
  import { join as join49, resolve as resolve13 } from "path";
13264
- import chalk136 from "chalk";
13558
+ import chalk140 from "chalk";
13265
13559
 
13266
13560
  // src/commands/screenshot/captureWindowPs1.ts
13267
13561
  var captureWindowPs1 = `
@@ -13412,20 +13706,20 @@ function screenshot(processName) {
13412
13706
  const config = loadConfig();
13413
13707
  const outputDir = resolve13(config.screenshot.outputDir);
13414
13708
  const outputPath = buildOutputPath(outputDir, processName);
13415
- console.log(chalk136.gray(`Capturing window for process "${processName}" ...`));
13709
+ console.log(chalk140.gray(`Capturing window for process "${processName}" ...`));
13416
13710
  try {
13417
13711
  runPowerShellScript(processName, outputPath);
13418
- console.log(chalk136.green(`Screenshot saved: ${outputPath}`));
13712
+ console.log(chalk140.green(`Screenshot saved: ${outputPath}`));
13419
13713
  } catch (error) {
13420
13714
  const msg = error instanceof Error ? error.message : String(error);
13421
- console.error(chalk136.red(`Failed to capture screenshot: ${msg}`));
13715
+ console.error(chalk140.red(`Failed to capture screenshot: ${msg}`));
13422
13716
  process.exit(1);
13423
13717
  }
13424
13718
  }
13425
13719
 
13426
13720
  // src/commands/sessions/summarise/index.ts
13427
13721
  import * as fs27 from "fs";
13428
- import chalk137 from "chalk";
13722
+ import chalk141 from "chalk";
13429
13723
 
13430
13724
  // src/commands/sessions/summarise/shared.ts
13431
13725
  import * as fs25 from "fs";
@@ -13565,22 +13859,22 @@ ${firstMessage}`);
13565
13859
  async function summarise3(options2) {
13566
13860
  const files = await discoverSessionJsonlPaths();
13567
13861
  if (files.length === 0) {
13568
- console.log(chalk137.yellow("No sessions found."));
13862
+ console.log(chalk141.yellow("No sessions found."));
13569
13863
  return;
13570
13864
  }
13571
13865
  const toProcess = selectCandidates(files, options2);
13572
13866
  if (toProcess.length === 0) {
13573
- console.log(chalk137.green("All sessions already summarised."));
13867
+ console.log(chalk141.green("All sessions already summarised."));
13574
13868
  return;
13575
13869
  }
13576
13870
  console.log(
13577
- chalk137.cyan(
13871
+ chalk141.cyan(
13578
13872
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
13579
13873
  )
13580
13874
  );
13581
13875
  const { succeeded, failed } = processSessions(toProcess);
13582
13876
  console.log(
13583
- chalk137.green(`Done: ${succeeded} summarised`) + (failed > 0 ? chalk137.yellow(`, ${failed} skipped`) : "")
13877
+ chalk141.green(`Done: ${succeeded} summarised`) + (failed > 0 ? chalk141.yellow(`, ${failed} skipped`) : "")
13584
13878
  );
13585
13879
  }
13586
13880
  function selectCandidates(files, options2) {
@@ -13600,16 +13894,16 @@ function processSessions(files) {
13600
13894
  let failed = 0;
13601
13895
  for (let i = 0; i < files.length; i++) {
13602
13896
  const file = files[i];
13603
- process.stdout.write(chalk137.dim(` [${i + 1}/${files.length}] `));
13897
+ process.stdout.write(chalk141.dim(` [${i + 1}/${files.length}] `));
13604
13898
  const summary = summariseSession(file);
13605
13899
  if (summary) {
13606
13900
  writeSummary(file, summary);
13607
13901
  succeeded++;
13608
- process.stdout.write(`${chalk137.green("\u2713")} ${summary}
13902
+ process.stdout.write(`${chalk141.green("\u2713")} ${summary}
13609
13903
  `);
13610
13904
  } else {
13611
13905
  failed++;
13612
- process.stdout.write(` ${chalk137.yellow("skip")}
13906
+ process.stdout.write(` ${chalk141.yellow("skip")}
13613
13907
  `);
13614
13908
  }
13615
13909
  }
@@ -13624,10 +13918,10 @@ function registerSessions(program2) {
13624
13918
  }
13625
13919
 
13626
13920
  // src/commands/statusLine.ts
13627
- import chalk139 from "chalk";
13921
+ import chalk143 from "chalk";
13628
13922
 
13629
13923
  // src/commands/buildLimitsSegment.ts
13630
- import chalk138 from "chalk";
13924
+ import chalk142 from "chalk";
13631
13925
  var FIVE_HOUR_SECONDS = 5 * 3600;
13632
13926
  var SEVEN_DAY_SECONDS = 7 * 86400;
13633
13927
  function formatTimeLeft(resetsAt) {
@@ -13650,10 +13944,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
13650
13944
  function colorizeRateLimit(pct, resetsAt, windowSeconds) {
13651
13945
  const label2 = `${Math.round(pct)}%`;
13652
13946
  const projected = projectUsage(pct, resetsAt, windowSeconds);
13653
- if (projected == null) return chalk138.green(label2);
13654
- if (projected > 100) return chalk138.red(label2);
13655
- if (projected > 75) return chalk138.yellow(label2);
13656
- return chalk138.green(label2);
13947
+ if (projected == null) return chalk142.green(label2);
13948
+ if (projected > 100) return chalk142.red(label2);
13949
+ if (projected > 75) return chalk142.yellow(label2);
13950
+ return chalk142.green(label2);
13657
13951
  }
13658
13952
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
13659
13953
  const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
@@ -13679,14 +13973,14 @@ function buildLimitsSegment(rateLimits) {
13679
13973
  }
13680
13974
 
13681
13975
  // src/commands/statusLine.ts
13682
- chalk139.level = 3;
13976
+ chalk143.level = 3;
13683
13977
  function formatNumber(num) {
13684
13978
  return num.toLocaleString("en-US");
13685
13979
  }
13686
13980
  function colorizePercent(pct) {
13687
13981
  const label2 = `${Math.round(pct)}%`;
13688
- if (pct > 80) return chalk139.red(label2);
13689
- if (pct > 40) return chalk139.yellow(label2);
13982
+ if (pct > 80) return chalk143.red(label2);
13983
+ if (pct > 40) return chalk143.yellow(label2);
13690
13984
  return label2;
13691
13985
  }
13692
13986
  async function statusLine() {
@@ -13709,7 +14003,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
13709
14003
  // src/commands/sync/syncClaudeMd.ts
13710
14004
  import * as fs28 from "fs";
13711
14005
  import * as path49 from "path";
13712
- import chalk140 from "chalk";
14006
+ import chalk144 from "chalk";
13713
14007
  async function syncClaudeMd(claudeDir, targetBase, options2) {
13714
14008
  const source = path49.join(claudeDir, "CLAUDE.md");
13715
14009
  const target = path49.join(targetBase, "CLAUDE.md");
@@ -13718,12 +14012,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
13718
14012
  const targetContent = fs28.readFileSync(target, "utf-8");
13719
14013
  if (sourceContent !== targetContent) {
13720
14014
  console.log(
13721
- chalk140.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
14015
+ chalk144.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
13722
14016
  );
13723
14017
  console.log();
13724
14018
  printDiff(targetContent, sourceContent);
13725
14019
  const confirm = options2?.yes || await promptConfirm(
13726
- chalk140.red("Overwrite existing CLAUDE.md?"),
14020
+ chalk144.red("Overwrite existing CLAUDE.md?"),
13727
14021
  false
13728
14022
  );
13729
14023
  if (!confirm) {
@@ -13739,7 +14033,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
13739
14033
  // src/commands/sync/syncSettings.ts
13740
14034
  import * as fs29 from "fs";
13741
14035
  import * as path50 from "path";
13742
- import chalk141 from "chalk";
14036
+ import chalk145 from "chalk";
13743
14037
  async function syncSettings(claudeDir, targetBase, options2) {
13744
14038
  const source = path50.join(claudeDir, "settings.json");
13745
14039
  const target = path50.join(targetBase, "settings.json");
@@ -13755,14 +14049,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
13755
14049
  if (mergedContent !== normalizedTarget) {
13756
14050
  if (!options2?.yes) {
13757
14051
  console.log(
13758
- chalk141.yellow(
14052
+ chalk145.yellow(
13759
14053
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
13760
14054
  )
13761
14055
  );
13762
14056
  console.log();
13763
14057
  printDiff(targetContent, mergedContent);
13764
14058
  const confirm = await promptConfirm(
13765
- chalk141.red("Overwrite existing settings.json?"),
14059
+ chalk145.red("Overwrite existing settings.json?"),
13766
14060
  false
13767
14061
  );
13768
14062
  if (!confirm) {
@@ -13876,6 +14170,7 @@ registerDotnet(program);
13876
14170
  registerNews(program);
13877
14171
  registerRavendb(program);
13878
14172
  registerSeq(program);
14173
+ registerSql(program);
13879
14174
  registerTranscript(program);
13880
14175
  registerVoice(program);
13881
14176
  registerSessions(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.207.0",
3
+ "version": "0.208.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -42,6 +42,7 @@
42
42
  "entities": "^7.0.1",
43
43
  "is-wsl": "^3.1.0",
44
44
  "minimatch": "^10.1.1",
45
+ "mssql": "^12.5.0",
45
46
  "node-notifier": "^10.0.1",
46
47
  "node-pty": "^1.1.0",
47
48
  "semver": "^7.7.3",
@@ -63,6 +64,7 @@
63
64
  "@semantic-release/git": "^10.0.1",
64
65
  "@types/better-sqlite3": "^7.6.13",
65
66
  "@types/blessed": "^0.1.27",
67
+ "@types/mssql": "^12.3.0",
66
68
  "@types/node": "^24.10.1",
67
69
  "@types/node-notifier": "^8.0.5",
68
70
  "@types/react": "^19.2.14",