@link-assistant/agent 0.0.8 → 0.0.11

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 (104) hide show
  1. package/EXAMPLES.md +80 -1
  2. package/MODELS.md +72 -24
  3. package/README.md +95 -2
  4. package/TOOLS.md +20 -0
  5. package/package.json +36 -2
  6. package/src/agent/agent.ts +68 -54
  7. package/src/auth/claude-oauth.ts +426 -0
  8. package/src/auth/index.ts +28 -26
  9. package/src/auth/plugins.ts +876 -0
  10. package/src/bun/index.ts +53 -43
  11. package/src/bus/global.ts +5 -5
  12. package/src/bus/index.ts +59 -53
  13. package/src/cli/bootstrap.js +12 -12
  14. package/src/cli/bootstrap.ts +6 -6
  15. package/src/cli/cmd/agent.ts +97 -92
  16. package/src/cli/cmd/auth.ts +468 -0
  17. package/src/cli/cmd/cmd.ts +2 -2
  18. package/src/cli/cmd/export.ts +41 -41
  19. package/src/cli/cmd/mcp.ts +210 -53
  20. package/src/cli/cmd/models.ts +30 -29
  21. package/src/cli/cmd/run.ts +269 -213
  22. package/src/cli/cmd/stats.ts +185 -146
  23. package/src/cli/error.ts +17 -13
  24. package/src/cli/ui.ts +78 -0
  25. package/src/command/index.ts +26 -26
  26. package/src/config/config.ts +528 -288
  27. package/src/config/markdown.ts +15 -15
  28. package/src/file/ripgrep.ts +201 -169
  29. package/src/file/time.ts +21 -18
  30. package/src/file/watcher.ts +51 -42
  31. package/src/file.ts +1 -1
  32. package/src/flag/flag.ts +26 -11
  33. package/src/format/formatter.ts +206 -162
  34. package/src/format/index.ts +61 -61
  35. package/src/global/index.ts +21 -21
  36. package/src/id/id.ts +47 -33
  37. package/src/index.js +554 -332
  38. package/src/json-standard/index.ts +173 -0
  39. package/src/mcp/index.ts +135 -128
  40. package/src/patch/index.ts +336 -267
  41. package/src/project/bootstrap.ts +15 -15
  42. package/src/project/instance.ts +43 -36
  43. package/src/project/project.ts +47 -47
  44. package/src/project/state.ts +37 -33
  45. package/src/provider/models-macro.ts +5 -5
  46. package/src/provider/models.ts +32 -32
  47. package/src/provider/opencode.js +19 -19
  48. package/src/provider/provider.ts +518 -277
  49. package/src/provider/transform.ts +143 -102
  50. package/src/server/project.ts +21 -21
  51. package/src/server/server.ts +111 -105
  52. package/src/session/agent.js +66 -60
  53. package/src/session/compaction.ts +136 -111
  54. package/src/session/index.ts +189 -156
  55. package/src/session/message-v2.ts +312 -268
  56. package/src/session/message.ts +73 -57
  57. package/src/session/processor.ts +180 -166
  58. package/src/session/prompt.ts +678 -533
  59. package/src/session/retry.ts +26 -23
  60. package/src/session/revert.ts +76 -62
  61. package/src/session/status.ts +26 -26
  62. package/src/session/summary.ts +97 -76
  63. package/src/session/system.ts +77 -63
  64. package/src/session/todo.ts +22 -16
  65. package/src/snapshot/index.ts +92 -76
  66. package/src/storage/storage.ts +157 -120
  67. package/src/tool/bash.ts +116 -106
  68. package/src/tool/batch.ts +73 -59
  69. package/src/tool/codesearch.ts +60 -53
  70. package/src/tool/edit.ts +319 -263
  71. package/src/tool/glob.ts +32 -28
  72. package/src/tool/grep.ts +72 -53
  73. package/src/tool/invalid.ts +7 -7
  74. package/src/tool/ls.ts +77 -64
  75. package/src/tool/multiedit.ts +30 -21
  76. package/src/tool/patch.ts +121 -94
  77. package/src/tool/read.ts +140 -122
  78. package/src/tool/registry.ts +38 -38
  79. package/src/tool/task.ts +93 -60
  80. package/src/tool/todo.ts +16 -16
  81. package/src/tool/tool.ts +45 -36
  82. package/src/tool/webfetch.ts +97 -74
  83. package/src/tool/websearch.ts +78 -64
  84. package/src/tool/write.ts +21 -15
  85. package/src/util/binary.ts +27 -19
  86. package/src/util/context.ts +8 -8
  87. package/src/util/defer.ts +7 -5
  88. package/src/util/error.ts +24 -19
  89. package/src/util/eventloop.ts +16 -10
  90. package/src/util/filesystem.ts +37 -33
  91. package/src/util/fn.ts +11 -8
  92. package/src/util/iife.ts +1 -1
  93. package/src/util/keybind.ts +44 -44
  94. package/src/util/lazy.ts +7 -7
  95. package/src/util/locale.ts +20 -16
  96. package/src/util/lock.ts +43 -38
  97. package/src/util/log.ts +95 -85
  98. package/src/util/queue.ts +8 -8
  99. package/src/util/rpc.ts +35 -23
  100. package/src/util/scrap.ts +4 -4
  101. package/src/util/signal.ts +5 -5
  102. package/src/util/timeout.ts +6 -6
  103. package/src/util/token.ts +2 -2
  104. package/src/util/wildcard.ts +38 -27
