├── README.md
├── passage.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── swiftpm
│ │ └── Package.resolved
└── project.pbxproj
├── LICENSE
├── .gitignore
└── passage
├── Prompt.swift
├── main.swift
└── PromptExecutor.swift
/README.md:
--------------------------------------------------------------------------------
1 | # Passage
2 |
--------------------------------------------------------------------------------
/passage.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/passage.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "b473f03a46d97c888cde0764ad3582d8bba7a93d94d06028851a2d553c1e8899",
3 | "pins" : [
4 | {
5 | "identity" : "swift-argument-parser",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/apple/swift-argument-parser.git",
8 | "state" : {
9 | "revision" : "41982a3656a71c768319979febd796c6fd111d5c",
10 | "version" : "1.5.0"
11 | }
12 | },
13 | {
14 | "identity" : "yams",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/jpsim/Yams",
17 | "state" : {
18 | "revision" : "b4b8042411dc7bbb696300a34a4bf3ba1b7ad19b",
19 | "version" : "5.3.1"
20 | }
21 | }
22 | ],
23 | "version" : 3
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Tyler Hall
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## Obj-C/Swift specific
9 | *.hmap
10 |
11 | ## App packaging
12 | *.ipa
13 | *.dSYM.zip
14 | *.dSYM
15 |
16 | ## Playgrounds
17 | timeline.xctimeline
18 | playground.xcworkspace
19 |
20 | # Swift Package Manager
21 | #
22 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
23 | # Packages/
24 | # Package.pins
25 | # Package.resolved
26 | # *.xcodeproj
27 | #
28 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
29 | # hence it is not needed unless you have added a package configuration file to your project
30 | # .swiftpm
31 |
32 | .build/
33 |
34 | # CocoaPods
35 | #
36 | # We recommend against adding the Pods directory to your .gitignore. However
37 | # you should judge for yourself, the pros and cons are mentioned at:
38 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
39 | #
40 | # Pods/
41 | #
42 | # Add this line if you want to avoid checking in source code from the Xcode workspace
43 | # *.xcworkspace
44 |
45 | # Carthage
46 | #
47 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
48 | # Carthage/Checkouts
49 |
50 | Carthage/Build/
51 |
52 | # fastlane
53 | #
54 | # It is recommended to not store the screenshots in the git repo.
55 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
56 | # For more information about the recommended setup visit:
57 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
58 |
59 | fastlane/report.xml
60 | fastlane/Preview.html
61 | fastlane/screenshots/**/*.png
62 | fastlane/test_output
63 | .DS_Store
64 |
--------------------------------------------------------------------------------
/passage/Prompt.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Prompt.swift
3 | // Passage
4 | //
5 | // Created by Tyler Hall on 2/14/25.
6 | //
7 |
8 | import Foundation
9 | import Yams
10 |
11 | struct Prompt: Codable {
12 | var name: String?
13 | var apiBaseURL: String?
14 | var apiToken: String?
15 | var model: String?
16 | var outputs: [Output]
17 | var text: String = ""
18 |
19 | enum CodingKeys: String, CodingKey {
20 | case name
21 | case model
22 | case outputs
23 | }
24 |
25 | enum OutputType: String, Codable {
26 | case stdout
27 | case variable
28 | case file
29 | }
30 |
31 | enum OutputMethod: String, Codable {
32 | case replace
33 | case append
34 | case prepend
35 | }
36 |
37 | struct Output: Codable {
38 | var type: OutputType
39 | var name: String?
40 | var method: OutputMethod?
41 | }
42 |
43 | init?(fileURL: URL) {
44 | do {
45 | let str = try String(contentsOf: fileURL, encoding: .utf8)
46 | let lines = str.components(separatedBy: .newlines)
47 |
48 | var parsingHeader = true
49 | var headerArr = [String]()
50 | var textArr = [String]()
51 |
52 | for line in lines {
53 | if parsingHeader {
54 | if line.hasPrefix("---") {
55 | parsingHeader = false
56 | } else {
57 | headerArr.append(line)
58 | }
59 | } else {
60 | textArr.append(line)
61 | }
62 | }
63 |
64 | guard let yamlData = headerArr.joined(separator: "\n").data(using: .utf8) else { return nil }
65 | let yaml = try YAMLDecoder().decode(Prompt.self, from: yamlData)
66 | self = yaml
67 |
68 | text = textArr.joined(separator: "\n")
69 | } catch {
70 | print(error)
71 | return nil
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/passage/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // Passage
4 | //
5 | // Created by Tyler Hall on 2/14/25.
6 | //
7 |
8 | import Foundation
9 | import ArgumentParser
10 |
11 | struct Passage: ParsableCommand {
12 |
13 | @Argument(help: "Path to the folder of text prompts")
14 | var promptsFolder: String
15 |
16 | @Option(name: .shortAndLong, help: "Path to initial text input")
17 | var inputFile: String?
18 |
19 | @Option(name: .shortAndLong, help: "Path to output folder")
20 | var outputFolder: String?
21 |
22 | func run() throws {
23 | var initialInput: String
24 | if let inputFile = inputFile {
25 | guard let str = try? String(contentsOfFile: inputFile, encoding: .utf8) else {
26 | print("Could not read input file at", inputFile)
27 | Passage.exit()
28 | }
29 | initialInput = str
30 | } else {
31 | let stdin = FileHandle.standardInput.readDataToEndOfFile()
32 | guard let str = String(data: stdin, encoding: .utf8) else {
33 | print("Could not read stdin")
34 | Passage.exit()
35 | }
36 | initialInput = str
37 | }
38 |
39 | var prompts = [Prompt]()
40 | let urls = try textFiles(in: promptsFolder)
41 | for url in urls {
42 | if let prompt = Prompt(fileURL: url) {
43 | prompts.append(prompt)
44 | }
45 | }
46 |
47 | let executor = PromptExecutor(initialInput: initialInput, prompts: prompts, ouputFolder: outputFolder)
48 | executor.runPrompts()
49 | }
50 |
51 | private func textFiles(in folderPath: String) throws -> [URL] {
52 | let textFileExtensions = ["txt", "md", "mdown", "markdown", "yml", "yaml"]
53 | let fileManager = FileManager.default
54 | let enumerator = fileManager.enumerator(atPath: folderPath)
55 | var urls: [URL] = []
56 |
57 | while let element = enumerator?.nextObject() as? String {
58 | let url = URL(fileURLWithPath: folderPath).appendingPathComponent(element)
59 | let ext = url.pathExtension.lowercased()
60 | if textFileExtensions.contains(ext) {
61 | urls.append(url)
62 | }
63 | }
64 |
65 | return urls.sorted { $0.path < $1.path }
66 | }
67 | }
68 |
69 | Passage.main()
70 |
--------------------------------------------------------------------------------
/passage/PromptExecutor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PromptExecutor.swift
3 | // Passage
4 | //
5 | // Created by Tyler Hall on 2/14/25.
6 | //
7 |
8 | import Foundation
9 |
10 | class PromptExecutor {
11 |
12 | private let defaultAPIBaseURLStr = "http://127.0.0.1:1234/v1"
13 | private let defaultAPIKey = "12345"
14 |
15 | private var initialInput: String
16 | private var prompts: [Prompt]
17 | private var memory: [String: String] = [:]
18 | private var outputFolder: String?
19 |
20 | init(initialInput: String, prompts: [Prompt], ouputFolder: String? = nil) {
21 | self.initialInput = initialInput
22 | self.prompts = prompts
23 | self.outputFolder = ouputFolder
24 | }
25 |
26 | func runPrompts() {
27 | for prompt in prompts {
28 | var message = prompt.text.replacingOccurrences(of: "{{input}}", with: initialInput)
29 | for (key, val) in memory {
30 | let needle = "{{\(key)}}"
31 | message = message.replacingOccurrences(of: needle, with: val)
32 | }
33 |
34 | var response: String
35 | if let model = prompt.model {
36 | response = synchronousLLMRequest(message: message, prompt: prompt, model: model)
37 | } else { // If no model, passthrough
38 | response = message
39 | }
40 |
41 | for output in prompt.outputs {
42 | switch output.type {
43 | case .stdout:
44 | print(response)
45 | case .variable:
46 | if let name = output.name, let method = output.method {
47 | switch method {
48 | case .replace:
49 | memory[name] = response
50 | case .append:
51 | memory[name] = (memory[name] == nil) ? response : (memory[name]! + "\n" + response)
52 | case .prepend:
53 | memory[name] = (memory[name] == nil) ? response : (response + "\n" + memory[name]!)
54 | }
55 | }
56 | case .file:
57 | if let filename = output.name, let method = output.method {
58 | switch method {
59 | case .replace:
60 | writeToFile(filename: filename, content: response)
61 | case .append:
62 | appendToFile(filename: filename, content: response)
63 | case .prepend:
64 | prependToFile(filename: filename, content: response)
65 | }
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
72 | private func synchronousLLMRequest(message: String, prompt: Prompt, model: String) -> String {
73 | let apiBaseURLStr = prompt.apiBaseURL ?? defaultAPIBaseURLStr
74 | let apiKey = prompt.apiToken ?? defaultAPIKey
75 |
76 | guard let url = URL(string: "\(apiBaseURLStr)/chat/completions") else {
77 | print("Invalid apiBaseURL: \(apiBaseURLStr)")
78 | exit(EXIT_FAILURE)
79 | }
80 |
81 | var request = URLRequest(url: url)
82 | request.httpMethod = "POST"
83 | request.addValue("application/json", forHTTPHeaderField: "Content-Type")
84 | request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
85 |
86 | let payload: [String: Any] = [
87 | "model": model,
88 | "messages": [
89 | ["role": "user", "content": message]
90 | ]
91 | ]
92 |
93 | do {
94 | request.httpBody = try JSONSerialization.data(withJSONObject: payload, options: [])
95 | } catch {
96 | print("Failed to parse JSON response", error)
97 | exit(EXIT_FAILURE)
98 | }
99 |
100 | let semaphore = DispatchSemaphore(value: 0)
101 | var result = ""
102 |
103 | let config = URLSessionConfiguration.default
104 | config.timeoutIntervalForRequest = TimeInterval.infinity
105 | config.timeoutIntervalForResource = TimeInterval.infinity
106 | let session = URLSession(configuration: config)
107 |
108 | let task = session.dataTask(with: request) { data, response, error in
109 | defer { semaphore.signal() }
110 |
111 | if let error = error {
112 | print("Request error:", error)
113 | exit(EXIT_FAILURE)
114 | }
115 |
116 | guard let data = data else {
117 | print("No response data")
118 | exit(EXIT_FAILURE)
119 | }
120 |
121 | do {
122 | if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
123 | let choices = json["choices"] as? [[String: Any]],
124 | let message = choices.first?["message"] as? [String: Any],
125 | let content = message["content"] as? String {
126 | result = content.trimmingCharacters(in: .whitespacesAndNewlines)
127 | } else {
128 | print("Unexpected response format", error ?? "")
129 | exit(EXIT_FAILURE)
130 | }
131 | } catch {
132 | print("Failed to parse response:", error)
133 | exit(EXIT_FAILURE)
134 | }
135 | }
136 |
137 | task.resume()
138 | semaphore.wait()
139 |
140 | return result
141 | }
142 |
143 | private func writeToFile(filename: String, content: String) {
144 | let folderPath = outputFolder ?? FileManager.default.currentDirectoryPath
145 | let fileURL = URL(filePath: folderPath).appending(path: filename, directoryHint: .notDirectory)
146 | do {
147 | try content.write(to: fileURL, atomically: true, encoding: .utf8)
148 | } catch {
149 | print("Failed to write output to", fileURL.path)
150 | exit(EXIT_FAILURE)
151 | }
152 | }
153 |
154 | private func appendToFile(filename: String, content: String) {
155 | let folderPath = outputFolder ?? FileManager.default.currentDirectoryPath
156 | let fileURL = URL(filePath: folderPath).appending(path: filename, directoryHint: .notDirectory)
157 |
158 | var newContents: String
159 | if let existingFileContents = try? String(contentsOf: fileURL, encoding: .utf8) {
160 | newContents = existingFileContents + "\n" + content
161 | } else {
162 | newContents = content
163 | }
164 | writeToFile(filename: filename, content: newContents)
165 | }
166 |
167 | private func prependToFile(filename: String, content: String) {
168 | let folderPath = outputFolder ?? FileManager.default.currentDirectoryPath
169 | let fileURL = URL(filePath: folderPath).appending(path: filename, directoryHint: .notDirectory)
170 |
171 | var newContents: String
172 | if let existingFileContents = try? String(contentsOf: fileURL, encoding: .utf8) {
173 | newContents = content + "\n" + existingFileContents
174 | } else {
175 | newContents = content
176 | }
177 | writeToFile(filename: filename, content: newContents)
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/passage.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | BAD8129A2DA83D6E0059983F /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = BAD812992DA83D6E0059983F /* ArgumentParser */; };
11 | C6EF60452DAB685F008FFBD7 /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = C6EF60442DAB685F008FFBD7 /* Yams */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | BAD8128C2DA83C240059983F /* CopyFiles */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = /usr/share/man/man1/;
19 | dstSubfolderSpec = 0;
20 | files = (
21 | );
22 | runOnlyForDeploymentPostprocessing = 1;
23 | };
24 | /* End PBXCopyFilesBuildPhase section */
25 |
26 | /* Begin PBXFileReference section */
27 | BAD8128E2DA83C240059983F /* passage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = passage; sourceTree = BUILT_PRODUCTS_DIR; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFileSystemSynchronizedRootGroup section */
31 | BAD812902DA83C240059983F /* passage */ = {
32 | isa = PBXFileSystemSynchronizedRootGroup;
33 | path = passage;
34 | sourceTree = "";
35 | };
36 | /* End PBXFileSystemSynchronizedRootGroup section */
37 |
38 | /* Begin PBXFrameworksBuildPhase section */
39 | BAD8128B2DA83C240059983F /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | C6EF60452DAB685F008FFBD7 /* Yams in Frameworks */,
44 | BAD8129A2DA83D6E0059983F /* ArgumentParser in Frameworks */,
45 | );
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | /* End PBXFrameworksBuildPhase section */
49 |
50 | /* Begin PBXGroup section */
51 | BAD812852DA83C240059983F = {
52 | isa = PBXGroup;
53 | children = (
54 | BAD812902DA83C240059983F /* passage */,
55 | BAD8128F2DA83C240059983F /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | BAD8128F2DA83C240059983F /* Products */ = {
60 | isa = PBXGroup;
61 | children = (
62 | BAD8128E2DA83C240059983F /* passage */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | /* End PBXGroup section */
68 |
69 | /* Begin PBXNativeTarget section */
70 | BAD8128D2DA83C240059983F /* passage */ = {
71 | isa = PBXNativeTarget;
72 | buildConfigurationList = BAD812952DA83C240059983F /* Build configuration list for PBXNativeTarget "passage" */;
73 | buildPhases = (
74 | BAD8128A2DA83C240059983F /* Sources */,
75 | BAD8128B2DA83C240059983F /* Frameworks */,
76 | BAD8128C2DA83C240059983F /* CopyFiles */,
77 | );
78 | buildRules = (
79 | );
80 | dependencies = (
81 | );
82 | fileSystemSynchronizedGroups = (
83 | BAD812902DA83C240059983F /* passage */,
84 | );
85 | name = passage;
86 | packageProductDependencies = (
87 | BAD812992DA83D6E0059983F /* ArgumentParser */,
88 | C6EF60442DAB685F008FFBD7 /* Yams */,
89 | );
90 | productName = prompter;
91 | productReference = BAD8128E2DA83C240059983F /* passage */;
92 | productType = "com.apple.product-type.tool";
93 | };
94 | /* End PBXNativeTarget section */
95 |
96 | /* Begin PBXProject section */
97 | BAD812862DA83C240059983F /* Project object */ = {
98 | isa = PBXProject;
99 | attributes = {
100 | BuildIndependentTargetsInParallel = 1;
101 | LastSwiftUpdateCheck = 1630;
102 | LastUpgradeCheck = 1630;
103 | TargetAttributes = {
104 | BAD8128D2DA83C240059983F = {
105 | CreatedOnToolsVersion = 16.3;
106 | };
107 | };
108 | };
109 | buildConfigurationList = BAD812892DA83C240059983F /* Build configuration list for PBXProject "passage" */;
110 | developmentRegion = en;
111 | hasScannedForEncodings = 0;
112 | knownRegions = (
113 | en,
114 | Base,
115 | );
116 | mainGroup = BAD812852DA83C240059983F;
117 | minimizedProjectReferenceProxies = 1;
118 | packageReferences = (
119 | BAD812982DA83D6E0059983F /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
120 | C6EF60432DAB685F008FFBD7 /* XCRemoteSwiftPackageReference "Yams" */,
121 | );
122 | preferredProjectObjectVersion = 77;
123 | productRefGroup = BAD8128F2DA83C240059983F /* Products */;
124 | projectDirPath = "";
125 | projectRoot = "";
126 | targets = (
127 | BAD8128D2DA83C240059983F /* passage */,
128 | );
129 | };
130 | /* End PBXProject section */
131 |
132 | /* Begin PBXSourcesBuildPhase section */
133 | BAD8128A2DA83C240059983F /* Sources */ = {
134 | isa = PBXSourcesBuildPhase;
135 | buildActionMask = 2147483647;
136 | files = (
137 | );
138 | runOnlyForDeploymentPostprocessing = 0;
139 | };
140 | /* End PBXSourcesBuildPhase section */
141 |
142 | /* Begin XCBuildConfiguration section */
143 | BAD812932DA83C240059983F /* Debug */ = {
144 | isa = XCBuildConfiguration;
145 | buildSettings = {
146 | ALWAYS_SEARCH_USER_PATHS = NO;
147 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
148 | CLANG_ANALYZER_NONNULL = YES;
149 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
150 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
151 | CLANG_ENABLE_MODULES = YES;
152 | CLANG_ENABLE_OBJC_ARC = YES;
153 | CLANG_ENABLE_OBJC_WEAK = YES;
154 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
155 | CLANG_WARN_BOOL_CONVERSION = YES;
156 | CLANG_WARN_COMMA = YES;
157 | CLANG_WARN_CONSTANT_CONVERSION = YES;
158 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
159 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
160 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
161 | CLANG_WARN_EMPTY_BODY = YES;
162 | CLANG_WARN_ENUM_CONVERSION = YES;
163 | CLANG_WARN_INFINITE_RECURSION = YES;
164 | CLANG_WARN_INT_CONVERSION = YES;
165 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
166 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
167 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
168 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
169 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
170 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
171 | CLANG_WARN_STRICT_PROTOTYPES = YES;
172 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
173 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
174 | CLANG_WARN_UNREACHABLE_CODE = YES;
175 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
176 | COPY_PHASE_STRIP = NO;
177 | DEBUG_INFORMATION_FORMAT = dwarf;
178 | ENABLE_STRICT_OBJC_MSGSEND = YES;
179 | ENABLE_TESTABILITY = YES;
180 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
181 | GCC_C_LANGUAGE_STANDARD = gnu17;
182 | GCC_DYNAMIC_NO_PIC = NO;
183 | GCC_NO_COMMON_BLOCKS = YES;
184 | GCC_OPTIMIZATION_LEVEL = 0;
185 | GCC_PREPROCESSOR_DEFINITIONS = (
186 | "DEBUG=1",
187 | "$(inherited)",
188 | );
189 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
191 | GCC_WARN_UNDECLARED_SELECTOR = YES;
192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
193 | GCC_WARN_UNUSED_FUNCTION = YES;
194 | GCC_WARN_UNUSED_VARIABLE = YES;
195 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
196 | MACOSX_DEPLOYMENT_TARGET = 15.4;
197 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
198 | MTL_FAST_MATH = YES;
199 | ONLY_ACTIVE_ARCH = YES;
200 | SDKROOT = macosx;
201 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
202 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
203 | };
204 | name = Debug;
205 | };
206 | BAD812942DA83C240059983F /* Release */ = {
207 | isa = XCBuildConfiguration;
208 | buildSettings = {
209 | ALWAYS_SEARCH_USER_PATHS = NO;
210 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
211 | CLANG_ANALYZER_NONNULL = YES;
212 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
214 | CLANG_ENABLE_MODULES = YES;
215 | CLANG_ENABLE_OBJC_ARC = YES;
216 | CLANG_ENABLE_OBJC_WEAK = YES;
217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
218 | CLANG_WARN_BOOL_CONVERSION = YES;
219 | CLANG_WARN_COMMA = YES;
220 | CLANG_WARN_CONSTANT_CONVERSION = YES;
221 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
223 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
224 | CLANG_WARN_EMPTY_BODY = YES;
225 | CLANG_WARN_ENUM_CONVERSION = YES;
226 | CLANG_WARN_INFINITE_RECURSION = YES;
227 | CLANG_WARN_INT_CONVERSION = YES;
228 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
229 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
230 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
232 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
233 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
234 | CLANG_WARN_STRICT_PROTOTYPES = YES;
235 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
236 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
237 | CLANG_WARN_UNREACHABLE_CODE = YES;
238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
239 | COPY_PHASE_STRIP = NO;
240 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
241 | ENABLE_NS_ASSERTIONS = NO;
242 | ENABLE_STRICT_OBJC_MSGSEND = YES;
243 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
244 | GCC_C_LANGUAGE_STANDARD = gnu17;
245 | GCC_NO_COMMON_BLOCKS = YES;
246 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
247 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
248 | GCC_WARN_UNDECLARED_SELECTOR = YES;
249 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
250 | GCC_WARN_UNUSED_FUNCTION = YES;
251 | GCC_WARN_UNUSED_VARIABLE = YES;
252 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
253 | MACOSX_DEPLOYMENT_TARGET = 15.4;
254 | MTL_ENABLE_DEBUG_INFO = NO;
255 | MTL_FAST_MATH = YES;
256 | SDKROOT = macosx;
257 | SWIFT_COMPILATION_MODE = wholemodule;
258 | };
259 | name = Release;
260 | };
261 | BAD812962DA83C240059983F /* Debug */ = {
262 | isa = XCBuildConfiguration;
263 | buildSettings = {
264 | CODE_SIGN_STYLE = Automatic;
265 | MACOSX_DEPLOYMENT_TARGET = 14.6;
266 | PRODUCT_NAME = "$(TARGET_NAME)";
267 | SWIFT_VERSION = 5.0;
268 | };
269 | name = Debug;
270 | };
271 | BAD812972DA83C240059983F /* Release */ = {
272 | isa = XCBuildConfiguration;
273 | buildSettings = {
274 | CODE_SIGN_STYLE = Automatic;
275 | MACOSX_DEPLOYMENT_TARGET = 14.6;
276 | PRODUCT_NAME = "$(TARGET_NAME)";
277 | SWIFT_VERSION = 5.0;
278 | };
279 | name = Release;
280 | };
281 | /* End XCBuildConfiguration section */
282 |
283 | /* Begin XCConfigurationList section */
284 | BAD812892DA83C240059983F /* Build configuration list for PBXProject "passage" */ = {
285 | isa = XCConfigurationList;
286 | buildConfigurations = (
287 | BAD812932DA83C240059983F /* Debug */,
288 | BAD812942DA83C240059983F /* Release */,
289 | );
290 | defaultConfigurationIsVisible = 0;
291 | defaultConfigurationName = Release;
292 | };
293 | BAD812952DA83C240059983F /* Build configuration list for PBXNativeTarget "passage" */ = {
294 | isa = XCConfigurationList;
295 | buildConfigurations = (
296 | BAD812962DA83C240059983F /* Debug */,
297 | BAD812972DA83C240059983F /* Release */,
298 | );
299 | defaultConfigurationIsVisible = 0;
300 | defaultConfigurationName = Release;
301 | };
302 | /* End XCConfigurationList section */
303 |
304 | /* Begin XCRemoteSwiftPackageReference section */
305 | BAD812982DA83D6E0059983F /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
306 | isa = XCRemoteSwiftPackageReference;
307 | repositoryURL = "https://github.com/apple/swift-argument-parser.git";
308 | requirement = {
309 | kind = upToNextMajorVersion;
310 | minimumVersion = 1.5.0;
311 | };
312 | };
313 | C6EF60432DAB685F008FFBD7 /* XCRemoteSwiftPackageReference "Yams" */ = {
314 | isa = XCRemoteSwiftPackageReference;
315 | repositoryURL = "https://github.com/jpsim/Yams";
316 | requirement = {
317 | kind = upToNextMajorVersion;
318 | minimumVersion = 5.3.1;
319 | };
320 | };
321 | /* End XCRemoteSwiftPackageReference section */
322 |
323 | /* Begin XCSwiftPackageProductDependency section */
324 | BAD812992DA83D6E0059983F /* ArgumentParser */ = {
325 | isa = XCSwiftPackageProductDependency;
326 | package = BAD812982DA83D6E0059983F /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
327 | productName = ArgumentParser;
328 | };
329 | C6EF60442DAB685F008FFBD7 /* Yams */ = {
330 | isa = XCSwiftPackageProductDependency;
331 | package = C6EF60432DAB685F008FFBD7 /* XCRemoteSwiftPackageReference "Yams" */;
332 | productName = Yams;
333 | };
334 | /* End XCSwiftPackageProductDependency section */
335 | };
336 | rootObject = BAD812862DA83C240059983F /* Project object */;
337 | }
338 |
--------------------------------------------------------------------------------