package/src/util/log.ts CHANGED
@@ -1,105 +1,111 @@
1
- import path from "path"
2
- import fs from "fs/promises"
3
- import { Global } from "../global"
4
- import z from "zod"
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { Global } from '../global';
4
+ import z from 'zod';
5
5
 
6
6
  export namespace Log {
7
- export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" })
8
- export type Level = z.infer<typeof Level>
7
+ export const Level = z
8
+ .enum(['DEBUG', 'INFO', 'WARN', 'ERROR'])
9
+ .meta({ ref: 'LogLevel', description: 'Log level' });
10
+ export type Level = z.infer<typeof Level>;
9
11
 
10
12
  const levelPriority: Record<Level, number> = {
11
13
  DEBUG: 0,
12
14
  INFO: 1,
13
15
  WARN: 2,
14
16
  ERROR: 3,
15
- }
17
+ };
16
18
 
17
- let level: Level = "INFO"
19
+ let level: Level = 'INFO';
18
20
 
19
21
  function shouldLog(input: Level): boolean {
20
- return levelPriority[input] >= levelPriority[level]
22
+ return levelPriority[input] >= levelPriority[level];
21
23
  }
22
24
 
23
25
  export type Logger = {
24
- debug(message?: any, extra?: Record<string, any>): void
25
- info(message?: any, extra?: Record<string, any>): void
26
- error(message?: any, extra?: Record<string, any>): void
27
- warn(message?: any, extra?: Record<string, any>): void
28
- tag(key: string, value: string): Logger
29
- clone(): Logger
26
+ debug(message?: any, extra?: Record<string, any>): void;
27
+ info(message?: any, extra?: Record<string, any>): void;
28
+ error(message?: any, extra?: Record<string, any>): void;
29
+ warn(message?: any, extra?: Record<string, any>): void;
30
+ tag(key: string, value: string): Logger;
31
+ clone(): Logger;
30
32
  time(
31
33
  message: string,
32
- extra?: Record<string, any>,
34
+ extra?: Record<string, any>
33
35
  ): {
34
- stop(): void
35
- [Symbol.dispose](): void
36
- }
37
- }
36
+ stop(): void;
37
+ [Symbol.dispose](): void;
38
+ };
39
+ };
38
40
 
39
- const loggers = new Map<string, Logger>()
41
+ const loggers = new Map<string, Logger>();
40
42
 
41
- export const Default = create({ service: "default" })
43
+ export const Default = create({ service: 'default' });
42
44
 
43
45
  export interface Options {
44
- print: boolean
45
- dev?: boolean
46
- level?: Level
46
+ print: boolean;
47
+ dev?: boolean;
48
+ level?: Level;
47
49
  }
48
50
 
49
- let logpath = ""
51
+ let logpath = '';
50
52
  export function file() {
51
- return logpath
53
+ return logpath;
52
54
  }
53
- let write = (msg: any) => Bun.stderr.write(msg)
55
+ let write = (msg: any) => Bun.stderr.write(msg);
54
56
 
55
57
  export async function init(options: Options) {
56
- if (options.level) level = options.level
57
- cleanup(Global.Path.log)
58
- if (options.print) return
58
+ if (options.level) level = options.level;
59
+ cleanup(Global.Path.log);
60
+ if (options.print) return;
59
61
  logpath = path.join(
60
62
  Global.Path.log,
61
- options.dev ? "dev.log" : new Date().toISOString().split(".")[0].replace(/:/g, "") + ".log",
62
- )
63
- const logfile = Bun.file(logpath)
64
- await fs.truncate(logpath).catch(() => {})
65
- const writer = logfile.writer()
63
+ options.dev
64
+ ? 'dev.log'
65
+ : new Date().toISOString().split('.')[0].replace(/:/g, '') + '.log'
66
+ );
67
+ const logfile = Bun.file(logpath);
68
+ await fs.truncate(logpath).catch(() => {});
69
+ const writer = logfile.writer();
66
70
  write = async (msg: any) => {
67
- const num = writer.write(msg)
68
- writer.flush()
69
- return num
70
- }
71
+ const num = writer.write(msg);
72
+ writer.flush();
73
+ return num;
74
+ };
71
75
  }
72
76
 
73
77
  async function cleanup(dir: string) {
74
- const glob = new Bun.Glob("????-??-??T??????.log")
78
+ const glob = new Bun.Glob('????-??-??T??????.log');
75
79
  const files = await Array.fromAsync(
76
80
  glob.scan({
77
81
  cwd: dir,
78
82
  absolute: true,
79
- }),
80
- )
81
- if (files.length <= 5) return
83
+ })
84
+ );
85
+ if (files.length <= 5) return;
82
86
 
83
- const filesToDelete = files.slice(0, -10)
84
- await Promise.all(filesToDelete.map((file) => fs.unlink(file).catch(() => {})))
87
+ const filesToDelete = files.slice(0, -10);
88
+ await Promise.all(
89
+ filesToDelete.map((file) => fs.unlink(file).catch(() => {}))
90
+ );
85
91
  }
86
92
 
87
93
  function formatError(error: Error, depth = 0): string {
88
- const result = error.message
94
+ const result = error.message;
89
95
  return error.cause instanceof Error && depth < 10
90
- ? result + " Caused by: " + formatError(error.cause, depth + 1)
91
- : result
96
+ ? result + ' Caused by: ' + formatError(error.cause, depth + 1)
97
+ : result;
92
98
  }
93
99
 
94
- let last = Date.now()
100
+ let last = Date.now();
95
101
  export function create(tags?: Record<string, any>) {
96
- tags = tags || {}
102
+ tags = tags || {};
97
103
 
98
- const service = tags["service"]
99
- if (service && typeof service === "string") {
100
- const cached = loggers.get(service)
104
+ const service = tags['service'];
105
+ if (service && typeof service === 'string') {
106
+ const cached = loggers.get(service);
101
107
  if (cached) {
102
- return cached
108
+ return cached;
103
109
  }
104
110
  }
105
111
 
@@ -110,68 +116,72 @@ export namespace Log {
110
116
  })
111
117
  .filter(([_, value]) => value !== undefined && value !== null)
112
118
  .map(([key, value]) => {
113
- const prefix = `${key}=`
114
- if (value instanceof Error) return prefix + formatError(value)
115
- if (typeof value === "object") return prefix + JSON.stringify(value)
116
- return prefix + value
119
+ const prefix = `${key}=`;
120
+ if (value instanceof Error) return prefix + formatError(value);
121
+ if (typeof value === 'object') return prefix + JSON.stringify(value);
122
+ return prefix + value;
117
123
  })
118
- .join(" ")
119
- const next = new Date()
120
- const diff = next.getTime() - last
121
- last = next.getTime()
122
- return [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message].filter(Boolean).join(" ") + "\n"
124
+ .join(' ');
125
+ const next = new Date();
126
+ const diff = next.getTime() - last;
127
+ last = next.getTime();
128
+ return (
129
+ [next.toISOString().split('.')[0], '+' + diff + 'ms', prefix, message]
130
+ .filter(Boolean)
131
+ .join(' ') + '\n'
132
+ );
123
133
  }
124
134
  const result: Logger = {
125
135
  debug(message?: any, extra?: Record<string, any>) {
126
- if (shouldLog("DEBUG")) {
127
- write("DEBUG " + build(message, extra))
136
+ if (shouldLog('DEBUG')) {
137
+ write('DEBUG ' + build(message, extra));
128
138
  }
129
139
  },
130
140
  info(message?: any, extra?: Record<string, any>) {
131
- if (shouldLog("INFO")) {
132
- write("INFO " + build(message, extra))
141
+ if (shouldLog('INFO')) {
142
+ write('INFO ' + build(message, extra));
133
143
  }
134
144
  },
135
145
  error(message?: any, extra?: Record<string, any>) {
136
- if (shouldLog("ERROR")) {
137
- write("ERROR " + build(message, extra))
146
+ if (shouldLog('ERROR')) {
147
+ write('ERROR ' + build(message, extra));
138
148
  }
139
149
  },
140
150
  warn(message?: any, extra?: Record<string, any>) {
141
- if (shouldLog("WARN")) {
142
- write("WARN " + build(message, extra))
151
+ if (shouldLog('WARN')) {
152
+ write('WARN ' + build(message, extra));
143
153
  }
144
154
  },
145
155
  tag(key: string, value: string) {
146
- if (tags) tags[key] = value
147
- return result
156
+ if (tags) tags[key] = value;
157
+ return result;
148
158
  },
149
159
  clone() {
150
- return Log.create({ ...tags })
160
+ return Log.create({ ...tags });
151
161
  },
152
162
  time(message: string, extra?: Record<string, any>) {
153
- const now = Date.now()
154
- result.info(message, { status: "started", ...extra })
163
+ const now = Date.now();
164
+ result.info(message, { status: 'started', ...extra });
155
165
  function stop() {
156
166
  result.info(message, {
157
- status: "completed",
167
+ status: 'completed',
158
168
  duration: Date.now() - now,
159
169
  ...extra,
160
- })
170
+ });
161
171
  }
162
172
  return {
163
173
  stop,
164
174
  [Symbol.dispose]() {
165
- stop()
175
+ stop();
166
176
  },
167
- }
177
+ };
168
178
  },
169
- }
179
+ };
170
180
 
171
- if (service && typeof service === "string") {
172
- loggers.set(service, result)
181
+ if (service && typeof service === 'string') {
182
+ loggers.set(service, result);
173
183
  }
174
184
 
175
- return result
185
+ return result;
176
186
  }
177
187
  }
package/src/util/queue.ts CHANGED
@@ -1,19 +1,19 @@
1
1
  export class AsyncQueue<T> implements AsyncIterable<T> {
2
- private queue: T[] = []
3
- private resolvers: ((value: T) => void)[] = []
2
+ private queue: T[] = [];
3
+ private resolvers: ((value: T) => void)[] = [];
4
4
 
5
5
  push(item: T) {
6
- const resolve = this.resolvers.shift()
7
- if (resolve) resolve(item)
8
- else this.queue.push(item)
6
+ const resolve = this.resolvers.shift();
7
+ if (resolve) resolve(item);
8
+ else this.queue.push(item);
9
9
  }
10
10
 
11
11
  async next(): Promise<T> {
12
- if (this.queue.length > 0) return this.queue.shift()!
13
- return new Promise((resolve) => this.resolvers.push(resolve))
12
+ if (this.queue.length > 0) return this.queue.shift()!;
13
+ return new Promise((resolve) => this.resolvers.push(resolve));
14
14
  }
15
15
 
16
16
  async *[Symbol.asyncIterator]() {
17
- while (true) yield await this.next()
17
+ while (true) yield await this.next();
18
18
  }
19
19
  }
package/src/util/rpc.ts CHANGED
@@ -1,42 +1,54 @@
1
1
  export namespace Rpc {
2
2
  type Definition = {
3
- [method: string]: (input: any) => any
4
- }
3
+ [method: string]: (input: any) => any;
4
+ };
5
5
 
6
6
  export function listen(rpc: Definition) {
7
7
  onmessage = async (evt) => {
8
- const parsed = JSON.parse(evt.data)
9
- if (parsed.type === "rpc.request") {
10
- const result = await rpc[parsed.method](parsed.input)
11
- postMessage(JSON.stringify({ type: "rpc.result", result, id: parsed.id }))
8
+ const parsed = JSON.parse(evt.data);
9
+ if (parsed.type === 'rpc.request') {
10
+ const result = await rpc[parsed.method](parsed.input);
11
+ postMessage(
12
+ JSON.stringify({ type: 'rpc.result', result, id: parsed.id })
13
+ );
12
14
  }
13
- }
15
+ };
14
16
  }
15
17
 
16
18
  export function client<T extends Definition>(target: {
17
- postMessage: (data: string) => void | null
18
- onmessage: ((this: Worker, ev: MessageEvent<any>) => any) | null
19
+ postMessage: (data: string) => void | null;
20
+ onmessage: ((this: Worker, ev: MessageEvent<any>) => any) | null;
19
21
  }) {
20
- const pending = new Map<number, (result: any) => void>()
21
- let id = 0
22
+ const pending = new Map<number, (result: any) => void>();
23
+ let id = 0;
22
24
  target.onmessage = async (evt) => {
23
- const parsed = JSON.parse(evt.data)
24
- if (parsed.type === "rpc.result") {
25
- const resolve = pending.get(parsed.id)
25
+ const parsed = JSON.parse(evt.data);
26
+ if (parsed.type === 'rpc.result') {
27
+ const resolve = pending.get(parsed.id);
26
28
  if (resolve) {
27
- resolve(parsed.result)
28
- pending.delete(parsed.id)
29
+ resolve(parsed.result);
30
+ pending.delete(parsed.id);
29
31
  }
30
32
  }
31
- }
33
+ };
32
34
  return {
33
- call<Method extends keyof T>(method: Method, input: Parameters<T[Method]>[0]): Promise<ReturnType<T[Method]>> {
34
- const requestId = id++
35
+ call<Method extends keyof T>(
36
+ method: Method,
37
+ input: Parameters<T[Method]>[0]
38
+ ): Promise<ReturnType<T[Method]>> {
39
+ const requestId = id++;
35
40
  return new Promise((resolve) => {
36
- pending.set(requestId, resolve)
37
- target.postMessage(JSON.stringify({ type: "rpc.request", method, input, id: requestId }))
38
- })
41
+ pending.set(requestId, resolve);
42
+ target.postMessage(
43
+ JSON.stringify({
44
+ type: 'rpc.request',
45
+ method,
46
+ input,
47
+ id: requestId,
48
+ })
49
+ );
50
+ });
39
51
  },
40
- }
52
+ };
41
53
  }
42
54
  }
package/src/util/scrap.ts CHANGED
@@ -1,10 +1,10 @@
1
- export const foo: string = "42"
2
- export const bar: number = 123
1
+ export const foo: string = '42';
2
+ export const bar: number = 123;
3
3
 
4
4
  export function dummyFunction(): void {
5
- console.log("This is a dummy function")
5
+ console.log('This is a dummy function');
6
6
  }
7
7
 
8
8
  export function randomHelper(): boolean {
9
- return Math.random() > 0.5
9
+ return Math.random() > 0.5;
10
10
  }
@@ -1,12 +1,12 @@
1
1
  export function signal() {
2
- let resolve: any
3
- const promise = new Promise((r) => (resolve = r))
2
+ let resolve: any;
3
+ const promise = new Promise((r) => (resolve = r));
4
4
  return {
5
5
  trigger() {
6
- return resolve()
6
+ return resolve();
7
7
  },
8
8
  wait() {
9
- return promise
9
+ return promise;
10
10
  },
11
- }
11
+ };
12
12
  }
@@ -1,14 +1,14 @@
1
1
  export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
2
- let timeout: NodeJS.Timeout
2
+ let timeout: NodeJS.Timeout;
3
3
  return Promise.race([
4
4
  promise.then((result) => {
5
- clearTimeout(timeout)
6
- return result
5
+ clearTimeout(timeout);
6
+ return result;
7
7
  }),
8
8
  new Promise<never>((_, reject) => {
9
9
  timeout = setTimeout(() => {
10
- reject(new Error(`Operation timed out after ${ms}ms`))
11
- }, ms)
10
+ reject(new Error(`Operation timed out after ${ms}ms`));
11
+ }, ms);
12
12
  }),
13
- ])
13
+ ]);
14
14
  }
package/src/util/token.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export namespace Token {
2
- const CHARS_PER_TOKEN = 4
2
+ const CHARS_PER_TOKEN = 4;
3
3
 
4
4
  export function estimate(input: string) {
5
- return Math.max(0, Math.round((input || "").length / CHARS_PER_TOKEN))
5
+ return Math.max(0, Math.round((input || '').length / CHARS_PER_TOKEN));
6
6
  }
7
7
  }
@@ -1,54 +1,65 @@
1
- import { sortBy, pipe } from "remeda"
1
+ import { sortBy, pipe } from 'remeda';
2
2
 
3
3
  export namespace Wildcard {
4
4
  export function match(str: string, pattern: string) {
5
5
  const regex = new RegExp(
6
- "^" +
6
+ '^' +
7
7
  pattern
8
- .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
9
- .replace(/\*/g, ".*") // * becomes .*
10
- .replace(/\?/g, ".") + // ? becomes .
11
- "$",
12
- "s", // s flag enables multiline matching
13
- )
14
- return regex.test(str)
8
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape special regex chars
9
+ .replace(/\*/g, '.*') // * becomes .*
10
+ .replace(/\?/g, '.') + // ? becomes .
11
+ '$',
12
+ 's' // s flag enables multiline matching
13
+ );
14
+ return regex.test(str);
15
15
  }
16
16
 
17
17
  export function all(input: string, patterns: Record<string, any>) {
18
- const sorted = pipe(patterns, Object.entries, sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"]))
19
- let result = undefined
18
+ const sorted = pipe(
19
+ patterns,
20
+ Object.entries,
21
+ sortBy([([key]) => key.length, 'asc'], [([key]) => key, 'asc'])
22
+ );
23
+ let result = undefined;
20
24
  for (const [pattern, value] of sorted) {
21
25
  if (match(input, pattern)) {
22
- result = value
23
- continue
26
+ result = value;
27
+ continue;
24
28
  }
25
29
  }
26
- return result
30
+ return result;
27
31
  }
28
32
 
29
- export function allStructured(input: { head: string; tail: string[] }, patterns: Record<string, any>) {
30
- const sorted = pipe(patterns, Object.entries, sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"]))
31
- let result = undefined
33
+ export function allStructured(
34
+ input: { head: string; tail: string[] },
35
+ patterns: Record<string, any>
36
+ ) {
37
+ const sorted = pipe(
38
+ patterns,
39
+ Object.entries,
40
+ sortBy([([key]) => key.length, 'asc'], [([key]) => key, 'asc'])
41
+ );
42
+ let result = undefined;
32
43
  for (const [pattern, value] of sorted) {
33
- const parts = pattern.split(/\s+/)
34
- if (!match(input.head, parts[0])) continue
44
+ const parts = pattern.split(/\s+/);
45
+ if (!match(input.head, parts[0])) continue;
35
46
  if (parts.length === 1 || matchSequence(input.tail, parts.slice(1))) {
36
- result = value
37
- continue
47
+ result = value;
48
+ continue;
38
49
  }
39
50
  }
40
- return result
51
+ return result;
41
52
  }
42
53
 
43
54
  function matchSequence(items: string[], patterns: string[]): boolean {
44
- if (patterns.length === 0) return true
45
- const [pattern, ...rest] = patterns
46
- if (pattern === "*") return matchSequence(items, rest)
55
+ if (patterns.length === 0) return true;
56
+ const [pattern, ...rest] = patterns;
57
+ if (pattern === '*') return matchSequence(items, rest);
47
58
  for (let i = 0; i < items.length; i++) {
48
59
  if (match(items[i], pattern) && matchSequence(items.slice(i + 1), rest)) {
49
- return true
60
+ return true;
50
61
  }
51
62
  }
52
- return false
63
+ return false;
53
64
  }
54
65
  }